- 論壇徽章:
- 0
|
Sniffer分析文檔
1.1 DNS基礎(chǔ)
DNS的名字空間和Unix的文件系統(tǒng)相似,也具有層次結(jié)構(gòu)。圖1 - 1 顯示了這種層次的組織形式。
每個結(jié)點(圖1-1中的圓圈)有一個至多6 3個字符長的標識。這顆樹的樹根是沒有任何標識的特殊結(jié)點。命名標識中一律不區(qū)分大寫和小寫。命名樹上任何一個結(jié)點的域名就是將從該結(jié)點到最高層的域名串連起來,中間使用一個點“.”分隔這些域名(注意這和U n i x文件系統(tǒng)路徑的形成不同,文件路徑是由樹根依次向下的形成的)。域名樹中的每個結(jié)點必須有一個唯一的域名,但域名樹中的不同結(jié)點可使用相同的標識。
以點“ .”結(jié)尾的域名稱為絕對域名或完全合格的域名FQDN(Full Qualified Domain
Name),例如sun.tuc.noao.edu .。如果一個域名不以點結(jié)尾,則認為該域名是不完全的。
如何使域名完整依賴于使用的DNS軟件。如果不完整的域名由兩個或兩個以上的標號組成,
圖1-1 DNS層次組織
1.1.1 DNS查詢和響應(yīng)報文格式
DNS定義了一個用于查詢和響應(yīng)的報文格式。圖1 - 2顯示這個報文的總體格式:
圖1-2 DNS查詢和響應(yīng)的一般格式
這個報文由1 2字節(jié)長的首部和4個長度可變的字段組成。標識字段由客戶程序設(shè)置并由服務(wù)器返回結(jié)果?蛻舫绦蛲ㄟ^它來確定響應(yīng)與查詢是否匹配。
16 bit的標志字段被劃分為若干子字段,如圖1 - 3所示。
QR
opcode
AA
TC
RD
RA
(zero)
rcode
1 4 1 1 1 1 3 4
圖1-3 DNS報文首部中的標志字段
我們從最左位開始依次介紹各子字段:
ü QR 是1 bit字段:0表示查詢報文,1表示響應(yīng)報文。
ü opcode是一個4 bit字段:通常值為0(標準查詢),其他值為1(反向查詢)和2(服務(wù)器狀態(tài)請求)。
ü AA是1 bit標志,表示“授權(quán)回答(authoritative answer)”。該名字服務(wù)器是授權(quán)于該域的。
ü TC是1 bit字段,表示“可截斷的(truncated)”。使用U D P時,它表示當應(yīng)答的總長度超過512字節(jié)時,只返回前512個字節(jié)。
ü RD是1 bit字段表示“期望遞歸recursion desired)”。該比特能在一個查詢中設(shè)置,并在響應(yīng)中返回。這個標志告訴名字服務(wù)器必須處理這個查詢,也稱為一個遞歸查詢。如果該位為0,且被請求的名字服務(wù)器沒有一個授權(quán)回答,它就返回一個能解答該查詢的
ü 其他名字服務(wù)器列表,這稱為迭代查詢。在后面的例子中,我們將看到這兩種類型查詢的例子。
ü RA是1 bit字段,表示“可用遞歸”。如果名字服務(wù)器支持遞歸查詢,則在響應(yīng)中將該比特設(shè)置為1。在后面的例子中可看到大多數(shù)名字服務(wù)器都提供遞歸查詢,除了某些根服務(wù)器。
ü 隨后的3 bit字段必須為0。
ü rcode是一個4 bit的返回碼字段。通常的值為0(沒有差錯)和3(名字差錯)。名字差錯
ü 只有從一個授權(quán)名字服務(wù)器上返回,它表示在查詢中制定的域名不存在。
ü 隨后的4個16 bit 字段說明最后4個變長字段中包含的條目數(shù)。對于查詢報文,問題(question)數(shù)通常是1,而其他3項則均為0。類似地,對于應(yīng)答報文,回答數(shù)至少是1,剩下的兩項可以是0或非0。
1.1.2 DNS查詢報文中的問題部分
問題部分中每個問題的格式如圖1 4 - 5所示,通常只有一個問題。
圖1-4 DNS查詢報文中問題部分的格式
查詢名是要查找的名字,它是一個或多個標識符的序列。每個標識符以首字節(jié)的計數(shù)值來說明隨后標識符的字節(jié)長度,每個名字以最后字節(jié)為0結(jié)束,長度為0的標識符是根標識符。計數(shù)字節(jié)的值必須是0 ~ 6 3的數(shù),因為標識符的最大長度僅為6 3(在本節(jié)的后面我們將看到計數(shù)字節(jié)的最高兩比特為1,即值1 9 2 ~ 2 5 5,將用于壓縮格式)。不像我們已經(jīng)看到的許多其他報文格式,該字段無需以整32 bit邊界結(jié)束,即無需填充字節(jié)。
圖1 - 5顯示了如何存儲域名gemini.tuc.noao.edu。
圖1-5域名gemini.tuc.noao.edu的表示
每個問題有一個查詢類型,而每個響應(yīng)(也稱一個資源記錄,我們下面將談到)也有一個類型。大約有2 0個不同的類型值,其中的一些目前已經(jīng)過時。圖1-6顯示了其中的一些值。查詢類型是類型的一個超集(superset):圖中顯示的類型值中只有兩個能用于查詢類型。
圖1-6 DNS問題和響應(yīng)的類型值和查詢類型值
最常用的查詢類型是A類型,表示期望獲得查詢名的I P地址。一個P T R查詢則請求獲得一個I P地址對應(yīng)的域名。這是一個指針查詢,我們將在1 4 . 5節(jié)介紹。其他的查詢類型將在1 4 . 6節(jié)介紹。
查詢類通常是1,指互聯(lián)網(wǎng)地址(某些站點也支持其他非I P地址)。
1.1.2 DNS響應(yīng)報文中的資源記錄部分
DNS報文中最后的三個字段,回答字段、授權(quán)字段和附加信息字段,均采用一種稱為資源記錄RR(Resource Record)的相同格式。圖1-7顯示了資源記錄的格式。
圖1-7 DNS資源記錄格式
域名是記錄中資源數(shù)據(jù)對應(yīng)的名字。它的格式和前面介紹的查詢名字段格式(圖1 - 2)相同。類型說明R R的類型碼。它的值和前面介紹的查詢類型值是一樣的。類通常為1,指Internet數(shù)據(jù)。生存時間字段是客戶程序保留該資源記錄的秒數(shù)。資源記錄通常的生存時間值為2天。資源數(shù)據(jù)長度說明資源數(shù)據(jù)的數(shù)量。該數(shù)據(jù)的格式依賴于類型字段的值。對于類型1(A記錄)資源數(shù)據(jù)是4字節(jié)的IP地址。
現(xiàn)在已經(jīng)介紹了DNS查詢和響應(yīng)的基本格式,我們將通過分析sniffer程序的DNS報文解碼過程來觀察具體的程序?qū)崿F(xiàn)。
1.2 DNS解碼過程
DNS解碼的過程實際是對DNS數(shù)據(jù)報處理的過程,解碼程序處理的DNS數(shù)據(jù)由監(jiān)聽程序通過Plugin_data數(shù)據(jù)結(jié)構(gòu)提供。下面我們就以sniffer程序中的解碼程序dns_plugin.plug為例詳細說明DNS的解碼過程。
1.2.1 數(shù)據(jù)定義
10 struct PL_DNS_header
11 {
12 unsigned short id, flags;
13 unsigned short nr_quest, nr_answ_RR, nr_auth_RR, nr_add_RR;
14 };
15 int PL_pos_max;
16
17 #define PL_DNS_QR 0x8000
18 #define PL_DNS_OPCODE 0x7800
19 #define PL_DNS_AA 0x0400
20 #define PL_DNS_TC 0x0200
21 #define PL_DNS_RD 0x0100
22 #define PL_DNS_RA 0x0080
23 #define PL_DNS_RCODE 0x000F
圖1.2.1.1
10-14行定義DNS數(shù)據(jù)報的報頭,DNS數(shù)據(jù)報報頭由12字節(jié)組成(詳見1.1中的DNS基礎(chǔ)),17-23行定義了報頭中16位的標志字段的值。
1.2.2 PL_DNS_plugin函數(shù)
71 void PL_DNS_plugin (struct Plugin_data *PLD)
72 {
73 struct IP_header *dns_iphead;
74 struct UDP_header *dns_udphead;
75 struct PL_DNS_header *dns_dnshead;
76 int i, j, dec_pos, answers, count, udp_start, len;
77 long pos;
78 unsigned char *so,*dest, *dns_p, *dns_buffer;
79 unsigned short fl, *r_dlen;
80 unsigned short *type, *class;
81
82 dns_buffer=PLD->PL_packet;
83 udp_start = PLD->PL_info.IP_len;
84 len=PLD->PL_info.IP_len + PLD->PL_info.UDP_len + PLD->PL_info.DATA_len;
85 dns_iphead= (struct IP_header *) dns_buffer;
86 dns_udphead= (struct UDP_header *) (dns_buffer+udp_start);
87 dns_dnshead= (struct DNS_header *) (dns_buffer+udp_start+sizeof(struct U
DP_header));
88
89 PL_pos_max = PLD->PL_info.DATA_len - 12;
90
91 so=(unsigned char *)&(dns_iphead->source);
92 dest=(unsigned char *)&(dns_iphead->destination);
93 if((ntohs(dns_udphead->source)!=53)&&(ntohs(dns_udphead->destination)!=5
3))
94 return;
73-80行定義變量,82-87行處理PLD數(shù)據(jù)結(jié)構(gòu),dns_buffer指針變量指向數(shù)據(jù)報的起始位置(包括IP頭、UDP頭、DNS頭信息和數(shù)據(jù)),udp_start整型變量記錄udp數(shù)據(jù)頭在IP數(shù)據(jù)報中的偏移量(等于IP數(shù)據(jù)頭的程度),len記錄dns_buffer緩存的長度,dns_iphead結(jié)構(gòu)指針指向dns_buffer的起始位置,dns­udphead結(jié)構(gòu)指針指向dns_buffer中udp數(shù)據(jù)報的起始位置,dns_dnshead結(jié)構(gòu)指針指向dns_buffer中DNS數(shù)據(jù)報的起始位置。
89行的Pl_pos_max變量記錄DNS數(shù)據(jù)報中的實際的數(shù)據(jù)長度(除了頭部信息的其他數(shù)據(jù))。
91-94行獲取IP數(shù)據(jù)報的源地址和目的地址并存入變量so和dest,然后判斷udp數(shù)據(jù)報的源端口和目的端口是否為通用端口53,不是則返回。
95 printf("DNS Sniffit Plugin Report:\n");
96 printf("Packet: %u.%u.%u.%u %u -> %u.%u.%u.%u %u\n",
97 so[0],so[1],so[2],so[3],ntohs(dns_udphead->source),
98 dest[0],dest[1],dest[2],dest[3],ntohs(dns_udphead->desti
nation));
99
100 printf("ID: %d \n",ntohs(dns_dnshead->id));
101 fl=ntohs(dns_dnshead->flags);
102
103 printf(" STATUS: %s ",(fl & PL_DNS_QR)? "Answer": "Query");
104 printf("(opcode: %X) , ",(fl & PL_DNS_OPCODE)>>11);
105 printf("%s , ",(fl & PL_DNS_AA)? "Auth. A.": "");
106 printf("%s , ",(fl & PL_DNS_TC)? "TRUNC": "");
107 printf("%s , ",(fl & PL_DNS_RD)? "Rec. Desired": "");
108 printf("%s , ",(fl & PL_DNS_RA)? "rec. Avail.": "rec. NOT Av.");
109 printf("ret: %d\n",(fl & PL_DNS_RCODE));
110
111 printf(" Q: %d Answ: %d Auth: %d Add: %d",
112 ntohs(dns_dnshead->nr_quest),
113 ntohs(dns_dnshead->nr_answ_RR),
114 ntohs(dns_dnshead->nr_auth_RR),
115 ntohs(dns_dnshead->nr_add_RR));
116
10-115向終端輸出DNS數(shù)據(jù)報的頭部信息。
117 dns_p=(dns_buffer+udp_start+sizeof(struct UDP_header)+12);
118 dec_pos=0;
119 for(i=0;inr_quest);i++)
120 {
121 printf("\n Query: ");
122 dec_pos=PL_DNS_decode(dns_p,dec_pos,NULL,0);
123 if(dec_pos
124 type=(unsigned short *) &(dns_p[dec_pos]);
125 class=(unsigned short *) &(dns_p[dec_pos+2]);
126 printf("\n Type: %d Class: %s",ntohs(*type),(ntohs(*class))?"IP":
"Unknown");
127 dec_pos+=4;
128 }
129
117-128行對DNS數(shù)據(jù)報中的數(shù)據(jù)解碼,dns_p指向DNS數(shù)據(jù)報緊接頭部信息的實際數(shù)據(jù)的起始位置,dec_pos記錄被解碼數(shù)據(jù)的當前位置。接下來的for循環(huán)調(diào)用解碼函數(shù)PL_DNS_decode對dns_p指向的數(shù)據(jù)解碼(dns_p指向的是查詢響應(yīng)報文段)。
130 if(fl & PL_DNS_TC)
131 {
132 printf("Truncated packet, not displayed...\n");
133 return;
134 }
135
136 /* dec_pos at beginning first answer field */
137 answers=ntohs(dns_dnshead->nr_answ_RR)+ntohs(dns_dnshead->nr_auth_RR)+
138 ntohs(dns_dnshead->nr_add_RR);
139 for(i=0;i
140 {
141 printf("\n Answer %d/%d: ",i+1,answers);
142 dec_pos=PL_DNS_decode(dns_p,dec_pos,NULL,0);
143 if(dec_pos
144 type=(unsigned short *) &(dns_p[dec_pos]);
145 class=(unsigned short *) &(dns_p[dec_pos+2]);
146 printf("\n Type: %d Class: %s",ntohs(*type),(ntohs(*class))?"IP":
"Unknown");
147 dec_pos+=8;
148 r_dlen=(unsigned short *)&(dns_p[dec_pos]);
149 dec_pos+=2;
150 if(ntohs(*type)==1)
151 {printf("\n Data: ");
152 for(j=0;j
153 printf("%u.",(unsigned char)dns_p[dec_pos+j]);
154 }
155 dec_pos+=ntohs(*r_dlen);
156 }
157 printf("\n\n");
158 }
附錄A:全局數(shù)據(jù)結(jié)構(gòu)
Plugin_data{}
PL_info
PL_iphead
PL_tcphead
PL_udphead
PL_data[MTU]
PL_packet[MTU]
圖A.1
圖A.1的數(shù)據(jù)結(jié)構(gòu)主要將DNS解碼時所需的數(shù)據(jù)報信息傳給解碼程序,其中PL_info成員是由unwrap結(jié)構(gòu)定義的結(jié)構(gòu)變量,用來記錄TCP、UDP、ICMP、IP等數(shù)據(jù)報的頭部長度。接下來的三個數(shù)據(jù)成員PL_iphead、PL_tcphead、PL_udphead分別用來記錄IP數(shù)據(jù)頭、TCP數(shù)據(jù)頭和UDP數(shù)據(jù)頭。
本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u/26031/showart_574104.html |
|