win系统下, CMD中可以使用nslookup命令查看域名IP地址。DNS协议与请求-编程之家

DNS服务器与客户端通过带有header和question的协议进行查询与返回,其中header分为六项,分别为ID(会话标识),Flags(标志),questions(问题数),Answer RRs(回答资源记录数),Authority RRs(授权 资源记录数),Addition RRs(附加资源记录数)。

1.header 填充函数

        首先判断输入参数是否有效,对暂不使用的线束进行归零处理。

struct dns_header {unsigned short id;unsigned short flags;unsigned short questions; unsigned short answer;unsigned short authority;unsigned short additional;};int dns_create_header(struct dns_header *header) {srandom(time(NULL));header->id = random();//1970年至今的秒数为范围产生一个随机数   为多线程不安全函数header->flags = htons(0x0100); //htons 为网络字节转换  将其转换为相应格式header->questions = htons(1);  //请求一个域名return 0;
}

         其中flags标志位分为以下位置(2字节)DNS协议与请求-编程之家

         QR为查询与响应标志,0查询,1响应

        opcode 0表示标准查询 1 反向查询 2 服务器请求状态

        AA表示授权回答 

        TC表示可截断的

        RD表示期望递归

        RA表示可用递归

        rcode表示返回码 0表示无差错 3表示名字错 2表示服务器错误

        Questions、Answer RRs、Authority RRs、Additional RRs 各自 表示后面的四个区域的数目。Questions 表示查询问题区域节的数量,Answers 表示回答区 域的数量,Authoritative namesversers 表示授权区域的数量,Additional recoreds 表示 附加区域的数量

2.问题创建

        由以下四部分组成,查询名 name,查询类型 type,class 查询类,length域名字节数

struct dns_question {int length;unsigned short qtype;  //1 表示IPV4 地址  5 表示查询规范域名unsigned short qclass; // 通常为1 表示inet数据unsigned char *name; // 
};

其中,name 不定长字符串,且域名需要按照相应规范书写。例如www.baidu.com应保存为3www5baidu3com0,末尾0不可省去。

int dns_create_question(struct dns_question *question, const char *hostname) {question->name = (char*)malloc(strlen(hostname) + 2);question->length = strlen(hostname) + 2;question->qtype = htons(1); question->qclass = htons(1);const char delim[2] = "."; //分隔符char *qname = question->name;char *hostname_dup = strdup(hostname); //  函数中存在一个malloc 进行复制一份需要对应freechar *token = strtok(hostname_dup, delim);  //分割出第一段 wwwwhile (token != NULL) {           //还没分割结束size_t len = strlen(token);   //长度*qname = len;                 //长度放入字符串qname ++;strncpy(qname, token, len+1); //字符串放入  +1可以使最后不需要单独放一次0qname += len;                 //向后移位token = strtok(NULL, delim);  //再次分割// 此处使用NULL 上次的tok还未结束,仍然tok的是hostname//如操作临界资源  则为线程不安全函数}free(hostname_dup);}

  3.数据发送

        建立一个sockfd句柄

int sockfd = socket(AF_INET, SOCK_DGRAM, 0);//AF_INET 表示协议组 SOCK_DGRAM表示数据报文方式

        建立地址结构,其中sockaddr_in为发往服务器结构,约定俗成三项地址定义,欢迎抬杠知识老师原话。

struct sockaddr_in servaddr = {0}; // 
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(PORT);
servaddr.sin_addr.s_addr = inet_addr(IP);

        创建header、question并进行合并。request即为将字符串合为一个。

struct dns_header header = {0};
dns_create_header(&header);struct dns_question question = {0};
dns_create_question(&question, domain);char request[1024] = {0};
int length = dns_build_request(&header, &question, request, 1024);

        数据发送,参数为sock句柄,发送的字符串,字符串长度,地址以及地址长度。

sendto(sockfd, request, length, 0, (struct sockaddr*)&servaddr, sizeof(struct sockaddr));

        数据接收,参数与上一个函数基本相同。在response中即可查询到相应IP地址。

	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);

4.UDP好处 

相较于TCP,UDP速度更快,不限下载带宽,一人下载一屋子骂人,且响应速度快,多应用于游戏中