How to drop incoming negative DNS responses in Linux? (I want a timeout instead) I'm thinking of creating an iptables rule:
iptables -I INPUT -p udp --sport 53 -m u32 ...
From wireshark:
000E start of IP Packet (fixed, at first, I wrote 0010)
0022 start of UDP Packet
002A start of DNS message
002C Flags
.... .... .... 0000 = Reply code: No error (0)
.... .... .... 0011 = Reply code: No such name (3)
I think the offset for -m u32 is counted from the ip header. Also subtracting 2 to get a 32bit.
$ echo $(( 0x002C - 0x000E - 2 ))
28
The mask for the last 4 bits is 0xF
So the rule should be something like this:
iptables -I INPUT -p udp --sport 53 -m u32 --u32 "28&0xF=3" -j DROP
Offset for DNS flags in ip packet is 28bytes and you need to check last 2 bits in 2byte field u32 rule for that is
"28&0x000F=0x03"
My test rule is:
iptables -A INPUT -m u32 -p udp --sport 53 --u32 "28&0x000F=0x03" -j LOG
BTW I like the idea to use this firewall rule for split horizon DNS, going to test it for some of my networks.
This drops BIND9 "rejected" replies to the current spoofed UDP queries!
@DukeLion is correct, but you should also be aware of NOERROR but NOANSWER. To drop this too, add this iptables rule:
PS. DNS RCODE in IP packet "real" offset is 31.5 bytes, so I don't like matching it use
0x1e&0x30000=0x30000
Dropping negative responses worked fine until I added more than one
search
domain to/etc/resolv.conf
: libc tries the suffixes sequentially and if I drop the negative responses for the wrong suffix initially picked by the libc resolver it gives up with a timeout before it tries the right suffix.So I decided to delay the negative responses instead of dropping them. This makes sure
dnsmasq
gets the positive response from the right server before it gets the negative responses from the other servers.Delaying is done not with
iptables
, but withiproute2
. Here's my configuration for a modern systemd Linux:/etc/modules-load.d/my-tc.conf
/etc/systemd/system/my-tc.service
/etc/NetworkManager/dispatcher.d/my-tc.sh