Hello,
One of my server had the whole syslog full of lines like this:
1 2 3 4 5 6 |
Feb 17 09:47:05 ns1 named[27994]: client 71.103.252.61#35085 (gqvqvprkgvp.www.x99moyu.net): view external: query (cache) 'gqvqvprkgvp.www.x99moyu.net/A/IN' denied Feb 17 09:47:05 ns1 named[27994]: client 42.225.49.146#34132 (jwhywxp.www.x99moyu.net): view external: query (cache) 'jwhywxp.www.x99moyu.net/A/IN' denied Feb 17 09:47:05 ns1 named[27994]: client 122.183.74.13#15741 (whtotgmli.www.x99moyu.net): view external: query (cache) 'whtotgmli.www.x99moyu.net/A/IN' denied Feb 17 09:47:05 ns1 named[27994]: client 79.31.53.2#53568 (qhnzwuw.www.x99moyu.net): view external: query (cache) 'qhnzwuw.www.x99moyu.net/A/IN' denied Feb 17 09:47:05 ns1 named[27994]: client 86.96.114.164#7526 (psgbswn.www.x99moyu.net): view external: query (cache) 'psgbswn.www.x99moyu.net/A/IN' denied Feb 17 09:47:05 ns1 named[27994]: client 107.68.3.25#55201 (k.www.x99moyu.net): view external: query (cache) 'k.www.x99moyu.net/A/IN' denied |
And it was happening for a long time. It wasn’t a big deal because the request is denied anyway until I had to do some serious modification on this server and discovered that syslog was nearly unusable, thanks to this amazing flood:
1 2 |
root@ns1.domaim.com:~# wc -l /var/log/syslog 84960 /var/log/syslog |
It seems to be impossible to have fine-grained logging with bind9, so I decided to try something else: let’s use shorewall (iptables frontend) to drop all pattern matching “x99moyu.net” (all requests are against this specific domain).
Let’s give iptables a try:
1 |
iptables -A INPUT -p udp --dport 53 -m string --algo bm --string x99moyu -j DROP |
Yeah! Syslog stopped complaining. However, I’m not really happy with solution:
- TCP is not handled as well
- IPV6 isn’t either
- It matches x99moyu instead of x99moyu.net
- It’s not integrated into the system
- It’s not self-documenting
Let’s try to figure out how to match the whole domain first:
1 |
iptables -A INPUT -p udp --dport 53 -m string --algo bm --string x99moyu.net -j DROP |
Won’t work. In fact, the DNS request in constructed a different way:
http://stackoverflow.com/questions/14096966/can-iptables-allow-dns-queries-only-for-a-certain-domain-name?answertab=votes#tab-top
If you look at the contents of the DNS request packet in wireshark or similar you will find that the dot character is not used. Each part of the domain name is a counted string, so the actual bytes of the request for google.com will be:
06 67 6f 6f 67 6c 65 03 63 6f 6d
The first byte (06) is the length of google, followed by the 6 ASCII characters, then a count byte (03) for the length of com followed by… you get the idea.
Yep, I got it. We’ll also need to do a “hex” match instead of a simple string:
1 |
iptables -A INPUT -p udp --dport 53 -m string --algo bm --hex-string "|07|x99moyu|03|net" |
Here we go, here’s the proper iptable line to use, now we can integrate it into our /etc/shorewall/rules and /etc/shorewall6/rules above the “DNS/ACCEPT” line.
# With logging (x99moy is a "tag" displayed in the log lines, limited to 6 chars)
#DNS/DROP:info:x99moy loc fw ; -m string --algo bm --hex-string "|07|x99moyu|03|net"
# Without logging
DNS/DROP loc fw ; -m string --algo bm --hex-string "|07|x99moyu|03|net"