dns ptr反查和报文解析实践

前文

之前在php扫描同路由下的设备中用到php 内置的gethostbyaddr去反查地址名称,但速度太慢了。
如下数据,扫描加反查要22秒。

  • gethostbyaddr
ip=192.168.2.1 name=RT-AC3100-C45B.lan send=1 recive=1 loss=0.00%  min=2.53ms max=2.53ms avg=2.53ms
ip=192.168.2.13 name=BL-c0-74-68.lan send=1 recive=1 loss=0.00%  min=49.27ms max=49.27ms avg=49.27ms
ip=192.168.2.50 name=192.168.2.50 send=1 recive=1 loss=0.00%  min=2.40ms max=2.40ms avg=2.40ms
ip=192.168.2.78 name=TL-IPC42A-4.lan send=1 recive=1 loss=0.00%  min=7.54ms max=7.54ms avg=7.54ms
ip=192.168.2.205 name=MI5-xiaomishouji.lan send=1 recive=1 loss=0.00%  min=158.06ms max=158.06ms avg=158.06ms
ip=192.168.2.215 name=lwb-R5zen.lan send=1 recive=1 loss=0.00%  min=0.23ms max=0.23ms avg=0.23ms
ip=192.168.2.240 name=192.168.2.240 send=1 recive=1 loss=0.00%  min=3.25ms max=3.25ms avg=3.25ms
total time_ms 22011.496067047
total cnt 6

尝试

在我思考如何能加速度的过程中,我逛到了php 的官方文档。其中有个评论是自己构建了一个可以设定超时,向指定服务器查询的gethostbyaddr_timeout。一顿操作,试了下。效果还可以,同样的代码,扫描加反查只要3.8秒。

  • gethostbyaddr_timeout
total time_ms 3872.8039264679
total cnt 6

单次查询对比

数据

  • 没有host返回的

    • 目标 1.0.0.2
    • 结果
    次序方法返回花费时间(s)
    1gethostbyaddr1.0.0.29.2134771347046
    2gethostbyaddr_timeout1.0.0.20.014039039611816
    3gethostbyaddr1.0.0.29.0230431556702
    4gethostbyaddr_timeout1.0.0.20.013981819152832
  • 有host返回的

    • 目标 8.8.8.8
    • 清除本地dns缓存
    次序方法返回花费时间(s)
    1gethostbyaddrdns.google0.0071818828582764
    2gethostbyaddr_timeoutdns.google0.0041348934173584
    3gethostbyaddrdns.google0.00032496452331543
    4gethostbyaddr_timeoutdns.google0.0037519931793213
    • 清除本地dns缓存
    次序方法返回花费时间(s)
    1gethostbyaddrdns.google0.0039701461791992
    2gethostbyaddr_timeoutdns.google0.0048518180847168
    3gethostbyaddrdns.google0.00065708160400391
    4gethostbyaddr_timeoutdns.google0.0048589706420898

小结

  1. 无host返回,gethostbyaddr_timeout 优势很明显。
  2. 有host返回时
    1. 无本地dns缓存时
      1. gethostbyaddr_timeout 首次稍微快一倍
    2. 有本地dns缓存时,gethostbyaddr 和 gethostbyaddr 差距很小
      这应该是本地查和到指定dns服务器查的差距
    3. gethostbyaddr 首次调用后之后的速度就很快了,似乎有进程内缓存
    4. gethostbyaddr_timeout 每次调用时间差不多

实例分析

首先我的脚本是扫描局域网内的设备,局域网内的路由器本身就是一个dns服务器。对于该场景下,明显通过gethostbyaddr_timeout向路由查询会就可以了。gethostbyaddr 会进行迭代查询,一层又一层,如果没有host返回,9s的阻塞不能接受的。并且,每个ip是运行没有host的,这并不是一个强制性的规范,如果直接使用,妥妥的九九八十一难了。正如开头,刚好2个设备就是没有host的,其22秒的组成也就是 9 + 9 + 4。

Obsoleting IQUERY

IQUERY 已过时, 且已被弃用。主要原因是:

  1. 概念不明确,
  2. 逆向查询处理会给服务器带来相当沉重的负担并且需要维护一个键值数据库
  3. 对于大型权威服务器会返回包过大容易被发起拒绝服务攻击
  4. 服务商通常会禁用这个功能
  5. 无法告知去那里获取全部记录
  6. 没有成型应用
  7. 有更好替代方案:指针记录(PTR)的反向解析

PTR反查报文

目标 192.168.2.215,PTR 发送一个查询报文,但查询内容为是 192.168.2.15 书写顺序相反的 215.2.168.192 作为前缀的 in-addr.arpa 子域名,即

215.2.168.192.in-addr.arpa

implode('.',array_reverse(explode('.','192.168.2.215')))
// 215.2.168.192

请求报文

## 头部
53 49 1 0 				# 53 49 标识	1 RD=1 ,表示客户端希望服务器可以执行递归查询
0 1 0 0 				# 问题记录 1个
0 0 0 0 
## 问题
3 					# 长度 3
50 49 53 				# 215
1 					# 长度 1
50 					# 2
3 					# 长度 3	
49 54 56 				# 168
3 					# 长度 3
49 57 50 				# 192
7 					# 长度 7
105 110 45 97 100 100 114 		# in-addr
4 					# 长度 4
97 114 112 97 				# arpa
0 					# 表示 根域
0 12 0 1				# type 12 PTR反查, class 1 ipv4
标志

其中 53 49 1 0 的标志“1 0”,转为二进制为

0 0000 0 0 1 0 000 0000

qurey codeopcode x4AATCRDRA保留位 x 3response code x 4
00001000
查询请求标准查询-非截短递归查询-0没有差错

返回报文

// 头部
55 53 133 128 
0 1 0 1 			## 01 问题1 ,01 答案 1 
0 0 0 0 
// 问题
3 50 49 53 
1 50 
3 49 54 56 
3 49 57 50 
7 105 110 45 97 100 100 114 
4 97 114 112 97 
0 
0 12 0 1 
// 答案
192 12 				## 压缩域名
0 12 0 1 			## type ,class
0 0 0 0 			## TTL	
0 15 				## 资源长度 
9 				## 长度
108 119 98 45 82 53 122 101 110 ## 见 Resource Data
3 				## 长度	
108 97 110 			## 见 Resource Data
0				## 根域
标志

“55 53 133 128”中的标志“133 128”,转为二进制为

1 0000 1 0 1 1 000 0000

qurey codeopcode x4AATCRDRA保留位 x 3response code x 4
10101100
查询应答标准查询权威回答非截短递归查询服务器支持递归查询0没有差错
答案
name

192 12 转为 二进制,这里并没有直接保存name,而是域名压缩,因为在问题里面已经包含了域名信息,所以这里采用字节偏移来表示。

11000000 1100

域名在报文中第二次出现时,只用两个字节来保存。第一个字节最高两位都是 1 ,余下部分和第二个字节组合在一起,表示域名第一次出现时在报文中的偏移量。通过这个偏移量,就可以找到对应的域名。

这里的12刚好是头部的长度,如果只有一个问题,这应该是个固定值,如果还有一个问题,那么第二个问题这个偏移就会再加上第一个问题的长度。

Resource Data
  • 108 119 98 45 82 53 122 101 110
(('108 119 98 45 82 53 122 101 110'.split(' ')).map(function(item){return String.fromCharCode(item)})).join('')
// 'lwb-R5zen'
  • 108 97 110
(('108 97 110'.split(' ')).map(function(item){return String.fromCharCode(item)})).join('')
// 'lan'

点拼接也就是

ip=192.168.2.215 name=lwb-R5zen.lan

收获

  1. 原本以为反查用的是dns中的IQUERY,甚至在看到IQUERY启用前,我还以为PTR只是反查报文的一种格式,其实二者完全不一样。
  2. dns的报文头是最容易理解的,固定长度,一一对应即可。而到了问题和答案,除了特定的结构外,还需要通过计算长度去获取后续信息,即便在PNG格式中已经接触过一次,还是在阅读上花费了不少时间。
  3. 应答的name压缩还是让我有点惊讶,最开始还理所应当的以为是问题一样,看半天怎么都对不上。直到发现是name压缩,不得不说,确实巧妙。
  4. 之前已经看过并摘录了DNS报文格式,但实际上,读抄远远不如上手操作一番,唯一的好处就是查的时候方便许多。

参考

gethostbyaddr_timeout
反向DNS
小菜学网络之DNS报文格式
[摘]DNS报文格式解析

原文地址

dns ptr反查和报文解析实践 https://bjun.tech/blog/xphp/131

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值