首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

C++ 實作 DNS 域名解析:從 UDP 封包構建到完整解析器

     編輯:C++ 入門

C++ 實作 DNS 域名解析完整指南

概述

實作一個 DNS 客戶端,輸入域名(如 www.baidu.com),透過 UDP Port 53 向 DNS 伺服器(如 114.114.114.114)發送查詢,解析回應封包取得 IP 列表、CName 別名與查詢耗時。

關鍵技術點

1. 協議選擇:UDP

標準 DNS 查詢/回應用 UDP(低開銷),Zone Transfer 用 TCP。本實作採 UDP Port 53。

2. DNS 封包結構(RFC 1035)

Header (12 bytes):
  ID(2) | Flags(2) | QDCOUNT(2) | ANCOUNT(2) | NSCOUNT(2) | ARCOUNT(2)

Question Section (QDCOUNT entries):
  Name (variable) | Type(2) | Class(2)

Answer Section (ANCOUNT entries):
  Name | Type | Class | TTL(4) | RDLENGTH(2) | RDATA(variable)

重點欄位:

  • QR=0 查詢、1 回應。
  • Type=1 (A) IPv4 位址、5 (CNAME) 規范名稱。
  • Class=1 (IN) Internet。

3. 域名編碼(Name 壓縮)

  • 標準格式:長度(1B) + 標籤內容,以 0 結束。例:www.baidu.com → 03 77 77 77 05 62 61 69 64 75 03 63 6f 6d 00。
  • 壓縮指標:高兩位 11,後 14 位為相對封包起始位移。支援巢狀指標。

核心類別設計 CDNSLookup

class CDNSLookup {
public:
    BOOL DNSLookup(ULONG dnsIP, char* domain,
                   vector* ipList = nullptr,
                   vector* cnameList = nullptr,
                   ULONG timeout = 1000, ULONG* timeSpent = nullptr);
private:
    BOOL SendDNSRequest(sockaddr_in&, char* domain);
    BOOL RecvDNSResponse(sockaddr_in&, ULONG timeout,
                         vector*, vector*, ULONG*);
    BOOL EncodeDotStr(char* dot, char* encoded, USHORT maxLen);
    BOOL DecodeDotStr(char* encoded, USHORT* encLen,
                      char* dot, USHORT maxDot, char* pktStart = nullptr);
    // ... 初始化/清理、Socket 管理
};

關鍵實作細節

  • SendDNSRequest:構建 Header(ID=ProcessID, Flags=0x0100, QDCOUNT=1)、編碼域名、附加 Type=A/Class=IN、sendto 發送。
  • RecvDNSResponse:WSAWaitForMultipleEvents 等待回應、recvfrom 接收、驗證 ID/Flags、解析 Question 區、迴圈解析 Answer 區(Type=A 存 IP、Type=CNAME 遞迴解碼 Name)、計算耗時。
  • DecodeDotStr 遞迴處理壓縮指標,需傳入封包起始位址以計算絕對位移。

使用範例

int main() {
    CDNSLookup dns;
    vector ips, cnames;
    ULONG ms = 0;
    BOOL ok = dns.DNSLookup(inet_addr("114.114.114.114"),
                            "www.baidu.com", &ips, &cnames, 1000, &ms);
    if (!ok) { printf("timeout\n"); return -1; }
    for (int i=0;i

輸出範例

IP1 = 180.101.49.11
IP2 = 180.101.49.12
CName1 = www.a.shifen.com
time spent = 23 ms
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved