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