From Bugzilla Helper: User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.7.5) Gecko/20041111 Firefox/1.0 Description of problem: If the subnet at the remote end of an IPSEC tunnel overlaps the local subnet the IPSEC policy matches local traffic too. (This prevents access to the local address of the machine). It also has the more serious side effect that when sending a large packet through the tunnel with the DF flag set, the generation of an ICMP: Frag Needed packet which matches the policy triggers a kernel bug, causing the kernel to hard-lock (I am discussing this kernel bug with the netdev mailing list at the moment). Version-Release number of selected component (if applicable): initscripts-7.93.5-1 How reproducible: Always Steps to Reproduce: 1. Set the LAN-facing address of the machine to 10.0.0.1/16 2. Set up an IPSEC tunnel with SRCNET=10.0.0.0/16 and DSTNET=10.0.0.0/8 3. Try to connect to 10.0.0.1 from a machine on SRCNET - this matches the policy and will be dropped since it isn't encrypted. 4. Connect from 10.0.0.1 to a machine on SRCNET - again, this will be dropped. 5. From a machine on the SRCNET, send a packet to the DSTNET with the DF flag set that is close to the MTU size (i.e. it will exceed the MTU when encrypted) - the kernel will lock up hard with no error message. Actual Results: For steps 3 and 4 the traffic was dropped as it matched the policy, despite being traffic on the local network instead of traffic going over the tunnel. For step 5 the whole kernel locks up with no error message - SysRq has no effect, caps/numlock lights don't toggle when hitting the keys. I am discussing this kernel bug on the netdev list and will file another bug for this part. Expected Results: Traffic between machines on the local network (i.e. not going over the tunnel) should be accepted. Additional info:
Created attachment 111886 [details] Adds an override policy for traffic staying in SRCNET This patch resolves the bug by adding a policy for traffic staying within SRCNET to override the policies requiring encryption.
Created attachment 111887 [details] ifdown-ipsec patch to complement the above ifup-ipsec patch.
Created attachment 111893 [details] Revised ifup-ipsec patch Now checks if the local subnet is smaller than the remote subnet before applying the new policies (if the subnets are completely different it doesn't matter either way)
Created attachment 111895 [details] Revised ifdown-ipsec script Checks if the local subnet is smaller than the remote subnet before deleting policies
(Sorry about the delay.) Why is the check for whether one subnet is bigger than the other really necessary? (Yes, it prevents extraneous policies, but I'm not sure it's worth the complication, and explanation of why the extraneous polices only occur in case X.)
Ok, an example: the endpoints of the tunnel are A and B with subnets like: A: 10.0.0.1/16 B: 10.1.0.1/8 The normal policies for both ends requre traffic to be encrypted if it matches either of: From: 10.0.0.0/16 To: 10.0.0.0/8 (encrypted) From: 10.0.0.0/8 To: 10.0.0.0/16 (encrypted) So for machine A, talking to another machine on the local subnet (10.0.0.2), the traffic matches the policy and is dropped since it's unencrypted. To fix this we add a policy to machine A based on the local subnet: From: 10.0.0.0/16 To: 10.0.0.0/16 (unencrypted) Because we're basing the policy on the local subnet, using the same code you would end up adding to machine B: From: 10.0.0.0/8 To: 10.0.0.0/8 (unencrypted) This is obviously bad since it will override the encrypted policies completely. The way around it is to simply check to see which subnet is bigger, which is what I've done in the second pair of patches. (Did that make sense? :)
I'm looking into the patches, and it seems it checks only what network has bigger netmask, not if the networks actually overlap. On an example... machine-a: SRCNET=192.168.1.0/24 DSTNET=192.168.0.0/16 machine-b: SRCNET=192.168.0.0/16 DSTNET=192.168.1.0/24 This is where I'd probably want to have overrides in place. On the other hand: machine-a: SRCNET=192.168.0.0/24 DSTNET=10.0.0.0/8 machine-b: SRCNET=10.0.0.0/8 DSTNET=192.168.0.0/24 is a case where I probably don't want any overrides...
> it seems it checks only what network has bigger netmask, not if the networks actually overlap. Correct, but it shouldn't actually matter if you add the override for non-overlapping networks... (Actually, I think it might break if you have multiple VPNs on exactly the wrong networks...) Testing if networks overlap is reasonably non-trivial from a shell script though I think.
It might be better to let user setup overrides in configuration file manually. system-config-network should than be patched to make best-guess configuration when it detects overlaping networks (and even better, let user edit the generated override list). I'll attach two patches against vanila ifup-ipsec and ifdown-ipsec. They use $OVERRIDE variable from configuration file, which is of format: OVERRIDE="1.2.3.0/24 4.5.6.0/24 7.8.9.0/24" The above would set overrides for three networks. Basically, list of networks that we don't want to have encrypted. Usefull feature even if there are no overlapping networks. I'm not sure if all spd entries from the patch are needed or if they are sufficient (just wrote the script, can't actually test it right now). Steve probably has much more experience with IPSec than I do, and can probably correct any of my sillyness ;-) The patches incorporate routefix patch too, as discussed in bug #146169. The only thing... This probably shouldn't be in per-interface configuration file, but rather in /etc/sysconfig/network (and probably renamed to $IPSEC_OVERRIDES). It should probably be executed once from /etc/init.d/network. Opinions? Patches follow...
Created attachment 114517 [details] ifup-ipsec "let user have full control" approach ifup-ipsec patch as discussed in comment #9
Created attachment 114518 [details] ifdown-ipsec "let user have full control" approach ifdown-ipsec patch as discussed in comment #9
Created attachment 114520 [details] ifup-ipsec "let user have full control" approach Fixed some syntax errors and added possibility to specify SRC/DST networks directly. OVERRIDE="1.2.3.0/24 2.3.4.0/24 5.6.7.0/24-6.7.8.0/24" would override IPSec for networks 1.2.3.0/24 and 2.3.4.0/24, and between src 5.6.7.0/24 and dst 6.7.8.0/24.
Created attachment 114521 [details] ifdown-ipsec "let user have full control" approach companion to ifup-ipsec patch.
Created attachment 114528 [details] fix routes for overlapped networks This is combined patch. I've tested the code, and it seems to give correct results in my test environment. It adds SPD entries, and also has bettern handling of routing than original routefix patch from bug #146169. Any and old comments and improvements more than welcome. IPSec is something new to me, so there might be some errors or omisions in this patch due to my limited knowledge of the subject.
I don't like the idea of having to manually specify the overrides - this seems like something that *could* be computed, or at least would be easy to mess up when doing it manually.
The thing is, it is not trivial to correctly compute it for general case. Especially in a shell script that has limited knowledge of user's configuration. Even then, the user might want to add some additional overrides (script has no way of knowing user's network topology). That's why I suggested placing this information into configuration file, and patching system-config-network instead to generate best-guess configuration (and really, it would really be best-guess configuration, not necessary correct in general case). System-config-network can than present user with whatever it computed are correct overrides, and allow user to change them if they are not correct for user's environment (put a nasty warning if user attemptes to change it, if it'll make you more comfortable). Best of both worlds. People with simple networks can use system-config-network and simply accept default configuration. People with non-trivial networks can tweak configuration to match their needs. An example of this is my test network that looks something like this (ASCII graphics, make sure non-proportional font is used to view it): +----------+ | VPN1 | +----+-----+ 192.168.1.2/24 | +----+-----+ 192.168.1.1/24 + Router +------------- many wires to the rest of 192.168.0.0/16 +----+-----+ 192.168.2.1/24 | +----+-----+ 192.168.2.2/24 | Firewall | +----+-----+ 192.168.3.1/25 | +----+-----+ 192.168.3.2/25 | VPN2 | +----+-----+ 192.168.3.129/25 | -----+----- wire for 192.168.3.128/25 network Now, I want to be able to reach Firewall from 192.168.3.128/25 network and VPN2 machine with no IPSec. The Firewall is not IPSec enabled at all. External interface on my VPN2 machine must be reachable from the rest of 192.168.0.0/16 without IPSec for administration (over SSH for example). All traffic from 192.168.0.0/16 outside Firewall to 192.168.3.128/25 must be encrypted (using IPSec tunnel between VPN1 and VPN2). There is simply no way for script to guess my network topology and compute correct configuration. With the proposed patch, I could simply put this into config file on VPN2: OVERRIDES="192.168.3.0/25 192.168.3.128/25 192.168.3.0/25-192.168.0.0/16" and things work correctly. All trafic that should be encrypted is encrypted, all traffic that should not be encrypted is not encrypted (spent about half an hour testing all cases I could think of, and than retested again).
After a long time, rethinking about this problem (and Bill's comment that this is something that should be completely automatic). The underlying problem is difference between IPSec policies and IP routing. IPSec policy says "encrypt everything that matches this source and that destination". What users usually want is to encrypt traffic that goes somewhere remote (basically, leaving the particular interface). In my own configurations, I was able to solve this discrepancy by using GRE tunnel, and than just having a host-to-host policy. To correctly autocompute everything (well, at least for most users), something like this would need to be performed. Add routes to remote network, so that packets are leaving correct interface with correct source address (already part of another bug report, I believe). Then, check the output of "ip route show", parse it, and generate policies that would reflect actuall routing. Hm, example. There's this remote VPN gateway. There's two local networks behind it. 192.168.0.0/24 and 192.168.1.0/24. I want everything between this two networks and the rest of 192.168.0.0/16 going through IPSec tunnel. So the IPSec policy might be something like encrypt everything between 192.168.0.0/23 and 192.168.0.0/16. However, this policy would obviously match the local traffic too (which is what this report is about). So, what we can work with is something like this: # ip addr show 1: lo: <LOOPBACK,UP> mtu 16436 qdisc noqueue link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 brd 127.255.255.255 scope host lo 2: eth0: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 1000 link/ether 11:22:33:44:55:66 brd ff:ff:ff:ff:ff:ff inet 1.2.3.4/24 brd 200.50.2.47 scope global eth0 3: eth1: <BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast qlen 1000 link/ether 66:55:44:33:22:11 brd ff:ff:ff:ff:ff:ff inet 192.168.1.2/24 brd 192.168.253.255 scope global eth1 And the routing looks something like this (with IPSec routes already added): 1.2.3.4/24 dev eth0 proto kernel scope link src 1.2.3.4 192.168.1.0/24 dev eth1 proto kernel scope link src 192.168.1.2 192.168.0.0/24 via 192.168.1.1 dev eth1 192.168.0.0/16 via 1.2.3.1 dev eth0 src 192.168.1.2 default via 1.2.3.1 dev eth0 From the above, I need to add exception for anything that matches 192.168.0.0/16 but is not to be routed to eth0. Repeat for all interfaces that are not eth0 (in this case only eth1). I hope the "root" keyword does what I think it does ;-) # ip route show root 192.168.0.0/16 dev eth1 192.168.1.0/24 proto kernel scope link src 192.168.1.2 192.168.0.0/24 via 192.168.1.1 dev eth1 Voila, there they are. The correct list of local networks that I need overrides for: 192.168.0.0/24 and 192.168.1.0/24. Does anybody see any obvious holes in this logic?
Created attachment 129336 [details] Exclude SRCNET<->SRCNET traffic if SRCNET is a subnet of DSTNET While ideally the IPsec policy rules should indeed match the relevant IP routing table, processing the routes would probably not be very reliable either: - Adding IPsec rules to exclude routes found during ifup-ipsec won't handle routes added later - In your example, the route "192.168.0.0/24 via 192.168.1.1 dev eth1" might be using IPsec, which could lead to "interesting" ordering-dependent results (either "ipsec" or "none" depending on which IPsec interface is activated first). This is probably fixable, but more complicated than I'd like. I'm inclined to just apply the attached patch which automatically solves the basic case, and leave the other cases for manual scripting or something like your $OVERRIDES.
Fedora Core 3 is now maintained by the Fedora Legacy project for security updates only. If this problem is a security issue, please reopen and reassign to the Fedora Legacy product. If it is not a security issue and hasn't been resolved in the current FC5 updates or in the FC6 test release, reopen and change the version to match. Thank you!
Fixed in 8.36-1.