程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> DIY一個DNS查詢器:了解DNS協議

DIY一個DNS查詢器:了解DNS協議

編輯:C#入門知識

 

每當我們在浏覽器上敲入任何一個域名訪問某個網站的時候,我們都要使用Dns協議進行一次”域名:IP”的查詢;作為命令行使用者,與dns有關用的最多的就是Nslookup 命令吧;作為程序員,以c#程序員為例,要得到一個域名的ip大概也是這麼一行“System.Net.Dns.GetHostByName(string UriHostName)”。

在這簡單使用的背面,很少人會真了解其協議的規則,這也許就是高度封裝給程序員帶來的一點麻煩吧。下面來了解一下dns協議的內容。

DNS結構:

整個dns分為5個部分,分別為Header、Question、Answer、Authority、Additional。

header

其中頭部的大小是固定的為12字節。這5個部分不是全部都是必須的,在向服務器發送查詢請求的時候,只需要前2個。回復的時候也不一定包含5個(按查詢的內容和返回的信息而定)。

Header 部分:

header頭部分是必須的,無論發送查詢或者返回結果都需要該部分,且長度一定,為12字節。結果如下圖

header2

ID:長度為16位,是一個用戶發送查詢的時候定義的隨機數,當服務器返回結果的時候,返回包的ID與用戶發送的一致。

QR:長度1位,值0是請求,1是應答。

Opcode:長度4位,值0是標准查詢,1是反向查詢,2死服務器狀態查詢。

AA:長度1位,授權應答(Authoritative Answer) - 這個比特位在應答的時候才有意義,指出給出應答的服務器是查詢域名的授權解析服務器。

TC:長度1位,截斷(TrunCation) - 用來指出報文比允許的長度還要長,導致被截斷。

RD:長度1位,期望遞歸(Recursion Desired) - 這個比特位被請求設置,應答的時候使用的相同的值返回。如果設置了RD,就建議域名服務器進行遞歸解析,遞歸查詢的支持是可選的。

RA:長度1位,支持遞歸(Recursion Available) - 這個比特位在應答中設置或取消,用來代表服務器是否支持遞歸查詢。

Z:長度3位,保留值,值為0.

RCode:長度4位,應答碼,類似http的stateCode一樣,值0沒有錯誤、1格式錯誤、2服務器錯誤、3名字錯誤、4服務器不支持、5拒絕。

QDCount:長度16位,報文請求段中的問題記錄數。

ANCount:長度16位,報文回答段中的回答記錄數。

NSCOUNT :長度16位,報文授權段中的授權記錄數。

ARCOUNT :長度16位,報文附加段中的附加記錄數。

Question 部分:

這部分的內容是你要查詢的內容。也是必須的。

question

QName:是你要查詢的域名,屬於不定長字段。他的格式是“長度(1字節)+N字節內容(N由前面的長度定義)+~~~+長度0。以一個長度單位N為開始,然後連續的N字節為其內容,然後又是一個N2長度的一字節,然後後面又是N2個字節內容,直到遇到長度為0的長度標記。

QType:長度16位,表示查詢類型。取值大概如下:

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, //指定文本信息。
UINFO=0x64, //指定用戶信息。
UID=0x65, //指定用戶標識符。
GID=0x66, //指定組名的組標識符。
ANY=0xFF //指定所有數據類型。
};

QClass:長度為16位,表示分類。

enum QueryClass //指定信息的協議組。
{
IN=0x01, //指定 Internet 類別。
CSNET=0x02, //指定 CSNET 類別。(已過時)
CHAOS=0x03, //指定 Chaos 類別。
HESIOD=0x04,//指定 MIT Athena Hesiod 類別。
ANY=0xFF //指定任何以前列出的通配符。
};

 

資源結構:

接下來的3個結構,格式可以說相同。都是如下圖的結構和字段。

re

Name:回復查詢的域名,不定長。 這裡的名字和Question結構的名字是一樣的,在這裡詳細說一下。

假設name字段的內容如下

05 6c 69 78 69 6e 02 6d 65 0

第一個字節是長度:5,那麼接下來的5個字節都是內容6c 69 78 69 6e ,ascii碼轉過來是“lixin”。然後又是長度2,後面2個字節的內容6d 65 字母為me,然後是長度0,表示結束了。最後還要把兩段文字組合起來中間加點號成lixin.me。

但是,在question結構是這樣,在之後的資源結構中,如果name字段的內容前面有出現了,那麼他就不會再浪費空間去重復記錄,而是指向某個前面出現了name的位置。如:

在question結構中的name字段的內容為lixin.me,即“05 6c 69 78 69 6e 02 6d 65 0”。然後在第3個結構中的answer中,第一個字段name的內容也是lixin.me,那麼他會指向question中的name地址,讓我們去那個地址讀name內容。所以此時answer結構的name字段的內容為:

C0 0C

C0:這時不是表示接下來的內容有多長,而是接下來的內容在偏移量中,

0C:十進制是12的意思,就是偏移12個字節。從頭開始12位,因為Header結構是固定的12字節,所以偏移0C就是到了Question的Name字段,即上面的“05 6c 69 78 69 6e 02 6d 65 0”。

 

Type:同上QType。

Class:同上QClass。

TTL:生存時間。4字節,指示RDATA中的資源記錄在緩存的生存時間。

RDLength:資源的長度。

RDdata:資源的內容。


在下一篇將講講具體開發一個dns查詢器的方法。先預報一下,程序還沒弄全好,使用的是c#,目前完成了大概70%。

 

 

轉載請注明:來自李鑫

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved