# ============================================================================ # FILE: ipfw2state.patch # PATCHES: /usr/src/sys/netinet/ipfw/ip_fw_dynamic.c # WRITTEN BY: Aaron D. Gifford - http://wwww.aarongifford.com/ # PURPOSE: Patch FreeBSD's ipfw2 firewall system so that # traffic can more tightly be controlled by logging # TCP state mismatches which may indicate a buggy # rule set, an asymmetrical routing problem, or # fishy TCP traffic. # # $Id: ipfw2state.patch,v 1.9 2010/04/14 15:10:55 adg Exp $ # ============================================================================ --- /usr/src/sys/netinet/ipfw/ip_fw_dynamic.c.orig 2010-04-07 12:50:48.000000000 -0600 +++ /usr/src/sys/netinet/ipfw/ip_fw_dynamic.c 2010-04-07 14:04:03.000000000 -0600 @@ -516,18 +516,37 @@ break; default: -#if 0 - /* - * reset or some invalid combination, but can also - * occur if we use keep-state the wrong way. - */ - if ( (q->state & ((TH_RST << 8)|TH_RST)) == 0) - printf("invalid state: 0x%x\n", q->state); -#endif - if (V_dyn_rst_lifetime >= V_dyn_keepalive_period) - V_dyn_rst_lifetime = V_dyn_keepalive_period - 1; - q->expire = time_uptime + V_dyn_rst_lifetime; - break; + if ((q->state & ((TH_RST << 8)|TH_RST)) != 0) { + /* Reset */ + if (V_dyn_rst_lifetime >= V_dyn_keepalive_period) + V_dyn_rst_lifetime = V_dyn_keepalive_period - 1; + q->expire = time_uptime + V_dyn_rst_lifetime; + break; + } else if (q->state == (TH_SYN | TH_ACK)) { + /* + * Both A-to-B SYN and ACK packets have been + * seen, without a B-to-A SYN+ACK response, + * either due to BOGUS TRAFFIC, or a BUGGY RULES, + * or alternate packet paths that bypass ipfw. + */ + if (fw_verbose) { + log(LOG_SECURITY | LOG_NOTICE, + "ipfw: Dynamic TCP rule (%d) expired " + "due to missing SYN+ACK during three-" + "way TCP handshake.\n", + q->rule->rulenum); + } + } else { + /* Any other state is invalid. */ + if (fw_verbose) { + log(LOG_SECURITY | LOG_NOTICE, + "ipfw: Dynamic TCP rule (%d) expired " + "due to invalid TCP state: 0x%x\n", + q->rule->rulenum, q->state); + } + } + q->expire = 0; /* Expire dynamic rule */ + return NULL; /* Act as if no match was found */ } } else if (pkt->proto == IPPROTO_UDP) { q->expire = time_uptime + V_dyn_udp_lifetime;