From Bugzilla Helper: User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.10) Gecko/20050721 CentOS/1.0.6-1.4.1.centos4 Firefox/1.0.6 Description of problem: If I define IPSec between two hosts in transport mode, Netfilter's connection tracking module fails to place returning packets into established state. Configuration details. Small note, I have patched ifup-ipsec/down scripts to allow for ESP-only IPSec. Host A /etc/sysconfig/network-scripts/ifcfg-hostb: TYPE=IPSEC ONBOOT=yes IKE_METHOD=PSK IKE_PSK=secret SRC=1.2.3.4 DST=4.3.2.1 AH_PROTO=none Host B /etc/sysconfig/network-scripts/ifcfg-hosta: TYPE=IPSEC ONBOOT=yes IKE_METHOD=PSK IKE_PSK=secret SRC=4.3.2.1 DST=1.2.3.4 AH_PROTO=none Host B /etc/sysconfig/iptables: *filter :INPUT DROP [0:0] :FORWARD DROP [0:0] :OUTPUT DROP [0:0] -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT -A OUTPUT -m state --state ESTABLISHED,RELATED -j ACCEPT -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT -A INPUT -p icmp --icmp-type ping -s 1.2.3.4 -m state --state NEW -j ACCEPT -A INPUT -p esp -s 1.2.3.4 -j ACCEPT -A INPUT -p udp -s 1.2.3.4 --sport 500 --dport 500 -m state --state NEW -j ACCEPT -A OUTPUT -p esp -d 1.2.3.4 -j ACCEPT -A OUTPUT -p udp -d 1.2.3.4 --sport 500 --dport 500 -m state --state NEW -j ACCEPT -A INPUT -j LOG --log-prefix "INPUT " -A OUTPUT -j LOG --log-prefix "OUTPUT " -A FORWARD -j LOG --log-prefix "FORWARD " COMMIT If I run "ping -c 1 hostb" and then go to hostb and run "iptables -nvxL", it shows following output: Chain INPUT (policy DROP 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED 0 0 ACCEPT icmp -- * * 1.2.3.4 0.0.0.0/0 icmp type 8 state NEW 1 120 ACCEPT esp -- * * 1.2.3.4 0.0.0.0/0 0 0 ACCEPT udp -- * * 1.2.3.4 0.0.0.0/0 udp spt:500 dpt:500 state NEW 0 0 LOG all -- * * 0.0.0.0/0 0.0.0.0/0 LOG flags 0 level 4 prefix `INPUT ' Chain FORWARD (policy DROP 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED 0 0 LOG all -- * * 0.0.0.0/0 0.0.0.0/0 LOG flags 0 level 4 prefix `FORWARD ' Chain OUTPUT (policy DROP 1 packets, 84 bytes) pkts bytes target prot opt in out source destination 0 0 ACCEPT all -- * * 0.0.0.0/0 0.0.0.0/0 state RELATED,ESTABLISHED 0 0 ACCEPT esp -- * * 0.0.0.0/0 1.2.3.4 0 0 ACCEPT udp -- * * 0.0.0.0/0 1.2.3.4 udp spt:500 dpt:500 state NEW 1 84 LOG all -- * * 0.0.0.0/0 0.0.0.0/0 LOG flags 0 level 4 prefix `OUTPUT ' As can be seen from this output, the decrypted packet never went to the filter chain of INPUT table. That's why the returning packet was not marked as being in ESTABLISHED state, and not matched by generic established/related rule in OUTPUT chain of filter table (it gets dropped). This also means that *all* packets comming from host A to host B will be accepted by Netfilter. It is not possible to filter what kind of network traffic (after IPSec packet is decrypted) will be allowed between A and B! Here's the generated log entry: OUTPUT IN= OUT=eth0 SRC=1.2.3.4 DST=4.3.2.1 LEN=84 TOS=0x00 PREC=0x00 TTL=64 ID=34905 PROTO=ICMP TYPE=0 CODE=0 ID=22355 SEQ=0 Workaround: Instead of configuring IPSec in transport mode, configure it in tunnel mode like this (host A config, similar change on host B): TYPE=IPSEC ONBOOT=yes IKE_METHOD=PSK IKE_PSK=secret SRC=1.2.3.4 DST=4.3.2.1 SRCNET=1.2.3.4/32 DSTNET=4.3.2.1/32 AH_PROTO=none Version-Release number of selected component (if applicable): kernel-2.6.9-11.EL How reproducible: Always Steps to Reproduce: 1. configure IPSec in transport mode between two hosts, ESP, no AH, let racoon handle the keying 2. place some firewall rules on either end 3. try to ping Additional info:
This is a well known deficiency in netfilter support in the kernel these days. It is, as a result, mostly unusable in conjunction with IPSEC. Netfilter hooks don't get called in a symmetric fashion in the presence of IPSEC, so that the packet can be seen at the proper pre-decrypted and post-decrypted states. Major surgery is required to rectify this. A fix is being worked on upstream, but it is exceeding unlikely that an RHEL4 update could ever possibly include the fix when we even have it, because: 1) the necessary fix is incredibly invasive 2) said fix is guarenteed to break the kernel ABI, and thus break 3rd party binary-only kernel modules And as such I'm for now marking this as a "CANTFIX" for RHEL4.
Many thanks for detail reply. I have just one final question. Once the solution is found and implemented in the upstream kernel, I guess it will apear relatively quickly in the Fedora Core kernels. Will it be possible to install (future) Fedora Core kernel RPM package on RHEL4 system, or at least rebuild kernel from SRPM? Or the scope of the changes is so big that it would require userland stuff that interacts with the kernel to be updated too (such as iptables, ipsec-tools, udev, and so on)? Or is it still too early to give any predictions? I'm aware that using Fedora Core kernel would break compatibility with binary 3rd party device drivers, and might push system into "unsupported" state.
It should be a kernel-only fix, I do not anticipate any userlevel components requiring a change.
For others finding this bug for the first time: also see bug #143374 which is essentially the same thing.