Skip site navigation (1)Skip section navigation (2)
Date:      21 Jan 2004 20:03:16 -0000
From:      Manuel Kasper <mk@neon1.net>
To:        FreeBSD-gnats-submit@FreeBSD.org
Subject:   kern/61685: [patch] ipnat + dummynet on same interface broken
Message-ID:  <20040121200316.10828.qmail@s0.m0n0.ch>
Resent-Message-ID: <200401212010.i0LKAA72042177@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         61685
>Category:       kern
>Synopsis:       [patch] ipnat + dummynet on same interface broken
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Jan 21 12:10:10 PST 2004
>Closed-Date:
>Last-Modified:
>Originator:     Manuel Kasper <mk@neon1.net>
>Release:        FreeBSD 4.9-RELEASE i386
>Organization:
>Environment:
System: FreeBSD nb.neon1.net 4.9-RELEASE FreeBSD 4.9-RELEASE #0: Thu Oct 30 20:20:56 CET 2003 root@nb.neon1.net:/usr/src/sys/compile/EVON600 i386

with ipfilter, ipfw and dummynet compiled into the kernel

>Description:
If ipfilter with ipnat is active on a particular interface and the ipfw
ruleset contains rules that send inbound packets on the same interface to
dummynet, they actually pass through ipnat twice, creating a bogus NAT table
entry, which later causes all outbound packets belonging to the same
connection to leave that interface effectively un-NATed (in the common case
of that interface being the external interface of a firewall with NAT, they
leave it with a private source IP address).

>How-To-Repeat:
Try to setup a firewall using ipfilter/ipnat and ipfw with dummynet rules
for inbound packets on the external interface at the same time. Create an
ipnat rdr rule to redirect traffic on some port on the external interface to
a host on the internal network. Notice that you cannot establish any
connection to it from the outside. If you have a look with tcpdump, you will
find that the internal host's reply packets (e.g. TCP SYNACK) leave the
external interface with an internal (i.e. un-NATed) source IP address.

>Fix:
Packets that enter ip_input() in sys/netinet/ip_input.c are first passed
through ipfilter (and NATed) before they reach ipfw. If a packet is sent to
dummynet, it later re-enters ip_input(), where it is decided right at the
beginning that this packet has come from dummynet. Execution then jumps to
the label "iphack:", which is right before the ipfilter section, so the
packet is NATed for the second time on the same interface. Fix: jump after
the ipfilter section instead of in front of it.

The following patch seems to fix the problem:


--- ip_input.c.patch begins here ---
--- sys/netinet/ip_input.c.orig	Tue Jan 20 20:53:51 2004
+++ sys/netinet/ip_input.c	Tue Jan 20 21:00:59 2004
@@ -340,7 +340,7 @@
 	if (args.rule) {	/* dummynet already filtered us */
 		ip = mtod(m, struct ip *);
 		hlen = IP_VHL_HL(ip->ip_vhl) << 2;
-		goto iphack ;
+		goto ipfw;	/* skip ipfilter now (already passed it)! */
 	}
 
 	ipstat.ips_total++;
@@ -451,7 +451,6 @@
 	 * - Encapsulate: put it in another IP and send out. <unimp.>
  	 */
 
-iphack:
 	/*
 	 * Check if we want to allow this packet to be processed.
 	 * Consider it to be bad if not.
@@ -463,6 +462,7 @@
 			return;
 		ip = mtod(m = m1, struct ip *);
 	}
+ipfw:
 	if (fw_enable && IPFW_LOADED) {
 		/*
 		 * If we've been forwarded from the output side, then
--- ip_input.c.patch ends here ---


>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20040121200316.10828.qmail>