kern/64240: IPFW tee terminates rule processing

Ian Freislich ianf at freislich.nom.za
Sat Mar 13 23:30:18 PST 2004


>Number:         64240
>Category:       kern
>Synopsis:       IPFW tee terminates rule processing
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sat Mar 13 23:30:17 PST 2004
>Closed-Date:
>Last-Modified:
>Originator:     Ian Freislich
>Release:        FreeBSD 5.2-CURRENT i386
>Organization:
private
>Environment:
System: FreeBSD brane-dead.freislich.nom.za 5.2-CURRENT FreeBSD 5.2-CURRENT #6: Sat Mar 13 23:50:41 SAST 2004     ianf at brane-dead.freislich.nom.za:/usr/src/sys/i386/compile/BRANE-DEAD  i386


>Description:
Noted in the BUGS section of the ipfw manual page:

    Packets that match a tee rule should not be immediately accepted,
    but should continue going through the rule list.  This may be
    fixed in a later version.

The following set of rules will cause IP packets to be accepted
unconditionally:

00001 tee 5000 ip from any to any
00002 deny ip from any to any

>How-To-Repeat:

Add a tee rule early in the ipfw ruleset and all packets matching
that rule will be copied to the divert port and accepted by the
firewall.

>Fix:

Apply the following patch (5-CURRENT > 20040314)

This patch removes a stale comment in ip_fw2.c - args->divert_rule
does not exist in the structure.  It adds tee_continue to the
ip_fw_args structure to defeat the one_pass check when continuing
with the checks after teeing the packet.


Index: sbin/ipfw/ipfw.8
===================================================================
RCS file: /home/ncvs/src/sbin/ipfw/ipfw.8,v
retrieving revision 1.139
diff -u -d -r1.139 ipfw.8
--- sbin/ipfw/ipfw.8	23 Jan 2004 06:37:19 -0000	1.139
+++ sbin/ipfw/ipfw.8	10 Mar 2004 09:03:06 -0000
@@ -658,10 +658,7 @@
 .Xr divert 4
 socket bound to port
 .Ar port .
-The search terminates and the original packet is accepted
-(but see Section
-.Sx BUGS
-below).
+The search continues at the next rule.
 .It Cm unreach Ar code
 Discard packets that match this rule, and try to send an ICMP
 unreachable notice with code
@@ -2169,12 +2166,6 @@
 are reassembled before delivery to the socket.
 The action used on those packet is the one from the
 rule which matches the first fragment of the packet.
-.Pp
-Packets that match a
-.Cm tee
-rule should not be immediately accepted, but should continue
-going through the rule list.
-This may be fixed in a later version.
 .Pp
 Packets diverted to userland, and then reinserted by a userland process
 may lose various packet attributes.
Index: sys/netinet/ip_fw.h
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_fw.h,v
retrieving revision 1.83
diff -u -d -r1.83 ip_fw.h
--- sys/netinet/ip_fw.h	25 Feb 2004 19:55:28 -0000	1.83
+++ sys/netinet/ip_fw.h	13 Mar 2004 21:43:03 -0000
@@ -400,6 +400,7 @@
 	int flags;			/* for dummynet			*/
 
 	struct ipfw_flow_id f_id;	/* grabbed from IP header	*/
+	int		tee_continue;	/* continue after packet tee	*/
 	u_int32_t	retval;
 };
 
Index: sys/netinet/ip_fw2.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_fw2.c,v
retrieving revision 1.56
diff -u -d -r1.56 ip_fw2.c
--- sys/netinet/ip_fw2.c	25 Feb 2004 19:55:28 -0000	1.56
+++ sys/netinet/ip_fw2.c	13 Mar 2004 21:58:28 -0000
@@ -1361,10 +1361,6 @@
  *	args->eh (in)	Mac header if present, or NULL for layer3 packet.
  *	args->oif	Outgoing interface, or NULL if packet is incoming.
  *		The incoming interface is in the mbuf. (in)
- *	args->divert_rule (in/out)
- *		Skip up to the first rule past this rule number;
- *		upon return, non-zero port number for divert or tee.
- *
  *	args->rule	Pointer to the last matching rule (in/out)
  *	args->next_hop	Socket we are forwarding to (out).
  *	args->f_id	Addresses grabbed from the packet (out)
@@ -1554,13 +1550,18 @@
 		 * to restart processing.
 		 *
 		 * If fw_one_pass != 0 then just accept it.
-		 * XXX should not happen here, but optimized out in
-		 * the caller.
+		 * XXX should not happen here unless the packet was tee'd,
+		 * but optimized out in the caller.
 		 */
-		if (fw_one_pass) {
+		if (fw_one_pass && !args->tee_continue) {
 			IPFW_UNLOCK(chain);	/* XXX optimize */
 			return 0;
 		}
+		/*
+		 * Reset this so that fw_one_pass is obeyed if we
+		 * land up here again for reasons other than tee_continue
+		 */
+		args->tee_continue = 0;
 
 		f = args->rule->next_rule;
 		if (f == NULL)
@@ -2044,6 +2045,7 @@
 				    cmd->arg1 | IP_FW_PORT_TEE_FLAG;
 				m_tag_prepend(m, mtag);
 				retval = dt->info;
+				args->rule = f; /* report matching rule */
 				goto done;
 			}
 
Index: sys/netinet/ip_input.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_input.c,v
retrieving revision 1.266
diff -u -d -r1.266 ip_input.c
--- sys/netinet/ip_input.c	1 Mar 2004 22:37:01 -0000	1.266
+++ sys/netinet/ip_input.c	13 Mar 2004 21:58:37 -0000
@@ -473,6 +473,9 @@
 		if (args.next_hop)
 			goto ours;
 
+#ifdef IPDIVERT
+again:
+#endif
 		args.m = m;
 		i = ip_fw_chk_ptr(&args);
 		m = args.m;
@@ -854,12 +857,11 @@
 		divert_packet(m, 1);
 		ipstat.ips_delivered++;
 
-		/* If 'tee', continue with original packet */
+		/* If 'tee', continue processing firewall rules
+		 * with the original packet */
 		if (clone == NULL)
 			return;
 		m = clone;
-		ip = mtod(m, struct ip *);
-		ip->ip_len += hlen;
 		/*
 		 * Jump backwards to complete processing of the
 		 * packet.  We do not need to clear args.next_hop
@@ -867,7 +869,8 @@
 		 * doesn't contain a divert packet tag so we won't
 		 * re-entry this block.
 		 */
-		goto pass;
+		args.tee_continue = 1;
+		goto again;
 	}
 #endif
 
Index: sys/netinet/ip_output.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_output.c,v
retrieving revision 1.211
diff -u -d -r1.211 ip_output.c
--- sys/netinet/ip_output.c	2 Mar 2004 14:37:23 -0000	1.211
+++ sys/netinet/ip_output.c	13 Mar 2004 21:58:51 -0000
@@ -731,6 +731,9 @@
 	if (fw_enable && IPFW_LOADED && !args.next_hop) {
 		struct sockaddr_in *old = dst;
 
+#ifdef IPDIVERT
+again:
+#endif
 		args.m = m;
 		args.next_hop = dst;
 		args.oif = ifp;
@@ -807,11 +810,14 @@
 			/* Deliver packet to divert input routine */
 			divert_packet(m, 0);
 
-			/* If 'tee', continue with original packet */
+			/*
+			 * If 'tee', continue processing firewall
+			 * rules with the original packet
+			 */
 			if (clone != NULL) {
 				m = clone;
-				ip = mtod(m, struct ip *);
-				goto pass;
+				args.tee_continue = 1;
+				goto again;
 			}
 			goto done;
 		}
>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list