IPsec and iptables
From Wikked
IPsec and iptables affect eachother in nonobvious ways, sometimes.
One of my hosts, femke, is a NAT router for another machine behind it (talon), because the available public IPs have suddenly been restricted to 1 at some point. To make the NAT as transparent as possible, femke is set up to forward all traffic to talon by default, besides some specific exceptions.
Implementation
This is implemented using iptables rules in the PREROUTING chain in the nat table. First, the exceptions are listed, e.g.:
# SSH
iptables -t nat -A PREROUTING -p tcp -i eth0 -d 84.35.36.41 --dport 22 \
-m state --state NEW,ESTABLISHED,RELATED -j RETURN
# Web server
iptables -t nat -A PREROUTING -p tcp -i eth0 -d 84.35.36.41 --dport 80:81 \
-m state --state NEW,ESTABLISHED,RELATED -j RETURN
Specific types of traffic are selected and exempted from destination NAT using a RETURN target.
After this, there was a generic DNAT target, DNATing all traffic to talon by default:
# DNAT everything to talon by default
iptables -t nat -A PREROUTING -i eth0 -d 84.35.36.41 \
-m state --state NEW,RELATED \
-j DNAT --to-destination 192.168.20.10
This seemed to work fine mostly, and local connections from femke kept working as well (although I have not really tested this).
Problems with IPsec
I noticed no problems in practice, until I set up an IPsec tunnel from sentry to femke. It appeared that the ESP packets used by IPsec were DNATed / forwarded to talon despite an exception rule I had added in front of the generic DNAT target in the PREROUTING chain. It seemed like netfilter was ignoring the chains/tables altogether for this traffic, and DNATed all of it to talon for some reason.
I solved it by making the DNAT rule less generic, and DNAT only TCP and UDP traffic by default:
iptables -t nat -A PREROUTING -i eth0 -p tcp -d 84.35.36.41 \
-m state --state NEW,RELATED \
-j DNAT --to-destination 192.168.20.10
iptables -t nat -A PREROUTING -i eth0 -p udp -d 84.35.36.41 \
-m state --state NEW,RELATED \
-j DNAT --to-destination 192.168.20.10
This didn't turn out to be a good solution! It crippled all communication from 192.168.20.*
