DNS模拟器详细内容
一、简介
DNS(域名系统,Domain Name System)是互联网的一项核心服务,用于将用户友好的域名转换为机器可读的IP地址,DNS解析过程涉及多个层次的查询和响应,包括本地缓存、递归查询和迭代查询等步骤,本文将详细介绍DNS模拟器的实现原理、数据结构以及代码示例,帮助读者深入理解DNS的工作机制。
二、DNS
简介
DNS是计算机域名系统或域名解析服务器的缩写,它是由解析器以及域名服务器组成的系统,域名服务器保存有网络中所有主机的域名和对应IP地址,并具有将域名转换为IP地址的功能,域名必须对应一个IP地址,而IP地址不一定有域名,将域名映射为IP地址的过程称为“域名解析”。
发展
DNS最早于1983年由保罗·莫卡派乔斯发明;原始的技术规范在882号因特网标准草案(RFC 882)中发布,1987年发布的第1034和1035号草案修正了DNS技术规范,并废除了之前的第882和883号草案,在此之后对因特网标准草案的修改基本上没有涉及到DNS技术规范部分的改动。
DNS域名结构
通常Internet主机域名的结构为:主机名.三级域名.二级域名.顶级域名,Internet的顶级域名由Internet网络协会域名注册查询负责网络地址分配的委员会进行登记和管理,它还为Internet的每一台主机分配唯一的IP地址,全世界现有三个大的网络信息中心:位于美国的InterNIC,负责美国及其他地区;位于荷兰的RIPENIC,负责欧洲地区;位于日本的APNIC,负责亚太地区。
DNS解析器
解析器,或另一台DNS服务器递归代表的情况下,域名解析器协商使用递归服务,使用查询头位,解析通常需要遍历多个名称服务器,找到所需要的信息,一些解析器的功能更简单地只用一个名称服务器进行通信,这些简单的解析器依赖于一个递归名称服务器(称为“存根解析器”),为他们寻找信息的执行工作。
三、DNS协议抓包分析
DNS解析过程
当客户机提出查询请求时,首先在本地计算机的缓存中查找,如果在本地无法查询信息,则将查询请求发给DNS服务器,具体过程如下:
客户机将域名查询请求发送到本地DNS服务器。
本地DNS服务器接到查询后,首先在该服务器管理的区域的记录中查找。
如果找不到记录,本地DNS服务器将查询请求转发给根DNS服务器。
根DNS服务器根据域名结构返回对应的顶级域(TLD)DNS服务器地址。
本地DNS服务器向顶级域DNS服务器发送查询请求。
顶级域DNS服务器返回对应的权威DNS服务器地址。
本地DNS服务器向权威DNS服务器发送查询请求,权威DNS服务器返回对应的IP地址。
本地DNS服务器将结果缓存并返回给客户机。
DNS协议报文结构
DNS协议报文分为查询报文和响应报文,两者结构相似,报文由以下部分组成:
Header(头部):包含标识符、标志、问题数、资源记录数等字段。
Question(问题部分):包含要查询的域名和类型。
Answer(回答部分):包含查询结果的资源记录。
DNS查询报文中每个查询问题的格式
每个查询问题由以下字段组成:
QNAME(要查询的域名):压缩格式存储。
QTYPE(查询类型):如A记录(主机地址)、AAAA记录(IPv6地址)、MX记录(邮件交换)等。
QCLASS(查询类别):通常为IN(互联网)。
DNS响应报文中的资源记录格式
响应报文中的资源记录由以下字段组成:
NAME(域名):压缩格式存储。
TYPE(记录类型)。
CLASS(记录类别)。
TTL(生存时间):指定该记录被缓存的时间。
RDLENGTH(资源数据长度)。
RDATA(资源数据):根据记录类型不同而不同,如A记录为4字节的IPv4地址。
5. 据包DNS查询(DNS query)
+++++++++ | | | | | | | | | ID RD RA Z AA TC RC QR Opcode | | | | | | | | | Q_COUNT A_COUNT NS_COUNT AR_COUNT
6. 数据包 DNS 响应(DNS Response)
+++++++++ | | | | | | | | | RA Z AA TC RC RCODE QR Opcode | | | | | | | | | Q_COUNT A_COUNT NS_COUNT AR_COUNT
四、DNS协议模拟实现
通过Winsock网络程序模拟UDP数据报,帮助读者深入理解DNS的作用,以下是一个简单的DNS查询器示例代码,使用C语言编写。
数据结构说明
typedef struct { unsigned short id; // 标识符 unsigned char rd : 1; // 递归欲望标志 unsigned char ra : 1; // 可用递归标志 #if BYTE_ORDER == BIG_ENDIAN unsigned char z : 2; // 保留位,必须是0 unsigned char aa : 1; // 授权回答标志 unsigned char tc : 1; // 可截断标志 #else /* BIG_ENDIAN */ unsigned char aa : 1; // 授权回答标志 unsigned char tc : 1; // 可截断标志 unsigned char z : 2; // 保留位,必须是0 #endif /* BYTE_ORDER == BIG_ENDIAN */ unsigned char qr : 1; // 响应回答标志 } DNSHeader;
代码
1) UDP套接字初始化及发送函数
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #define BUF_SIZE 512 #define DNS_PORT 53 #define NS_QUERY 0x0100 // 标准查询操作码 int main(int argc, char *argv[]) { int udp_fd; struct sockaddr_in server_addr; char buffer[BUF_SIZE]; char *query = "www.example.com"; // 要查询的域名 int query_len = strlen(query); struct hostent *host_entry; char **address_list; int i; if (argc != 2) { fprintf(stderr, "Usage: %s <domain_name> ", argv[0]); exit(EXIT_FAILURE); } // 创建UDP套接字 udp_fd = socket(AF_INET, SOCK_DGRAM, 0); if (udp_fd < 0) { perror("socket"); exit(EXIT_FAILURE); } // 设置服务器地址结构体 memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(DNS_PORT); inet_pton(AF_INET, "8.8.8.8", &server_addr.sin_addr); // Google公共DNS服务器地址 // 构建DNS查询报文头部 DNSHeader *dns_header = (DNSHeader *)buffer; dns_header>id = (unsigned short)(time(NULL)); // 随机ID生成方式之一 dns_header>rd = 1; // 递归欲望标志置位 dns_header>qr = 0; // 查询报文 dns_header>aa = 0; // 非权威回答 dns_header>tc = 0; // 不可截断 dns_header>z = 0; // 保留位清零 dns_header>ra = 0; // 可用递归标志清零 dns_header>opcode = NS_QUERY; // 标准查询操作码 dns_header>q_count = htons(1); // 一个问题 dns_header>ans_count = 0; // 无回答资源记录 dns_header>auth_count = 0; // 无授权资源记录 dns_header>additional_count = 0; // 无附加资源记录 // 构建DNS查询报文问题部分 char *qname_pos = buffer + sizeof(DNSHeader); for (i = 0; query[i] != ' '; i++) { if (query[i] == '.') { *qname_pos++ = query[i]; // 点符号直接复制 } else { *qname_pos++ = tolower(query[i]); // 其他字符转为小写后复制 } } *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符 *qname_pos++ = ' '; // 结束符
来源互联网整合,作者:小编,如若转载,请注明出处:https://www.aiboce.com/ask/93019.html