1. 程式人生 > >DNS協議詳解

DNS協議詳解

一、前言
  foxmail新版中有一個《郵件特快專遞》的功能。起先搞不懂如何用,後來知道要在 工具->系統選項 那邊設定 本地DNS伺服器的IP地址。
  覺得這個新功能蠻好用的。不需要通過SMTP代理,可以直接通過本地往郵箱所在的郵件交換器傳送郵件。在暑假一開始想在VC++中實現這個功能。用IRIS截包後,發現程式後mx8.263.net傳送郵箱,不知道這個是什麼東西所以作罷。   後來才想到這個就是263.net的MX記錄主機,原來特快專遞的原理就是往這個主機上傳送資料就行。
  執行nslookup程式:
  set type=mx
  263.net
  有了,有了,得到結果:
  Non-authoritative answer:
  263.net MX preference = 10, mail exchanger = mx06.263.net
  263.net MX preference = 10, mail exchanger = mx08.263.net
  263.net MX preference = 10, mail exchanger = mx09.263.net
  263.net MX preference = 10, mail exchanger = mx11.263.net
  263.net MX preference = 10, mail exchanger = mx12.263.net
  263.net MX preference = 40, mail exchanger = mx03.263.net
  263.net MX preference = 10, mail exchanger = mx01.263.net
  沒有錯了。就是這個了。後來因為不知道怎麼實現nslookup的功能,就放棄了,學了半個多月的C#。後來偶然在網上查詢到了一些相關的文件。幾次實驗。把我的開發過程拿過來分享,我第一次寫教程性文件。所以不規範之處,請大家包涵。本文涉及的域名、郵箱及IP均為真實的。

二、DNS協議原理
  我認為,要想成為一個好的網路軟體程式設計師,必須得讀懂RFC文件。因為本文是面向大多廣泛程式愛好者,所以我儘量從細節上寫,如果高手的話,可以跳過此部分。
  DNS協議的相關RFC文件:
  RFC1034-《DOMAIN NAMES - CONCEPTS AND FACILITIES》
  RFC1035-《DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION》
  網上的計算機用形如 220.162.75.1 這樣稱為IP地址的數字串來標識一臺計算機。而如果每次訪問一臺計算機都是通過輸入這樣的東東來訪問,那不就太可怕了?以是出了DNS這樣的好東東,用要指示其繫結的IP地址,當我們在瀏覽器內輸入 http://zzsy.com 時,瀏覽器不知道網頁該到哪裡取,於是就向設定好的DNS伺服器查詢zzsy.com這個域名。DNS伺服器會先尋找自己的記錄庫,如果沒有發現就轉向上一級DNS伺服器進行查詢(轉發請求)。把找到後的IP告知你的瀏覽器。這裡邊瀏覽器查詢的記錄型別是A記錄。RFC1035文件第11頁中定義有16種記錄型別,而常見的有A(地址)記錄、CNAME(別名)記錄、MX(郵件交換)記錄。我們本篇要關心的是MX記錄。
  查詢的過程一般是:客戶向DNS伺服器的53埠傳送UDP報文,DNS伺服器收到後進行處理,並把結果記錄仍以UDP報文的形式返回過來。
  此UDP報文的一般格式:

+---------------------+
| 報文頭 |
+---------------------+
| 問題  | 向伺服器提出的查詢部分
+---------------------+
| 回答  | 伺服器回覆的資源記錄
+---------------------+
| 授權 | 權威的資源記錄
+---------------------+
| 格外的 | 格外的資源記錄
+---------------------+

  除了報文頭是固定的12位元組外,其他每一部分的長度均為不定位元組數。
  我們在這邊關心的是報文頭、問題、回答這三個部分。

  其中報文頭的格式:


1 1 1 1 1 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ID |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|QR| Opcode |AA|TC|RD|RA| Z | RCODE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QDCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ANCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| NSCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| ARCOUNT |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

  好傢伙,是什麼鬼畫符!
  其中最上邊是位的數字標識,0-15(注意,後邊的10-15寫成上下的形式了,一開始我楞沒看懂)。
  接下來是:
  ID:佔16位,2個位元組。此報文的編號,由客戶端指定。DNS回覆時帶上此標識,以指示處理的對應請應請求。
  QR:佔1位,1/8位元組。0代表查詢,1代表DNS回覆
  Opcode:佔4位,1/2位元組。指示查詢種類:0:標準查詢;1:反向查詢;2:伺服器狀態查詢;3-15:未使用。
  AA:佔1位,1/8位元組。是否權威回覆。
  TC:佔1位,1/8位元組。因為一個UDP報文為512位元組,所以該位指示是否截掉超過的部分。
  RD:佔1位,1/8位元組。此位在查詢中指定,回覆時相同。設定為1指示伺服器進行遞迴查詢。
  RA:佔1位,1/8位元組。由DNS回覆返回指定,說明DNS伺服器是否支援遞迴查詢。
  Z:佔3位,3/8位元組。保留欄位,必須設定為0。
  RCODE:佔4位,1/2位元組。由回覆時指定的返回碼:0:無差錯;1:格式錯;2:DNS出錯;3:域名不存在;4:DNS不支援這類查詢;5:DNS拒絕查詢;6-15:保留欄位。 
  QDCOUNT:佔16位,2位元組。一個無符號數指示查詢記錄的個數。
  ANCOUNT:佔16位,2位元組。一個無符號數指明回覆記錄的個數。
  NSCOUNT:佔16位,2位元組。一個無符號數指明權威記錄的個數。
  ARCOUNT:佔16位,2位元組。一個無符號數指明格外記錄的個數。

  其中每個查詢的資源記錄格式:


1 1 1 1 1 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| |
/ QNAME /
/ /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QTYPE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| QCLASS |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
  QNAME:不定長,表示要查詢的域名。(兩邊的方框用 / 來表示不定長)
  QTYPE:2位元組,根據RFC1035及nslookup的幫助文件,我定義以下列舉型別:
enum QueryType //查詢的資源記錄型別。
{
A=0x01, //指定計算機 IP 地址。
NS=0x02, //指定用於命名區域的 DNS 名稱伺服器。
MD=0x03, //指定郵件接收站(此型別已經過時了,使用MX代替)
MF=0x04, //指定郵件中轉站(此型別已經過時了,使用MX代替)
CNAME=0x05, //指定用於別名的規範名稱。
SOA=0x06, //指定用於 DNS 區域的“起始授權機構”。
MB=0x07, //指定郵箱域名。
MG=0x08, //指定郵件組成員。
MR=0x09, //指定郵件重新命名域名。
NULL=0x0A, //指定空的資源記錄
WKS=0x0B, //描述已知服務。
PTR=0x0C, //如果查詢是 IP 地址,則指定計算機名;否則指定指向其它資訊的指標。
HINFO=0x0D, //指定計算機 CPU 以及作業系統型別。
MINFO=0x0E, //指定郵箱或郵件列表資訊。
MX=0x0F, //指定郵件交換器。
TXT=0x10, //指定文字資訊。 
AAAA=0x1c,//IPV6資源記錄。
UINFO=0x64, //指定使用者資訊。
UID=0x65, //指定使用者識別符號。
GID=0x66, //指定組名的組識別符號。
ANY=0xFF //指定所有資料型別。
};
QTYPE:2位元組。 根據RFC1035及nslookup的幫助文件,我定義以下列舉型別:
enum QueryClass //指定資訊的協議組。
{
IN=0x01, //指定 Internet 類別。
CSNET=0x02, //指定 CSNET 類別。(已過時)
CHAOS=0x03, //指定 Chaos 類別。
HESIOD=0x04,//指定 MIT Athena Hesiod 類別。
ANY=0xFF //指定任何以前列出的萬用字元。
};

  QTYPE中的A,MX,CNAME為常用,QCLASS中的IN為常用。

  其中每個回覆的記錄格式:


1 1 1 1 1 1
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| |
/ /
/ NAME /
| |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| TYPE |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| CLASS |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| TTL |
| |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
| RDLENGTH |
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
/ RDATA /
/ /
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

  NAME:回覆查詢的域名,不定長。
  TYPE:回覆的型別。2位元組,與查詢同義。指示RDATA中的資源記錄型別。
  CLASS:回覆的類。2位元組,與查詢同義。指示RDATA中的資源記錄類。
  TTL:生存時間。4位元組,指示RDATA中的資源記錄在快取的生存時間。
  RDLENGTH:長度。2位元組,指示RDATA塊的長度。
  RDATA:資源記錄。不定義,依TYPE的不同,此記錄的格示不同,通常一個MX記錄是由一個2位元組的指示該郵件交換器的優先順序值及不定長的郵件交換器名組成的。

  這邊述說一下名稱的組合形式。名稱由多個標識序列組成,每一個標識序列的首位元組說明該識別符號的長度,接著用是ASCII碼錶示字元,多個序列之後由位元組0表示名字結束。其中某一個標識序列的首字元的長度若是0xC0的話,表示下一位元組指示不是識別符號序列,而是指示接下部分在本接收包內的偏移位置。
  比如 bbs.zzsy.com 以.分開bbs、zzsy、com三個部分。每個部分的長度為3、4、3
  在DNS報文中的形式就如 3 b b s 4 z z s y 3 c o m 0
  假如在包內的第12個位元組位置存在有 4 z z s y 3 c o m 0 這樣的名稱了。
  那此時有可能為:3 b b s 4 z z s y 0xC0 0x0C 這樣的形式。

三、DNS協議例項講解
  說了這麼多理論屁話,可能頭都有兩個大了吧。還是用一個例項的方法來說明吧。
  我選用著名的網路截包及協議分析工具IRIS 4.05,您可以從我的站點上下載:
  http://itboy.cn/data/Iris405Full.rar
  執行Iris,點選選單的Filters 選 Port標籤頁 運用 53 埠後點確定。
  點選Iris工具欄上的綠色執行圖示進行監聽。

  在windows中執行nslookup程式。
  輸入以下命令:
   set type=mx
  然後返回nslookup程式。
  再輸入命令:
   yahoo.com.cn
  會得到
   yahoo.com.cn MX preference = 20, mail exchanger = mx5.mail.yahoo.com
   yahoo.com.cn MX preference = 10, mail exchanger = mta-v1.mail.

=====================================================================


DNS報文格式:




該報文由12位元組的首部和4個長度可變的欄位組成。
標識欄位由客戶程式設定並有伺服器返回結果。
16bit的標誌欄位 如下:



QR:0表示查詢報文,1表示響應報文
Opcode:通常值為0(標準查詢),其他值為1(反向查詢)和2(伺服器狀態請求)。
AA:表示授權回答(authoritative answer).
TC:表示可截斷的(truncated)
RD:表示期望遞迴
RA:表示可用遞迴
隨後3bit必須為0
Rcode:返回碼,通常為0(沒有差錯)和3(名字差錯)
後面4個16bit欄位說明最後4個變長欄位中包含的條目數。

問題部分:
報文格式:




查詢名為要查詢的名字,它由一個或者多個標示符序列組成。每個標示符已首位元組數的計數值來說明該標示符長度,每個名字以0結束。計數字節數必須是0~63之間。該欄位無需填充位元組。如:gemini.tuc.noao.edu



每個問題有一個查詢型別,通常查詢型別為A(由名字獲得IP地址)或者PTR(獲得IP地址對應的域名)
資源記錄部分:
報文格式:
DNS最後3個欄位,回答欄位,授權欄位和附加資訊欄位均採用資源記錄RR(Resource Record)的相同格式。




域名是記錄中資源資料對應的名字。它的格式和查詢名欄位格式相同。
型別說明R R的型別碼。類通常為1,指I n t e r n e t資料。
生存時間

欄位是客戶程式保留該資源記錄的秒數。
資源資料長度說明資源資料的數量。該資料的格式依賴於型別欄位的值。對於型別1(A記錄)資源資料是4位元組的I P地址。

資料包DNS 查詢:(DNS query)
0000  00 19 56 6e 19 bf 00 17   a4 1a b2 e0 08 00 45 00 ..Vn.... ......E.
0010  00 3b ed c6 00 00 80 11   e3 c3 ac 15 0f 04 ac 15 .;...... ........
0020  01 f9 04 a9 00 35 00 27   2f bd 3e 3a 01 00 00 01 .....5.' /.>:....
0030   00 00 00 00 00 00 03 77   77 77 06 67 6f 6f 67 6c .......w ww.googl
0040   65 02 63 6e 00 00 01 00   01                      e.cn.... .   
說明:

前面三段分別為乙太網包頭,ip包頭和UDP包頭。
從0020行後面開始為DNS資料包.
3e 3a   為標識欄位
01 00 為標誌欄位,該欄位設定了TC表示該報文是可截斷的。
00 01   查詢報文數量為1。
00 00 00 00 00 00 表示回答,授權和額外資訊都為0。
03 77   77 77 06 67 6f 6f 67 6c 65 02 63 6e 00 表示查詢的名字為
www.google.com
00 01 為型別,1表示A查詢
00 01 為類,1表示Internet資料。

資料包 DNS response (DNS response)
0000  00 17 a4 1a b2 e0 00 19   56 6e 19 bf 08 00 45 00 ........ Vn....E.
0010  00 78 48 af 00 00 7d 11   8b 9e ac 15 01 f9 ac 15 .xH...}. ........
0020  0f 04 00 35 04 a9 00 64   75 db 3e 3a 81 80 00 01 ...5...d u.>:....
0030   00 03 00 00 00 00 03 77   77 77 06 67 6f 6f 67 6c .......w ww.googl
0040   65 02 63 6e 00 00 01 00   01 c0 0c 00 05 00 01 00 e.cn.... ........
0050   00 05 42 00 11 02 63 6e   01 6c 06 67 6f 6f 67 6c ..B...cn .l.googl
0060   65 03 63 6f 6d 00 c0 2b   00 01 00 01 00 00 00 5f e.com..+ ......._
0070   00 04 cb d0 21 65 c0 2b   00 01 00 01 00 00 00 5f ....!e.+ ......._
0080   00 04 cb d0 21 64                               ....!d          
說明:

前面三段分別為乙太網包頭,ip包頭和UDP包頭。
3e 3a   為標識欄位
81 80  為標誌欄位,其中設定了QR = 1,RD = 1,RA = 1
00 01  問題數1,00 03  回答數3,其餘兩個為0。
03 77   77 77 06 67 6f 6f 67 6c 65 02 63 6e 00
表示查詢的名字為
www.google.com
00 01 為型別,1表示A查詢
00 01 為類,1表示Internet資料。
接下來為回答報文,
c0 0c 為域名指標
00 05  表示CNAME(規範名稱)
00 01  類,表示為Internet資料
00 00 05 42  生存時間
00 11  資料長度
02 63 6e   01 6c 06 67 6f 6f 67 6c 65 03 63 6f 6d 00 為資料 cn.l.google.cn
然後接下來兩段為另外兩個回答。
最後的資料為IP地址