aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDarren Reed <darrenr@FreeBSD.org>2000-08-13 04:28:25 +0000
committerDarren Reed <darrenr@FreeBSD.org>2000-08-13 04:28:25 +0000
commit6adaca6e12219fdf42e3224f40ff9e27cf86f3e1 (patch)
tree059d81384d9dc8039dafc0ae0dec499bc65ded08
parent4dca8a6de1933456e724af9c9bd7ea3d726230ce (diff)
downloadsrc-6adaca6e12219fdf42e3224f40ff9e27cf86f3e1.tar.gz
src-6adaca6e12219fdf42e3224f40ff9e27cf86f3e1.zip
Import IP Filter 3.4.9 bits into the kernel
Notes
Notes: svn path=/vendor-sys/ipfilter/dist-old/; revision=64578
-rw-r--r--sys/netinet/fil.c49
-rw-r--r--sys/netinet/ip_auth.c4
-rw-r--r--sys/netinet/ip_compat.h6
-rw-r--r--sys/netinet/ip_fil.c6
-rw-r--r--sys/netinet/ip_ftp_pxy.c6
-rw-r--r--sys/netinet/ip_log.c4
-rw-r--r--sys/netinet/ip_nat.c88
-rw-r--r--sys/netinet/ip_state.c298
-rw-r--r--sys/netinet/ipl.h4
-rw-r--r--sys/netinet/mlfk_ipl.c4
10 files changed, 367 insertions, 102 deletions
diff --git a/sys/netinet/fil.c b/sys/netinet/fil.c
index 623e84e2ffa8..91b5108b407c 100644
--- a/sys/netinet/fil.c
+++ b/sys/netinet/fil.c
@@ -7,7 +7,7 @@
*/
#if !defined(lint)
static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed";
-static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.18 2000/07/19 13:13:40 darrenr Exp $";
+static const char rcsid[] = "@(#)$Id: fil.c,v 2.35.2.20 2000/08/13 04:15:43 darrenr Exp $";
#endif
#include <sys/errno.h>
@@ -820,18 +820,6 @@ int out;
fin->fin_qfm = m;
fin->fin_qif = qif;
# endif
-# ifdef USE_INET6
- if (v == 6) {
- ATOMIC_INCL(frstats[0].fr_ipv6[out]);
- } else
-# endif
- if (!out && fr_chksrc && !fr_verifysrc(ip->ip_src, ifp)) {
- ATOMIC_INCL(frstats[0].fr_badsrc);
-# if !SOLARIS
- m_freem(m);
-# endif
- return error;
- }
#endif /* _KERNEL */
/*
@@ -847,8 +835,29 @@ int out;
fin->fin_out = out;
fin->fin_mp = mp;
fr_makefrip(hlen, ip, fin);
- pass = fr_pass;
+#ifdef _KERNEL
+# ifdef USE_INET6
+ if (v == 6) {
+ ATOMIC_INCL(frstats[0].fr_ipv6[out]);
+ } else
+# endif
+ if (!out && fr_chksrc && !fr_verifysrc(ip->ip_src, ifp)) {
+ ATOMIC_INCL(frstats[0].fr_badsrc);
+# ifdef IPFILTER_LOG
+ if (fr_chksrc == 2) {
+ fin->fin_group = -2;
+ pass = FR_INQUE|FR_NOMATCH|FR_LOGB;
+ (void) IPLLOG(pass, ip, fin, m);
+ }
+# endif
+# if !SOLARIS
+ m_freem(m);
+# endif
+ return error;
+ }
+#endif
+ pass = fr_pass;
if (fin->fin_fi.fi_fl & FI_SHORT) {
ATOMIC_INCL(frstats[out].fr_short);
}
@@ -1367,7 +1376,7 @@ nodata:
* SUCH DAMAGE.
*
* @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94
- * $Id: fil.c,v 2.35.2.18 2000/07/19 13:13:40 darrenr Exp $
+ * $Id: fil.c,v 2.35.2.20 2000/08/13 04:15:43 darrenr Exp $
*/
/*
* Copy data from an mbuf chain starting "off" bytes from the beginning,
@@ -1846,11 +1855,14 @@ size_t c;
int err;
#if SOLARIS
- copyin(a, &ca, sizeof(ca));
+ if (copyin(a, &ca, sizeof(ca)))
+ return EFAULT;
#else
bcopy(a, &ca, sizeof(ca));
#endif
err = copyin(ca, b, c);
+ if (err)
+ err = EFAULT;
return err;
}
@@ -1863,11 +1875,14 @@ size_t c;
int err;
#if SOLARIS
- copyin(b, &ca, sizeof(ca));
+ if (copyin(b, &ca, sizeof(ca)))
+ return EFAULT;
#else
bcopy(b, &ca, sizeof(ca));
#endif
err = copyout(a, ca, c);
+ if (err)
+ err = EFAULT;
return err;
}
diff --git a/sys/netinet/ip_auth.c b/sys/netinet/ip_auth.c
index 9fa24d630dd4..d737b9c7b71f 100644
--- a/sys/netinet/ip_auth.c
+++ b/sys/netinet/ip_auth.c
@@ -6,7 +6,7 @@
* to the original author and the contributors.
*/
#if !defined(lint)
-static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.11.2.3 2000/06/17 06:24:31 darrenr Exp $";
+static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.11.2.4 2000/08/05 14:48:50 darrenr Exp $";
#endif
#include <sys/errno.h>
@@ -46,7 +46,7 @@ static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.11.2.3 2000/06/17 06:24:31 d
# include <sys/stream.h>
# include <sys/kmem.h>
#endif
-#if (_BSDI_VERSION >= 199802) || (__FreeBSD_Version >= 400000)
+#if (_BSDI_VERSION >= 199802) || (__FreeBSD_version >= 400000)
# include <sys/queue.h>
#endif
#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi)
diff --git a/sys/netinet/ip_compat.h b/sys/netinet/ip_compat.h
index 9b7cddfaf4bd..ba9e014c8c59 100644
--- a/sys/netinet/ip_compat.h
+++ b/sys/netinet/ip_compat.h
@@ -6,7 +6,7 @@
* to the original author and the contributors.
*
* @(#)ip_compat.h 1.8 1/14/96
- * $Id: ip_compat.h,v 2.26.2.3 2000/04/28 14:56:49 darrenr Exp $
+ * $Id: ip_compat.h,v 2.26.2.4 2000/08/13 03:51:03 darrenr Exp $
*/
#ifndef __IP_COMPAT_H__
@@ -126,6 +126,10 @@ typedef int minor_t;
#endif /* SOLARIS */
#define IPMINLEN(i, h) ((i)->ip_len >= ((i)->ip_hl * 4 + sizeof(struct h)))
+#if defined(__FreeBSD__) && (__FreeBSD__ >= 5) && defined(_KERNEL)
+# include <machine/in_cksum.h>
+#endif
+
#ifndef IP_OFFMASK
#define IP_OFFMASK 0x1fff
#endif
diff --git a/sys/netinet/ip_fil.c b/sys/netinet/ip_fil.c
index fe6af664669f..2e8af2699e00 100644
--- a/sys/netinet/ip_fil.c
+++ b/sys/netinet/ip_fil.c
@@ -7,7 +7,7 @@
*/
#if !defined(lint)
static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed";
-static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.42.2.14 2000/07/18 13:57:55 darrenr Exp $";
+static const char rcsid[] = "@(#)$Id: ip_fil.c,v 2.42.2.15 2000/08/05 14:49:08 darrenr Exp $";
#endif
#ifndef SOLARIS
@@ -1139,8 +1139,10 @@ int dst;
return ENOBUFS;
MCLGET(m, M_DONTWAIT);
- if (!m)
+ if ((m->m_flags & M_EXT) == 0) {
+ m_freem(m);
return ENOBUFS;
+ }
avail = (m->m_flags & M_EXT) ? MCLBYTES : MHLEN;
xtra = MIN(ntohs(oip6->ip6_plen) + sizeof(ip6_t),
avail - hlen - sizeof(*icmp) - max_linkhdr);
diff --git a/sys/netinet/ip_ftp_pxy.c b/sys/netinet/ip_ftp_pxy.c
index 5ea94a17f714..84dc8b9b264a 100644
--- a/sys/netinet/ip_ftp_pxy.c
+++ b/sys/netinet/ip_ftp_pxy.c
@@ -2,7 +2,7 @@
* Simple FTP transparent proxy for in-kernel use. For use with the NAT
* code.
*
- * $Id: ip_ftp_pxy.c,v 2.7.2.12 2000/07/19 13:06:13 darrenr Exp $
+ * $Id: ip_ftp_pxy.c,v 2.7.2.13 2000/08/07 12:35:27 darrenr Exp $
*/
#if SOLARIS && defined(_KERNEL)
extern kmutex_t ipf_rw;
@@ -263,7 +263,7 @@ int dlen;
ip->ip_len = slen;
ip->ip_src = swip;
}
- return inc;
+ return APR_INC(inc);
}
@@ -703,7 +703,7 @@ int rv;
t->ftps_seq = ntohl(tcp->th_ack);
f->ftps_rptr = rptr;
f->ftps_wptr = wptr;
- return inc;
+ return APR_INC(inc);
}
diff --git a/sys/netinet/ip_log.c b/sys/netinet/ip_log.c
index 08073bbcdadf..8adc410e80b7 100644
--- a/sys/netinet/ip_log.c
+++ b/sys/netinet/ip_log.c
@@ -5,7 +5,7 @@
* provided that this notice is preserved and due credit is given
* to the original author and the contributors.
*
- * $Id: ip_log.c,v 2.5.2.1 2000/07/19 13:11:47 darrenr Exp $
+ * $Id: ip_log.c,v 2.5.2.2 2000/08/13 03:50:41 darrenr Exp $
*/
#include <sys/param.h>
#if defined(KERNEL) && !defined(_KERNEL)
@@ -21,8 +21,6 @@
# endif
# else
# ifdef KLD_MODULE
-# include <sys/osreldate.h>
-# else
# include <osreldate.h>
# endif
# endif
diff --git a/sys/netinet/ip_nat.c b/sys/netinet/ip_nat.c
index d25f3f78ada9..bbcff77b7b5d 100644
--- a/sys/netinet/ip_nat.c
+++ b/sys/netinet/ip_nat.c
@@ -9,7 +9,7 @@
*/
#if !defined(lint)
static const char sccsid[] = "@(#)ip_nat.c 1.11 6/5/96 (C) 1995 Darren Reed";
-static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.37.2.16 2000/07/18 13:57:40 darrenr Exp $";
+static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.37.2.21 2000/08/12 07:32:40 darrenr Exp $";
#endif
#if defined(__FreeBSD__) && defined(KERNEL) && !defined(_KERNEL)
@@ -126,7 +126,7 @@ hostmap_t **maptable = NULL;
u_long fr_defnatage = DEF_NAT_AGE,
fr_defnaticmpage = 6; /* 3 seconds */
-static natstat_t nat_stats;
+natstat_t nat_stats;
int fr_nat_lock = 0;
#if (SOLARIS || defined(__sgi)) && defined(_KERNEL)
extern kmutex_t ipf_rw, ipf_hostmap;
@@ -403,8 +403,11 @@ int mode;
KMALLOC(nt, ipnat_t *);
if ((cmd == SIOCADNAT) || (cmd == SIOCRMNAT))
error = IRCOPYPTR(data, (char *)&natd, sizeof(natd));
- else if (cmd == SIOCIPFFL) /* SIOCFLNAT & SIOCCNATL */
+ else if (cmd == SIOCIPFFL) { /* SIOCFLNAT & SIOCCNATL */
error = IRCOPY(data, (char *)&arg, sizeof(arg));
+ if (error)
+ error = EFAULT;
+ }
if (error)
goto done;
@@ -498,7 +501,7 @@ int mode;
* mapping range. In all cases, the range is inclusive of
* the start and ending IP addresses.
* If to a CIDR address, lose 2: broadcast + network address
- * (so subtract 1)
+ * (so subtract 1)
* If to a range, add one.
* If to a single IP address, set to 1.
*/
@@ -641,7 +644,8 @@ int mode;
sizeof(fr_nat_lock));
if (!error)
fr_nat_lock = arg;
- }
+ } else
+ error = EFAULT;
break;
case SIOCSTPUT :
if (fr_nat_lock)
@@ -666,6 +670,8 @@ int mode;
MUTEX_DOWNGRADE(&ipf_nat);
error = IWCOPY((caddr_t)&iplused[IPL_LOGNAT], (caddr_t)data,
sizeof(iplused[IPL_LOGNAT]));
+ if (error)
+ error = EFAULT;
#endif
break;
default :
@@ -732,7 +738,7 @@ caddr_t data;
static int fr_natgetent(data)
caddr_t data;
{
- nat_save_t ipn, *ipnp, *ipnn;
+ nat_save_t ipn, *ipnp, *ipnn = NULL;
register nat_t *n, *nat;
ap_session_t *aps;
int error;
@@ -785,33 +791,33 @@ caddr_t data;
ipn.ipn_dsize += aps->aps_psiz;
KMALLOCS(ipnn, nat_save_t *, sizeof(*ipnn) + ipn.ipn_dsize);
if (ipnn == NULL)
- return NULL;
+ return ENOMEM;
bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn));
- bcopy((char *)aps, ipn.ipn_data, sizeof(*aps));
+ bcopy((char *)aps, ipnn->ipn_data, sizeof(*aps));
if (aps->aps_data) {
- bcopy(aps->aps_data, ipn.ipn_data + sizeof(*aps),
+ bcopy(aps->aps_data, ipnn->ipn_data + sizeof(*aps),
aps->aps_psiz);
- ipn.ipn_dsize += aps->aps_psiz;
+ ipnn->ipn_dsize += aps->aps_psiz;
}
error = IWCOPY((caddr_t)ipnn, ipnp,
sizeof(ipn) + ipn.ipn_dsize);
if (error)
- return EFAULT;
+ error = EFAULT;
KFREES(ipnn, sizeof(*ipnn) + ipn.ipn_dsize);
} else {
error = IWCOPY((caddr_t)&ipn, ipnp, sizeof(ipn));
if (error)
- return EFAULT;
+ error = EFAULT;
}
- return 0;
+ return error;
}
static int fr_natputent(data)
caddr_t data;
{
- nat_save_t ipn, *ipnp, *ipnn;
+ nat_save_t ipn, *ipnp, *ipnn = NULL;
register nat_t *n, *nat;
ap_session_t *aps;
frentry_t *fr;
@@ -825,6 +831,7 @@ caddr_t data;
error = IRCOPY((caddr_t)ipnp, (caddr_t)&ipn, sizeof(ipn));
if (error)
return EFAULT;
+ nat = NULL;
if (ipn.ipn_dsize) {
KMALLOCS(ipnn, nat_save_t *, sizeof(ipn) + ipn.ipn_dsize);
if (ipnn == NULL)
@@ -832,14 +839,18 @@ caddr_t data;
bcopy((char *)&ipn, (char *)ipnn, sizeof(ipn));
error = IRCOPY((caddr_t)ipnp, (caddr_t)ipn.ipn_data,
ipn.ipn_dsize);
- if (error)
- return EFAULT;
+ if (error) {
+ error = EFAULT;
+ goto junkput;
+ }
} else
ipnn = NULL;
KMALLOC(nat, nat_t *);
- if (nat == NULL)
- return ENOMEM;
+ if (nat == NULL) {
+ error = EFAULT;
+ goto junkput;
+ }
bcopy((char *)&ipn.ipn_nat, (char *)nat, sizeof(*nat));
/*
@@ -1458,7 +1469,7 @@ int dir;
icmphdr_t *icmp;
tcphdr_t *tcp = NULL;
ip_t *oip;
- int flags = 0, type;
+ int flags = 0, type, minlen;
icmp = (icmphdr_t *)fin->fin_dp;
/*
@@ -1478,13 +1489,45 @@ int dir;
return NULL;
oip = (ip_t *)((char *)fin->fin_dp + 8);
- if (ip->ip_len < ICMPERR_MAXPKTLEN + ((oip->ip_hl - 5) << 2))
+ minlen = (oip->ip_hl << 2);
+ if (minlen < sizeof(ip_t))
return NULL;
+ if (ip->ip_len < ICMPERR_IPICMPHLEN + minlen)
+ return NULL;
+ /*
+ * Is the buffer big enough for all of it ? It's the size of the IP
+ * header claimed in the encapsulated part which is of concern. It
+ * 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
+ * all here now.
+ */
+#ifdef _KERNEL
+ {
+ mb_t *m;
+
+# if SOLARIS
+ m = fin->fin_qfm;
+ if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN > (char *)m->b_wptr)
+ return NULL;
+# else
+ m = *(mb_t **)fin->fin_mp;
+ if ((char *)oip + fin->fin_dlen - ICMPERR_ICMPHLEN >
+ (char *)ip + m->m_len)
+ return NULL;
+# endif
+ }
+#endif
+
if (oip->ip_p == IPPROTO_TCP)
flags = IPN_TCP;
else if (oip->ip_p == IPPROTO_UDP)
flags = IPN_UDP;
if (flags & IPN_TCPUDP) {
+ minlen += 8; /* + 64bits of data to get ports */
+ if (ip->ip_len < ICMPERR_IPICMPHLEN + minlen)
+ return NULL;
tcp = (tcphdr_t *)((char *)oip + (oip->ip_hl << 2));
if (dir == NAT_INBOUND)
return nat_inlookup(fin->fin_ifp, flags,
@@ -1576,7 +1619,10 @@ int dir;
if ((flags & IPN_TCPUDP) != 0) {
tcphdr_t *tcp;
- /* XXX - what if this is bogus hl and we go off the end ? */
+ /*
+ * XXX - what if this is bogus hl and we go off the end ?
+ * In this case, nat_icmpinlookup() will have returned NULL.
+ */
tcp = (tcphdr_t *)((((char *)oip) + (oip->ip_hl << 2)));
if (nat->nat_dir == NAT_OUTBOUND) {
diff --git a/sys/netinet/ip_state.c b/sys/netinet/ip_state.c
index fa8e0504e6d8..f05c8875e357 100644
--- a/sys/netinet/ip_state.c
+++ b/sys/netinet/ip_state.c
@@ -7,7 +7,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.12 2000/06/19 02:38:37 darrenr Exp $";
+static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.30.2.17 2000/08/08 16:01:03 darrenr Exp $";
#endif
#include <sys/errno.h>
@@ -180,7 +180,7 @@ static ips_stat_t *fr_statetstats()
* flush state tables. two actions currently defined:
* which == 0 : flush all state table entries
* which == 1 : flush TCP connections which have started to close but are
- * stuck for some reason.
+ * stuck for some reason.
*/
static int fr_state_flush(which)
int which;
@@ -371,8 +371,8 @@ caddr_t data;
sizeof(ips.ips_fr));
error = IWCOPY((caddr_t)&ips, ipsp, sizeof(ips));
if (error)
- return EFAULT;
- return 0;
+ error = EFAULT;
+ return error;
}
@@ -477,6 +477,7 @@ register ipstate_t *is;
is->is_phnext = ips_table + hv;
is->is_hnext = ips_table[hv];
ips_table[hv] = is;
+ ips_num++;
}
@@ -557,7 +558,6 @@ u_int flags;
case ND_NEIGHBOR_SOLICIT :
is->is_icmp.ics_type = ic->icmp_type + 1;
break;
- break;
#endif
case ICMP_ECHO :
case ICMP_TSTAMP :
@@ -669,11 +669,10 @@ u_int flags;
if (pass & FR_LOGFIRST)
is->is_pass &= ~(FR_LOGFIRST|FR_LOG);
fr_stinsert(is);
- ips_num++;
if (is->is_p == IPPROTO_TCP) {
MUTEX_ENTER(&is->is_lock);
fr_tcp_age(&is->is_age, is->is_state, fin,
- tcp->th_sport == is->is_sport);
+ 0); /* 0 = packet from the source */
MUTEX_EXIT(&is->is_lock);
}
#ifdef IPFILTER_LOG
@@ -785,7 +784,8 @@ tcphdr_t *tcp;
* Nearing end of connection, start timeout.
*/
MUTEX_ENTER(&is->is_lock);
- fr_tcp_age(&is->is_age, is->is_state, fin, source);
+ /* source ? 0 : 1 -> !source */
+ fr_tcp_age(&is->is_age, is->is_state, fin, !source);
MUTEX_EXIT(&is->is_lock);
ret = 1;
}
@@ -970,12 +970,12 @@ fr_info_t *fin;
union i6addr dst, src;
struct icmp *ic;
u_short savelen;
+ icmphdr_t *icmp;
fr_info_t ofin;
+ int type, len;
tcphdr_t *tcp;
- icmphdr_t *icmp;
frentry_t *fr;
ip_t *oip;
- int type;
u_int hv;
/*
@@ -1000,6 +1000,46 @@ fr_info_t *fin;
if (fin->fin_plen < ICMPERR_MAXPKTLEN + ((oip->ip_hl - 5) << 2))
return NULL;
+ /*
+ * Sanity checks.
+ */
+ len = fin->fin_dlen - ICMPERR_ICMPHLEN;
+ if ((len <= 0) || ((oip->ip_hl << 2) > len))
+ return NULL;
+
+ /*
+ * Is the buffer big enough for all of it ? It's the size of the IP
+ * header claimed in the encapsulated part which is of concern. It
+ * 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
+ * all here now.
+ */
+#ifdef _KERNEL
+ {
+ mb_t *m;
+
+# if SOLARIS
+ m = fin->fin_qfm;
+ if ((char *)oip + len > (char *)m->b_wptr)
+ return NULL;
+# else
+ m = *(mb_t **)fin->fin_mp;
+ if ((char *)oip + len > (char *)ip + m->m_len)
+ return NULL;
+# endif
+ }
+#endif
+
+ /*
+ * in the IPv4 case we must zero the i6addr union otherwise
+ * the IP6EQ and IP6NEQ macros produce the wrong results because
+ * of the 'junk' in the unused part of the union
+ */
+ bzero(&src, sizeof(src));
+ bzero(&dst, sizeof(dst));
+
if (oip->ip_p == IPPROTO_ICMP) {
icmp = (icmphdr_t *)((char *)oip + (oip->ip_hl << 2));
@@ -1028,9 +1068,11 @@ fr_info_t *fin;
hv += icmp->icmp_seq;
hv %= fr_statesize;
- oip->ip_len = ntohs(oip->ip_len);
+ savelen = oip->ip_len;
+ oip->ip_len = len;
+ ofin.fin_v = 4;
fr_makefrip(oip->ip_hl << 2, oip, &ofin);
- oip->ip_len = htons(oip->ip_len);
+ oip->ip_len = savelen;
ofin.fin_ifp = fin->fin_ifp;
ofin.fin_out = !fin->fin_out;
ofin.fin_mp = NULL; /* if dereferenced, panic XXX */
@@ -1077,7 +1119,8 @@ fr_info_t *fin;
* order. Any change we make must be undone afterwards.
*/
savelen = oip->ip_len;
- oip->ip_len = ip->ip_len - (ip->ip_hl << 2) - ICMPERR_ICMPHLEN;
+ oip->ip_len = len;
+ ofin.fin_v = 4;
fr_makefrip(oip->ip_hl << 2, oip, &ofin);
oip->ip_len = savelen;
ofin.fin_ifp = fin->fin_ifp;
@@ -1198,7 +1241,15 @@ fr_info_t *fin;
case IPPROTO_TCP :
{
register u_short dport = tcp->th_dport, sport = tcp->th_sport;
+ register int i;
+ i = tcp->th_flags;
+ /*
+ * Just plain ignore RST flag set with either FIN or SYN.
+ */
+ if ((i & TH_RST) &&
+ ((i & (TH_FIN|TH_SYN|TH_RST)) != TH_RST))
+ break;
tryagain = 0;
retry_tcp:
hvm = hv % fr_statesize;
@@ -1384,6 +1435,27 @@ void fr_timeoutstate()
/*
* Original idea freom Pradeep Krishnan for use primarily with NAT code.
* (pkrishna@netcom.com)
+ *
+ * Rewritten by Arjan de Vet <Arjan.deVet@adv.iae.nl>, 2000-07-29:
+ *
+ * - (try to) base state transitions on real evidence only,
+ * i.e. packets that are sent and have been received by ipfilter;
+ * diagram 18.12 of TCP/IP volume 1 by W. Richard Stevens was used.
+ *
+ * - deal with half-closed connections correctly;
+ *
+ * - store the state of the source in state[0] such that ipfstat
+ * displays the state as source/dest instead of dest/source; the calls
+ * to fr_tcp_age have been changed accordingly.
+ *
+ * Parameters:
+ *
+ * state[0] = state of source (host that initiated connection)
+ * state[1] = state of dest (host that accepted the connection)
+ *
+ * dir == 0 : a packet from source to dest
+ * dir == 1 : a packet from dest to source
+ *
*/
void fr_tcp_age(age, state, fin, dir)
u_long *age;
@@ -1410,67 +1482,192 @@ int dir;
return;
}
- *age = fr_tcptimeout; /* 1 min */
+ *age = fr_tcptimeout; /* default 4 mins */
switch(state[dir])
{
- case TCPS_CLOSED:
+ case TCPS_CLOSED: /* 0 */
+ if ((flags & TH_OPENING) == TH_OPENING) {
+ /*
+ * 'dir' received an S and sends SA in response,
+ * CLOSED -> SYN_RECEIVED
+ */
+ state[dir] = TCPS_SYN_RECEIVED;
+ *age = fr_tcptimeout;
+ } else if ((flags & (TH_SYN|TH_ACK)) == TH_SYN) {
+ /* 'dir' sent S, CLOSED -> SYN_SENT */
+ state[dir] = TCPS_SYN_SENT;
+ *age = fr_tcptimeout;
+ }
+ /*
+ * 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
+ */
if ((flags & (TH_FIN|TH_SYN|TH_RST|TH_ACK)) == TH_ACK) {
+ /* we saw an A, guess 'dir' is in ESTABLISHED mode */
state[dir] = TCPS_ESTABLISHED;
*age = fr_tcpidletimeout;
}
- case TCPS_FIN_WAIT_2:
- if ((flags & TH_OPENING) == TH_OPENING)
+ /*
+ * TODO: besides regular ACK packets we can have other
+ * packets as well; it is yet to be determined how we
+ * should initialize the states in those cases
+ */
+ break;
+
+ case TCPS_LISTEN: /* 1 */
+ /* NOT USED */
+ break;
+
+ case TCPS_SYN_SENT: /* 2 */
+ if ((flags & (TH_SYN|TH_FIN|TH_ACK)) == TH_ACK) {
+ /*
+ * We see an A from 'dir' which is in SYN_SENT
+ * state: 'dir' sent an A in response to an SA
+ * which it received, SYN_SENT -> ESTABLISHED
+ */
+ state[dir] = TCPS_ESTABLISHED;
+ *age = fr_tcpidletimeout;
+ } else if (flags & TH_FIN) {
+ /*
+ * We see an F from 'dir' which is in SYN_SENT
+ * state and wants to close its side of the
+ * connection; SYN_SENT -> FIN_WAIT_1
+ */
+ state[dir] = TCPS_FIN_WAIT_1;
+ *age = fr_tcpidletimeout; /* or fr_tcptimeout? */
+ } else if ((flags & TH_OPENING) == TH_OPENING) {
+ /*
+ * We see an SA from 'dir' which is already in
+ * SYN_SENT state, this means we have a
+ * simultaneous open; SYN_SENT -> SYN_RECEIVED
+ */
state[dir] = TCPS_SYN_RECEIVED;
- else if (flags & TH_SYN)
- state[dir] = TCPS_SYN_SENT;
+ *age = fr_tcptimeout;
+ }
break;
- case TCPS_SYN_RECEIVED:
- case TCPS_SYN_SENT:
- if ((flags & (TH_FIN|TH_ACK)) == TH_ACK) {
+
+ case TCPS_SYN_RECEIVED: /* 3 */
+ if ((flags & (TH_SYN|TH_FIN|TH_ACK)) == TH_ACK) {
+ /*
+ * We see an A from 'dir' which was in SYN_RECEIVED
+ * state so it must now be in established state,
+ * SYN_RECEIVED -> ESTABLISHED
+ */
state[dir] = TCPS_ESTABLISHED;
*age = fr_tcpidletimeout;
- } else if ((flags & (TH_FIN|TH_ACK)) == (TH_FIN|TH_ACK)) {
- state[dir] = TCPS_CLOSE_WAIT;
- if (!(flags & TH_PUSH) && !dlen &&
- ostate > TCPS_ESTABLISHED)
- *age = fr_tcplastack;
- else
- *age = fr_tcpclosewait;
+ } else if (flags & TH_FIN) {
+ /*
+ * We see an F from 'dir' which is in SYN_RECEIVED
+ * state and wants to close its side of the connection;
+ * SYN_RECEIVED -> FIN_WAIT_1
+ */
+ state[dir] = TCPS_FIN_WAIT_1;
+ *age = fr_tcpidletimeout; /* or fr_tcptimeout? */
}
break;
- case TCPS_ESTABLISHED:
+
+ case TCPS_ESTABLISHED: /* 4 */
if (flags & TH_FIN) {
- state[dir] = TCPS_CLOSE_WAIT;
- if (!(flags & TH_PUSH) && !dlen &&
- ostate > TCPS_ESTABLISHED)
- *age = fr_tcplastack;
- else
- *age = fr_tcpclosewait;
- } else {
- if (ostate < TCPS_CLOSE_WAIT)
+ /*
+ * 'dir' closed its side of the connection; this
+ * gives us a half-closed connection;
+ * ESTABLISHED -> FIN_WAIT_1
+ */
+ state[dir] = TCPS_FIN_WAIT_1;
+ *age = fr_tcpidletimeout;
+ } else if (flags & TH_ACK) {
+ /* an ACK, should we exclude other flags here? */
+ if (ostate == TCPS_FIN_WAIT_1) {
+ /*
+ * We know the other side did an active close,
+ * so we are ACKing the recvd FIN packet (does
+ * the window matching code guarantee this?)
+ * and go into CLOSE_WAIT state; this gives us
+ * a half-closed connection
+ */
+ state[dir] = TCPS_CLOSE_WAIT;
+ *age = fr_tcpidletimeout;
+ } else if (ostate < TCPS_CLOSE_WAIT)
+ /*
+ * Still a fully established connection,
+ * reset timeout
+ */
*age = fr_tcpidletimeout;
}
break;
- case TCPS_CLOSE_WAIT:
- if ((flags & TH_FIN) && !(flags & TH_PUSH) && !dlen &&
- ostate > TCPS_ESTABLISHED) {
+
+ case TCPS_CLOSE_WAIT: /* 5 */
+ if (flags & TH_FIN) {
+ /*
+ * Application closed and 'dir' sent a FIN, we're now
+ * going into LAST_ACK state
+ */
*age = fr_tcplastack;
state[dir] = TCPS_LAST_ACK;
+ } else {
+ /*
+ * We remain in CLOSE_WAIT because the other side has
+ * closed already and we did not close our side yet;
+ * reset timeout
+ */
+ *age = fr_tcpidletimeout;
+ }
+ break;
+
+ case TCPS_FIN_WAIT_1: /* 6 */
+ if ((flags & TH_ACK) && ostate > TCPS_CLOSE_WAIT) {
+ /*
+ * If the other side is not active anymore it has sent
+ * us a FIN packet that we are ack'ing now with an ACK;
+ * this means both sides have now closed the connection
+ * and we go into TIME_WAIT
+ */
+ /*
+ * XXX: how do we know we really are ACKing the FIN
+ * packet here? does the window code guarantee that?
+ */
+ state[dir] = TCPS_TIME_WAIT;
+ *age = fr_tcptimeout;
} else
- *age = fr_tcpclosewait;
+ /*
+ * We closed our side of the connection already but the
+ * other side is still active (ESTABLISHED/CLOSE_WAIT);
+ * continue with this half-closed connection
+ */
+ *age = fr_tcpidletimeout;
+ break;
+
+ case TCPS_CLOSING: /* 7 */
+ /* NOT USED */
break;
- case TCPS_LAST_ACK:
+
+ case TCPS_LAST_ACK: /* 8 */
if (flags & TH_ACK) {
- state[dir] = TCPS_FIN_WAIT_2;
- if (!(flags & TH_PUSH) && !dlen &&
- ostate > TCPS_ESTABLISHED)
+ if ((flags & TH_PUSH) || dlen)
+ /*
+ * There is still data to be delivered, reset
+ * timeout
+ */
*age = fr_tcplastack;
- else {
- *age = fr_tcpclosewait;
- state[dir] = TCPS_CLOSE_WAIT;
- }
}
+ /*
+ * We cannot detect when we go out of LAST_ACK state to CLOSED
+ * because that is based on the reception of ACK packets;
+ * ipfilter can only detect that a packet has been sent by a
+ * host
+ */
+ break;
+
+ case TCPS_FIN_WAIT_2: /* 9 */
+ /* NOT USED */
+ break;
+
+ case TCPS_TIME_WAIT: /* 10 */
+ /* we're in 2MSL timeout now */
break;
}
}
@@ -1579,6 +1776,7 @@ fr_info_t *fin;
hv %= fr_statesize;
oip->ip6_plen = ntohs(oip->ip6_plen);
+ ofin.fin_v = 6;
fr_makefrip(sizeof(*oip), (ip_t *)oip, &ofin);
oip->ip6_plen = htons(oip->ip6_plen);
ofin.fin_ifp = fin->fin_ifp;
diff --git a/sys/netinet/ipl.h b/sys/netinet/ipl.h
index bb2523d2ed8e..866d34dd6f52 100644
--- a/sys/netinet/ipl.h
+++ b/sys/netinet/ipl.h
@@ -6,12 +6,12 @@
* to the original author and the contributors.
*
* @(#)ipl.h 1.21 6/5/96
- * $Id: ipl.h,v 2.15.2.9 2000/07/19 13:40:04 darrenr Exp $
+ * $Id: ipl.h,v 2.15.2.10 2000/08/07 15:10:09 darrenr Exp $
*/
#ifndef __IPL_H__
#define __IPL_H__
-#define IPL_VERSION "IP Filter: v3.4.8"
+#define IPL_VERSION "IP Filter: v3.4.9"
#endif
diff --git a/sys/netinet/mlfk_ipl.c b/sys/netinet/mlfk_ipl.c
index 4412960e7b52..f869149869da 100644
--- a/sys/netinet/mlfk_ipl.c
+++ b/sys/netinet/mlfk_ipl.c
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: mlfk_ipl.c,v 2.1.2.1 2000/04/26 12:17:24 darrenr Exp $
+ * $Id: mlfk_ipl.c,v 2.1.2.3 2000/08/13 03:42:42 darrenr Exp $
*/
@@ -37,6 +37,7 @@
#include <net/if.h>
#include <netinet/in_systm.h>
#include <netinet/in.h>
+#include <netinet/ip.h>
#include <netinet/ipl.h>
@@ -82,6 +83,7 @@ SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_authused, CTLFLAG_RD,
&fr_authused, 0, "");
SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_defaultauthage, CTLFLAG_RW,
&fr_defaultauthage, 0, "");
+SYSCTL_INT(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &fr_chksrc, 0, "");
#define CDEV_MAJOR 79
static struct cdevsw ipl_cdevsw = {