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

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

我有一位客户正在向我的 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

-

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

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

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

你能发现一些错误吗?

谢谢

答案1

不要这样做

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

如何做(最佳、正确)

但假设您要根据 QNAME 阻止 DNS 查询。 QNAME 包含一组“标签”。尽管我们请参阅点分符号中的标签,在查询数据包中,每个标签都以其字节长度为前缀,所有标签均以 NUL 结尾。1

1 OP 已经弄清楚了这部分,但听起来它与六角弦有关。

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

HEXSTRING := SUBSTRING [ SUBSTRING ... ]

其中每个SUBSTRING都是其中之一

'\' CHAR
'|' HEXDIGIT HEXDIGIT [ SPACE ] '|'
CHAR

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

接下来,优化搜索:Query 部分开始不早于 DNS 请求的第 13 个字节,这意味着从字节 40 ( 20 (IP) + 8 (UDP) + 13 - 1 ) 开始。如果您可以测试该数据包是一个查询(您应该这样做),那么您无需担心搜索的限制 - 只需搜索到数据包的末尾即可。要测试是否是查询,请测试数据包中字节 31 的高 5 位。您可能还需要考虑 IP 标头的细微差别,在极少数情况下,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" 

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

在 RHEL 6.5 iptables 1.4.7 上测试。

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

答案2

我自己发现的。十六进制字符串不正确。这是正确的。

此外,在更简单的格式中 --hex-string "|04|wpad|06|domanin|04|name|",数值表示单词的长度

-A INPUT -s 5.172.121.170/32 -p udp -m udp --dport 53 -m string \
--hex-string "|047770616406646f6d61696e046e616d65|" --algo kmp \
--to 65535 -m comment --comment "wpad.domain.name" -j DROP

相关内容