本文共 4063 字,大约阅读时间需要 13 分钟。
DNS(Domain Name System,域名系统)是互联网中用于将易于记忆的域名(如www.google.com)转换为机器可理解的IP地址(如172.217.27.142)的系统。通过DNS,用户无需记住复杂的IP地址即可访问网站,这大大简化了网络通信过程。
DNS解析过程主要包括以下几个步骤:
DNS系统的核心作用是将人类友好的域名映射到机器友好的IP地址。IP地址是网络中计算机识别的标识符,但其长难记。通过DNS,用户可以用更简洁的方式访问网站。
DNS使用UDP协议(端口53)进行通信,因为UDP速度快且开销低。然而,对于复杂的DNS查询(如区域传输),TCP协议也被用于确保数据完整性。
DNS报文包括以下几个部分:
DNS查询格式如下:
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+| || QNAME || |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+| QTYPE |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+| QCLASS |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
DNS回答格式如下:
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+| || || NAME || |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+| TYPE |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+| CLASS |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+| TTL || |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+| RDLENGTH |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|| RDATA || |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|
以下是DNS协议的代码实现示例:
struct dnshdr { uint16_t id; uint16_t flags; uint16_t quest; uint16_t ans; uint16_t auth; uint16_t add;};struct dnshdr_name { const char *ns_name; int ns_name_len; unsigned int labels;};static unsigned int qname_labels_count(const char *name, int name_len) { unsigned int labels = 0; if (name_len > 1) { for (int i = 0; i < name_len; ++i) { if (name[i] == '.') { labels++; } } labels++; } return labels;}int get_dns_name(u_char *dns_data, int offset, int max_len, int dns_data_offset, const char **name, int *name_len) { int len; len = expand_dns_name(dns_data, offset, max_len, dns_data_offset, name, name_len); if (name[0] == '\0' && len <= MIN_DNAME_LEN) { *name = " "; *name_len = (int)strlen(*name); return len; } if ((len < MIN_DNAME_LEN) || (len > MIN_DNAME_LEN && name_len == 0)) { printf("ReportedBoundsError\n"); } return len;}static void dissect_dns(u_char *data_info, int payload_len) { int used_bytes = 0; dnshdr_name dns_domain; used_bytes = get_dns_name(data_info, DNS_HDRLEN, 0, 0, &dns_domain.ns_name, &dns_domain.ns_name_len); dns_domain.labels = qname_labels_count(dns_domain.ns_name, dns_domain.ns_name_len); printf("ns_name: %s\n", dns_domain.ns_name); printf("ns_name_len: %d\n", dns_domain.ns_name_len); printf("labels: %d\n", dns_domain.labels);}static void confirm_dns_packet(struct ip *pIp) { int iIpTotalLen = ntohs(pIp->ip_len); int offset = 0; int nFragSeq = 0; struct udphdr *pUdpHdr = (struct udphdr *)(char *)pIp + (pIp->ip_hl < 2); if (pIp->ip_p == IPPROTO_UDP && (ntohs(pUdpHdr->dest) == DEFAULT_DNS_PORT_RANGE || ntohs(pUdpHdr->source) == DEFAULT_DNS_PORT_RANGE)) { printf("\n"); printf("info udp\n"); int iPayloadLen = iIpTotalLen - (pIp->ip_hl < 2) - 8; printf("UDP Payload Len %d\n", iPayloadLen); u_char *pDnsHdr = (u_char *)(pUdpHdr + 1); dissect_dns(pDnsHdr, iPayloadLen); }} 以下是DNS协议的实际抓包示例:
DNS Query:- Domain Name: www.google.com- Query Type: A- Class: 1DNS Response:- Name: www.google.com- Type: 1 (A Record)- Class: 1- TTL: 60- RDATA: 172.217.27.142
DNS协议通过将易于记忆的域名映射到机器友好的IP地址,为互联网用户和设备提供了便利。深入理解DNS协议,建议参考RFC官方文档。
欢迎关注微信公众号【程序猿编码】,加入技术交流群,共同探讨技术奥秘!
转载地址:http://yuiy.baihongyu.com/