教你動手寫UDP協(xié)議棧系列文章序號內(nèi)容1《教你動手寫UDP協(xié)議棧-UDP協(xié)議棧格式》2《教你動手寫UDP協(xié)議棧-DHCP報文解析》3《教你動手寫UDP協(xié)議棧-OTA上位機》4《教你動手寫UDP協(xié)議棧-DNS報文解析》背景因特網(wǎng)上的節(jié)點通過IP地址唯一標識,并且能通過IP地址來識別參與分布式應(yīng)用的主機。但對于大多數(shù)人來說,這些地址太繁瑣而且難以使用和記憶(特別是IPV6地址)。因此互聯(lián)網(wǎng)支持使用主機名稱來識別包括客戶機和服務(wù)器在內(nèi)的主機。
為了使用如TCP和IP等協(xié)議,主機名稱可以通過稱為域名解析的過程轉(zhuǎn)換成IP地址。在互聯(lián)網(wǎng)中存在不同形式的名稱解析,但是最普遍、最重要的一種是采用分布式數(shù)據(jù)庫系統(tǒng),即我們熟知的域名系統(tǒng)(DNS),也是這篇文章的主角。DNS - 是一個分布式的客戶機-服務(wù)器網(wǎng)絡(luò)數(shù)據(jù)庫,TCP/IP應(yīng)用程序使用它來完成主機名稱和IP地址之間的映射,提供電子郵件路由信息、服務(wù)命名和其他服務(wù)。DNS使用TCP和UDP的端口--53。DNS - 為了可擴展性,DNS名稱是分層的。每一級域名長度的限制是63個字符,域名總長度則不能超過253個字符。下面來介紹DNS報文的格式解析,以及如何將域名轉(zhuǎn)為IP地址的流程。準備工具工具介紹WireShark網(wǎng)絡(luò)封包分析軟件,分析數(shù)據(jù)包CMDwindow 命令行DNS報文解析抓包分析打開CMD和WireShark工具。在WireShark中設(shè)置過濾信息,我們只抓取DNS報文。在CMD鍵入ping www.baidu.com,然后查看WireShark的抓包信息。
可以看到兩包DNS報文,一個是DNS發(fā)送報文,一個是DNS接收報文發(fā)送報文
接收報文
發(fā)送報文和接收報文格式是不一樣的,從上面截圖可以看到,接收報文多一個Answers字段。
DNS可以使用UDP與TCP兩種協(xié)議。這里我們主要以UDP進行分析。
DNS報文字段解析DNS報文格式:
DNS字段格式:發(fā)送報文
接收報文
DNS報文頭部
字段說明字段說明Transaction ID辨別DNS應(yīng)答報文是哪個請求報文的響應(yīng)QRFlags字段,1為響應(yīng),0位查詢OpCodeFlags字段,查詢或響應(yīng)類型,0為標準,1為反向,2為服務(wù)器狀態(tài)請求AAFlags字段,授權(quán)回答TCFlags字段,截斷,1表示超過512字節(jié)并已被截斷,0表示沒有發(fā)送截斷RDFlags字段,是否希望得到遞歸回答RAFlags字段,響應(yīng)報文中為1便是得到遞歸響應(yīng)ZFlags字段,0ADFlags字段,真是數(shù)據(jù)CDFlags字段,禁止校驗RCODEFlags字段,返回碼:0-無差錯,1-格式錯誤,2-服務(wù)器失效,3-不存在域名,4-查詢類型不支持,5-被禁止,6-15保留QuestionsFlags字段,查詢數(shù)AnswerFlags字段,資源記錄數(shù)AuthorityFlags字段,授權(quán)資源記錄數(shù)AdditionalFlags字段,額外資源記錄數(shù)代碼實現(xiàn)/** DNS message header */PACK_STRUCT_BEGINstruct dns_header { PACK_STRUCT_FIELD(uint16_t id); PACK_STRUCT_FIELD(uint8_t flags1); PACK_STRUCT_FIELD(uint8_t flags2); PACK_STRUCT_FIELD(uint16_t numquestions); PACK_STRUCT_FIELD(uint16_t numanswers); PACK_STRUCT_FIELD(uint16_t numauthrr); PACK_STRUCT_FIELD(uint16_t numextrarr);}PACK_STRUCT_STRUCT;PACK_STRUCT_ENDDNS報文問題字段
字段說明查詢名稱格式:
字段說明name查詢名稱,不定長type查詢類型class查詢類代碼實現(xiàn)(由于名字是不定長,另作處理)PACK_STRUCT_BEGINstruct dns_query { PACK_STRUCT_FIELD(uint16_t type); PACK_STRUCT_FIELD(uint16_t class);}PACK_STRUCT_STRUCT;PACK_STRUCT_ENDDNS報文應(yīng)答字段
字段說明(此字段只有應(yīng)答包才有)字段說明name查詢名稱,不定長type查詢類型class查詢類TTL該資源記錄的生命周期data length資源數(shù)據(jù)長度address返回的IP地址,即域名轉(zhuǎn)換的IP地址代碼實現(xiàn)struct dns_answer { PACK_STRUCT_FIELD(uint16_t name); PACK_STRUCT_FIELD(uint16_t type); PACK_STRUCT_FIELD(uint16_t class); PACK_STRUCT_FIELD(uint32_t ttl); PACK_STRUCT_FIELD(uint16_t len); PACK_STRUCT_FIELD(struct ip_addr server_ip);}PACK_STRUCT_STRUCT;PACK_STRUCT_ENDDNS報文發(fā)送實現(xiàn)代碼實現(xiàn)static void dns_packet_output(uint8_t *host_name){ struct dns_header dns_hdr = {0}; struct dns_query dns_qry = {0}; struct dest_device_info dest_info = {0}; uint8_t *dns_packet = NULL; uint8_t *dns_name = NULL; uint16_t query_index = 0; uint16_t label_len = 0; uint16_t dns_name_len = strlen(host_name) + 2;
dns_packet = malloc(DNS_HDR_SIZE + dns_name_len + DNS_QUERY_SIZE); dns_name = malloc(strlen(host_name) + 2);
if(dns_packet != NULL && dns_name !=NULL) { //打包DNS header memset(&dns_hdr, 0, DNS_HDR_SIZE); dns_hdr.id = mu_htons(TRANSACTION_ID); dns_hdr.flags1 = DNS_FLAG1_RD; dns_hdr.numquestions = mu_htons(1); memcpy(dns_packet, &dns_hdr, DNS_HDR_SIZE);
//將域名轉(zhuǎn)換DNS數(shù)據(jù)包格式 change_to_dns_name(dns_name, host_name);
memcpy(dns_packet + DNS_HDR_SIZE, dns_name, dns_name_len);
dns_qry.type = mu_htons(DNS_RRTYPE_A); dns_qry.class = mu_htons(DNS_RRCLASS_IN); //打包DNS query memcpy(dns_packet + DNS_HDR_SIZE + dns_name_len, &dns_qry, DNS_QUERY_SIZE);
memcpy(&dest_info.dest_mac, get_gw_mac(), MAC_ADDR_SIZE); memcpy(&dest_info.dest_ip, get_dns_server(), IP_ADDR_SIZE); dest_info.src_port = DNS_CLIENT_PORT; dest_info.dest_port = DNS_SERVER_PORT; //通過UDP報文發(fā)送 mini_udp_output(&dest_info, dns_packet, (DNS_HDR_SIZE + dns_name_len + DNS_QUERY_SIZE)); }
if(dns_packet != NULL) { free(dns_packet); } if(dns_name != NULL) { free(dns_name); }}驗證代碼結(jié)果,我們通過查詢CSDN的IP地址,CSDN的域名:www.csdn.net
通過wireshark抓包,可以看到我們DNS報文已發(fā)送成功,并且有應(yīng)答包
DNS報文接收實現(xiàn)代碼實現(xiàn)static void dns_packet_input(void *dns_packet_data){ struct dns_header *dns_hdr = {0}; struct dns_answer *dns_ans = {0}; uint16_t dns_name_len = strlen("www.csdn.net") + 2; uint8_t *server_dns_name = malloc(strlen("www.csdn.net") + 2);
if(server_dns_name == NULL) { LOG_E("malloc fail!!"); return; }
dns_hdr = dns_packet_data; if(dns_hdr->id == mu_ntohs(TRANSACTION_ID) && (dns_hdr->numanswers > 1)) { change_to_dns_name(server_dns_name, "www.csdn.net");
if(strncmp(dns_packet_data + DNS_HDR_SIZE, server_dns_name, dns_name_len) == 0) { dns_ans = dns_packet_data + DNS_HDR_SIZE + dns_name_len + DNS_QUERY_SIZE;
printf("CSDN IP: %d:%d:%d:%d ", dns_ans->server_ip.a(chǎn)ddr[0], dns_ans->server_ip.a(chǎn)ddr[1], dns_ans->server_ip.a(chǎn)ddr[2], dns_ans->server_ip.a(chǎn)ddr[3]); } } free(server_dns_name);}通過wireshark抓包的IP與代碼捕獲的IP一致:
審核編輯:符乾江
-
DNS
+關(guān)注
關(guān)注
0文章
225瀏覽量
20265 -
UDP協(xié)議棧
+關(guān)注
關(guān)注
0文章
4瀏覽量
1190
發(fā)布評論請先 登錄
深度解析Linux中的DNS服務(wù)
深入淺出解析低功耗藍牙協(xié)議棧

PROFINET通訊協(xié)議報文解析
【教程】DNS域名解析服務(wù)systemd-resolved使用指南

一文了解Android UDP通信
UDP丟包的原因和解決方案

云解析的高防DNS是什么?高防DNS有什么作用?
深度解析TCP與UDP協(xié)議

評論