2009-07-11

Iptables: router performance

Original: Iptables – производительность роутера (Russian)
Incorrect iptables settings may cause poor router performance. I'll show you how can you improve iptables performance

Disable connection tracking

The first thing you need to do (if you are not using NAT) is to disable connection tracking in nat table, PREROUTING chain:
iptables -A PREROUTING -j NOTRACK

Notice that if you have rules with match module, you'll have to change them to avoid match module. Also, all rules using conntrack will stop working.

Place 'hottest' rules to the top

Iptables checks rules in linear order, one by one, and each network packet would go through the chain from first rule and until first condition match, That's why it's important to place most popular rules to beginning of the chain.
You could check what rules are hottest using following commend:
iptables -L -n -v
Example: We have border router with ~10 000 clients. Some of the ip addresses needs to be blocked. E.g. we have 2 000 blocked ip addresses, so we have 2 000 rules in iptables like
iptables -A FORWARD -s 192.168.0.1 -j DROP
iptables -A FORWARD -s 192.168.0.20 -j DROP
iptables -A FORWARD -s 192.168.0.34 -j DROP
# and so on 
iptables -A FORWARD -s 192.168.1.2 -j DROP
iptables -A FORWARD -s 192.168.1.15 -j DROP
iptables -A FORWARD -s 192.168.1.23 -j DROP
# and so on 
iptables -A FORWARD -s 192.168.2.1 -j DROP
iptables -A FORWARD -s 192.168.2.2 -j DROP
iptables -A FORWARD -s 192.168.2.3 -j DROP
# and so on
iptables -A FORWARD -s 192.168.7.10 -j DROP
iptables -A FORWARD -s 192.168.7.18 -j DROP
iptables -A FORWARD -s 192.168.7.254 -j DROP
# and allow all other ip addresses
iptables -A FORWARD  -j ACCEPT

In this configuration every single packet (e.g. from non-blocked 192.168.2.123) would be checked 2 000 times. This is terrible!
But there is a solution: rewrite rules as follows:

# create chain for every subnet
iptables -A FORWARD -s 192.168.0.0/24 -j NET-00
iptables -A FORWARD -s 192.168.1.0/24 -j NET-01
iptables -A FORWARD -s 192.168.2.0/24 -j NET-02
iptables -A FORWARD -s 192.168.3.0/24 -j NET-03
iptables -A FORWARD -s 192.168.4.0/24 -j NET-04
iptables -A FORWARD -s 192.168.5.0/24 -j NET-05
iptables -A FORWARD -s 192.168.6.0/24 -j NET-06
iptables -A FORWARD -s 192.168.7.0/24 -j NET-07
# and check blocked ip addresses in this chains
iptables -A NET-00 -s 192.168.0.1 -j DROP
iptables -A NET-00 -s 192.168.0.20 -j DROP
iptables -A NET-00 -s 192.168.0.34 -j DROP
# and so on
iptables -A NET-01 -s 192.168.1.2 -j DROP
iptables -A NET-01 -s 192.168.1.25 -j DROP
iptables -A NET-01 -s 192.168.1.23 -j DROP
# and so on for all other chains
# and accept pachet in the end:
iptables -A FORWARD  -j ACCEPT

In this case maximum 255 checks would be applied to the packet, which is much better.
Another way to solve bottleneck is to use ipset.