summaryrefslogtreecommitdiffstats
path: root/sys/contrib/ipfilter/netinet/ip_state.c
diff options
context:
space:
mode:
authorguido <guido@FreeBSD.org>2006-08-16 11:51:32 +0000
committerguido <guido@FreeBSD.org>2006-08-16 11:51:32 +0000
commit83043906d8f7c639d3fecb55801bf3f68a800501 (patch)
tree52617df41b107d5e06265a19cc8b3c2f31aa23b1 /sys/contrib/ipfilter/netinet/ip_state.c
parent74f74123f3fdf4235d201dc8b4227d9d11d7dce5 (diff)
downloadFreeBSD-src-83043906d8f7c639d3fecb55801bf3f68a800501.zip
FreeBSD-src-83043906d8f7c639d3fecb55801bf3f68a800501.tar.gz
Import IP Filter 4.1.13
Diffstat (limited to 'sys/contrib/ipfilter/netinet/ip_state.c')
-rw-r--r--sys/contrib/ipfilter/netinet/ip_state.c120
1 files changed, 72 insertions, 48 deletions
diff --git a/sys/contrib/ipfilter/netinet/ip_state.c b/sys/contrib/ipfilter/netinet/ip_state.c
index b0bf742..32aa805 100644
--- a/sys/contrib/ipfilter/netinet/ip_state.c
+++ b/sys/contrib/ipfilter/netinet/ip_state.c
@@ -107,7 +107,7 @@ struct file;
#if !defined(lint)
static const char sccsid[] = "@(#)ip_state.c 1.8 6/5/96 (C) 1993-2000 Darren Reed";
-static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.186.2.36 2005/12/04 22:25:36 darrenr Exp $";
+static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.186.2.41 2006/04/01 10:16:28 darrenr Exp $";
#endif
static ipstate_t **ips_table = NULL;
@@ -668,6 +668,7 @@ caddr_t data;
fr->fr_ref = 0;
fr->fr_dsize = 0;
fr->fr_data = NULL;
+ fr->fr_type = FR_T_NONE;
fr_resolvedest(&fr->fr_tif, fr->fr_v);
fr_resolvedest(&fr->fr_dif, fr->fr_v);
@@ -801,6 +802,11 @@ int rev;
/* Inserts it into the state table and appends to the bottom of the active */
/* list. If the capacity of the table has reached the maximum allowed then */
/* the call will fail and a flush is scheduled for the next timeout call. */
+/* */
+/* NOTE: The use of stsave to point to nat_state will result in memory */
+/* corruption. It should only be used to point to objects that will */
+/* either outlive this (not expired) or will deref the ip_state_t */
+/* when they are deleted. */
/* ------------------------------------------------------------------------ */
ipstate_t *fr_addstate(fin, stsave, flags)
fr_info_t *fin;
@@ -823,28 +829,30 @@ u_int flags;
if ((fin->fin_flx & FI_OOW) && !(fin->fin_tcpf & TH_SYN))
return NULL;
- fr = fin->fin_fr;
- if ((fr->fr_statemax == 0) && (ips_num == fr_statemax)) {
- ATOMIC_INCL(ips_stats.iss_max);
- fr_state_doflush = 1;
- return NULL;
- }
-
/*
* If a "keep state" rule has reached the maximum number of references
* to it, then schedule an automatic flush in case we can clear out
- * some "dead old wood".
+ * some "dead old wood". Note that because the lock isn't held on
+ * fr it is possible that we could overflow. The cost of overflowing
+ * is being ignored here as the number by which it can overflow is
+ * a product of the number of simultaneous threads that could be
+ * executing in here, so a limit of 100 won't result in 200, but could
+ * result in 101 or 102.
*/
- MUTEX_ENTER(&fr->fr_lock);
- if ((fr != NULL) && (fr->fr_statemax != 0) &&
- (fr->fr_statecnt >= fr->fr_statemax)) {
- MUTEX_EXIT(&fr->fr_lock);
- ATOMIC_INCL(ips_stats.iss_maxref);
- fr_state_doflush = 1;
- return NULL;
+ fr = fin->fin_fr;
+ if (fr != NULL) {
+ if ((ips_num == fr_statemax) && (fr->fr_statemax == 0)) {
+ ATOMIC_INCL(ips_stats.iss_max);
+ fr_state_doflush = 1;
+ return NULL;
+ }
+ if ((fr->fr_statemax != 0) &&
+ (fr->fr_statecnt >= fr->fr_statemax)) {
+ ATOMIC_INCL(ips_stats.iss_maxref);
+ fr_state_doflush = 1;
+ return NULL;
+ }
}
- fr->fr_statecnt++;
- MUTEX_EXIT(&fr->fr_lock);
pass = (fr == NULL) ? 0 : fr->fr_flags;
@@ -1046,16 +1054,16 @@ u_int flags;
break;
}
if (is != NULL)
- goto cantaddstate;
+ return NULL;
if (ips_stats.iss_bucketlen[hv] >= fr_state_maxbucket) {
ATOMIC_INCL(ips_stats.iss_bucketfull);
- goto cantaddstate;
+ return NULL;
}
KMALLOC(is, ipstate_t *);
if (is == NULL) {
ATOMIC_INCL(ips_stats.iss_nomem);
- goto cantaddstate;
+ return NULL;
}
bcopy((char *)&ips, (char *)is, sizeof(*is));
/*
@@ -1140,6 +1148,7 @@ u_int flags;
is->is_optmsk[0] &= ~0x8;
is->is_optmsk[1] &= ~0x8;
}
+ is->is_me = stsave;
is->is_sec = fin->fin_secmsk;
is->is_secmsk = 0xffff;
is->is_auth = fin->fin_auth;
@@ -1154,7 +1163,6 @@ u_int flags;
is->is_pass &= ~(FR_LOGFIRST|FR_LOG);
READ_ENTER(&ipf_state);
- is->is_me = stsave;
fr_stinsert(is, fin->fin_rev);
@@ -1188,14 +1196,6 @@ u_int flags;
(void) fr_newfrag(fin, pass ^ FR_KEEPSTATE);
return is;
-
-cantaddstate:
- if (fr != NULL) {
- MUTEX_ENTER(&fr->fr_lock);
- fr->fr_statecnt--;
- MUTEX_EXIT(&fr->fr_lock);
- }
- return NULL;
}
@@ -1455,18 +1455,6 @@ int flags;
win = ntohs(tcp->th_win);
else
win = ntohs(tcp->th_win) << fdata->td_winscale;
-#if 0
- /*
- * XXX - This is a kludge is here because IPFilter doesn't track SACK
- * options in TCP packets. This is not a trivial to do if one is to
- * consider the performance impact of it. So instead, if the
- * receiver has said SACK is ok, double the allowed window size.
- * This is disabled for testing of another workaround for a problem
- * with Microsoft Windows - see below.
- */
- if ((tdata->td_winflags & TCP_SACK_PERMIT) != 0)
- win *= 2;
-#endif
/*
* A window of 0 produces undesirable behaviour from this function.
@@ -1553,6 +1541,39 @@ int flags;
(fdata->td_winflags & TCP_SACK_PERMIT) &&
(tdata->td_winflags & TCP_SACK_PERMIT)) {
inseq = 1;
+ /*
+ * Sometimes a TCP RST will be generated with only the ACK field
+ * set to non-zero.
+ */
+ } else if ((seq == 0) && (tcpflags == (TH_RST|TH_ACK)) &&
+ (ackskew >= -1) && (ackskew <= 1)) {
+ inseq = 1;
+ } else if (!(flags & IS_TCPFSM)) {
+ int i;
+
+ i = (fin->fin_rev << 1) + fin->fin_out;
+
+#if 0
+ if (is_pkts[i]0 == 0) {
+ /*
+ * Picking up a connection in the middle, the "next"
+ * packet seen from a direction that is new should be
+ * accepted, even if it appears out of sequence.
+ */
+ inseq = 1;
+ } else
+#endif
+ if (!(fdata->td_winflags &
+ (TCP_WSCALE_SEEN|TCP_WSCALE_FIRST))) {
+ /*
+ * No TCPFSM and no window scaling, so make some
+ * extra guesses.
+ */
+ if ((seq == fdata->td_maxend) && (ackskew == 0))
+ inseq = 1;
+ else if (SEQ_GE(seq + maxwin, fdata->td_end - maxwin))
+ inseq = 1;
+ }
}
if (inseq) {
@@ -2339,7 +2360,8 @@ icmp6again:
if ((is->is_p != pr) || (is->is_v != v))
continue;
is = fr_matchsrcdst(fin, is, &src, &dst, NULL, FI_CMP);
- if (is != NULL &&
+ if ((is != NULL) &&
+ (ic->icmp_id == is->is_icmp.ici_id) &&
fr_matchicmpqueryreply(v, &is->is_icmp,
ic, fin->fin_rev)) {
if (fin->fin_rev)
@@ -2432,11 +2454,13 @@ retry_tcpudp:
break;
}
- if ((is != NULL) && ((is->is_sti.tqe_flags & TQE_RULEBASED) != 0) &&
- (is->is_tqehead[fin->fin_rev] != NULL))
- ifq = is->is_tqehead[fin->fin_rev];
- if (ifq != NULL && ifqp != NULL)
- *ifqp = ifq;
+ if (is != NULL) {
+ if (((is->is_sti.tqe_flags & TQE_RULEBASED) != 0) &&
+ (is->is_tqehead[fin->fin_rev] != NULL))
+ ifq = is->is_tqehead[fin->fin_rev];
+ if (ifq != NULL && ifqp != NULL)
+ *ifqp = ifq;
+ }
return is;
}
OpenPOWER on IntegriCloud