iptables drop negative DNS responses

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

Solution 1:

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.

Solution 2:

This drops BIND9 "rejected" replies to the current spoofed UDP queries!

iptables -F OUTPUT 
#iptables -A OUTPUT -p udp --sport 53 -j LOG --log-prefix="OUT-UPD-RAW : "
#iptables -A OUTPUT -m u32 -p udp --sport 53 --u32 "28&0xFFFF=0x8105" -j LOG --log-prefix="STOPPED-DNS-REJECTED-REPLY "
iptables -A OUTPUT -m u32 -p udp --sport 53 --u32 "28&0xFFFF=0x8105" -j DROP
iptables -A OUTPUT -p udp --sport 53 -j LOG --log-prefix="OUT-UPD-SENT: "

Solution 3:

@DukeLion is correct, but you should also be aware of NOERROR but NOANSWER. To drop this too, add this iptables rule:

iptables -I INPUT -m u32 -p udp --sport 53 --u32 "32&0xFFFF=0x0000" -j DROP

PS. DNS RCODE in IP packet "real" offset is 31.5 bytes, so I don't like matching it use 0x1e&0x30000=0x30000