Hello, in early January this year there was a discussion about the way ipfw interacts with ipsec. Last November ipfw was changed to process ipsec datagrams twice: Once before and a second time after the decoding procedure. This makes life easier for people who use gif tunnels with ipsec transport mode, but it makes life harder for people (like myself) who use native ipsec tunnel mode.
Someone suggested to make the ipfw behavior adjustable through a sysctl, another approach was to port the Open(/Net)BSD enc0 virtual interface. I made up a refined sysctl solution for a FreeBSD machine that is acting as a IPsec tunnel endpoint for roadwarriors in a WLAN environment. The idea is simple: I introduced a new sysctl "net.inet.ip.fw.ipsec_reinject" which defaults to "1". The value is an integer and defines at which rule number ipsec datagrams should be reinjected into the ipfw ruleset. Set it to "0", and it won't be reinjected at all. Set it to "1" (default) and the datagram would be reinjected at the very beginning. You also can put your post ipsec filter rules put at 10000+ and set the sysctl to "10000". Flexible? This is a first patch against -STABLE to demonstrate the concept. Any comments? I may provide a patch that includes ip_fw2.c and check whether it applies to -CURRENT. " Bjorn Fischer
diff -ur sys/netinet/ip_fw.c /sys/netinet/ip_fw.c --- sys/netinet/ip_fw.c Thu Nov 21 01:27:30 2002 +++ /sys/netinet/ip_fw.c Wed Jan 15 17:48:23 2003 @@ -106,6 +106,8 @@ &fw_verbose, 0, "Log matches to ipfw rules"); SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &fw_verbose_limit, 0, "Set upper limit of matches of ipfw rules logged"); +SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, ipsec_reinject, CTLFLAG_RW, + &fw_ipsec_reinject, 1, "Reinject decoded IPsec datagrams at this rule"); /* * Extension for stateful ipfw. @@ -1088,7 +1090,7 @@ u_short src_port = 0, dst_port = 0; struct in_addr src_ip, dst_ip; u_int8_t proto= 0, flags = 0; - u_int16_t skipto; + u_int16_t skipto = 0; u_int16_t ip_len=0; int dyn_checked = 0 ; /* set after dyn.rules have been checked. */ @@ -1106,9 +1108,18 @@ } else hlen = ip->ip_hl << 2; +#ifdef IPSEC + if (ipsec_gethist(*m, NULL) && + args->divert_rule == 0 && + fw_ipsec_reinject > 1) + skipto = fw_ipsec_reinject - 1; +#endif + /* Grab and reset cookie */ - skipto = *cookie; - *cookie = 0; + if (*cookie != 0) { + skipto = *cookie; + *cookie = 0; + } #define PULLUP_TO(len) do { \ if ((*m)->m_len < (len)) { \ diff -ur sys/netinet/ip_fw.h /sys/netinet/ip_fw.h --- sys/netinet/ip_fw.h Tue Jul 9 09:11:42 2002 +++ /sys/netinet/ip_fw.h Wed Jan 15 16:56:38 2003 @@ -367,6 +367,7 @@ extern ip_fw_ctl_t *ip_fw_ctl_ptr; extern int fw_one_pass; extern int fw_enable; +extern int fw_ipsec_reinject; extern struct ipfw_flow_id last_pkt; #define IPFW_LOADED (ip_fw_chk_ptr != NULL) #endif /* _KERNEL */ diff -ur sys/netinet/ip_input.c /sys/netinet/ip_input.c --- sys/netinet/ip_input.c Mon Nov 25 05:23:00 2002 +++ /sys/netinet/ip_input.c Wed Jan 15 17:01:58 2003 @@ -193,6 +193,7 @@ ip_fw_chk_t *ip_fw_chk_ptr; int fw_enable = 1 ; int fw_one_pass = 1; +int fw_ipsec_reinject = 1; /* Dummynet hooks */ ip_dn_io_t *ip_dn_io_ptr; @@ -422,6 +423,11 @@ * - Wrap: fake packet's addr/port <unimpl.> * - Encapsulate: put it in another IP and send out. <unimp.> */ + +#ifdef IPSEC + if (ipsec_gethist(m, NULL) && fw_ipsec_reinject == 0) + goto pass; +#endif iphack: /*