# FILE: ipfw2state.patch # PATCHES: /usr/src/sys/netinet/ip_fw2.c # WRITTEN BY: Aaron D. Gifford - http://wwww.adg.us/ # PURPOSE: Patch the FreeBSD kernel's ipfw2 system so that # traffic can more tightly be controlled by warning # the firewall administrator when there's a buggy # rule set or if a stateful rule following TCP flow # notices that the TCP flow does something fishy. # # $Id: ipfw2state.patch,v 1.4 2005/11/02 23:00:04 adg Exp $ # --- /usr/src/sys/netinet/ip_fw2.c.orig Sat Sep 17 07:43:36 2005 +++ /usr/src/sys/netinet/ip_fw2.c Wed Nov 2 15:36:52 2005 @@ -1260,18 +1260,38 @@ 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 (dyn_rst_lifetime >= dyn_keepalive_period) + if ( (q->state & ((TH_RST << 8)|TH_RST)) != 0) { + /* Reset */ + if (dyn_rst_lifetime >= dyn_keepalive_period) dyn_rst_lifetime = dyn_keepalive_period - 1; - q->expire = time_second + dyn_rst_lifetime; - break; + q->expire = time_second + dyn_rst_lifetime; + break; + } else if (q->state == (TH_SYN | TH_ACK)) { + /* + * Both forward SYN and ACK packets have been + * seen, without a reverse SYN+ACK packet, + * because of bogus traffic, a buggy rule set, + * or alternate packet paths bypassing this + * firewall. + */ + 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 also 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 and act */ + return NULL; /* as if there was no match found */ } } else if (pkt->proto == IPPROTO_UDP) { q->expire = time_second + dyn_udp_lifetime;