From 15d169cdfcc633be9595e83cac604b7637123f9b Mon Sep 17 00:00:00 2001 From: darrenr Date: Sun, 13 Aug 2000 04:28:25 +0000 Subject: Import IP Filter 3.4.9 bits into the kernel --- sys/contrib/ipfilter/netinet/fil.c | 49 +++-- sys/contrib/ipfilter/netinet/ip_auth.c | 4 +- sys/contrib/ipfilter/netinet/ip_compat.h | 6 +- sys/contrib/ipfilter/netinet/ip_fil.c | 6 +- sys/contrib/ipfilter/netinet/ip_ftp_pxy.c | 6 +- sys/contrib/ipfilter/netinet/ip_log.c | 4 +- sys/contrib/ipfilter/netinet/ip_nat.c | 88 ++++++--- sys/contrib/ipfilter/netinet/ip_state.c | 298 +++++++++++++++++++++++++----- sys/contrib/ipfilter/netinet/ipl.h | 4 +- sys/contrib/ipfilter/netinet/mlfk_ipl.c | 4 +- 10 files changed, 367 insertions(+), 102 deletions(-) (limited to 'sys/contrib/ipfilter/netinet') diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c index 623e84e..91b5108 100644 --- a/sys/contrib/ipfilter/netinet/fil.c +++ b/sys/contrib/ipfilter/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 @@ -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/contrib/ipfilter/netinet/ip_auth.c b/sys/contrib/ipfilter/netinet/ip_auth.c index 9fa24d6..d737b9c 100644 --- a/sys/contrib/ipfilter/netinet/ip_auth.c +++ b/sys/contrib/ipfilter/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 @@ -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 # include #endif -#if (_BSDI_VERSION >= 199802) || (__FreeBSD_Version >= 400000) +#if (_BSDI_VERSION >= 199802) || (__FreeBSD_version >= 400000) # include #endif #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(bsdi) diff --git a/sys/contrib/ipfilter/netinet/ip_compat.h b/sys/contrib/ipfilter/netinet/ip_compat.h index 9b7cddf..ba9e014 100644 --- a/sys/contrib/ipfilter/netinet/ip_compat.h +++ b/sys/contrib/ipfilter/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 +#endif + #ifndef IP_OFFMASK #define IP_OFFMASK 0x1fff #endif diff --git a/sys/contrib/ipfilter/netinet/ip_fil.c b/sys/contrib/ipfilter/netinet/ip_fil.c index fe6af66..2e8af26 100644 --- a/sys/contrib/ipfilter/netinet/ip_fil.c +++ b/sys/contrib/ipfilter/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/contrib/ipfilter/netinet/ip_ftp_pxy.c b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c index 5ea94a1..84dc8b9 100644 --- a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c +++ b/sys/contrib/ipfilter/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/contrib/ipfilter/netinet/ip_log.c b/sys/contrib/ipfilter/netinet/ip_log.c index 08073bb..8adc410 100644 --- a/sys/contrib/ipfilter/netinet/ip_log.c +++ b/sys/contrib/ipfilter/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 #if defined(KERNEL) && !defined(_KERNEL) @@ -21,8 +21,6 @@ # endif # else # ifdef KLD_MODULE -# include -# else # include # endif # endif diff --git a/sys/contrib/ipfilter/netinet/ip_nat.c b/sys/contrib/ipfilter/netinet/ip_nat.c index d25f3f7..bbcff77 100644 --- a/sys/contrib/ipfilter/netinet/ip_nat.c +++ b/sys/contrib/ipfilter/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/contrib/ipfilter/netinet/ip_state.c b/sys/contrib/ipfilter/netinet/ip_state.c index fa8e050..f05c887 100644 --- a/sys/contrib/ipfilter/netinet/ip_state.c +++ b/sys/contrib/ipfilter/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 @@ -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 , 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/contrib/ipfilter/netinet/ipl.h b/sys/contrib/ipfilter/netinet/ipl.h index bb2523d..866d34d 100644 --- a/sys/contrib/ipfilter/netinet/ipl.h +++ b/sys/contrib/ipfilter/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/contrib/ipfilter/netinet/mlfk_ipl.c b/sys/contrib/ipfilter/netinet/mlfk_ipl.c index 4412960..f869149 100644 --- a/sys/contrib/ipfilter/netinet/mlfk_ipl.c +++ b/sys/contrib/ipfilter/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 #include #include +#include #include @@ -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 = { -- cgit v1.1