Conntrack and UDP DNS with iptables

Conntrack (or rather connection tracking) is a pretty useful thing; That’s however not necessarily the case with udp dns packets. Here’s how to disable it with iptables.

If you want to read more on the topic I really suggest the article Linux connection tracking and DNS in ISCs knowledge base.

Disabling connection tracking for UDP DNS

Basically the following disables connection tracking for UDP/DNS:

iptables -t raw -A PREROUTING -p udp --sport 53 -j NOTRACK
iptables -t raw -A PREROUTING -p udp --dport 53 -j NOTRACK
 
iptables -t raw -A OUTPUT -p udp --sport 53 -j NOTRACK
iptables -t raw -A OUTPUT -p udp --dport 53 -j NOTRACK

Additional, since no inbound filtering should be used (well you may, though prefer using Response Rate Limiting on authoritative servers) to accept those packets early you can accept the state UNTRACKED:

iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED,UNTRACKED -j ACCEPT

Connection tracking with TCP DNS

The ISC article states that conntrack is fine for TCP and that they haven’t had any issues there; I’ve read some articles in which people state that disabling connection tracking in general offers better latency/performance especially on high bandwidth systems. I wasn’t able to reproduce that / I didn’t notice any performance benefit from disabling connection tracking in TCP. If you want to do so, you might just duplicate the above rules in the raw-table and replace udp with tcp. If you don’t, you’ll most likely want the following rules:

iptables -A INPUT -p tcp --dport 53 -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -p tcp --sport 53 -m conntrack --ctstate NEW -j ACCEPT

Example

So a pretty simple stateful firewall might look like this:

# exempt udp dns of connection tracking
iptables -t raw -A PREROUTING -p udp --sport 53 -j NOTRACK
iptables -t raw -A PREROUTING -p udp --dport 53 -j NOTRACK
iptables -t raw -A OUTPUT -p udp --sport 53 -j NOTRACK
iptables -t raw -A OUTPUT -p udp --dport 53 -j NOTRACK
 
# allow related, established and untracked packets
iptables -A INPUT -m conntrack --ctstate UNTRACKED -j ACCEPT
iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
 
# allow new tcp dns packets
iptables -A INPUT -p tcp --dport 53 -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -p tcp --sport 53 -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -p tcp --dport 53 -j REJECT
iptables -A INPUT -p tcp --sport 53 -j REJECT
# in case you do not use the UNTRACKED ACCEPT rule above because you
# want to be more restrictive, use this instead
# iptables -A INPUT -p udp --dport 53 -j ACCEPT 
# iptables -A INPUT -p udp --sport 53 -j ACCEPT
 
# allow new ssh packets
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -j REJECT
 
# drop all invalid packets
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP

For IPv6 you would duplicate the above rules and use ip6tables.

Update: Modified example rulesets a bit and also added examples for nftables here

No Comments

Post a Comment