教你动手写UDP协议栈—DNS报文解析

教你动手写udp协议栈系列文章序号内容1《教你动手写udp协议栈-udp协议栈格式》2《教你动手写udp协议栈-dhcp报文解析》3《教你动手写udp协议栈-ota上位机》4《教你动手写udp协议栈-dns报文解析》背景因特网上的节点通过ip地址唯一标识,并且能通过ip地址来识别参与分布式应用的主机。但对于大多数人来说,这些地址太繁琐而且难以使用和记忆(特别是ipv6地址)。因此互联网支持使用主机名称来识别包括客户机和服务器在内的主机。
为了使用如tcp和ip等协议,主机名称可以通过称为域名解析的过程转换成ip地址。在互联网中存在不同形式的名称解析,但是最普遍、最重要的一种是采用分布式数据库系统,即我们熟知的域名系统(dns),也是这篇文章的主角。dns - 是一个分布式的客户机-服务器网络数据库,tcp/ip应用程序使用它来完成主机名称和ip地址之间的映射,提供电子邮件路由信息、服务命名和其他服务。dns使用tcp和udp的端口--53。dns - 为了可扩展性,dns名称是分层的。每一级域名长度的限制是63个字符,域名总长度则不能超过253个字符。下面来介绍dns报文的格式解析,以及如何将域名转为ip地址的流程。准备工具工具介绍wireshark网络封包分析软件,分析数据包cmdwindow 命令行dns报文解析抓包分析打开cmd和wireshark工具。在wireshark中设置过滤信息,我们只抓取dns报文。在cmd键入ping www.baidu.com,然后查看wireshark的抓包信息。
可以看到两包dns报文,一个是dns发送报文,一个是dns接收报文发送报文
接收报文
发送报文和接收报文格式是不一样的,从上面截图可以看到,接收报文多一个answers字段。
dns可以使用udp与tcp两种协议。这里我们主要以udp进行分析。
dns报文字段解析dns报文格式:
dns字段格式:发送报文
接收报文
dns报文头部
字段说明字段说明transaction id辨别dns应答报文是哪个请求报文的响应qrflags字段,1为响应,0位查询opcodeflags字段,查询或响应类型,0为标准,1为反向,2为服务器状态请求aaflags字段,授权回答tcflags字段,截断,1表示超过512字节并已被截断,0表示没有发送截断rdflags字段,是否希望得到递归回答raflags字段,响应报文中为1便是得到递归响应zflags字段,0adflags字段,真是数据cdflags字段,禁止校验rcodeflags字段,返回码:0-无差错,1-格式错误,2-服务器失效,3-不存在域名,4-查询类型不支持,5-被禁止,6-15保留questionsflags字段,查询数answerflags字段,资源记录数authorityflags字段,授权资源记录数additionalflags字段,额外资源记录数代码实现/** 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查询类代码实现(由于名字是不定长,另作处理)pack_struct_beginstruct dns_query {  pack_struct_field(uint16_t type);  pack_struct_field(uint16_t class);}pack_struct_struct;pack_struct_enddns报文应答字段
字段说明(此字段只有应答包才有)字段说明name查询名称,不定长type查询类型class查询类ttl该资源记录的生命周期data length资源数据长度address返回的ip地址,即域名转换的ip地址代码实现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报文发送实现代码实现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);
       //将域名转换dns数据包格式        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报文发送        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);    }}验证代码结果,我们通过查询csdn的ip地址,csdn的域名:www.csdn.net
通过wireshark抓包,可以看到我们dns报文已发送成功,并且有应答包
dns报文接收实现代码实现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.addr[0],                                                    dns_ans->server_ip.addr[1],                                                   dns_ans->server_ip.addr[2],                                                   dns_ans->server_ip.addr[3]);        }    }    free(server_dns_name);}通过wireshark抓包的ip与代码捕获的ip一致:


深度学习领域Facebook等巨头在2017都做了什么
百度AI芯片:7nm昆仑2即将进入量产
ucc28019引脚图和特点
财付通扣钱人工服务电话
自适应微带相控阵天线建模模块设计
教你动手写UDP协议栈—DNS报文解析
脑机接口真的值得我们期待吗?
玖云平台智能云调度助力证券行业95号码申请落地
龙芯国产网络安全主板,网安守护就看它
伺服电机的工作原理是什么
飞腾与中国信通院开展联合培训,助力集成电路知识产权保护
物联网开启了安防智能化的深度应用 为大家提供了更加广泛的想象空间
国微思尔芯获评上海市“专精特新”企业
电子战系统中的数字射频存储器(DRFM)应用
多核异构工业开发板:创龙科技T113-i
红米note4x,魅蓝note5这几款手机闭着眼睛都不会买错的
微软收购5G核心网供应商引起大反响
LED显示屏灌封胶有什么特点,选购时有哪些注意事项
激光雷达与视觉感知的优劣对比
桥堆的芯片的作用