Linux: Block DNS queries for specific zone with IPTables

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'
Leave A Reply - 5 Replies
Replies
Dan 2015-03-24 10:28am - No Email - Logged IP: 98.174.147.34

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.

Renny 2015-05-31 05:14am - rennyindia@... - Logged IP: 122.178.63.178

I think for A record the code is 0001 not 0011

Renny N 2015-10-20 02:09pm - rennyindia@... - Logged IP: 198.24.6.220

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.

Appa 2018-11-05 09:31pm - No Email - Logged IP: 67.11.156.208

Thank you for this! Been battling a botnet and this using this method is what ultimately did the trick.

John 2022-04-21 09:32am - No Email - Logged IP: 39.109.132.118

how to drop "." queries or all ANY queries?

All content licensed under the Creative Commons License