博客
关于我
DNS传输协议解析!pcap报文中的域名获取
阅读量:96 次
发布时间:2019-02-26

本文共 4886 字,大约阅读时间需要 16 分钟。

回想一下,当我们想访问谷歌的时候,通常输入域名(网址):https://www.google.com,其实这就是一个域名。

DNS 解析过程涉及将主机名(例如 https://www.google.com)转换为计算机友好的 IP 地址(例如 172.217.27.142)。Internet 上的每个设备都被分配了一个 IP 地址,必须有该地址才能找到相应的 Internet 设备 。就像使用街道地址来查找特定住所一样。

我们今天主要做的就是解析DNS协议中的域名。

域名系统(DNS)

IP地址是计算机识别Internet上其他计算机的方式。IP地址并不是特别友好。谁想记住一个地址为 34.25.19.8?或者更长的IPV6地址:2401:8954:3291:26a4:7830:8c12:78ce:95c1?

该域名系统(DNS)给了我们人类一种简单的方法来找出我们想要去访问的互联网。我们只需输入“ www.google.com”之类的域名。

一个域名是人类友好的地址,一个网站,东西很容易让我们记住。

DNS传输协议

DNS使用端口53上的用户数据报协议(UDP)来服务DNS查询。首选UDP协议,因为它速度快且开销低。DNS查询是来自DNS客户端的单个UDP请求,然后是来自服务器的单个UDP答复。

/* 用于DNS的端口。  */#define DEFAULT_DNS_PORT_RANGE   "53"#define DEFAULT_DNS_TCP_PORT_RANGE   "53,5353" /*包括mDNS  */#define SCTP_PORT_DNS             53#define UDP_PORT_MDNS           5353#define UDP_PORT_LLMNR          5355#define TCP_PORT_DNS_TLS         853#define UDP_PORT_DNS_DTLS        853

如果DNS响应大于512字节,或者DNS服务器正在管理区域传输之类的任务,则使用传输控制协议(TCP)代替UDP,以实现数据完整性检查。

DNS报文结构

DNS通信通过两种消息发生:查询和响应。DNS查询格式和响应格式都具有以下结构

在这里插入图片描述

Header部分 包含标识、查询数量、响应数量、和其他资源记录数。

Flags字段 包含1位或4位的部分,指示消息的类型,名称服务器是否权威;查询是否是递归的,请求是否被截断以及状态。
Questions部分包含 要解析的域名和记录类型(A,AAAA,MX,TXT等)。域名中的每个标签都以其长度为前缀。
Answer 具有查询名称的资源记录。

DNS Questions

DNS Questions的格式为:

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+| || QNAME || |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+| QTYPE |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+| QCLASS |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

QNAME以标签序列表示的域名,其中每个标签由一个长度组成八位位组,后跟该八位位组的数量。域名以零长度结尾八位位组,表示根的空标签。

QTYPE一个两个八位字节的代码,用于指定查询的类型。您应该为此项目使用0x0001 ,代表A记录(主机地址)。如果您要完成此项目的研究生版本,您还需要将0x000f用于邮件服务器(MX)记录,并将0x0002用于名称服务器(NS)记录。

QCLASS一个两个八位字节的代码,用于指定查询的类。您应该为此始终使用0x0001项目,代表Internet地址。

Wireshark抓包报文查询格式:

在这里插入图片描述

DNS Answers

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+| || || NAME || |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+| TYPE |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+| CLASS |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+| TTL || |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+| RDLENGTH |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--|| RDATA || |+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

NAME查询的域名,与Questions中的QNAME格式相同。TYPE包含第一个类型代码的两个八位位组。此字段指定数据的含义RDATA字段。您应该准备好解释类型0x0001 ( A记录)和类型0x0005( CNAME )。

如果您要完成此项目的研究生版本,则还应该准备接受类型0x0002 (名称服务器)和0x000f (邮件服务器)。

CLASS两个八位字节,用于指定RDATA字段中数据的类别。您应该期望0x0001该项目的Internet地址。

TTL可缓存结果的秒数。

RDLENGTH RDATA字段的长度。

RDATA响应的数据。格式取决于TYPE字段

Wireshark抓包报文响应格式:

在这里插入图片描述

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;};/*	qname_labels_count函数计算'.'的数量,在字符串中加1,	以计算标签数。 */static unsigned int qname_labels_count(const  char* name, int name_len){       unsigned int labels = 0;    int i = 0;    if (name_len > 1) {           /* 这不是零长度的名称 */        for (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);  /* Zero-length name means "root server" */  if (**name == '\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 PayloadLen){ int used_bytes = 0; dnshdr_name dns_domain; //printf("DnsHdr 0x%.2X,0x%.2X,0x%.2X,0x%.2X\n",data_info[0],data_info[1],data_info[2],data_info[3]); 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("used_bytes: %d\n",used_bytes); 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协议可帮助Internet用户和网络设备使用人提供可读的主机名,而不是数字IP地址来发现网站。

对于,深入的理解DNS协议,大家可以看看RFC官方文档。

参考:https://www.rfc-editor.org/info/rfc1035

欢迎关注微信公众号【程序猿编码】,欢迎添加本人微信号(17865354792),欢迎进入技术交流群。我们一起学习进步!

转载地址:http://yuiy.baihongyu.com/

你可能感兴趣的文章
mysql 主从
查看>>
mysql 主从 lock_mysql 主从同步权限mysql 行锁的实现
查看>>
mysql 主从互备份_mysql互为主从实战设置详解及自动化备份(Centos7.2)
查看>>
mysql 主从关系切换
查看>>
MYSQL 主从同步文档的大坑
查看>>
mysql 主键重复则覆盖_数据库主键不能重复
查看>>
Mysql 事务知识点与优化建议
查看>>
Mysql 优化 or
查看>>
mysql 优化器 key_mysql – 选择*和查询优化器
查看>>
MySQL 优化:Explain 执行计划详解
查看>>
Mysql 会导致锁表的语法
查看>>
mysql 使用sql文件恢复数据库
查看>>
mysql 修改默认字符集为utf8
查看>>
Mysql 共享锁
查看>>
MySQL 内核深度优化
查看>>
mysql 内连接、自然连接、外连接的区别
查看>>
mysql 写入慢优化
查看>>
mysql 分组统计SQL语句
查看>>
Mysql 分页
查看>>
Mysql 分页语句 Limit原理
查看>>