Linux: Block DNS queries for specific zone with IPTables
转载自 https://www.perturb.org/display/1186_Linux_Block_DNS_queries_for_specific_zone_with_IPTables.html
I have been seeing a lot of weird/bogus DNS traffic (thousands of queries a second) hitting our servers lately and I decided to try and block it. Specifically I saw tons of requests coming in for proxypipe.net
with a bunch of random hosts prepended. Things like: 6Gdb1QlP.f.proxypipe.net., mhl00ULG.e.proxypipe.net., clacqxlG.f.proxypipe.net., etc. I decided I would block all DNS requests that contained the “proxypipe.net” anywhere in the packet.
The easiest way is to use iptables to block packets that contain a specific string. The problem with this approach is that DNS packets do not contain the actual string. Instead they are encoded in this manner: X domain Y TLD
Where X is the number of bytes in the domain portion, and Y is the number bytes of characters in the TLD portion. This makes your iptables rules look like this:
iptables -A INPUT -i eth0 -p udp --dport 53 -m string --hex-string "|09|proxypipe|03|net" --algo bm -j DROP
iptables -A INPUT -i eth0 -p udp --dport 53 -m string --hex-string "|06|kitten|02|ru" --algo bm -j DROP
iptables -A INPUT -i eth0 -p udp --dport 53 -m string --hex-string "|03|www|07|puppies|04|woof" --algo bm -j DROP
Advanced:
Technically the query looks like X domain Y TLD 0
where the zero indicates that there are no more parts of the domain. This is immediately followed by two bytes indicating the type of query.
This allows you to get fancy and only block specific types of queries for a domain while allowing others:
Type | Code |
---|---|
Any | 00ff |
A | 0011 |
CNAME | 0005 |
MX | 000f |
AAAA | 001c |
NS | 0002 |
SOA | 0006 |
If you wanted to block all MX requests for domain.com
you would do a rule like this:
iptables -A INPUT -i eth0 -p udp --dport 53 -m string --hex-string "|06|domain|03|com|00000f|" --algo bm -j DROP
IPTables converts your string rules to hex, so it is helpful to add a comment so you can read them later using iptables -vnL
. You can use the iptables comment module to document your rules.
iptables -A INPUT -i eth0 -p udp --dport 53 -m string --hex-string "|06|domain|03|net|00000f|" \
--algo bm -j DROP -m comment --comment 'Block domain.net MX'
Nice iptables mention here. However, while I am following you on this post completely and others……
What does the 06 and the 03 in the line …..
AHHHH HAHA I get it….. that is the character count. |06|domain…..|03|net… etc.
Nice.
I think for A record the code is 0001 not 0011
I wanted to write a rule to allow only dns query(A record) for domain ‘example.domain.com’ and drop all other quires.
I applied the below rule ###############################################3 iptables -A INPUT -d 10.X.X.X -p udp –dport 53 -m string –hex-string “|07|example|06|domain|03|com|000001|” –algo bm -j ACCEPT -m comment –comment “Allow dns query for fqdn example.domain.com”
iptables -N LOGGING iptables -A INPUT -p tcp –dport 53 -d 10..X.X.X -j LOGGING -m comment –comment “Drop all other packets hitting tcp port 53 ”
iptables -A LOGGING -m limit –limit 2/sec -j LOG –log-prefix “IPTables-Dropped: ” –log-level 4 iptables -A LOGGING -j DROP ####################################################33
This works fine .. but the rule also allows the DNS query for FQDN X.example.domain.com.. Can any one please suggest to improve the rules.. so that it blocks ‘X.example.domain.com’ as well.