本文部分內(nèi)容參考Linux C/C++ 開(kāi)發(fā)(學(xué)習(xí)筆記九 ):DNS協(xié)議與請(qǐng)求的實(shí)現(xiàn)_菊頭蝙蝠的博客-博客_struct dns
湞江網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)建站!從網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、APP開(kāi)發(fā)、響應(yīng)式網(wǎng)站等網(wǎng)站項(xiàng)目制作,到程序開(kāi)發(fā),運(yùn)營(yíng)維護(hù)。創(chuàng)新互聯(lián)建站于2013年創(chuàng)立到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來(lái)保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)建站。?域名系統(tǒng)(英文:Domain Name System,縮寫(xiě):DNS)的作用是將人類(lèi)可讀的域名 (如,www.example.com) 轉(zhuǎn)換為機(jī)器可讀的 IP 地址(如,192.0.2.44)。
DNS的分層??域名系統(tǒng)是分層次的。在域名系統(tǒng)的層次結(jié)構(gòu)中,各種域名都隸屬于域名系統(tǒng)根域的下級(jí)。域名的第一級(jí)是頂級(jí)域,它包括通用頂級(jí)域,例如 .com、.net 和 .org;以及國(guó)家和 地區(qū)頂級(jí)域,例如 .us、.cn 和 .tk。頂級(jí)域名下一層是二級(jí)域名,一級(jí)一級(jí)地往下。這 些域名向人們提供注冊(cè)服務(wù),人們可以用它創(chuàng)建公開(kāi)的互聯(lián)網(wǎng)資源或運(yùn)行網(wǎng)站。頂級(jí)域名的管理服務(wù)由對(duì)應(yīng)的域名注冊(cè)管理機(jī)構(gòu)(域名注冊(cè)局)負(fù)責(zé),注冊(cè)服務(wù)通常由域名注冊(cè)商負(fù)責(zé)。
DNS服務(wù)類(lèi)型授權(quán)型DNS——一種授權(quán)型DNS服務(wù)提供一種更新機(jī)制,供開(kāi)發(fā)人員用于管理其公用DNS名稱。然后,它響應(yīng)DNS查詢,將域名轉(zhuǎn)換為IP地址,以便計(jì)算機(jī)可以相互通信。授權(quán)型DNS對(duì)域有最終授權(quán)且負(fù)責(zé)提供遞歸型DNS服務(wù)器對(duì)IP地址信息的響應(yīng)。阿里云是一種授權(quán)型DNS系統(tǒng)。
遞歸型DNS——客戶端通常不會(huì)對(duì)授權(quán)型DNS服務(wù)直接進(jìn)行查詢。而是通常連接到稱為解析程序的其他DNS服務(wù),或遞歸型DNS服務(wù)。遞歸型DNS服務(wù)就像是旅館的門(mén)童:盡管沒(méi)有任何自身的DNS記錄,但是可充當(dāng)代表您獲得DNS信息的中間程序。如果遞歸型DNS擁有已緩存或存儲(chǔ)一段時(shí)間的DNS參考,那么它會(huì)通過(guò)提供源或IP信息來(lái)響應(yīng)DNS查詢。如果沒(méi)有,則它會(huì)將查詢傳遞到一個(gè)或多個(gè)授權(quán)型DNS服務(wù)器以查找信息。
記錄類(lèi)型DNS server內(nèi)的每一個(gè)網(wǎng)域都有自己的檔案,這個(gè)檔案一般會(huì)稱為區(qū)域檔案,如”named.ca”或”named.local” 檔案…等等。?區(qū)域檔案是由多個(gè)記錄組成的,每一個(gè)記錄稱為資源記錄(Resource Record,簡(jiǎn)稱RR)。?當(dāng)在設(shè)定DNS名稱解析、反向解析及其他的管理目的時(shí),需要使用不同類(lèi)型的RR,底下將介紹常用的RR類(lèi)型及表示法。
NS 記錄(域名服務(wù)) ─ 指定解析域名或子域名的 DNS 服務(wù)器。 MX 記錄(郵件交換) ─ 指定接收信息的郵件服務(wù)器。A 記錄(地址) ─ 指定域名對(duì)應(yīng)的 IPv4 地址記錄。
AAAA 記錄(地址) ─ 指定域名對(duì)應(yīng)的 IPv6 地址記錄。
CNAME (規(guī)范) ─ 一個(gè)域名映射到另一個(gè)域名或 CNAME 記錄( baidu.com 指向 www.baidu.com )或映射到一個(gè) A 記錄。PTR 記錄(反向記錄) ─ PTR 記錄用于定義與 IP 地址相關(guān)聯(lián)的名稱。 PTR 記錄 是 A 或 AAAA 記錄的逆。 PTR 記錄是唯一的,因?yàn)樗鼈円?.arpa 根開(kāi)始并被委派 給 IP 地址的所有者。(反向DNS查找或反向DNS解析(rDNS)是查詢域名系統(tǒng)(DNS)來(lái)確定IP地址關(guān)聯(lián)的域名的技術(shù)——通常的“轉(zhuǎn)發(fā)”的反向DNS查找域名的IP地址。反向DNS查詢的過(guò)程使用PTR記錄。互聯(lián)網(wǎng)的反向DNS數(shù)據(jù)庫(kù)植根于 .arpa 頂級(jí)域名。)
域名解析主機(jī)名到IP地址映射有兩種方式:
靜態(tài)映射 - 在本機(jī)上配置域名和 IP 的映射,旨在本機(jī)上使用。 Windows 和 Linux 的 hosts 文件中的內(nèi)容就屬于靜態(tài)映射 動(dòng)態(tài)映射 - 建立一套域名解析系統(tǒng)( DNS ),只在專門(mén)的 DNS 服務(wù)器上配置主機(jī)到IP 地址的映射,網(wǎng)絡(luò)上需要使用主機(jī)名通信的設(shè)備,首先需要到 DNS 服務(wù)器查詢主機(jī)所對(duì)應(yīng)的 IP 地址。 ? ? 通過(guò)域名去查詢域名服務(wù)器,得到IP地址的過(guò)程叫做域名解析。在解析域名時(shí),一般先靜態(tài)域名解析,再動(dòng)態(tài)解析域名??梢詫⒁恍┏S玫挠蛎湃腱o態(tài)域名解析表中,這樣可以大大提高域名解析效率。?
二、DNS協(xié)議?級(jí)別最低的域名寫(xiě)在左邊,級(jí)別最高的域名寫(xiě)在右邊。域名服務(wù)主要是基于UDP 實(shí)現(xiàn)的,服務(wù)器的端口號(hào)為 53。
域名服務(wù)器域名需要由遍及全世界的域名服務(wù)器去解析,域名服務(wù)器實(shí)際上就是裝有域名系統(tǒng)的主機(jī)。由高向低進(jìn)行層次劃分,可分為以下幾大類(lèi):
根域名服務(wù)器:最高層次的域名服務(wù)器,也是最重要的域名服務(wù)器,本地域名服務(wù)器如果解析不了域名就會(huì)向根域名服務(wù)器求助。全球共有 13 個(gè)不同 IP 地址的根域名服務(wù)器,它們的名稱用一個(gè)英文字母命名,從 a 一直到 m。 這些服務(wù)器由各種組織控制,并由 ICANN(互聯(lián)網(wǎng)名稱和數(shù)字地址分配公司)授權(quán),由于每分鐘都要解析的名稱數(shù)量多得令人難以置信,所以實(shí)際上每個(gè)根服務(wù)器都有鏡像服務(wù)器, 每個(gè)根服務(wù)器與它的鏡像 服務(wù)器共享同一個(gè) IP 地址,中國(guó)大陸地區(qū)內(nèi)只有 6 組根服務(wù)器鏡像(F,I(3 臺(tái)),J,L)。當(dāng)你對(duì)某個(gè)根服務(wù)器發(fā)出請(qǐng)求時(shí),請(qǐng)求會(huì)被路由到該根服務(wù)器離你最近的鏡像服務(wù)器。所有的根域名服務(wù)器都知道所有的頂級(jí)域名服務(wù)器的域名和地址,如果向根服務(wù)器發(fā)出對(duì) 0voice.com 的請(qǐng)求,則根服務(wù)器是不能在它的記錄文件中找到與0voice.com 匹配的記錄。但是它會(huì)找到.com 的頂級(jí)域名記錄,并把負(fù)責(zé).com 地址的頂級(jí)域名服務(wù)器的地址發(fā)回給請(qǐng)求。 頂級(jí)(TLD)域名服務(wù)器:負(fù)責(zé)管理在該頂級(jí)域名服務(wù)器下注冊(cè)的二級(jí)域名。當(dāng)根域名服務(wù)器告 訴查詢者頂級(jí)域名服務(wù)器地址時(shí),查詢者緊接著就會(huì)到頂級(jí)域名服務(wù)器進(jìn)行查詢。比如還是查詢 0voice.com,根域名服務(wù)器已經(jīng)告訴了查詢者 com 頂級(jí)域名服務(wù)器的地址, com 頂級(jí)域名服務(wù)器會(huì)找到 0voice.com 的域名服務(wù)器的記錄,域名服務(wù)器檢查其區(qū)域文件,并發(fā)現(xiàn)它有與 0voice.com 相關(guān)聯(lián)的區(qū)域文件。在此文件的內(nèi)部,有該主機(jī)的記錄。此記錄說(shuō)明此主機(jī)所在的 IP 地址,并向請(qǐng)求者返回最終答案。權(quán)限(權(quán)威)域名服務(wù)器:當(dāng)遞歸解析器收到來(lái)自 TLD 域名服務(wù)器的響應(yīng)時(shí),該響應(yīng)會(huì)將解析器定向到權(quán)威性域名服務(wù)器。權(quán)威性域名服務(wù)器通常是解析器查找 IP 地址過(guò)程中的最后一步。權(quán)威名稱服務(wù)器包含特定于其服務(wù)域名的信息(例如,google.com),并且它可為遞歸解析器提供在DNS A記錄中找到的服務(wù)器的 IP 地址,或者如果該域具有?CNAME記錄(別名),它將為遞歸解析器提供一個(gè)別名域,這時(shí)遞歸解析器將必須執(zhí)行全新 DNS 查找,以便從權(quán)威性域名服務(wù)器獲取記錄(通常為包含 IP 地址的 A 記錄)。
本地域名服務(wù)器:當(dāng)一個(gè)主機(jī)發(fā)出 DNS 查詢請(qǐng)求的時(shí)候,這個(gè)查詢請(qǐng)求首先就是發(fā)給本地域名服務(wù)器的。
域名解析過(guò)程域名解析總體可分為兩大步驟,第一個(gè)步驟是本機(jī)向本地域名服務(wù)器發(fā)出一個(gè) DNS 請(qǐng)求報(bào)文,報(bào)文里攜帶需要查詢的域名;第二個(gè)步驟是本地域名服務(wù)器向本機(jī)回應(yīng)一個(gè) DNS 響應(yīng) 報(bào)文,里面包含域名對(duì)應(yīng)的 IP 地址。從下面對(duì) 0voice.com 進(jìn)行域名解析的報(bào)文中可明顯 看出這兩大步驟。注意:第二大步驟中采用的是迭代查詢,其實(shí)是包含了很多小步驟的, 詳情見(jiàn)下面的流程分析
其具體的流程可描述如下: 1. 主機(jī) 192.168.1.124 先向本地域名服務(wù)器 192.168.1.2 進(jìn)行 遞歸查詢 2. 本地域名服務(wù)器采用 迭代查詢 ,向一個(gè)根域名服務(wù)器進(jìn)行查詢 3. 根域名服務(wù)器告訴本地域名服務(wù)器,下一次應(yīng)該查詢的頂級(jí)域名服務(wù)器 0voice.com 的 IP 地址 4. 本地域名服務(wù)器向頂級(jí)域名服務(wù)器 0voice.com 進(jìn)行查詢 5. 頂級(jí)域名服務(wù)器 .com 告訴本地域名服務(wù)器,下一步查詢權(quán)限服務(wù)器 www.0voice.com 的 IP 地址 6. 本地域名服務(wù)器向權(quán)限服務(wù)器 www.0voice.com 進(jìn)行查詢 7. 權(quán)限服務(wù)器 www.0voice.com 告訴本地域名服務(wù)器所查詢的主機(jī)的 IP 地址 8. 本地域名服務(wù)器最后把查詢結(jié)果告訴 122.152.222.180 遞歸查詢和迭代查詢圖2-18所示的例子利用了遞歸查詢和迭代查詢。從cse.nyu.edu到dns.nyu.edu發(fā)出的查詢是遞歸查詢,因?yàn)樵摬樵円宰约旱拿x請(qǐng)求dns.nyu.edu來(lái)獲得該映射。而后繼的3個(gè)查詢是迭代查詢,因?yàn)樗械幕卮鸲际侵苯臃祷亟odns.nyu.edu。從理論上講,任何DNS查詢既可以是迭代的也能是遞歸的。例如,圖2-19顯示了一條DNS查詢鏈,其中的所有查詢都是遞歸的。實(shí)踐中,查詢通常遵循圖2-18中的模式:從請(qǐng)求主機(jī)到本地DNS服務(wù)器的查詢是遞歸的,其余的查詢是迭代的。
協(xié)議報(bào)文格式頭部會(huì)話標(biāo)識(shí)(2字節(jié)):是DNS報(bào)文的ID標(biāo)識(shí),對(duì)于請(qǐng)求報(bào)文和其對(duì)應(yīng)的應(yīng)答報(bào)文,這個(gè)字段是相同的,通過(guò)它可以區(qū)分DNS應(yīng)答報(bào)文是哪個(gè)請(qǐng)求的響應(yīng)。?
標(biāo)志(2字節(jié)):
QR(1bit )查詢 / 響應(yīng)標(biāo)志, 0 為查詢, 1 為響應(yīng) opcode(4bit) 0 表示標(biāo)準(zhǔn)查詢, 1 表示反向查詢, 2 表示服務(wù)器狀態(tài)請(qǐng)求 AA(1bit )表示授權(quán)回答 TC(1bit )表示可截?cái)嗟? RD(1bit )表示期望遞歸 RA(1bit )表示可用遞歸 rcode(4bit )表示返回碼, 0 表示沒(méi)有差錯(cuò), 3 表示名字差錯(cuò), 2 表示服務(wù)器錯(cuò)誤( Server Failure ) 數(shù)量字段(總共 8 字節(jié)): Questions、Answer RRs、Authority RRs、Additional RRs 各自 表示后面的四個(gè)區(qū)域的數(shù)目。Questions 表示查詢問(wèn)題區(qū)域節(jié)的數(shù)量,Answers 表示回答區(qū) 域的數(shù)量,Authoritative namesversers 表示授權(quán)區(qū)域的數(shù)量,Additional recoreds 表示 附加區(qū)域的數(shù)量 正文查詢名:長(zhǎng)度不固定,且不使用填充字節(jié),一般該字段表示的就是需要查詢的域名(如果是反向查詢,則為IP,反向查詢即由IP地址反查域名),一般的格式如下圖所示
查詢類(lèi):通常為 1,表明是 Internet 數(shù)據(jù) 源記錄源記錄(RR)包括回答區(qū)域,授權(quán)區(qū)域和附加區(qū)域
域名(2字節(jié)或不定長(zhǎng)):它的格式和Queries區(qū)域的查詢名字字段是一樣的。有一點(diǎn)不同就是,當(dāng)報(bào)文中域名重復(fù)出現(xiàn)的時(shí)候,該字段使用2個(gè)字節(jié)的偏移指針來(lái)表示。比如,在資源記錄中,域名通常是查詢問(wèn)題部分的域名的重復(fù),因此用2字節(jié)的指針來(lái)表示,具體格式是最前面的兩個(gè)高位是11,用于識(shí)別指針。其余的14位從DNS報(bào)文的開(kāi)始處計(jì)數(shù)(從0開(kāi)始),指出該報(bào)文中的相應(yīng)字節(jié)數(shù)。一個(gè)典型的例子,C00C(1100000000001100,12 正好是頭部的長(zhǎng)度,其正好指向 Queries 區(qū)域的查詢名字字段)。
查詢類(lèi)型:表明資源記錄的類(lèi)型,如前文中查詢類(lèi)型表格所示
查詢類(lèi):對(duì)于Internet信息,總是IN
生存時(shí)間(TTL):以秒為單位,表示的是資源記錄的聲明周期,一般用于當(dāng)?shù)刂方馕龀绦蛉〕鲑Y源記錄后決定保存及使用緩存數(shù)據(jù)的時(shí)間,它同時(shí)也可以表明該資源記錄的穩(wěn)定程度,極為穩(wěn)定的信息會(huì)被分配一個(gè)很大的值(比如86400,這是一天的秒數(shù))
資源數(shù)據(jù): 該字段是一個(gè)可變長(zhǎng)字段,表示按照查詢段的要求返回的相關(guān)資源記錄的數(shù) 據(jù)。可以是 Address(表明查詢報(bào)文想要的回應(yīng)是一個(gè) IP 地址)或者 CNAME(表明查詢 報(bào)文想要的回應(yīng)是一個(gè)規(guī)范主機(jī)名)等。 Wireshark抓取DNS報(bào)文從上到下分別是物理層、數(shù)據(jù)鏈路層、網(wǎng)絡(luò)層、傳輸層、應(yīng)用層
可展開(kāi)觀察DNS協(xié)議的具體細(xì)節(jié)
三、實(shí)現(xiàn)DNS請(qǐng)求 1.首部header和question結(jié)構(gòu)體struct dns_header{
unsigned short id;
unsigned short flags;
unsigned short questions;
unsigned short answers;
unsigned short authority;
unsigned short additional;
};
struct dns_question{
int length;
unsigned short qtype;
unsigned short qclass;
char* name;//域名
};
2.初始化dns首部//client send to dns server
int dns_create_header(dns_header* header){
if(header==NULL) return -1;
memset(header,0,sizeof(header));
//random
srandom(time(NULL));//設(shè)置種子(因?yàn)榉N子根據(jù)時(shí)間有關(guān),每次random也會(huì)變,因此這是一個(gè)線程不安全的)
header->id=random();//獲得隨機(jī)數(shù)
header->flags=htons(0x0100);//轉(zhuǎn)化為網(wǎng)絡(luò)字節(jié)序
header->questions=htons(1);//每次查詢一個(gè)域名
return 0;
}
3.?初始化questionstrdup函數(shù)聲明
#includechar *strdup(const char *s);
函數(shù)介紹:
strdup()函數(shù)是c語(yǔ)言中常用的一種字符串拷貝庫(kù)函數(shù),一般和free()函數(shù)成對(duì)出現(xiàn)。
strdup()在內(nèi)部調(diào)用了malloc()為變量分配內(nèi)存,不需要使用返回的字符串時(shí),需要用free()釋放相應(yīng)的內(nèi)存空間,否則會(huì)造成內(nèi)存泄漏。該函數(shù)的返回值是返回一個(gè)指針,指向?yàn)閺?fù)制字符串分配的空間;如果分配空間失敗,則返回NULL值。
strtok() 函數(shù)聲明
char *strtok(char *str, const char *delim)
返回值:該函數(shù)返回被分解的第一個(gè)子字符串,如果沒(méi)有可檢索的字符串,則返回一個(gè)空指針。?
char *strncpy(char *dest, const char *src, size_t n)
把?src?所指向的字符串復(fù)制到?dest,最多復(fù)制?n?個(gè)字符。當(dāng) src 的長(zhǎng)度小于 n 時(shí),dest 的剩余部分將用空字節(jié)填充。
該函數(shù)返回最終復(fù)制的字符串。
//創(chuàng)建question
//hostname:www.baidu.com
//name:3www5baidu3com'\0'
int dns_create_question(dns_question* question,const char* hostname){
if(question==NULL||hostname==NULL) return -1;
memset(question,0,sizeof(question));
question->name=(char*)malloc(strlen(hostname)+2);//因?yàn)橐袛嘟Y(jié)尾'\0',然后再補(bǔ)充一個(gè)開(kāi)頭3
if(question->name==NULL){//如果內(nèi)存分配失敗
return -2;
}
question->length=strlen(hostname)+2;
question->qtype=htons(1);//查詢類(lèi)型,(1表示:由域名獲得 IPv4 地址)
question->qclass=htons(1);//通常為 1,表明是 Internet 數(shù)據(jù)
//hostname->name
const char delim[2]=".";//分隔符,末尾補(bǔ)個(gè)'\0'
char* qname=question->name;
char* hostname_dup=strdup(hostname);//復(fù)制一份hostname --->malloc(所以后續(xù)要free)
char* token=strtok(hostname_dup,delim);
while(token!=NULL){
size_t len=strlen(token);//第一個(gè)循環(huán)token為www,len=3
*qname=len;//先把長(zhǎng)度放上去
qname++;
strncpy(qname,token,len+1);//復(fù)制www,這里不+1也是可以的,這樣是為了把最后的'\0'也復(fù)制過(guò)來(lái),因?yàn)樽詈笠矔?huì)被覆蓋的。(如果這邊不+1,最后一步,需要額外加上'\0')
qname+=len;
token=strtok(NULL,delim);//因?yàn)樯弦淮?,token獲取還未結(jié)束,因此可以指定NULL即可。(注意:要依賴上一次的結(jié)果,因此也是線程不安全的)
}
free(hostname_dup);
}
4.合并header和question//struct dns_header* header
//struct dns_question* question
//把上面兩個(gè)合到request中 返回長(zhǎng)度
int dns_build_requestion(dns_header* header,dns_question* question,char* request,int rlen){
if(header==NULL||question==NULL||request==NULL) return -1;
memset(request,0,rlen);
//header-->request
memcpy(request,header,sizeof(dns_header));//把header的數(shù)據(jù) 拷貝 到request中
int offset=sizeof(dns_header);
//question-->request
memcpy(request+offset,question->name,question->length);
offset+=question->length;
memcpy(request+offset,&question->qtype,sizeof(question->qtype));
offset+=sizeof(question->qtype);
memcpy(request+offset,&question->qclass,sizeof(question->qclass));
offset+=sizeof(question->qclass);
return offset;
}
5.通過(guò)socket實(shí)現(xiàn)dns請(qǐng)求int dns_client_commit(const char* domin){
int sockfd=socket(AF_INET,SOCK_DGRAM,0);//創(chuàng)建sockfd,AF_INET表示ipv4, SOCK_DGRAM為報(bào)文方式(UDP);
if(sockfd<0){//創(chuàng)建失敗
return -1;
}
struct sockaddr_in servaddr={0};//服務(wù)器地址(sockaddr_in存儲(chǔ))
servaddr.sin_family=AF_INET;//協(xié)議簇
servaddr.sin_port=htons(DNS_SERVER_PORT);//端口
servaddr.sin_addr.s_addr=inet_addr(DNS_SERVER_IP);//添加dns服務(wù)器ip
int ret=connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr));//目的是為sendto開(kāi)辟一條路徑,
printf("connect:%d",ret);
dns_header header={0};
dns_create_header(&header);
dns_question question={0};
dns_create_question(&question,domin);
char request[1024]={0};//假設(shè)定義為1024長(zhǎng)度
int length = dns_build_requestion(&header,&question,request,1024);
//request 發(fā)送請(qǐng)求
int slen=sendto(sockfd,request,length,0,(struct sockaddr*)&servaddr,sizeof(struct sockaddr));
//receive from 接受數(shù)據(jù)
char response[1024]={0};
struct sockaddr_in addr;
size_t addr_len=sizeof(struct sockaddr_in);
int n = recvfrom(sockfd,response,sizeof(response),0,(struct sockaddr*)&addr,(socklen_t*)&addr_len);
printf("recvfrom:%d \n",n);
for(int i=0;i
6.解析結(jié)果? C 庫(kù)函數(shù)?void *calloc(size_t nitems, size_t size)?分配所需的內(nèi)存空間,并返回一個(gè)指向它的指針。malloc?和?calloc?之間的不同點(diǎn)是,malloc 不會(huì)設(shè)置內(nèi)存為零,而 calloc 會(huì)設(shè)置分配的內(nèi)存為零。
void *calloc(size_t nitems, size_t size)
void bzero(void *s, int n);
bzero()將參數(shù)s 所指的內(nèi)存區(qū)域前n 個(gè)字節(jié)全部設(shè)為零
typedef struct dns_item{
char *domain;
char *ip;
}dns_item;
int is_pointer(int in) { //in與0xc0相與,結(jié)果等于0xc0時(shí)為真 192
return ((in & 0xC0) == 0xC0);
}
//參數(shù)1:存放DNS服務(wù)器返回結(jié)果的緩沖區(qū) 參數(shù)2:指向返回結(jié)果某一區(qū)域的指針 參數(shù)3存放Answer中name字段的緩沖區(qū)
//將Answer中name字段放入緩沖區(qū)
void dns_parse_name(unsigned char *chunk, unsigned char *ptr, char *out, int *len) {
int flag = 0, n = 0, alen = 0;
char *pos = out + (*len); //pos指向
while (1) {
flag = (int)ptr[0];
if (flag == 0) break;
if (is_pointer(flag)) {
n = (int)ptr[1];
ptr = chunk + n;
dns_parse_name(chunk, ptr, out, len);
break;
} else {
ptr ++;
memcpy(pos, ptr, flag);
pos += flag;
ptr += flag;
*len += flag;
if ((int)ptr[0] != 0) {
memcpy(pos, ".", 1);
pos += 1;
(*len) += 1;
}
}
}
}
// 參數(shù)1:存放dns服務(wù)器返回結(jié)果的緩沖區(qū) 參數(shù)2:指向dns_item結(jié)構(gòu)體的指針
int dns_parse_response(char *buffer, struct dns_item **domains){
int i = 0;
unsigned char *ptr = (unsigned char* )buffer; //ptr是指向buffer的指針
ptr += 4; //向后移動(dòng)4字節(jié)
//將一個(gè)無(wú)符號(hào)短整型數(shù)從網(wǎng)絡(luò)字節(jié)順序轉(zhuǎn)換為主機(jī)字節(jié)順序
int querys = ntohs(*(unsigned short*)ptr); //獲取questions字段 查詢問(wèn)題區(qū)域節(jié)的數(shù)量
ptr += 2;
int answers = ntohs(*(unsigned short*)ptr);//獲取Answer RRs字段
ptr += 6; //指向Queries字段
for (i = 0;i< querys;i ++) { //此處循環(huán)目的是跳過(guò)查詢字段
while (1) {
int flag = (int)ptr[0]; //第一部分的長(zhǎng)度
ptr += (flag + 1); //ptr指向下一部分
if (flag == 0) break; //查詢名的結(jié)尾為0
}
ptr += 4; //指向回答區(qū)域
}
char cname[128], aname[128], ip[20], netip[4];
int len, type, ttl, datalen;
int cnt = 0;
struct dns_item *list = (struct dns_item*)calloc(answers, sizeof(struct dns_item)); //為dns_item結(jié)構(gòu)體分配內(nèi)存空間
if (list == NULL) {
return -1;
}
for (i = 0;i< answers;i ++) {
bzero(aname, sizeof(aname)); //將aname空間元素置為0
len = 0;
//ptr指向Answers字段 將buffer中answer的Name字段放入aname中
dns_parse_name((unsigned char* )buffer, ptr, aname, &len);
ptr += 2;
type = htons(*(unsigned short*)ptr);
ptr += 4;
ttl = htons(*(unsigned short*)ptr);
ptr += 4;
datalen = ntohs(*(unsigned short*)ptr);
ptr += 2;
if (type == DNS_CNAME) {
bzero(cname, sizeof(cname));
len = 0;
dns_parse_name((unsigned char* )buffer, ptr, cname, &len);
ptr += datalen;
} else if (type == DNS_HOST) {
bzero(ip, sizeof(ip));
if (datalen == 4) {
memcpy(netip, ptr, datalen);
inet_ntop(AF_INET , netip , ip , sizeof(struct sockaddr));
printf("%s has address %s\n" , aname, ip);
printf("\tTime to live: %d minutes , %d seconds\n", ttl / 60, ttl % 60);
list[cnt].domain = (char *)calloc(strlen(aname) + 1, 1);
memcpy(list[cnt].domain, aname, strlen(aname));
list[cnt].ip = (char *)calloc(strlen(ip) + 1, 1);
memcpy(list[cnt].ip, ip, strlen(ip));
cnt ++;
}
ptr += datalen;
}
}
*domains = list;
ptr += 2;
return cnt;
}
7.main函數(shù)int main(int argc,char* argv[]){
if(argc<2) return -1;
dns_client_commit(argv[1]);
return 0;
}
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧