IPTables - 十六进制字符串块 DNS 查询

Fed*_*eri 1 dns iptables

我有一个客户在我的 DNS 服务器上发送大量针对特定域的查询。我想阻止该查询,我找到了可以实现的十六进制字符串。那是字符串:

iptables -I INPUT 1 -p udp --dport 53 --match string --algo kmp --hex-string '|77 70 61 64 2e 64 6f 6d 61 69 6e 2e 6e 61 6d 65|' -j DROP
Run Code Online (Sandbox Code Playgroud)

——

0     0 DROP       udp  --  *      *       0.0.0.0/0            0.0.0.0/0            udp dpt:53 STRING match  "wpad.domain.name" ALGO name kmp TO 65535
Run Code Online (Sandbox Code Playgroud)

但似乎这不起作用,因为当我对该服务器查询该名称时,我可以看到回复并且计数器保持为零

root@banana:~# dig @5.172.120.59 wpad.domain.name

; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> @5.172.120.59 wpad.domain.name
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: SERVFAIL, id: 29891
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;wpad.domain.name.              IN      A

;; Query time: 136 msec
;; SERVER: 5.172.120.59#53(5.172.120.59)
;; WHEN: Thu Nov 26 22:55:30 2015
;; MSG SIZE  rcvd: 34
Run Code Online (Sandbox Code Playgroud)

你能发现一些错误吗?

谢谢

Oth*_*eus 6

不要这样做

...至少不是对于这个特定的 DNS 请求。为什么不?嗯,首先,你并没有真正让你自己和你的 CPU 变得更容易,而且你让客户端变得更糟。当给定 DHCP 地址时,几乎每个平台上的每个浏览器都使用“自动代理检测”。这种自动检测的工作原理是寻找一个主机名DNS条目wpad.subdomain.subdomain.currentdomain.xx过程使用到wpad.currentdomain.xx。其次,浏览器请求操作系统获取 DNS,操作系统(受制于各种 TCP/UDP 参数)将不断尝试向 DNS 服务器请求,直到得到答复。当您阻止输入时,您将完全阻止您的 DNS 服务器给出任何答案,因此客户端会再次尝试一次又一次。通过阻止它,您不会以某种方式“训练”客户端停止发送请求。如果它没有得到答案,它只是停止尝试使用代理并使用直接连接。同时,用户只是那里等待浏览器尝试直接连接。在浏览器响应之前,她可能会在那里等待 15 秒。此机制现已内置于所有 Android 和 iOS 设备中,因此每台 iPad、AppleTV、三星智能手机都需要很长时间才能连接到互联网。所以基本上,你带来了一个家伙。

怎么做(最佳,正确)

但是假设您要阻止基于 QNAME 的 DNS 查询。QNAME 包含一组“标签”。虽然我们看到点分符号中的标签,但在查询数据包中,每个标签都以其长度为前缀,以字节为单位,所有这些都以 NUL 结尾。1

1 OP 已经弄清楚了这部分,但听起来好像与十六进制字符串有关。

十六进制字符串,正如我通过查看 iptables 的来源所确认的那样1.4.9,因为我找不到任何手册来充分描述其行为,是(准 BNF)形式

HEXSTRING := SUBSTRING [ SUBSTRING ... ]
Run Code Online (Sandbox Code Playgroud)

其中每个SUBSTRING都是其中之一

'\' CHAR
'|' HEXDIGIT HEXDIGIT [ SPACE ] '|'
CHAR
Run Code Online (Sandbox Code Playgroud)

其中 CHAR 几乎是输入可以处理的任何内容,而 HEXDIGIT 是 isxdigit() 所说的内容,组合通过sscanf(s,"%x",buf). 转义字符确保可以绕过“十六进制模式”并匹配文字字符串“|”。否则,它没有什么特别的。|如果当前 SUBSTRING 是 HEX-STRING 中的最后一个,则尾随不是绝对必要的。

接下来优化搜索:Query部分不早于DNS请求的第13个字节开始,即从第40字节开始(20(IP)+8(UDP)+13-1)。如果您可以测试数据包是否是一个查询,那么您就不必担心搜索的限制——只需搜索到数据包的末尾即可。要测试它是否是查询,请测试数据包中字节 31 的高 5 位。您可能还需要考虑 IP 标头的细微差别,在极少数情况下,它是 24+ 个字节而不是 20 个,从而使字节测试为 35(或 39)。

使用bm(Boyer-Moore) 算法进一步优化。没有任何问题kmp,但总的来说,Boyer-Moore 速度更快,使用的资源更少。

把它们结合在一起,我们应该有这样的东西:

-A INPUT -s 5.172.121.170/32 -p udp -m udp --dport 53 \
-m u32 --u32 "28 & 0xF8 = 0" \
-m string --algo bm --from 40 \
--hex-string "|04|wpad|08|mydomain|03|isa|04|dick" 
Run Code Online (Sandbox Code Playgroud)

--u32部分说“从数据包的第 28 个(0 索引)字节开始抓取 4 个字节……即字节 28、29、30、31,并用 0x000000F8 掩码 32 位值……这只是查看字节 31 的高五位……如果是 0,则匹配。” 的--from部分,如前所述,开始包的“问题”一节中的字符串搜索。这应该避免误报。

在 RHEL 6.5 iptables 1.4.7 上测试。

为了迂腐,制定另一个规则,测试 IP 头字段字节 0 的头长度,并匹配从字节 32 开始的 DNS 查询。