[2.2.14] : bugfix for advanced routing with masquerading (still there in 2.3.99-pre5)

Message ID 39088DF8.EAA5AAAB@vianova.at
State New, archived
Headers show
  • [2.2.14] : bugfix for advanced routing with masquerading (still there in 2.3.99-pre5)
Related show

Commit Message

Rene Mayrhofer April 27, 2000, 6:59 p.m. UTC
Hi all

I have discovered a bug in the advanced routing / masquerading code 2 weeks ago
and have tried to make a patch since (patch attached after the bug description).
The bug is reproduceable:

1. you need 2 PCs (at minimum), each one with a network card
2. PC 1 acts as a source-based, masquerading router
3. PC 2 acts as the client, using PC 1 as default gateway

You should have something like this (both addresses of PC1 can be on one
interface without problems):

----- ----- ------
|PC2|---------------------|PC1|---------------------| GW |-...
-----                     -----                     ------

4. setup PC 1 as follows:
   ip addr add dev eth0
   ip addr add dev eth0
   ip rule add prio 1 table main
   ip route add table 2 default via src dev eth0
   ip rule add prio 102 iif eth0 from nat table 2
   ip rule add prio 32000 iif lo table 2
   ip route flush cache
   echo 1 > /proc/sys/net/ipv4/ip_forward
   echo 3 > /proc/sys/net/ipv4/ip_masq_debug
   for i in /proc/sys/net/ipv4/conf/*/log_martians; do
     echo 1 > $i
   for i in /proc/sys/net/ipv4/conf/*/rp_filter; do
     echo 1 > $i
   ipchains -I input -l
   ipchains -I output -l
   ipchains -I forward -l

5. setup PC 2 as follows:
   ip addr add dev eth0
   ip route add default via

6. on PC 2, do
   ping (or ping <whatever> if PC 1 is connected to others)
   You can see that the ping works and that PC 1 does masquerading.

7. on PC 1, do
   ip rule del prio 32000
   Now PC 1 has no default route (no default route for packets coming
   from iface lo), pings do not work from PC 1 - that's ok.

8. on PC 2, do
   ping (or ping <whatever>)
   Now the ping does not work. If you look at the syslog on PC 1, you
   can see that it masquerades the packets coming from as, which is perfectly ok. Then the packets come back from to (they come through the input chain) and get
   thrown away. They do not appear in the output chain, just silently
   dropped (if log_martians is switched on, there is a message).

I was able to track the bug down to the following: In net/ipv4/route.c, function
ip_route_input_slow, line 1183, fib_validate_source is called. There, the
reverse fib_lookup in line 207 fails because there is no routing entry for
packets coming -from- iface lo. After that, fib_validate_source returns an error
line 234 when rp_filter is activated. This causes ip_route_input_slow to drop
the packet and log a "martian source".
I think this behaviour should be changed, because the kernel masqueraded the
packets in the forward direction, but does not allow them to be masqueraded.

This patch solves the problem for me, but I am completely unsure about the
performance impact of calling ip_fw_demasquerade and I am also unsure if it
the packet in a bad way during the check. Please see this patch as an idea on
what should be changed. I do not understand the masquerading code fully and
therefore I do not claim that there aren't side-effects. Also this is my first
kernel patch, so please be patient with me :)

Please could somebody comment on the solution ? Would it be better to check this
in fib_validate_source ? I think so, but then I would need to change the
interface of fib_validate_source. 

The problem is still there in 2.3.99-pre5 (the codes are equal), but my patch
can't work on 2.3.99, since there is no ip_fw_demasquerade and I don't know
anything about how the netfilter framework does masquerading now. However, the
same procedure (with the ipchains module loaded of course) can be used to
reproduce the bug with 2.3.99-pre5.

Please reply directly to me, since I am not subscribed to the mailing list.

best greets,
Rene Mayrhofer


--- linux-2.2.14/net/ipv4/route.c	Tue Jan  4 19:12:26 2000
+++ linux/net/ipv4/route.c	Thu Apr 27 16:30:23 2000
@@ -52,6 +52,7 @@ 
  *	Tobias Ringstrom	:	Uninitialized res.type in ip_route_output_slow.
  *	Vladimir V. Ivanov	:	IP rule info (flowid) is really useful.
  *		Marc Boucher	:	routing by fwmark
+ *		Rene Mayrhofer	:	valid packet rejected bug in ip_route_input_slow
  *		This program is free software; you can redistribute it and/or
  *		modify it under the terms of the GNU General Public License
@@ -93,6 +94,9 @@ 
 #include <linux/sysctl.h>
+#include <net/ip_masq.h>
 #define IP_MAX_MTU	0xFFF0
@@ -1182,8 +1186,28 @@ 
 		int result;
 		result = fib_validate_source(saddr, daddr, tos, loopback_dev.ifindex,
 					     dev, &spec_dst, &itag);
-		if (result < 0)
+		if (result < 0) {
+			/*
+			 * Is this packet going to be demasqueraded ? 
+			 * In that case, fib_validate_source returns an error when there is no
+			 * default route for packets coming from loopback and rp_filter is
+			 * activated for the interface that the returning packet has been 
+			 * recieved on.
+			 * But in such a special case (a combination of source-based routing
+			 * and masquerading), the returning packet is indeed valid. It will 
+			 * get demasqueraded later on.
+			 */
+			{
+				struct sk_buff *tmp = skb;
+				if(ip_fw_demasquerade(&tmp) <= 0) {
+					goto martian_source;
+				}
+			}
 			goto martian_source;
+		}
 		if (result)
 			flags |= RTCF_DIRECTSRC;
 		spec_dst = daddr;