summaryrefslogtreecommitdiffstats
path: root/contrib/ipfilter/ip_state.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ipfilter/ip_state.c')
-rw-r--r--contrib/ipfilter/ip_state.c172
1 files changed, 114 insertions, 58 deletions
diff --git a/contrib/ipfilter/ip_state.c b/contrib/ipfilter/ip_state.c
index 5ab78cc..4934279 100644
--- a/contrib/ipfilter/ip_state.c
+++ b/contrib/ipfilter/ip_state.c
@@ -93,7 +93,7 @@
#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.30.2.77 2002/12/06 11:40:24 darrenr Exp $";
+static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.30.2.88 2004/01/05 12:46:05 darrenr Exp $";
#endif
#ifndef MIN
@@ -921,7 +921,8 @@ tcphdr_t *tcp;
fdata->td_wscale = wscale;
else if (wscale == -2)
fdata->td_wscale = tdata->td_wscale = 0;
- win <<= fdata->td_wscale;
+ if (!(tcp->th_flags & TH_SYN))
+ win <<= fdata->td_wscale;
if ((fdata->td_end == 0) &&
(!is->is_fsm || ((tcp->th_flags & TH_OPENING) == TH_OPENING))) {
@@ -955,14 +956,15 @@ tcphdr_t *tcp;
(SEQ_GE(seq, fdata->td_end - maxwin)) &&
/* XXX what about big packets */
#define MAXACKWINDOW 66000
- (ackskew >= -MAXACKWINDOW) &&
- (ackskew <= MAXACKWINDOW)) {
- /* if ackskew < 0 then this should be due to fragented
+ (-ackskew <= (MAXACKWINDOW << tdata->td_wscale)) &&
+ ( ackskew <= (MAXACKWINDOW << tdata->td_wscale))) {
+
+ /* if ackskew < 0 then this should be due to fragmented
* packets. There is no way to know the length of the
* total packet in advance.
* We do know the total length from the fragment cache though.
* Note however that there might be more sessions with
- * exactly the same source and destination paramters in the
+ * exactly the same source and destination parameters in the
* state cache (and source and destination is the only stuff
* that is saved in the fragment cache). Note further that
* some TCP connections in the state cache are hashed with
@@ -1208,6 +1210,10 @@ fr_info_t *fin;
oip = (ip_t *)((char *)ic + ICMPERR_ICMPHLEN);
ohlen = oip->ip_hl << 2;
+ /*
+ * Check if the at least the old IP header (with options) and
+ * 8 bytes of payload is present.
+ */
if (fin->fin_plen < ICMPERR_MAXPKTLEN + ohlen - sizeof(*oip))
return NULL;
@@ -1224,7 +1230,7 @@ fr_info_t *fin;
* may be too big to be in this buffer but not so big that it's
* outside the ICMP packet, leading to TCP deref's causing problems.
* This is possible because we don't know how big oip_hl is when we
- * do the pullup early in fr_check() and thus can't gaurantee it is
+ * do the pullup early in fr_check() and thus can't guarantee it is
* all here now.
*/
#ifdef _KERNEL
@@ -1251,9 +1257,43 @@ fr_info_t *fin;
bzero((char *)&src, sizeof(src));
bzero((char *)&dst, sizeof(dst));
bzero((char *)&ofin, sizeof(ofin));
+ /*
+ * We make an fin entry to be able to feed it to
+ * matchsrcdst. Note that not all fields are encessary
+ * but this is the cleanest way. Note further that we
+ * fill in fin_mp such that if someone uses it we'll get
+ * a kernel panic. fr_matchsrcdst does not use this.
+ */
ofin.fin_ifp = fin->fin_ifp;
ofin.fin_out = !fin->fin_out;
+ ofin.fin_mp = NULL;
ofin.fin_v = 4;
+ /*
+ * watch out here, as ip is in host order and oip in network
+ * order. Any change we make must be undone afterwards, like
+ * oip->ip_off - it is still in network byte order so fix it.
+ */
+ savelen = oip->ip_len;
+ oip->ip_len = len;
+ oip->ip_off = ntohs(oip->ip_off);
+ (void) fr_makefrip(ohlen, oip, &ofin);
+ /*
+ * Reset the short flag here because in fr_matchsrcdst() the flags
+ * for the current packet (fin_fl) are compared against * those for
+ * the existing session.
+ */
+ ofin.fin_fl &= ~FI_SHORT;
+
+ /*
+ * Put old values of ip_len and ip_off back as we don't know
+ * if we have to forward the packet (or process it again.
+ */
+ oip->ip_len = savelen;
+ oip->ip_off = htons(oip->ip_off);
+
+#if SOLARIS
+ ofin.fin_qfm = NULL;
+#endif
fr = NULL;
switch (oip->ip_p)
@@ -1262,7 +1302,7 @@ fr_info_t *fin;
icmp = (icmphdr_t *)((char *)oip + ohlen);
/*
- * a ICMP error can only be generated as a result of an
+ * an ICMP error can only be generated as a result of an
* ICMP query, not as the response on an ICMP error
*
* XXX theoretically ICMP_ECHOREP and the other reply's are
@@ -1286,18 +1326,15 @@ fr_info_t *fin;
hv += icmp->icmp_seq;
hv %= fr_statesize;
- savelen = oip->ip_len;
- oip->ip_len = len;
- fr_makefrip(ohlen, oip, &ofin);
- oip->ip_len = savelen;
-
READ_ENTER(&ipf_state);
for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext)
if ((is->is_p == pr) && (is->is_v == 4) &&
+ (is->is_icmppkts < is->is_pkts) &&
fr_matchsrcdst(is, src, dst, &ofin, NULL) &&
- fr_matchicmpqueryreply(is->is_v, is, icmp, fin->fin_rev)) {
+ fr_matchicmpqueryreply(is->is_v, is, icmp,
+ fin->fin_rev)) {
ips_stats.iss_hits++;
- is->is_pkts++;
+ is->is_icmppkts++;
is->is_bytes += ip->ip_len;
fr = is->is_rule;
break;
@@ -1326,20 +1363,7 @@ fr_info_t *fin;
hv += dport;
hv += sport;
hv %= fr_statesize;
- /*
- * we make an fin entry to be able to feed it to
- * matchsrcdst note that not all fields are encessary
- * but this is the cleanest way. Note further we fill
- * in fin_mp such that if someone uses it we'll get
- * a kernel panic. fr_matchsrcdst does not use this.
- *
- * watch out here, as ip is in host order and oip in network
- * order. Any change we make must be undone afterwards.
- */
- savelen = oip->ip_len;
- oip->ip_len = len;
- fr_makefrip(ohlen, oip, &ofin);
- oip->ip_len = savelen;
+
READ_ENTER(&ipf_state);
for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) {
/*
@@ -1347,13 +1371,16 @@ fr_info_t *fin;
* encapsulated packet was allowed through the
* other way around. Note that the minimal amount
* of info present does not allow for checking against
- * tcp internals such as seq and ack numbers.
+ * tcp internals such as seq and ack numbers. Only the
+ * ports are known to be present and can be even if the
+ * short flag is set.
*/
if ((is->is_p == pr) && (is->is_v == 4) &&
+ (is->is_icmppkts < is->is_pkts) &&
fr_matchsrcdst(is, src, dst, &ofin, tcp)) {
fr = is->is_rule;
ips_stats.iss_hits++;
- is->is_pkts++;
+ is->is_icmppkts++;
is->is_bytes += fin->fin_plen;
/*
* we deliberately do not touch the timeouts
@@ -1675,8 +1702,8 @@ void *ifp;
for (is = ips_list; is; is = is->is_next) {
for (i = 0; i < 4; i++) {
if (is->is_ifp[i] == ifp) {
- is->is_ifpin = GETUNIT(is->is_ifname[i],
- is->is_v);
+ is->is_ifp[i] = GETUNIT(is->is_ifname[i],
+ is->is_v);
if (!is->is_ifp[i])
is->is_ifp[i] = (void *)-1;
}
@@ -1843,17 +1870,41 @@ int dir, fsm;
state[dir] = TCPS_SYN_SENT;
newage = fr_tcptimeout;
}
+
+ /*
+ * It is apparently possible that a hosts sends two syncs
+ * before the remote party is able to respond with a SA. In
+ * such a case the remote server sometimes ACK's the second
+ * sync, and then responds with a SA. The following code
+ * is used to prevent this ack from being blocked.
+ *
+ * We do not reset the timeout here to fr_tcptimeout because
+ * a connection connect timeout does not renew after every
+ * packet that is sent. We need to set newage to something
+ * to indicate the packet has passed the check for its flags
+ * being valid in the TCP FSM.
+ */
+ else if ((ostate == TCPS_SYN_SENT) &&
+ ((flags & (TH_FIN|TH_SYN|TH_RST|TH_ACK)) == TH_ACK)) {
+ newage = *age;
+ }
+
/*
* The next piece of code makes it possible to get
* already established connections into the state table
* after a restart or reload of the filter rules; this
* does not work when a strict 'flags S keep state' is
- * used for tcp connections of course
+ * used for tcp connections of course, however, use a
+ * lower time-out so the state disappears quickly if
+ * the other side does not pick it up.
*/
- if (!fsm && (flags & (TH_FIN|TH_SYN|TH_RST|TH_ACK)) == TH_ACK) {
+ else if (!fsm &&
+ (flags & (TH_FIN|TH_SYN|TH_RST|TH_ACK)) == TH_ACK) {
/* we saw an A, guess 'dir' is in ESTABLISHED mode */
- if (state[1 - dir] == TCPS_CLOSED ||
- state[1 - dir] == TCPS_ESTABLISHED) {
+ if (ostate == TCPS_CLOSED) {
+ state[dir] = TCPS_ESTABLISHED;
+ newage = fr_tcptimeout;
+ } else if (ostate == TCPS_ESTABLISHED) {
state[dir] = TCPS_ESTABLISHED;
newage = fr_tcpidletimeout;
}
@@ -2056,7 +2107,7 @@ u_int type;
int types[1];
ipsl.isl_type = type;
- ipsl.isl_pkts = is->is_pkts;
+ ipsl.isl_pkts = is->is_pkts + is->is_icmppkts;
ipsl.isl_bytes = is->is_bytes;
ipsl.isl_src = is->is_src;
ipsl.isl_dst = is->is_dst;
@@ -2084,7 +2135,11 @@ u_int type;
sizes[0] = sizeof(ipsl);
types[0] = 0;
- (void) ipllog(IPL_LOGSTATE, NULL, items, sizes, types, 1);
+ if (ipllog(IPL_LOGSTATE, NULL, items, sizes, types, 1)) {
+ ATOMIC_INCL(ips_stats.iss_logged);
+ } else {
+ ATOMIC_INCL(ips_stats.iss_logfail);
+ }
}
#endif
@@ -2134,12 +2189,30 @@ fr_info_t *fin;
bzero((char *)&ofin, sizeof(ofin));
ofin.fin_out = !fin->fin_out;
ofin.fin_ifp = fin->fin_ifp;
+ ofin.fin_mp = NULL;
ofin.fin_v = 6;
+#if SOLARIS
+ ofin.fin_qfm = NULL;
+#endif
+ /*
+ * We make a fin entry to be able to feed it to
+ * matchsrcdst. Note that not all fields are necessary
+ * but this is the cleanest way. Note further we fill
+ * in fin_mp such that if someone uses it we'll get
+ * a kernel panic. fr_matchsrcdst does not use this.
+ *
+ * watch out here, as ip is in host order and oip in network
+ * order. Any change we make must be undone afterwards.
+ */
+ savelen = oip->ip6_plen;
+ oip->ip6_plen = ip->ip6_plen - sizeof(*ip) - ICMPERR_ICMPHLEN;
+ fr_makefrip(sizeof(*oip), (ip_t *)oip, &ofin);
+ oip->ip6_plen = savelen;
if (oip->ip6_nxt == IPPROTO_ICMPV6) {
oic = (struct icmp6_hdr *)(oip + 1);
/*
- * a ICMP error can only be generated as a result of an
+ * an ICMP error can only be generated as a result of an
* ICMP query, not as the response on an ICMP error
*
* XXX theoretically ICMP_ECHOREP and the other reply's are
@@ -2160,10 +2233,6 @@ fr_info_t *fin;
hv += oic->icmp6_seq;
hv %= fr_statesize;
- oip->ip6_plen = ntohs(oip->ip6_plen);
- fr_makefrip(sizeof(*oip), (ip_t *)oip, &ofin);
- oip->ip6_plen = htons(oip->ip6_plen);
-
READ_ENTER(&ipf_state);
for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext)
if ((is->is_p == pr) &&
@@ -2207,20 +2276,7 @@ fr_info_t *fin;
hv += dport;
hv += sport;
hv %= fr_statesize;
- /*
- * we make an fin entry to be able to feed it to
- * matchsrcdst note that not all fields are encessary
- * but this is the cleanest way. Note further we fill
- * in fin_mp such that if someone uses it we'll get
- * a kernel panic. fr_matchsrcdst does not use this.
- *
- * watch out here, as ip is in host order and oip in network
- * order. Any change we make must be undone afterwards.
- */
- savelen = oip->ip6_plen;
- oip->ip6_plen = ip->ip6_plen - sizeof(*ip) - ICMPERR_ICMPHLEN;
- fr_makefrip(sizeof(*oip), (ip_t *)oip, &ofin);
- oip->ip6_plen = savelen;
+
READ_ENTER(&ipf_state);
for (isp = &ips_table[hv]; (is = *isp); isp = &is->is_hnext) {
/*
OpenPOWER on IntegriCloud