From b8cc98bd6c45a4a050a69e926139c5db53e1601d Mon Sep 17 00:00:00 2001 From: darrenr Date: Mon, 4 Jun 2007 02:50:28 +0000 Subject: Import IPFilter 4.1.23 to vendor branch. See src/contrib/ipfilter/HISTORY for details of changes since 4.1.13 --- sys/contrib/ipfilter/netinet/fil.c | 1302 +++++++++++++++++++++---- sys/contrib/ipfilter/netinet/ip_auth.c | 702 ++++++++----- sys/contrib/ipfilter/netinet/ip_auth.h | 6 +- sys/contrib/ipfilter/netinet/ip_compat.h | 122 +-- sys/contrib/ipfilter/netinet/ip_fil.h | 188 +++- sys/contrib/ipfilter/netinet/ip_fil_freebsd.c | 238 ++--- sys/contrib/ipfilter/netinet/ip_frag.c | 196 +++- sys/contrib/ipfilter/netinet/ip_frag.h | 27 +- sys/contrib/ipfilter/netinet/ip_ftp_pxy.c | 36 +- sys/contrib/ipfilter/netinet/ip_htable.c | 406 ++++++-- sys/contrib/ipfilter/netinet/ip_htable.h | 15 +- sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c | 6 +- sys/contrib/ipfilter/netinet/ip_irc_pxy.c | 4 +- sys/contrib/ipfilter/netinet/ip_log.c | 16 +- sys/contrib/ipfilter/netinet/ip_lookup.c | 178 +++- sys/contrib/ipfilter/netinet/ip_lookup.h | 35 +- sys/contrib/ipfilter/netinet/ip_nat.c | 969 +++++++++++++----- sys/contrib/ipfilter/netinet/ip_nat.h | 37 +- sys/contrib/ipfilter/netinet/ip_pool.c | 375 +++++-- sys/contrib/ipfilter/netinet/ip_pool.h | 15 +- sys/contrib/ipfilter/netinet/ip_pptp_pxy.c | 7 +- sys/contrib/ipfilter/netinet/ip_proxy.c | 17 +- sys/contrib/ipfilter/netinet/ip_proxy.h | 5 +- sys/contrib/ipfilter/netinet/ip_raudio_pxy.c | 6 +- sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c | 4 +- sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c | 12 +- sys/contrib/ipfilter/netinet/ip_scan.c | 34 +- sys/contrib/ipfilter/netinet/ip_scan.h | 4 +- sys/contrib/ipfilter/netinet/ip_state.c | 759 +++++++++----- sys/contrib/ipfilter/netinet/ip_state.h | 9 +- sys/contrib/ipfilter/netinet/ip_sync.c | 7 +- sys/contrib/ipfilter/netinet/ip_sync.h | 24 +- sys/contrib/ipfilter/netinet/ipl.h | 6 +- sys/contrib/ipfilter/netinet/mlfk_ipl.c | 36 +- 34 files changed, 4276 insertions(+), 1527 deletions(-) (limited to 'sys/contrib') diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c index 8f911e6..e2b6e92 100644 --- a/sys/contrib/ipfilter/netinet/fil.c +++ b/sys/contrib/ipfilter/netinet/fil.c @@ -15,7 +15,11 @@ #include #if defined(__NetBSD__) # if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL) -# include "opt_ipfilter_log.h" +# if (__NetBSD_Version__ < 399001400) +# include "opt_ipfilter_log.h" +# else +# include "opt_ipfilter.h" +# endif # endif #endif #if defined(_KERNEL) && defined(__FreeBSD_version) && \ @@ -32,6 +36,9 @@ #else # include #endif +#if (defined(__SVR4) || defined(__svr4__)) && defined(sun) +# include +#endif #if !defined(_AIX51) # include #endif @@ -79,7 +86,11 @@ struct file; # endif # include "radix_ipf.h" #endif -#include +#ifdef __osf__ +# include "radix_ipf.h" +#else +# include +#endif #include #include #include @@ -98,6 +109,9 @@ struct file; #ifdef __hpux # undef _NET_ROUTE_INCLUDED #endif +#ifdef __osf__ +# undef _RADIX_H_ +#endif #include "netinet/ip_compat.h" #ifdef USE_INET6 # include @@ -137,7 +151,7 @@ struct file; #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.243.2.78 2006/03/29 11:19:54 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: fil.c,v 2.243.2.109 2007/05/31 12:27:33 darrenr Exp $"; #endif #ifndef _KERNEL @@ -149,7 +163,7 @@ extern int opts; fr_info_t frcache[2][8]; -struct filterstats frstats[2] = { { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0 } }; +struct filterstats frstats[2]; struct frentry *ipfilter[2][2] = { { NULL, NULL }, { NULL, NULL } }, *ipfilter6[2][2] = { { NULL, NULL }, { NULL, NULL } }, *ipacct6[2][2] = { { NULL, NULL }, { NULL, NULL } }, @@ -230,11 +244,14 @@ static INLINE int frpr_udpcommon __P((fr_info_t *)); static int fr_updateipid __P((fr_info_t *)); #ifdef IPFILTER_LOOKUP static int fr_grpmapinit __P((frentry_t *fr)); -static INLINE void *fr_resolvelookup __P((u_int, u_int, lookupfunc_t *)); +static INLINE void *fr_resolvelookup __P((u_int, u_int, i6addr_t *, lookupfunc_t *)); #endif static void frsynclist __P((frentry_t *, void *)); static ipftuneable_t *fr_findtunebyname __P((const char *)); static ipftuneable_t *fr_findtunebycookie __P((void *, void **)); +static int ipf_geniter __P((ipftoken_t *, ipfgeniter_t *)); +static int ipf_frruleiter __P((void *, int, void *)); +static void ipf_unlinktoken __P((ipftoken_t *)); /* @@ -314,7 +331,7 @@ static ipfunc_resolve_t fr_availfuncs[] = { { "fr_srcgrpmap", fr_srcgrpmap, fr_grpmapinit }, { "fr_dstgrpmap", fr_dstgrpmap, fr_grpmapinit }, #endif - { "", NULL } + { "", NULL, NULL } }; @@ -527,7 +544,16 @@ int multiple, proto; return IPPROTO_NONE; hdr = fin->fin_dp; - shift = 8 + (hdr->ip6e_len << 3); + switch (proto) + { + case IPPROTO_FRAGMENT : + shift = 8; + break; + default : + shift = 8 + (hdr->ip6e_len << 3); + break; + } + if (shift > fin->fin_dlen) { /* Nasty extension header length? */ fin->fin_flx |= FI_BAD; return IPPROTO_NONE; @@ -546,6 +572,7 @@ int multiple, proto; break; } + fin->fin_exthdr = fin->fin_dp; fin->fin_dp = (char *)fin->fin_dp + shift; fin->fin_dlen -= shift; @@ -595,24 +622,22 @@ static INLINE int frpr_routing6(fin) fr_info_t *fin; { struct ip6_ext *hdr; - int shift; if (frpr_ipv6exthdr(fin, 0, IPPROTO_ROUTING) == IPPROTO_NONE) return IPPROTO_NONE; + hdr = fin->fin_exthdr; - hdr = fin->fin_dp; - shift = 8 + (hdr->ip6e_len << 3); - /* - * Nasty extension header length? - */ - if ((shift < sizeof(struct ip6_hdr)) || - ((shift - sizeof(struct ip6_hdr)) & 15)) { + if ((hdr->ip6e_len & 1) != 0) { + /* + * The routing header data is made up of 128 bit IPv6 addresses + * which means it must be a multiple of 2 lots of 8 in length. + */ fin->fin_flx |= FI_BAD; /* * Compensate for the changes made in frpr_ipv6exthdr() */ - fin->fin_dlen += shift; - fin->fin_dp = (char *)fin->fin_dp - shift; + fin->fin_dlen += 8 + (hdr->ip6e_len << 3); + fin->fin_dp = hdr; return IPPROTO_NONE; } @@ -638,16 +663,20 @@ static INLINE void frpr_fragment6(fin) fr_info_t *fin; { struct ip6_frag *frag; + int extoff; fin->fin_flx |= FI_FRAG; if (frpr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT) == IPPROTO_NONE) return; + extoff = (char *)fin->fin_exthdr - (char *)fin->fin_dp; + if (frpr_pullup(fin, sizeof(*frag)) == -1) return; - frag = fin->fin_dp; + fin->fin_exthdr = (char *)fin->fin_dp + extoff; + frag = fin->fin_exthdr; /* * Fragment but no fragmentation info set? Bad packet... */ @@ -697,10 +726,12 @@ fr_info_t *fin; int minicmpsz = sizeof(struct icmp6_hdr); struct icmp6_hdr *icmp6; - if (frpr_pullup(fin, ICMP6ERR_MINPKTLEN + 8 - sizeof(ip6_t)) == -1) + if (frpr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1) return; if (fin->fin_dlen > 1) { + ip6_t *ip6; + icmp6 = fin->fin_dp; fin->fin_data[0] = *(u_short *)icmp6; @@ -715,12 +746,26 @@ fr_info_t *fin; case ICMP6_PACKET_TOO_BIG : case ICMP6_TIME_EXCEEDED : case ICMP6_PARAM_PROB : + fin->fin_flx |= FI_ICMPERR; if ((fin->fin_m != NULL) && (M_LEN(fin->fin_m) < fin->fin_plen)) { if (fr_coalesce(fin) != 1) return; } - fin->fin_flx |= FI_ICMPERR; + + if (frpr_pullup(fin, ICMP6ERR_MINPKTLEN) == -1) + return; + + /* + * If the destination of this packet doesn't match the + * source of the original packet then this packet is + * not correct. + */ + ip6 = (ip6_t *)((char *)icmp6 + ICMPERR_ICMPHLEN); + if (IP6_NEQ(&fin->fin_fi.fi_dst, + (i6addr_t *)&ip6->ip6_src)) + fin->fin_flx |= FI_BAD; + minicmpsz = ICMP6ERR_IPICMPHLEN - sizeof(ip6_t); break; default : @@ -747,8 +792,13 @@ fr_info_t *fin; frpr_short6(fin, sizeof(struct udphdr)); - if (frpr_udpcommon(fin) == 0) + if (frpr_udpcommon(fin) == 0) { + u_char p = fin->fin_p; + + fin->fin_p = IPPROTO_UDP; fr_checkv6sum(fin); + fin->fin_p = p; + } } @@ -767,8 +817,13 @@ fr_info_t *fin; frpr_short6(fin, sizeof(struct tcphdr)); - if (frpr_tcpcommon(fin) == 0) + if (frpr_tcpcommon(fin) == 0) { + u_char p = fin->fin_p; + + fin->fin_p = IPPROTO_TCP; fr_checkv6sum(fin); + fin->fin_p = p; + } } @@ -857,18 +912,26 @@ static INLINE int frpr_pullup(fin, plen) fr_info_t *fin; int plen; { -#if defined(_KERNEL) if (fin->fin_m != NULL) { if (fin->fin_dp != NULL) plen += (char *)fin->fin_dp - ((char *)fin->fin_ip + fin->fin_hlen); plen += fin->fin_hlen; if (M_LEN(fin->fin_m) < plen) { +#if defined(_KERNEL) if (fr_pullup(fin->fin_m, fin, plen) == NULL) return -1; +#else + /* + * Fake fr_pullup failing + */ + *fin->fin_mp = NULL; + fin->fin_m = NULL; + fin->fin_ip = NULL; + return -1; +#endif } } -#endif return 0; } @@ -982,6 +1045,22 @@ fr_info_t *fin; oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN); if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0) fin->fin_flx |= FI_BAD; + + /* + * If the destination of this packet doesn't match the + * source of the original packet then this packet is + * not correct. + */ + if (oip->ip_src.s_addr != fin->fin_daddr) + fin->fin_flx |= FI_BAD; + + /* + * If the destination of this packet doesn't match the + * source of the original packet then this packet is + * not correct. + */ + if (oip->ip_src.s_addr != fin->fin_daddr) + fin->fin_flx |= FI_BAD; break; default : break; @@ -1049,14 +1128,27 @@ fr_info_t *fin; */ if ((flags & TH_URG) != 0 && (tcp->th_urp == 0)) { fin->fin_flx |= FI_BAD; +#if 0 } else if ((flags & TH_URG) == 0 && (tcp->th_urp != 0)) { - /* Ignore this case, it shows up in "real" traffic with */ - /* bogus values in the urgent pointer field. */ - ; + /* + * Ignore this case (#if 0) as it shows up in "real" + * traffic with bogus values in the urgent pointer field. + */ + fin->fin_flx |= FI_BAD; +#endif } else if (((flags & (TH_SYN|TH_FIN)) != 0) && ((flags & (TH_RST|TH_ACK)) == TH_RST)) { /* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */ fin->fin_flx |= FI_BAD; +#if 1 + } else if (((flags & TH_SYN) != 0) && + ((flags & (TH_URG|TH_PUSH)) != 0)) { + /* + * SYN with URG and PUSH set is not for normal TCP but it is + * possible(?) with T/TCP...but who uses T/TCP? + */ + fin->fin_flx |= FI_BAD; +#endif } else if (!(flags & TH_ACK)) { /* * If the ack bit isn't set, then either the SYN or @@ -1342,13 +1434,16 @@ fr_info_t *fin; */ off &= IP_MF|IP_OFFMASK; if (off != 0) { + int morefrag = off & IP_MF; + fi->fi_flx |= FI_FRAG; off &= IP_OFFMASK; if (off != 0) { fin->fin_flx |= FI_FRAGBODY; off <<= 3; if ((off + fin->fin_dlen > 65535) || - (fin->fin_dlen == 0) || (fin->fin_dlen & 7)) { + (fin->fin_dlen == 0) || + ((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) { /* * The length of the packet, starting at its * offset cannot exceed 65535 (0xffff) as the @@ -1502,18 +1597,24 @@ fr_info_t *fin; fin->fin_rule = 0xffffffff; fin->fin_group[0] = -1; fin->fin_group[1] = '\0'; - fin->fin_dlen = fin->fin_plen - hlen; fin->fin_dp = (char *)ip + hlen; v = fin->fin_v; - if (v == 4) + if (v == 4) { + fin->fin_plen = ip->ip_len; + fin->fin_dlen = fin->fin_plen - hlen; + frpr_ipv4hdr(fin); #ifdef USE_INET6 - else if (v == 6) { + } else if (v == 6) { + fin->fin_plen = ntohs(((ip6_t *)ip)->ip6_plen); + fin->fin_dlen = fin->fin_plen; + fin->fin_plen += hlen; + if (frpr_ipv6hdr(fin) == -1) return -1; - } #endif + } if (fin->fin_ip == NULL) return -1; return 0; @@ -1675,7 +1776,7 @@ int portcmp; */ i = ((*lip & *lm) != *ld); FR_DEBUG(("0. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); + ntohl(*lip), ntohl(*lm), ntohl(*ld))); if (i) return 1; @@ -1686,7 +1787,7 @@ int portcmp; lip++, lm++, ld++; i |= ((*lip & *lm) != *ld); FR_DEBUG(("1. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); + ntohl(*lip), ntohl(*lm), ntohl(*ld))); if (i) return 1; @@ -1709,20 +1810,20 @@ int portcmp; #endif i = ((*lip & *lm) != *ld); FR_DEBUG(("2a. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); + ntohl(*lip), ntohl(*lm), ntohl(*ld))); if (fi->fi_v == 6) { lip++, lm++, ld++; i |= ((*lip & *lm) != *ld); FR_DEBUG(("2b. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); + ntohl(*lip), ntohl(*lm), ntohl(*ld))); lip++, lm++, ld++; i |= ((*lip & *lm) != *ld); FR_DEBUG(("2c. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); + ntohl(*lip), ntohl(*lm), ntohl(*ld))); lip++, lm++, ld++; i |= ((*lip & *lm) != *ld); FR_DEBUG(("2d. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); + ntohl(*lip), ntohl(*lm), ntohl(*ld))); } else { lip += 3; lm += 3; @@ -1751,20 +1852,20 @@ int portcmp; #endif i = ((*lip & *lm) != *ld); FR_DEBUG(("3a. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); + ntohl(*lip), ntohl(*lm), ntohl(*ld))); if (fi->fi_v == 6) { lip++, lm++, ld++; i |= ((*lip & *lm) != *ld); FR_DEBUG(("3b. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); + ntohl(*lip), ntohl(*lm), ntohl(*ld))); lip++, lm++, ld++; i |= ((*lip & *lm) != *ld); FR_DEBUG(("3c. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); + ntohl(*lip), ntohl(*lm), ntohl(*ld))); lip++, lm++, ld++; i |= ((*lip & *lm) != *ld); FR_DEBUG(("3d. %#08x & %#08x != %#08x\n", - *lip, *lm, *ld)); + ntohl(*lip), ntohl(*lm), ntohl(*ld))); } else { lip += 3; lm += 3; @@ -2292,9 +2393,6 @@ int out; int v = IP_V(ip); mb_t *mc = NULL; mb_t *m; -#ifdef USE_INET6 - ip6_t *ip6; -#endif /* * The first part of fr_check() deals with making sure that what goes * into the filtering engine makes some sense. Information about the @@ -2390,13 +2488,10 @@ int out; * structures to handle comfortably, for now, so just drop * them. */ - ip6 = (ip6_t *)ip; - fin->fin_plen = ntohs(ip6->ip6_plen); - if (fin->fin_plen == 0) { + if (((ip6_t *)ip)->ip6_plen == 0) { pass = FR_BLOCK|FR_NOMATCH; goto finished; } - fin->fin_plen += sizeof(ip6_t); } else #endif { @@ -2404,7 +2499,6 @@ int out; ip->ip_len = ntohs(ip->ip_len); ip->ip_off = ntohs(ip->ip_off); #endif - fin->fin_plen = ip->ip_len; } if (fr_makefrip(hlen, ip, fin) == -1) { @@ -2434,8 +2528,7 @@ int out; } #ifdef USE_INET6 else if (v == 6) { - ip6 = (ip6_t *)ip; - if (ip6->ip6_hlim < fr_minttl) { + if (((ip6_t *)ip)->ip6_hlim < fr_minttl) { ATOMIC_INCL(frstats[0].fr_badttl); fin->fin_flx |= FI_LOWTTL; } @@ -2459,8 +2552,7 @@ int out; fr = fr_checkauth(fin, &pass); if (!out) { if (fr_checknatin(fin, &pass) == -1) { - RWLOCK_EXIT(&ipf_mutex); - goto finished; + goto filterdone; } } if (!out) @@ -2502,8 +2594,7 @@ int out; (void) fr_acctpkt(fin, NULL); if (fr_checknatout(fin, &pass) == -1) { - RWLOCK_EXIT(&ipf_mutex); - goto finished; + ; } else if ((fr_update_ipid != 0) && (v == 4)) { if (fr_updateipid(fin) == -1) { ATOMIC_INCL(frstats[1].fr_ipud); @@ -2515,20 +2606,26 @@ int out; } } +filterdone: #ifdef IPFILTER_LOG if ((fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) { (void) fr_dolog(fin, &pass); } #endif + /* + * The FI_STATE flag is cleared here so that calling fr_checkstate + * will work when called from inside of fr_fastroute. Although + * there is a similar flag, FI_NATED, for NAT, it does have the same + * impact on code execution. + */ if (fin->fin_state != NULL) { - fr_statederef(fin, (ipstate_t **)&fin->fin_state); - fin->fin_state = NULL; + fr_statederef((ipstate_t **)&fin->fin_state); + fin->fin_flx ^= FI_STATE; } if (fin->fin_nat != NULL) { fr_natderef((nat_t **)&fin->fin_nat); - fin->fin_nat = NULL; } /* @@ -2783,6 +2880,7 @@ int len; /* ip(I) - pointer to IP header */ /* l4proto(I) - protocol to caclulate checksum for */ /* l4hdr(I) - pointer to layer 4 header */ +/* l3len(I) - length of layer 4 data plus layer 3 header */ /* */ /* Calculates the TCP checksum for the packet held in "m", using the data */ /* in the IP header "ip" to seed it. */ @@ -2791,6 +2889,8 @@ int len; /* and the TCP header. We also assume that data blocks aren't allocated in */ /* odd sizes. */ /* */ +/* For IPv6, l3len excludes extension header size. */ +/* */ /* Expects ip_len to be in host byte order when called. */ /* ------------------------------------------------------------------------ */ u_short fr_cksum(m, ip, l4proto, l4hdr, l3len) @@ -2833,9 +2933,9 @@ void *l4hdr; } else if (IP_V(ip) == 6) { ip6 = (ip6_t *)ip; hlen = sizeof(*ip6); - slen = ntohs(l3len); + slen = l3len - hlen; sum = htons((u_short)l4proto); - sum += slen; + sum += htons(slen); sp = (u_short *)&ip6->ip6_src; sum += *sp++; /* ip6_src */ sum += *sp++; @@ -3021,6 +3121,12 @@ nodata: # endif /* defined(BSD) || defined(sun) */ # endif /* MENTAT */ #else /* _KERNEL */ + /* + * Add up IP Header portion + */ + if (sp != (u_short *)l4hdr) + sp = (u_short *)l4hdr; + for (; slen > 1; slen -= 2) sum += *sp++; if (slen) @@ -3066,7 +3172,7 @@ nodata: * SUCH DAMAGE. * * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 - * $Id: fil.c,v 2.243.2.78 2006/03/29 11:19:54 darrenr Exp $ + * $Id: fil.c,v 2.243.2.109 2007/05/31 12:27:33 darrenr Exp $ */ /* * Copy data from an mbuf chain starting "off" bytes from the beginning, @@ -3657,13 +3763,15 @@ void *ifp; if (fr->fr_type == FR_T_IPF && fr->fr_satype == FRI_LOOKUP && fr->fr_srcptr == NULL) { fr->fr_srcptr = fr_resolvelookup(fr->fr_srctype, - fr->fr_srcnum, + fr->fr_srcsubtype, + &fr->fr_slookup, &fr->fr_srcfunc); } if (fr->fr_type == FR_T_IPF && fr->fr_datype == FRI_LOOKUP && fr->fr_dstptr == NULL) { fr->fr_dstptr = fr_resolvelookup(fr->fr_dsttype, - fr->fr_dstnum, + fr->fr_dstsubtype, + &fr->fr_dlookup, &fr->fr_dstfunc); } #endif @@ -3735,17 +3843,19 @@ void *src, *dst; size_t size; { caddr_t ca; - int err; + int error; # if SOLARIS - err = COPYIN(src, (caddr_t)&ca, sizeof(ca)); - if (err != 0) - return err; + error = COPYIN(src, (caddr_t)&ca, sizeof(ca)); + if (error != 0) + return error; # else bcopy(src, (caddr_t)&ca, sizeof(ca)); # endif - err = COPYIN(ca, dst, size); - return err; + error = COPYIN(ca, dst, size); + if (error != 0) + error = EFAULT; + return error; } @@ -3765,11 +3875,13 @@ void *src, *dst; size_t size; { caddr_t ca; - int err; + int error; bcopy(dst, (caddr_t)&ca, sizeof(ca)); - err = COPYOUT(src, ca, size); - return err; + error = COPYOUT(src, ca, size); + if (error != 0) + error = EFAULT; + return error; } #endif @@ -3945,7 +4057,8 @@ int rev; /* Function: fr_resolvelookup */ /* Returns: void * - NULL = failure, else success. */ /* Parameters: type(I) - type of lookup these parameters are for. */ -/* number(I) - table number to use when searching */ +/* subtype(I) - whether the info below contains number/name */ +/* info(I) - pointer to name/number of the lookup data */ /* funcptr(IO) - pointer to pointer for storing IP address */ /* searching function. */ /* */ @@ -3954,20 +4067,35 @@ int rev; /* call to do the IP address search will be change, regardless of whether */ /* or not the "table" number exists. */ /* ------------------------------------------------------------------------ */ -static void *fr_resolvelookup(type, number, funcptr) -u_int type, number; +static void *fr_resolvelookup(type, subtype, info, funcptr) +u_int type, subtype; +i6addr_t *info; lookupfunc_t *funcptr; { - char name[FR_GROUPLEN]; + char label[FR_GROUPLEN], *name; iphtable_t *iph; ip_pool_t *ipo; void *ptr; + if (subtype == 0) { #if defined(SNPRINTF) && defined(_KERNEL) - SNPRINTF(name, sizeof(name), "%u", number); + SNPRINTF(label, sizeof(label), "%u", info->iplookupnum); #else - (void) sprintf(name, "%u", number); + (void) sprintf(label, "%u", info->iplookupnum); #endif + name = label; + } else if (subtype == 1) { + /* + * Because iplookupname is currently only a 12 character + * string and FR_GROUPLEN is 16, copy all of it into the + * label buffer and add on a NULL at the end. + */ + strncpy(label, info->iplookupname, sizeof(info->iplookupname)); + label[sizeof(info->iplookupname)] = '\0'; + name = label; + } else { + return NULL; + } READ_ENTER(&ip_poolrw); @@ -4139,16 +4267,6 @@ caddr_t data; fprev = &fg->fg_start; } - ftail = fprev; - for (f = *ftail; (f = *ftail) != NULL; ftail = &f->fr_next) { - if (fp->fr_collect <= f->fr_collect) { - ftail = fprev; - f = NULL; - break; - } - fprev = ftail; - } - /* * Copy in extra data for the rule. */ @@ -4158,6 +4276,8 @@ caddr_t data; if (!ptr) return ENOMEM; error = COPYIN(uptr, ptr, fp->fr_dsize); + if (error != 0) + error = EFAULT; } else { ptr = uptr; error = 0; @@ -4216,8 +4336,11 @@ caddr_t data; #ifdef IPFILTER_LOOKUP case FRI_LOOKUP : fp->fr_srcptr = fr_resolvelookup(fp->fr_srctype, - fp->fr_srcnum, + fp->fr_srcsubtype, + &fp->fr_slookup, &fp->fr_srcfunc); + if (fp->fr_srcptr == NULL) + return ESRCH; break; #endif default : @@ -4241,8 +4364,11 @@ caddr_t data; #ifdef IPFILTER_LOOKUP case FRI_LOOKUP : fp->fr_dstptr = fr_resolvelookup(fp->fr_dsttype, - fp->fr_dstnum, + fp->fr_dstsubtype, + &fp->fr_dlookup, &fp->fr_dstfunc); + if (fp->fr_dstptr == NULL) + return ESRCH; break; #endif default : @@ -4283,6 +4409,20 @@ caddr_t data; fp->fr_cksum += *p; WRITE_ENTER(&ipf_mutex); + + /* + * Now that the filter rule lists are locked, we can walk the + * chain of them without fear. + */ + ftail = fprev; + for (f = *ftail; (f = *ftail) != NULL; ftail = &f->fr_next) { + if (fp->fr_collect <= f->fr_collect) { + ftail = fprev; + f = NULL; + break; + } + fprev = ftail; + } bzero((char *)frcache, sizeof(frcache)); for (; (f = *ftail) != NULL; ftail = &f->fr_next) { @@ -4326,6 +4466,8 @@ caddr_t data; if ((f->fr_dsize != 0) && (uptr != NULL)) error = COPYOUT(f->fr_data, uptr, f->fr_dsize); + if (error != 0) + error = EFAULT; if (error == 0) { f->fr_hits = 0; f->fr_bytes = 0; @@ -4422,7 +4564,7 @@ caddr_t data; fr_fixskip(ftail, f, -1); *ftail = f->fr_next; f->fr_next = NULL; - (void)fr_derefrule(&f); + (void) fr_derefrule(&f); } } else { /* @@ -4571,7 +4713,7 @@ void *data; #if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__FreeBSD__)) || \ - (defined(__FreeBSD__) && (__FreeBSD_version < 490000)) || \ + (defined(__FreeBSD__) && (__FreeBSD_version < 501000)) || \ (defined(__NetBSD__) && (__NetBSD_Version__ < 105000000)) || \ (defined(__OpenBSD__) && (OpenBSD < 200006)) /* @@ -4636,6 +4778,7 @@ frentry_t **frp; frentry_t *fr; fr = *frp; + *frp = NULL; MUTEX_ENTER(&fr->fr_lock); fr->fr_ref--; @@ -4661,7 +4804,6 @@ frentry_t **frp; } else { MUTEX_EXIT(&fr->fr_lock); } - *frp = NULL; return -1; } @@ -5191,55 +5333,47 @@ char *buffer; /* data(I) - pointer to ioctl data */ /* cmd(I) - ioctl command */ /* mode(I) - mode value */ +/* uid(I) - uid making the ioctl call */ +/* ctx(I) - pointer to context data */ /* */ /* Based on the value of unit, call the appropriate ioctl handler or return */ /* EIO if ipfilter is not running. Also checks if write perms are req'd */ /* for the device in order to execute the ioctl. */ /* ------------------------------------------------------------------------ */ -int fr_ioctlswitch(unit, data, cmd, mode) -int unit, mode; +int fr_ioctlswitch(unit, data, cmd, mode, uid, ctx) +int unit, mode, uid; ioctlcmd_t cmd; -void *data; +void *data, *ctx; { int error = 0; switch (unit) { case IPL_LOGIPF : - error = -1; + error = fr_ipf_ioctl(data, cmd, mode, uid, ctx); break; case IPL_LOGNAT : if (fr_running > 0) - error = fr_nat_ioctl(data, cmd, mode); + error = fr_nat_ioctl(data, cmd, mode, uid, ctx); else error = EIO; break; case IPL_LOGSTATE : if (fr_running > 0) - error = fr_state_ioctl(data, cmd, mode); + error = fr_state_ioctl(data, cmd, mode, uid, ctx); else error = EIO; break; case IPL_LOGAUTH : - if (fr_running > 0) { - if ((cmd == (ioctlcmd_t)SIOCADAFR) || - (cmd == (ioctlcmd_t)SIOCRMAFR)) { - if (!(mode & FWRITE)) { - error = EPERM; - } else { - error = frrequest(unit, cmd, data, - fr_active, 1); - } - } else { - error = fr_auth_ioctl(data, cmd, mode); - } - } else + if (fr_running > 0) + error = fr_auth_ioctl(data, cmd, mode, uid, ctx); + else error = EIO; break; case IPL_LOGSYNC : #ifdef IPFILTER_SYNC if (fr_running > 0) - error = fr_sync_ioctl(data, cmd, mode); + error = fr_sync_ioctl(data, cmd, mode, uid, ctx); else #endif error = EIO; @@ -5247,7 +5381,7 @@ void *data; case IPL_LOGSCAN : #ifdef IPFILTER_SCAN if (fr_running > 0) - error = fr_scan_ioctl(data, cmd, mode); + error = fr_scan_ioctl(data, cmd, mode, uid, ctx); else #endif error = EIO; @@ -5255,7 +5389,7 @@ void *data; case IPL_LOGLOOKUP : #ifdef IPFILTER_LOOKUP if (fr_running > 0) - error = ip_lookup_ioctl(data, cmd, mode); + error = ip_lookup_ioctl(data, cmd, mode, uid, ctx); else #endif error = EIO; @@ -5273,9 +5407,7 @@ void *data; * This array defines the expected size of objects coming into the kernel * for the various recognised object types. */ -#define NUM_OBJ_TYPES 14 - -static int fr_objbytes[NUM_OBJ_TYPES][2] = { +static int fr_objbytes[IPFOBJ_COUNT][2] = { { 1, sizeof(struct frentry) }, /* frentry */ { 0, sizeof(struct friostat) }, { 0, sizeof(struct fr_info) }, @@ -5289,7 +5421,13 @@ static int fr_objbytes[NUM_OBJ_TYPES][2] = { { 1, sizeof(struct ipstate) }, /* ipstate */ { 0, sizeof(struct ips_stat) }, { 0, sizeof(struct frauth) }, - { 0, sizeof(struct ipftune) } + { 0, sizeof(struct ipftune) }, + { 0, sizeof(struct nat) }, /* nat_t */ + { 0, sizeof(struct ipfruleiter) }, + { 0, sizeof(struct ipfgeniter) }, + { 0, sizeof(struct ipftable) }, + { 0, sizeof(struct ipflookupiter) }, + { 0, sizeof(struct ipftq) * IPF_TCP_NSTATES }, }; @@ -5312,7 +5450,7 @@ int type; ipfobj_t obj; int error = 0; - if ((type < 0) || (type > NUM_OBJ_TYPES-1)) + if ((type < 0) || (type >= IPFOBJ_COUNT)) return EINVAL; BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj)); @@ -5324,8 +5462,9 @@ int type; if ((fr_objbytes[type][0] & 1) != 0) { if (obj.ipfo_size < fr_objbytes[type][1]) return EINVAL; - } else if (obj.ipfo_size != fr_objbytes[type][1]) + } else if (obj.ipfo_size != fr_objbytes[type][1]) { return EINVAL; + } #else if (obj.ipfo_rev != IPFILTER_VERSION) /* XXX compatibility hook here */ @@ -5346,6 +5485,8 @@ int type; error = COPYIN((caddr_t)obj.ipfo_ptr, (caddr_t)ptr, obj.ipfo_size); } + if (error != 0) + error = EFAULT; return error; } @@ -5372,7 +5513,7 @@ int type, sz; ipfobj_t obj; int error; - if ((type < 0) || (type > NUM_OBJ_TYPES-1)) + if ((type < 0) || (type >= IPFOBJ_COUNT)) return EINVAL; if (((fr_objbytes[type][0] & 1) == 0) || (sz < fr_objbytes[type][1])) return EINVAL; @@ -5395,6 +5536,8 @@ int type, sz; #endif error = COPYIN((caddr_t)obj.ipfo_ptr, (caddr_t)ptr, sz); + if (error != 0) + error = EFAULT; return error; } @@ -5421,7 +5564,7 @@ int type, sz; ipfobj_t obj; int error; - if ((type < 0) || (type > NUM_OBJ_TYPES-1) || + if ((type < 0) || (type > IPFOBJ_COUNT) || ((fr_objbytes[type][0] & 1) == 0) || (sz < fr_objbytes[type][1])) return EINVAL; @@ -5444,6 +5587,8 @@ int type, sz; #endif error = COPYOUT((caddr_t)ptr, (caddr_t)obj.ipfo_ptr, sz); + if (error != 0) + error = EFAULT; return error; } @@ -5467,7 +5612,7 @@ int type; ipfobj_t obj; int error; - if ((type < 0) || (type > NUM_OBJ_TYPES-1)) + if ((type < 0) || (type > IPFOBJ_COUNT)) return EINVAL; BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj)); @@ -5495,6 +5640,8 @@ int type; #endif error = COPYOUT((caddr_t)ptr, (caddr_t)obj.ipfo_ptr, obj.ipfo_size); + if (error != 0) + error = EFAULT; return error; } @@ -5565,9 +5712,11 @@ fr_info_t *fin; if (csump != NULL) hdrsum = *csump; - if (dosum) + if (dosum) { sum = fr_cksum(fin->fin_m, fin->fin_ip, - fin->fin_p, fin->fin_dp, fin->fin_plen); + fin->fin_p, fin->fin_dp, + fin->fin_dlen + fin->fin_hlen); + } #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID) } #endif @@ -5768,100 +5917,104 @@ fr_info_t *fin; ipftuneable_t ipf_tuneables[] = { /* filtering */ { { &fr_flags }, "fr_flags", 0, 0xffffffff, - sizeof(fr_flags), 0 }, + sizeof(fr_flags), 0, NULL }, { { &fr_active }, "fr_active", 0, 0, - sizeof(fr_active), IPFT_RDONLY }, + sizeof(fr_active), IPFT_RDONLY, NULL }, { { &fr_control_forwarding }, "fr_control_forwarding", 0, 1, - sizeof(fr_control_forwarding), 0 }, + sizeof(fr_control_forwarding), 0, NULL }, { { &fr_update_ipid }, "fr_update_ipid", 0, 1, - sizeof(fr_update_ipid), 0 }, + sizeof(fr_update_ipid), 0, NULL }, { { &fr_chksrc }, "fr_chksrc", 0, 1, - sizeof(fr_chksrc), 0 }, + sizeof(fr_chksrc), 0, NULL }, { { &fr_minttl }, "fr_minttl", 0, 1, - sizeof(fr_minttl), 0 }, + sizeof(fr_minttl), 0, NULL }, { { &fr_icmpminfragmtu }, "fr_icmpminfragmtu", 0, 1, - sizeof(fr_icmpminfragmtu), 0 }, + sizeof(fr_icmpminfragmtu), 0, NULL }, { { &fr_pass }, "fr_pass", 0, 0xffffffff, - sizeof(fr_pass), 0 }, + sizeof(fr_pass), 0, NULL }, /* state */ { { &fr_tcpidletimeout }, "fr_tcpidletimeout", 1, 0x7fffffff, - sizeof(fr_tcpidletimeout), IPFT_WRDISABLED }, + sizeof(fr_tcpidletimeout), IPFT_WRDISABLED, NULL }, { { &fr_tcpclosewait }, "fr_tcpclosewait", 1, 0x7fffffff, - sizeof(fr_tcpclosewait), IPFT_WRDISABLED }, + sizeof(fr_tcpclosewait), IPFT_WRDISABLED, NULL }, { { &fr_tcplastack }, "fr_tcplastack", 1, 0x7fffffff, - sizeof(fr_tcplastack), IPFT_WRDISABLED }, + sizeof(fr_tcplastack), IPFT_WRDISABLED, NULL }, { { &fr_tcptimeout }, "fr_tcptimeout", 1, 0x7fffffff, - sizeof(fr_tcptimeout), IPFT_WRDISABLED }, + sizeof(fr_tcptimeout), IPFT_WRDISABLED, NULL }, { { &fr_tcpclosed }, "fr_tcpclosed", 1, 0x7fffffff, - sizeof(fr_tcpclosed), IPFT_WRDISABLED }, + sizeof(fr_tcpclosed), IPFT_WRDISABLED, NULL }, { { &fr_tcphalfclosed }, "fr_tcphalfclosed", 1, 0x7fffffff, - sizeof(fr_tcphalfclosed), IPFT_WRDISABLED }, + sizeof(fr_tcphalfclosed), IPFT_WRDISABLED, NULL }, { { &fr_udptimeout }, "fr_udptimeout", 1, 0x7fffffff, - sizeof(fr_udptimeout), IPFT_WRDISABLED }, + sizeof(fr_udptimeout), IPFT_WRDISABLED, NULL }, { { &fr_udpacktimeout }, "fr_udpacktimeout", 1, 0x7fffffff, - sizeof(fr_udpacktimeout), IPFT_WRDISABLED }, + sizeof(fr_udpacktimeout), IPFT_WRDISABLED, NULL }, { { &fr_icmptimeout }, "fr_icmptimeout", 1, 0x7fffffff, - sizeof(fr_icmptimeout), IPFT_WRDISABLED }, + sizeof(fr_icmptimeout), IPFT_WRDISABLED, NULL }, { { &fr_icmpacktimeout }, "fr_icmpacktimeout", 1, 0x7fffffff, - sizeof(fr_icmpacktimeout), IPFT_WRDISABLED }, + sizeof(fr_icmpacktimeout), IPFT_WRDISABLED, NULL }, { { &fr_iptimeout }, "fr_iptimeout", 1, 0x7fffffff, - sizeof(fr_iptimeout), IPFT_WRDISABLED }, + sizeof(fr_iptimeout), IPFT_WRDISABLED, NULL }, { { &fr_statemax }, "fr_statemax", 1, 0x7fffffff, - sizeof(fr_statemax), 0 }, + sizeof(fr_statemax), 0, NULL }, { { &fr_statesize }, "fr_statesize", 1, 0x7fffffff, - sizeof(fr_statesize), IPFT_WRDISABLED }, + sizeof(fr_statesize), IPFT_WRDISABLED, NULL }, { { &fr_state_lock }, "fr_state_lock", 0, 1, - sizeof(fr_state_lock), IPFT_RDONLY }, + sizeof(fr_state_lock), IPFT_RDONLY, NULL }, { { &fr_state_maxbucket }, "fr_state_maxbucket", 1, 0x7fffffff, - sizeof(fr_state_maxbucket), IPFT_WRDISABLED }, + sizeof(fr_state_maxbucket), IPFT_WRDISABLED, NULL }, { { &fr_state_maxbucket_reset }, "fr_state_maxbucket_reset", 0, 1, - sizeof(fr_state_maxbucket_reset), IPFT_WRDISABLED }, + sizeof(fr_state_maxbucket_reset), IPFT_WRDISABLED, NULL }, { { &ipstate_logging }, "ipstate_logging", 0, 1, - sizeof(ipstate_logging), 0 }, + sizeof(ipstate_logging), 0, NULL }, /* nat */ { { &fr_nat_lock }, "fr_nat_lock", 0, 1, - sizeof(fr_nat_lock), IPFT_RDONLY }, + sizeof(fr_nat_lock), IPFT_RDONLY, NULL }, { { &ipf_nattable_sz }, "ipf_nattable_sz", 1, 0x7fffffff, - sizeof(ipf_nattable_sz), IPFT_WRDISABLED }, + sizeof(ipf_nattable_sz), IPFT_WRDISABLED, NULL }, { { &ipf_nattable_max }, "ipf_nattable_max", 1, 0x7fffffff, - sizeof(ipf_nattable_max), 0 }, + sizeof(ipf_nattable_max), 0, NULL }, { { &ipf_natrules_sz }, "ipf_natrules_sz", 1, 0x7fffffff, - sizeof(ipf_natrules_sz), IPFT_WRDISABLED }, + sizeof(ipf_natrules_sz), IPFT_WRDISABLED, NULL }, { { &ipf_rdrrules_sz }, "ipf_rdrrules_sz", 1, 0x7fffffff, - sizeof(ipf_rdrrules_sz), IPFT_WRDISABLED }, + sizeof(ipf_rdrrules_sz), IPFT_WRDISABLED, NULL }, { { &ipf_hostmap_sz }, "ipf_hostmap_sz", 1, 0x7fffffff, - sizeof(ipf_hostmap_sz), IPFT_WRDISABLED }, + sizeof(ipf_hostmap_sz), IPFT_WRDISABLED, NULL }, { { &fr_nat_maxbucket }, "fr_nat_maxbucket", 1, 0x7fffffff, - sizeof(fr_nat_maxbucket), IPFT_WRDISABLED }, + sizeof(fr_nat_maxbucket), IPFT_WRDISABLED, NULL }, { { &fr_nat_maxbucket_reset }, "fr_nat_maxbucket_reset", 0, 1, - sizeof(fr_nat_maxbucket_reset), IPFT_WRDISABLED }, + sizeof(fr_nat_maxbucket_reset), IPFT_WRDISABLED, NULL }, { { &nat_logging }, "nat_logging", 0, 1, - sizeof(nat_logging), 0 }, + sizeof(nat_logging), 0, NULL }, { { &fr_defnatage }, "fr_defnatage", 1, 0x7fffffff, - sizeof(fr_defnatage), IPFT_WRDISABLED }, + sizeof(fr_defnatage), IPFT_WRDISABLED, NULL }, { { &fr_defnatipage }, "fr_defnatipage", 1, 0x7fffffff, - sizeof(fr_defnatipage), IPFT_WRDISABLED }, + sizeof(fr_defnatipage), IPFT_WRDISABLED, NULL }, { { &fr_defnaticmpage }, "fr_defnaticmpage", 1, 0x7fffffff, - sizeof(fr_defnaticmpage), IPFT_WRDISABLED }, + sizeof(fr_defnaticmpage), IPFT_WRDISABLED, NULL }, + { { &fr_nat_doflush }, "fr_nat_doflush", 0, 1, + sizeof(fr_nat_doflush), 0, NULL }, + /* proxy */ + { { &ipf_proxy_debug }, "ipf_proxy_debug", 0, 10, + sizeof(ipf_proxy_debug), 0, 0 }, /* frag */ { { &ipfr_size }, "ipfr_size", 1, 0x7fffffff, - sizeof(ipfr_size), IPFT_WRDISABLED }, + sizeof(ipfr_size), IPFT_WRDISABLED, NULL }, { { &fr_ipfrttl }, "fr_ipfrttl", 1, 0x7fffffff, - sizeof(fr_ipfrttl), IPFT_WRDISABLED }, + sizeof(fr_ipfrttl), IPFT_WRDISABLED, NULL }, #ifdef IPFILTER_LOG /* log */ { { &ipl_suppress }, "ipl_suppress", 0, 1, - sizeof(ipl_suppress), 0 }, - { { &ipl_buffer_sz }, "ipl_buffer_sz", 0, 0, - sizeof(ipl_buffer_sz), IPFT_RDONLY }, + sizeof(ipl_suppress), 0, NULL }, { { &ipl_logmax }, "ipl_logmax", 0, 0x7fffffff, - sizeof(ipl_logmax), IPFT_WRDISABLED }, + sizeof(ipl_logmax), IPFT_WRDISABLED, NULL }, { { &ipl_logall }, "ipl_logall", 0, 1, - sizeof(ipl_logall), 0 }, + sizeof(ipl_logall), 0, NULL }, { { &ipl_logsize }, "ipl_logsize", 0, 0x80000, - sizeof(ipl_logsize), 0 }, + sizeof(ipl_logsize), 0, NULL }, #endif - { { NULL }, NULL, 0, 0 } + { { NULL }, NULL, 0, 0, + 0, 0, NULL } }; static ipftuneable_t *ipf_tunelist = NULL; @@ -6172,6 +6325,8 @@ int fr_initialise() { int i; + bzero(&frstats, sizeof(frstats)); + #ifdef IPFILTER_LOG i = fr_loginit(); if (i < 0) @@ -6275,12 +6430,12 @@ caddr_t data; int error; fr_getstat(&fio); - error = copyoutptr(&fio, data, sizeof(fio)); + error = fr_outobj(data, &fio, IPFOBJ_IPFSTAT); if (error) return EFAULT; WRITE_ENTER(&ipf_mutex); - bzero((char *)frstats, sizeof(*frstats) * 2); + bzero(&frstats, sizeof(frstats)); RWLOCK_EXIT(&ipf_mutex); return 0; @@ -6359,3 +6514,800 @@ int v; nic = (void *)-1; return nic; } + + +ipftoken_t *ipftokenhead = NULL, **ipftokentail = &ipftokenhead; + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_expiretokens */ +/* Returns: None. */ +/* Parameters: None. */ +/* */ +/* This function is run every ipf tick to see if there are any tokens that */ +/* have been held for too long and need to be freed up. */ +/* ------------------------------------------------------------------------ */ +void ipf_expiretokens() +{ + ipftoken_t *it; + void *data; + + WRITE_ENTER(&ipf_tokens); + while ((it = ipftokenhead) != NULL) { + if (it->ipt_die > fr_ticks) + break; + + data = it->ipt_data; + + ipf_freetoken(it); + } + RWLOCK_EXIT(&ipf_tokens); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_deltoken */ +/* Returns: int - 0 = success, else error */ +/* Parameters: type(I) - the token type to match */ +/* uid(I) - uid owning the token */ +/* ptr(I) - context pointer for the token */ +/* */ +/* This function looks for a a token in the current list that matches up */ +/* the fields (type, uid, ptr). If none is found, ESRCH is returned, else */ +/* call ipf_freetoken() to remove it from the list. */ +/* ------------------------------------------------------------------------ */ +int ipf_deltoken(type, uid, ptr) +int type, uid; +void *ptr; +{ + ipftoken_t *it; + int error = ESRCH; + + WRITE_ENTER(&ipf_tokens); + for (it = ipftokenhead; it != NULL; it = it->ipt_next) + if (ptr == it->ipt_ctx && type == it->ipt_type && + uid == it->ipt_uid) { + ipf_freetoken(it); + error = 0; + break; + } + RWLOCK_EXIT(&ipf_tokens); + + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_findtoken */ +/* Returns: ipftoken_t * - NULL if no memory, else pointer to token */ +/* Parameters: type(I) - the token type to match */ +/* uid(I) - uid owning the token */ +/* ptr(I) - context pointer for the token */ +/* */ +/* This function looks for a live token in the list of current tokens that */ +/* matches the tuple (type, uid, ptr). If one cannot be found then one is */ +/* allocated. If one is found then it is moved to the top of the list of */ +/* currently active tokens. */ +/* */ +/* NOTE: It is by design that this function returns holding a read lock on */ +/* ipf_tokens. Callers must make sure they release it! */ +/* ------------------------------------------------------------------------ */ +ipftoken_t *ipf_findtoken(type, uid, ptr) +int type, uid; +void *ptr; +{ + ipftoken_t *it, *new; + + KMALLOC(new, ipftoken_t *); + + WRITE_ENTER(&ipf_tokens); + for (it = ipftokenhead; it != NULL; it = it->ipt_next) { + if (it->ipt_alive == 0) + continue; + if (ptr == it->ipt_ctx && type == it->ipt_type && + uid == it->ipt_uid) + break; + } + + if (it == NULL) { + it = new; + new = NULL; + if (it == NULL) + return NULL; + it->ipt_data = NULL; + it->ipt_ctx = ptr; + it->ipt_uid = uid; + it->ipt_type = type; + it->ipt_next = NULL; + it->ipt_alive = 1; + } else { + if (new != NULL) { + KFREE(new); + new = NULL; + } + + ipf_unlinktoken(it); + } + it->ipt_pnext = ipftokentail; + *ipftokentail = it; + ipftokentail = &it->ipt_next; + it->ipt_next = NULL; + + it->ipt_die = fr_ticks + 2; + + MUTEX_DOWNGRADE(&ipf_tokens); + + return it; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_unlinktoken */ +/* Returns: None. */ +/* Parameters: token(I) - pointer to token structure */ +/* */ +/* This function unlinks a token structure from the linked list of tokens */ +/* that "own" it. The head pointer never needs to be explicitly adjusted */ +/* but the tail does due to the linked list implementation. */ +/* ------------------------------------------------------------------------ */ +static void ipf_unlinktoken(token) +ipftoken_t *token; +{ + + if (ipftokentail == &token->ipt_next) + ipftokentail = token->ipt_pnext; + + *token->ipt_pnext = token->ipt_next; + if (token->ipt_next != NULL) + token->ipt_next->ipt_pnext = token->ipt_pnext; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_freetoken */ +/* Returns: None. */ +/* Parameters: token(I) - pointer to token structure */ +/* */ +/* This function unlinks a token from the linked list and on the path to */ +/* free'ing the data, it calls the dereference function that is associated */ +/* with the type of data pointed to by the token as it is considered to */ +/* hold a reference to it. */ +/* ------------------------------------------------------------------------ */ +void ipf_freetoken(token) +ipftoken_t *token; +{ + void *data, **datap; + + ipf_unlinktoken(token); + + data = token->ipt_data; + datap = &data; + + if ((data != NULL) && (data != (void *)-1)) { + switch (token->ipt_type) + { + case IPFGENITER_IPF : + (void) fr_derefrule((frentry_t **)datap); + break; + case IPFGENITER_IPNAT : + WRITE_ENTER(&ipf_nat); + fr_ipnatderef((ipnat_t **)datap); + RWLOCK_EXIT(&ipf_nat); + break; + case IPFGENITER_NAT : + fr_natderef((nat_t **)datap); + break; + case IPFGENITER_STATE : + fr_statederef((ipstate_t **)datap); + break; + case IPFGENITER_FRAG : +#ifdef USE_MUTEXES + fr_fragderef((ipfr_t **)datap, &ipf_frag); +#else + fr_fragderef((ipfr_t **)datap); +#endif + break; + case IPFGENITER_NATFRAG : +#ifdef USE_MUTEXES + fr_fragderef((ipfr_t **)datap, &ipf_natfrag); +#else + fr_fragderef((ipfr_t **)datap); +#endif + break; + case IPFGENITER_HOSTMAP : + fr_hostmapdel((hostmap_t **)datap); + break; + default : +#ifdef IPFILTER_LOOKUP + ip_lookup_iterderef(token->ipt_type, data); +#endif + break; + } + } + + KFREE(token); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_getnextrule */ +/* Returns: int - 0 = success, else error */ +/* Parameters: t(I) - pointer to destination information to resolve */ +/* ptr(I) - pointer to ipfobj_t to copyin from user space */ +/* */ +/* This function's first job is to bring in the ipfruleiter_t structure via */ +/* the ipfobj_t structure to determine what should be the next rule to */ +/* return. Once the ipfruleiter_t has been brought in, it then tries to */ +/* find the 'next rule'. This may include searching rule group lists or */ +/* just be as simple as looking at the 'next' field in the rule structure. */ +/* When we have found the rule to return, increase its reference count and */ +/* if we used an existing rule to get here, decrease its reference count. */ +/* ------------------------------------------------------------------------ */ +int ipf_getnextrule(ipftoken_t *t, void *ptr) +{ + frentry_t *fr, *next, zero; + int error, count, out; + ipfruleiter_t it; + frgroup_t *fg; + char *dst; + + if (t == NULL || ptr == NULL) + return EFAULT; + error = fr_inobj(ptr, &it, IPFOBJ_IPFITER); + if (error != 0) + return error; + if ((it.iri_inout < 0) || (it.iri_inout > 3)) + return EINVAL; + if ((it.iri_active != 0) && (it.iri_active != 1)) + return EINVAL; + if (it.iri_nrules == 0) + return ENOSPC; + if (it.iri_rule == NULL) + return EFAULT; + + out = it.iri_inout & F_OUT; + fr = t->ipt_data; + READ_ENTER(&ipf_mutex); + if (fr == NULL) { + if (*it.iri_group == '\0') { + if ((it.iri_inout & F_ACIN) != 0) { + if (it.iri_v == 4) + next = ipacct[out][it.iri_active]; + else + next = ipacct6[out][it.iri_active]; + } else { + if (it.iri_v == 4) + next = ipfilter[out][it.iri_active]; + else + next = ipfilter6[out][it.iri_active]; + } + } else { + fg = fr_findgroup(it.iri_group, IPL_LOGIPF, + it.iri_active, NULL); + if (fg != NULL) + next = fg->fg_start; + else + next = NULL; + } + } else { + next = fr->fr_next; + } + + dst = (char *)it.iri_rule; + /* + * The ipfruleiter may ask for more than 1 rule at a time to be + * copied out, so long as that many exist in the list to start with! + */ + for (count = it.iri_nrules; count > 0; count--) { + if (next != NULL) { + MUTEX_ENTER(&next->fr_lock); + next->fr_ref++; + MUTEX_EXIT(&next->fr_lock); + t->ipt_data = next; + } else { + bzero(&zero, sizeof(zero)); + next = &zero; + ipf_freetoken(t); + fr = NULL; + t = NULL; + count = 1; + } + RWLOCK_EXIT(&ipf_mutex); + + if (fr != NULL) { + (void) fr_derefrule(&fr); + } + + error = COPYOUT(next, dst, sizeof(*next)); + if (error != 0) + return EFAULT; + + if (next->fr_data != NULL) { + dst += sizeof(*next); + error = COPYOUT(next->fr_data, dst, next->fr_dsize); + if (error != 0) + error = EFAULT; + else + dst += next->fr_dsize; + } + + if ((count == 1) || (next->fr_next == NULL) || (error != 0)) + break; + + READ_ENTER(&ipf_mutex); + fr = next; + next = fr->fr_next; + } + + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_frruleiter */ +/* Returns: int - 0 = success, else error */ +/* Parameters: data(I) - the token type to match */ +/* uid(I) - uid owning the token */ +/* ptr(I) - context pointer for the token */ +/* */ +/* This function serves as a stepping stone between fr_ipf_ioctl and */ +/* ipf_getnextrule. It's role is to find the right token in the kernel for */ +/* the process doing the ioctl and use that to ask for the next rule. */ +/* ------------------------------------------------------------------------ */ +static int ipf_frruleiter(data, uid, ctx) +void *data, *ctx; +int uid; +{ + ipftoken_t *token; + int error; + + token = ipf_findtoken(IPFGENITER_IPF, uid, ctx); + if (token != NULL) + error = ipf_getnextrule(token, data); + else + error = EFAULT; + RWLOCK_EXIT(&ipf_tokens); + + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_geniter */ +/* Returns: int - 0 = success, else error */ +/* Parameters: token(I) - pointer to ipftoken_t structure */ +/* itp(I) - */ +/* */ +/* ------------------------------------------------------------------------ */ +static int ipf_geniter(token, itp) +ipftoken_t *token; +ipfgeniter_t *itp; +{ + int error; + + switch (itp->igi_type) + { + case IPFGENITER_FRAG : +#ifdef USE_MUTEXES + error = fr_nextfrag(token, itp, + &ipfr_list, &ipfr_tail, &ipf_frag); +#else + error = fr_nextfrag(token, itp, &ipfr_list, &ipfr_tail); +#endif + break; + default : + error = EINVAL; + break; + } + + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_genericiter */ +/* Returns: int - 0 = success, else error */ +/* Parameters: data(I) - the token type to match */ +/* uid(I) - uid owning the token */ +/* ptr(I) - context pointer for the token */ +/* */ +/* ------------------------------------------------------------------------ */ +int ipf_genericiter(data, uid, ctx) +void *data, *ctx; +int uid; +{ + ipftoken_t *token; + ipfgeniter_t iter; + int error; + + error = fr_inobj(data, &iter, IPFOBJ_GENITER); + if (error != 0) + return error; + + token = ipf_findtoken(iter.igi_type, uid, ctx); + if (token != NULL) { + token->ipt_subtype = iter.igi_type; + error = ipf_geniter(token, &iter); + } else + error = EFAULT; + RWLOCK_EXIT(&ipf_tokens); + + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_ipf_ioctl */ +/* Returns: int - 0 = success, else error */ +/* Parameters: data(I) - the token type to match */ +/* cmd(I) - the ioctl command number */ +/* mode(I) - mode flags for the ioctl */ +/* uid(I) - uid owning the token */ +/* ptr(I) - context pointer for the token */ +/* */ +/* This function handles all of the ioctl command that are actually isssued */ +/* to the /dev/ipl device. */ +/* ------------------------------------------------------------------------ */ +int fr_ipf_ioctl(data, cmd, mode, uid, ctx) +caddr_t data; +ioctlcmd_t cmd; +int mode, uid; +void *ctx; +{ + friostat_t fio; + int error, tmp; + SPL_INT(s); + + switch (cmd) + { + case SIOCFRENB : + if (!(mode & FWRITE)) + error = EPERM; + else { + error = BCOPYIN((caddr_t)data, (caddr_t)&tmp, + sizeof(tmp)); + if (error != 0) { + error = EFAULT; + break; + } + + RWLOCK_EXIT(&ipf_global); + WRITE_ENTER(&ipf_global); + if (tmp) { + if (fr_running > 0) + error = 0; + else + error = ipfattach(); + if (error == 0) + fr_running = 1; + else + (void) ipfdetach(); + } else { + error = ipfdetach(); + if (error == 0) + fr_running = -1; + } + } + break; + + case SIOCIPFSET : + if (!(mode & FWRITE)) { + error = EPERM; + break; + } + /* FALLTHRU */ + case SIOCIPFGETNEXT : + case SIOCIPFGET : + error = fr_ipftune(cmd, (void *)data); + break; + + case SIOCSETFF : + if (!(mode & FWRITE)) + error = EPERM; + else { + error = BCOPYIN((caddr_t)data, (caddr_t)&fr_flags, + sizeof(fr_flags)); + if (error != 0) + error = EFAULT; + } + break; + + case SIOCGETFF : + error = BCOPYOUT((caddr_t)&fr_flags, (caddr_t)data, + sizeof(fr_flags)); + if (error != 0) + error = EFAULT; + break; + + case SIOCFUNCL : + error = fr_resolvefunc((void *)data); + break; + + case SIOCINAFR : + case SIOCRMAFR : + case SIOCADAFR : + case SIOCZRLST : + if (!(mode & FWRITE)) + error = EPERM; + else + error = frrequest(IPL_LOGIPF, cmd, (caddr_t)data, + fr_active, 1); + break; + + case SIOCINIFR : + case SIOCRMIFR : + case SIOCADIFR : + if (!(mode & FWRITE)) + error = EPERM; + else + error = frrequest(IPL_LOGIPF, cmd, (caddr_t)data, + 1 - fr_active, 1); + break; + + case SIOCSWAPA : + if (!(mode & FWRITE)) + error = EPERM; + else { + WRITE_ENTER(&ipf_mutex); + bzero((char *)frcache, sizeof(frcache[0]) * 2); + error = BCOPYOUT((caddr_t)&fr_active, (caddr_t)data, + sizeof(fr_active)); + if (error != 0) + error = EFAULT; + else + fr_active = 1 - fr_active; + RWLOCK_EXIT(&ipf_mutex); + } + break; + + case SIOCGETFS : + fr_getstat(&fio); + error = fr_outobj((void *)data, &fio, IPFOBJ_IPFSTAT); + break; + + case SIOCFRZST : + if (!(mode & FWRITE)) + error = EPERM; + else + error = fr_zerostats((caddr_t)data); + break; + + case SIOCIPFFL : + if (!(mode & FWRITE)) + error = EPERM; + else { + error = BCOPYIN((caddr_t)data, (caddr_t)&tmp, + sizeof(tmp)); + if (!error) { + tmp = frflush(IPL_LOGIPF, 4, tmp); + error = BCOPYOUT((caddr_t)&tmp, (caddr_t)data, + sizeof(tmp)); + if (error != 0) + error = EFAULT; + } else + error = EFAULT; + } + break; + +#ifdef USE_INET6 + case SIOCIPFL6 : + if (!(mode & FWRITE)) + error = EPERM; + else { + error = BCOPYIN((caddr_t)data, (caddr_t)&tmp, + sizeof(tmp)); + if (!error) { + tmp = frflush(IPL_LOGIPF, 6, tmp); + error = BCOPYOUT((caddr_t)&tmp, (caddr_t)data, + sizeof(tmp)); + if (error != 0) + error = EFAULT; + } else + error = EFAULT; + } + break; +#endif + + case SIOCSTLCK : + error = BCOPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); + if (error == 0) { + fr_state_lock = tmp; + fr_nat_lock = tmp; + fr_frag_lock = tmp; + fr_auth_lock = tmp; + } else + error = EFAULT; + break; + +#ifdef IPFILTER_LOG + case SIOCIPFFB : + if (!(mode & FWRITE)) + error = EPERM; + else { + tmp = ipflog_clear(IPL_LOGIPF); + error = BCOPYOUT((caddr_t)&tmp, (caddr_t)data, + sizeof(tmp)); + if (error) + error = EFAULT; + } + break; +#endif /* IPFILTER_LOG */ + + case SIOCFRSYN : + if (!(mode & FWRITE)) + error = EPERM; + else { + RWLOCK_EXIT(&ipf_global); + WRITE_ENTER(&ipf_global); +#ifdef MENTAT + error = ipfsync(); +#else + frsync(NULL); + error = 0; +#endif + + } + break; + + case SIOCGFRST : + error = fr_outobj((void *)data, fr_fragstats(), + IPFOBJ_FRAGSTAT); + break; + +#ifdef IPFILTER_LOG + case FIONREAD : + tmp = (int)iplused[IPL_LOGIPF]; + + error = BCOPYOUT((caddr_t)&tmp, (caddr_t)data, sizeof(tmp)); + break; +#endif + + case SIOCIPFITER : + SPL_SCHED(s); + error = ipf_frruleiter(data, uid, ctx); + SPL_X(s); + break; + + case SIOCGENITER : + SPL_SCHED(s); + error = ipf_genericiter(data, uid, ctx); + SPL_X(s); + break; + break; + + case SIOCIPFDELTOK : + SPL_SCHED(s); + error = BCOPYIN((caddr_t)data, (caddr_t)&tmp, sizeof(tmp)); + if (error == 0) + error = ipf_deltoken(tmp, uid, ctx); + SPL_X(s); + break; + break; + + default : + error = EINVAL; + break; + } + + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ipf_queueflush */ +/* Returns: int - number of entries flushed (0 = none) */ +/* Parameters: deletefn(I) - function to call to delete entry */ +/* ipfqs(I) - top of the list of ipf internal queues */ +/* userqs(I) - top of the list of user defined timeouts */ +/* */ +/* This fucntion gets called when the state/NAT hash tables fill up and we */ +/* need to try a bit harder to free up some space. The algorithm used is */ +/* to look for the oldest entries on each timeout queue and free them if */ +/* they are within the given window we are considering. Where the window */ +/* starts and the steps taken to increase its size depend upon how long ipf */ +/* has been running (fr_ticks.) Anything modified in the last 30 seconds */ +/* is not touched. */ +/* touched */ +/* die fr_ticks 30*1.5 1800*1.5 | 43200*1.5 */ +/* | | | | | | */ +/* future <--+----------+--------+-----------+-----+-----+-----------> past */ +/* now \_int=30s_/ \_int=1hr_/ \_int=12hr */ +/* */ +/* Points to note: */ +/* - tqe_die is the time, in the future, when entries die. */ +/* - tqe_die - fr_ticks is how long left the connection has to live in ipf */ +/* ticks. */ +/* - tqe_touched is when the entry was last used by NAT/state */ +/* - the closer tqe_touched is to fr_ticks, the further tqe_die will be for */ +/* any given timeout queue and vice versa. */ +/* - both tqe_die and tqe_touched increase over time */ +/* - timeout queues are sorted with the highest value of tqe_die at the */ +/* bottom and therefore the smallest values of each are at the top */ +/* */ +/* We start by setting up a maximum range to scan for things to move of */ +/* iend (newest) to istart (oldest) in chunks of "interval". If nothing is */ +/* found in that range, "interval" is adjusted (so long as it isn't 30) and */ +/* we start again with a new value for "iend" and "istart". The downside */ +/* of the current implementation is that it may return removing just 1 entry*/ +/* every time (pathological case) where it could remove more. */ +/* ------------------------------------------------------------------------ */ +int ipf_queueflush(deletefn, ipfqs, userqs) +ipftq_delete_fn_t deletefn; +ipftq_t *ipfqs, *userqs; +{ + u_long interval, istart, iend; + ipftq_t *ifq, *ifqnext; + ipftqent_t *tqe, *tqn; + int removed; + + /* + * NOTE: Use of "* 15 / 10" is required here because if "* 1.5" is + * used then the operations are upgraded to floating point + * and kernels don't like floating point... + */ + if (fr_ticks > IPF_TTLVAL(43200 * 15 / 10)) { + istart = IPF_TTLVAL(86400 * 4); + interval = IPF_TTLVAL(43200); + } else if (fr_ticks > IPF_TTLVAL(1800 * 15 / 10)) { + istart = IPF_TTLVAL(43200); + interval = IPF_TTLVAL(1800); + } else if (fr_ticks > IPF_TTLVAL(30 * 15 / 10)) { + istart = IPF_TTLVAL(1800); + interval = IPF_TTLVAL(30); + } else { + return 0; + } + if (istart > fr_ticks) { + istart = (fr_ticks / interval) * interval; + } + + iend = fr_ticks - interval; + if (istart > iend) + istart = iend - interval; + removed = 0; + + while (removed == 0) { + u_long try; + + try = fr_ticks - istart; + + for (ifq = ipfqs; ifq != NULL; ifq = ifq->ifq_next) { + for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { + if (try < tqe->tqe_touched) + break; + tqn = tqe->tqe_next; + if ((*deletefn)(tqe->tqe_parent) == 0) + removed++; + } + } + + for (ifq = userqs; ifq != NULL; ifq = ifqnext) { + ifqnext = ifq->ifq_next; + + for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { + if (try < tqe->tqe_touched) + break; + tqn = tqe->tqe_next; + if ((*deletefn)(tqe->tqe_parent) == 0) + removed++; + } + } + + istart -= interval; + if (try >= iend) { + if (interval == IPF_TTLVAL(43200)) { + interval = IPF_TTLVAL(1800); + } else if (interval == IPF_TTLVAL(1800)) { + interval = IPF_TTLVAL(30); + } else { + break; + } + if (interval >= fr_ticks) + break; + + iend = fr_ticks - interval; + } + } + + return removed; +} diff --git a/sys/contrib/ipfilter/netinet/ip_auth.c b/sys/contrib/ipfilter/netinet/ip_auth.c index 0f0c2ff..50d6b95 100644 --- a/sys/contrib/ipfilter/netinet/ip_auth.c +++ b/sys/contrib/ipfilter/netinet/ip_auth.c @@ -117,7 +117,7 @@ extern struct ifqueue ipintrq; /* ip packet input queue */ /* END OF INCLUDES */ #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.73.2.13 2006/03/29 11:19:55 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_auth.c,v 2.73.2.20 2007/05/29 13:48:54 darrenr Exp $"; #endif @@ -142,7 +142,19 @@ frauthent_t *fae_list = NULL; frentry_t *ipauth = NULL, *fr_authlist = NULL; +void fr_authderef __P((frauthent_t **)); +int fr_authgeniter __P((ipftoken_t *, ipfgeniter_t *)); +int fr_authreply __P((char *)); +int fr_authwait __P((char *)); +/* ------------------------------------------------------------------------ */ +/* Function: fr_authinit */ +/* Returns: int - 0 == success, else error */ +/* Parameters: None */ +/* */ +/* Allocate memory and initialise data structures used in handling auth */ +/* rules. */ +/* ------------------------------------------------------------------------ */ int fr_authinit() { KMALLOCS(fr_auth, frauth_t *, fr_authsize * sizeof(*fr_auth)); @@ -172,11 +184,16 @@ int fr_authinit() } -/* - * Check if a packet has authorization. If the packet is found to match an - * authorization result and that would result in a feedback loop (i.e. it - * will end up returning FR_AUTH) then return FR_BLOCK instead. - */ +/* ------------------------------------------------------------------------ */ +/* Function: fr_checkauth */ +/* Returns: frentry_t* - pointer to ipf rule if match found, else NULL */ +/* Parameters: fin(I) - pointer to ipftoken structure */ +/* passp(I) - pointer to ipfgeniter structure */ +/* */ +/* Check if a packet has authorization. If the packet is found to match an */ +/* authorization result and that would result in a feedback loop (i.e. it */ +/* will end up returning FR_AUTH) then return FR_BLOCK instead. */ +/* ------------------------------------------------------------------------ */ frentry_t *fr_checkauth(fin, passp) fr_info_t *fin; u_32_t *passp; @@ -233,7 +250,12 @@ u_32_t *passp; fr = fra->fra_info.fin_fr; fin->fin_fr = fr; RWLOCK_EXIT(&ipf_auth); + WRITE_ENTER(&ipf_auth); + /* + * fr_authlist is populated with the rules malloc'd + * above and only those. + */ if ((fr != NULL) && (fr != fra->fra_info.fin_fr)) { fr->fr_next = fr_authlist; fr_authlist = fr; @@ -275,11 +297,16 @@ u_32_t *passp; } -/* - * Check if we have room in the auth array to hold details for another packet. - * If we do, store it and wake up any user programs which are waiting to - * hear about these events. - */ +/* ------------------------------------------------------------------------ */ +/* Function: fr_newauth */ +/* Returns: int - 0 == success, else error */ +/* Parameters: m(I) - pointer to mb_t with packet in it */ +/* fin(I) - pointer to packet information */ +/* */ +/* Check if we have room in the auth array to hold details for another */ +/* packet. If we do, store it and wake up any user programs which are */ +/* waiting to hear about these events. */ +/* ------------------------------------------------------------------------ */ int fr_newauth(m, fin) mb_t *m; fr_info_t *fin; @@ -318,7 +345,10 @@ fr_info_t *fin; fra = fr_auth + i; fra->fra_index = i; - fra->fra_pass = fin->fin_fr->fr_flags; + if (fin->fin_fr != NULL) + fra->fra_pass = fin->fin_fr->fr_flags; + else + fra->fra_pass = 0; fra->fra_age = fr_defaultauthage; bcopy((char *)fin, (char *)&fra->fra_info, sizeof(*fin)); #if !defined(sparc) && !defined(m68k) @@ -356,23 +386,59 @@ fr_info_t *fin; } -int fr_auth_ioctl(data, cmd, mode) +/* ------------------------------------------------------------------------ */ +/* Function: fr_auth_ioctl */ +/* Returns: int - 0 == success, else error */ +/* Parameters: data(IO) - pointer to ioctl data */ +/* cmd(I) - ioctl command */ +/* mode(I) - mode flags associated with open descriptor */ +/* uid(I) - uid associatd with application making the call */ +/* ctx(I) - pointer for context */ +/* */ +/* This function handles all of the ioctls recognised by the auth component */ +/* in IPFilter - ie ioctls called on an open fd for /dev/ipauth */ +/* ------------------------------------------------------------------------ */ +int fr_auth_ioctl(data, cmd, mode, uid, ctx) caddr_t data; ioctlcmd_t cmd; -int mode; +int mode, uid; +void *ctx; { - frauth_t auth, *au = &auth, *fra; - int i, error = 0, len; - char *t; - mb_t *m; -#if defined(_KERNEL) && !defined(MENTAT) && !defined(linux) && \ - (!defined(__FreeBSD_version) || (__FreeBSD_version < 501000)) - struct ifqueue *ifq; + int error = 0, i; SPL_INT(s); -#endif switch (cmd) { + case SIOCGENITER : + { + ipftoken_t *token; + ipfgeniter_t iter; + + error = fr_inobj(data, &iter, IPFOBJ_GENITER); + if (error != 0) + break; + + SPL_SCHED(s); + token = ipf_findtoken(IPFGENITER_AUTH, uid, ctx); + if (token != NULL) + error = fr_authgeniter(token, &iter); + else + error = ESRCH; + RWLOCK_EXIT(&ipf_tokens); + SPL_X(s); + + break; + } + + case SIOCADAFR : + case SIOCRMAFR : + if (!(mode & FWRITE)) + error = EPERM; + else + error = frrequest(IPL_LOGAUTH, cmd, data, + fr_active, 1); + break; + case SIOCSTLCK : if (!(mode & FWRITE)) { error = EPERM; @@ -392,202 +458,17 @@ int mode; i = fr_authflush(); RWLOCK_EXIT(&ipf_auth); SPL_X(s); - error = copyoutptr((char *)&i, data, sizeof(i)); + error = BCOPYOUT((char *)&i, data, sizeof(i)); + if (error != 0) + error = EFAULT; break; case SIOCAUTHW: -fr_authioctlloop: - error = fr_inobj(data, au, IPFOBJ_FRAUTH); - if (error != 0) - break; - READ_ENTER(&ipf_auth); - if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) { - error = fr_outobj(data, &fr_auth[fr_authnext], - IPFOBJ_FRAUTH); - if (error != 0) - break; - if (auth.fra_len != 0 && auth.fra_buf != NULL) { - /* - * Copy packet contents out to user space if - * requested. Bail on an error. - */ - m = fr_authpkts[fr_authnext]; - len = MSGDSIZE(m); - if (len > auth.fra_len) - len = auth.fra_len; - auth.fra_len = len; - for (t = auth.fra_buf; m && (len > 0); ) { - i = MIN(M_LEN(m), len); - error = copyoutptr(MTOD(m, char *), - &t, i); - len -= i; - t += i; - if (error != 0) - break; - m = m->m_next; - } - } - RWLOCK_EXIT(&ipf_auth); - if (error != 0) - break; - SPL_NET(s); - WRITE_ENTER(&ipf_auth); - fr_authnext++; - if (fr_authnext == fr_authsize) - fr_authnext = 0; - RWLOCK_EXIT(&ipf_auth); - SPL_X(s); - return 0; - } - RWLOCK_EXIT(&ipf_auth); - /* - * We exit ipf_global here because a program that enters in - * here will have a lock on it and goto sleep having this lock. - * If someone were to do an 'ipf -D' the system would then - * deadlock. The catch with releasing it here is that the - * caller of this function expects it to be held when we - * return so we have to reacquire it in here. - */ - RWLOCK_EXIT(&ipf_global); - - MUTEX_ENTER(&ipf_authmx); -#ifdef _KERNEL -# if SOLARIS - error = 0; - if (!cv_wait_sig(&ipfauthwait, &ipf_authmx.ipf_lk)) - error = EINTR; -# else /* SOLARIS */ -# ifdef __hpux - { - lock_t *l; - - l = get_sleep_lock(&fr_authnext); - error = sleep(&fr_authnext, PZERO+1); - spinunlock(l); - } -# else -# ifdef __osf__ - error = mpsleep(&fr_authnext, PSUSP|PCATCH, "fr_authnext", 0, - &ipf_authmx, MS_LOCK_SIMPLE); -# else - error = SLEEP(&fr_authnext, "fr_authnext"); -# endif /* __osf__ */ -# endif /* __hpux */ -# endif /* SOLARIS */ -#endif - MUTEX_EXIT(&ipf_authmx); - READ_ENTER(&ipf_global); - if (error == 0) - goto fr_authioctlloop; + error = fr_authwait(data); break; case SIOCAUTHR: - error = fr_inobj(data, &auth, IPFOBJ_FRAUTH); - if (error != 0) - return error; - SPL_NET(s); - WRITE_ENTER(&ipf_auth); - i = au->fra_index; - fra = fr_auth + i; - error = 0; - if ((i < 0) || (i >= fr_authsize) || - (fra->fra_info.fin_id != au->fra_info.fin_id)) { - RWLOCK_EXIT(&ipf_auth); - SPL_X(s); - return ESRCH; - } - m = fr_authpkts[i]; - fra->fra_index = -2; - fra->fra_pass = au->fra_pass; - fr_authpkts[i] = NULL; - RWLOCK_EXIT(&ipf_auth); -#ifdef _KERNEL - if ((m != NULL) && (au->fra_info.fin_out != 0)) { -# ifdef MENTAT - error = ipf_inject(&fra->fra_info); - if (error != 0) { - FREE_MB_T(m); - error = ENOBUFS; - } -# else /* MENTAT */ -# if defined(linux) || defined(AIX) -# else -# if (_BSDI_VERSION >= 199802) || defined(__OpenBSD__) || \ - (defined(__sgi) && (IRIX >= 60500) || defined(AIX) || \ - (defined(__FreeBSD__) && (__FreeBSD_version >= 470102))) - error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, - NULL); -# else - error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL); -# endif -# endif /* Linux */ -# endif /* MENTAT */ - if (error != 0) - fr_authstats.fas_sendfail++; - else - fr_authstats.fas_sendok++; - } else if (m) { -# ifdef MENTAT - error = ipf_inject(&fra->fra_info); - if (error != 0) { - FREE_MB_T(m); - error = ENOBUFS; - } -# else /* MENTAT */ -# if defined(linux) || defined(AIX) -# else -# if (__FreeBSD_version >= 501000) - netisr_dispatch(NETISR_IP, m); -# else -# if (IRIX >= 60516) - ifq = &((struct ifnet *)fra->fra_info.fin_ifp)->if_snd; -# else - ifq = &ipintrq; -# endif - if (IF_QFULL(ifq)) { - IF_DROP(ifq); - FREE_MB_T(m); - error = ENOBUFS; - } else { - IF_ENQUEUE(ifq, m); -# if IRIX < 60500 - schednetisr(NETISR_IP); -# endif - } -# endif -# endif /* Linux */ -# endif /* MENTAT */ - if (error != 0) - fr_authstats.fas_quefail++; - else - fr_authstats.fas_queok++; - } else - error = EINVAL; - /* - * If we experience an error which will result in the packet - * not being processed, make sure we advance to the next one. - */ - if (error == ENOBUFS) { - fr_authused--; - fra->fra_index = -1; - fra->fra_pass = 0; - if (i == fr_authstart) { - while (fra->fra_index == -1) { - i++; - if (i == fr_authsize) - i = 0; - fr_authstart = i; - if (i == fr_authend) - break; - } - if (fr_authstart == fr_authend) { - fr_authnext = 0; - fr_authstart = fr_authend = 0; - } - } - } -#endif /* _KERNEL */ - SPL_X(s); + error = fr_authreply(data); break; default : @@ -598,9 +479,13 @@ fr_authioctlloop: } -/* - * Free all network buffer memory used to keep saved packets. - */ +/* ------------------------------------------------------------------------ */ +/* Function: fr_authunload */ +/* Returns: None */ +/* Parameters: None */ +/* */ +/* Free all network buffer memory used to keep saved packets. */ +/* ------------------------------------------------------------------------ */ void fr_authunload() { register int i; @@ -654,17 +539,21 @@ void fr_authunload() } -/* - * Slowly expire held auth records. Timeouts are set - * in expectation of this being called twice per second. - */ +/* ------------------------------------------------------------------------ */ +/* Function: fr_authexpire */ +/* Returns: None */ +/* Parameters: None */ +/* */ +/* Slowly expire held auth records. Timeouts are set in expectation of */ +/* this being called twice per second. */ +/* ------------------------------------------------------------------------ */ void fr_authexpire() { - register int i; - register frauth_t *fra; - register frauthent_t *fae, **faep; - register frentry_t *fr, **frp; + frauthent_t *fae, **faep; + frentry_t *fr, **frp; + frauth_t *fra; mb_t *m; + int i; SPL_INT(s); if (fr_auth_lock) @@ -683,11 +572,13 @@ void fr_authexpire() } } + /* + * Expire pre-auth rules + */ for (faep = &fae_list; ((fae = *faep) != NULL); ) { fae->fae_age--; if (fae->fae_age == 0) { - *faep = fae->fae_next; - KFREE(fae); + fr_authderef(&fae); fr_authstats.fas_expire++; } else faep = &fae->fae_next; @@ -708,6 +599,15 @@ void fr_authexpire() SPL_X(s); } + +/* ------------------------------------------------------------------------ */ +/* Function: fr_preauthcmd */ +/* Returns: int - 0 == success, else error */ +/* Parameters: cmd(I) - ioctl command for rule */ +/* fr(I) - pointer to ipf rule */ +/* fptr(I) - pointer to caller's 'fr' */ +/* */ +/* ------------------------------------------------------------------------ */ int fr_preauthcmd(cmd, fr, frptr) ioctlcmd_t cmd; frentry_t *fr, **frptr; @@ -718,7 +618,7 @@ frentry_t *fr, **frptr; if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR)) return EIO; - + for (faep = &fae_list; ((fae = *faep) != NULL); ) { if (&fae->fae_fr == fr) break; @@ -752,6 +652,7 @@ frentry_t *fr, **frptr; fae->fae_age = fr_defaultauthage; fae->fae_fr.fr_hits = 0; fae->fae_fr.fr_next = *frptr; + fae->fae_ref = 1; *frptr = &fae->fae_fr; fae->fae_next = *faep; *faep = fae; @@ -766,11 +667,18 @@ frentry_t *fr, **frptr; } -/* - * Flush held packets. - * Must already be properly SPL'ed and Locked on &ipf_auth. - * - */ +/* ------------------------------------------------------------------------ */ +/* Function: fr_authflush */ +/* Returns: int - number of auth entries flushed */ +/* Parameters: None */ +/* Locks: WRITE(ipf_auth) */ +/* */ +/* This function flushs the fr_authpkts array of any packet data with */ +/* references still there. */ +/* It is expected that the caller has already acquired the correct locks or */ +/* set the priority level correctly for this to block out other code paths */ +/* into these data structures. */ +/* ------------------------------------------------------------------------ */ int fr_authflush() { register int i, num_flushed; @@ -802,7 +710,339 @@ int fr_authflush() } +/* ------------------------------------------------------------------------ */ +/* Function: fr_auth_waiting */ +/* Returns: int - number of packets in the auth queue */ +/* Parameters: None */ +/* */ +/* Returns the numbers of packets queued up, waiting to be processed with */ +/* a pair of SIOCAUTHW and SIOCAUTHR calls. */ +/* ------------------------------------------------------------------------ */ int fr_auth_waiting() { return (fr_authnext != fr_authend) && fr_authpkts[fr_authnext]; } + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_authgeniter */ +/* Returns: int - 0 == success, else error */ +/* Parameters: token(I) - pointer to ipftoken structure */ +/* itp(I) - pointer to ipfgeniter structure */ +/* */ +/* ------------------------------------------------------------------------ */ +int fr_authgeniter(token, itp) +ipftoken_t *token; +ipfgeniter_t *itp; +{ + frauthent_t *fae, *next, zero; + int error; + + if (itp->igi_data == NULL) + return EFAULT; + + if (itp->igi_type != IPFGENITER_AUTH) + return EINVAL; + + fae = token->ipt_data; + READ_ENTER(&ipf_auth); + if (fae == NULL) { + next = fae_list; + } else { + next = fae->fae_next; + } + + if (next != NULL) { + /* + * If we find an auth entry to use, bump its reference count + * so that it can be used for is_next when we come back. + */ + ATOMIC_INC(next->fae_ref); + if (next->fae_next == NULL) { + ipf_freetoken(token); + token = NULL; + } else { + token->ipt_data = next; + } + } else { + bzero(&zero, sizeof(zero)); + next = &zero; + } + RWLOCK_EXIT(&ipf_auth); + + /* + * If we had a prior pointer to an auth entry, release it. + */ + if (fae != NULL) { + WRITE_ENTER(&ipf_auth); + fr_authderef(&fae); + RWLOCK_EXIT(&ipf_auth); + } + + /* + * This should arguably be via fr_outobj() so that the auth + * structure can (if required) be massaged going out. + */ + error = COPYOUT(next, itp->igi_data, sizeof(*next)); + if (error != 0) + error = EFAULT; + + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_authderef */ +/* Returns: None */ +/* Parameters: faep(IO) - pointer to caller's frauthent_t pointer */ +/* Locks: WRITE(ipf_auth) */ +/* */ +/* This function unconditionally sets the pointer in the caller to NULL, */ +/* to make it clear that it should no longer use that pointer, and drops */ +/* the reference count on the structure by 1. If it reaches 0, free it up. */ +/* ------------------------------------------------------------------------ */ +void fr_authderef(faep) +frauthent_t **faep; +{ + frauthent_t *fae; + + fae = *faep; + *faep = NULL; + + fae->fae_ref--; + if (fae->fae_ref == 0) { + KFREE(fae); + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_authwait */ +/* Returns: int - 0 == success, else error */ +/* Parameters: data(I) - pointer to data from ioctl call */ +/* */ +/* This function is called when an application is waiting for a packet to */ +/* match an "auth" rule by issuing an SIOCAUTHW ioctl. If there is already */ +/* a packet waiting on the queue then we will return that _one_ immediately.*/ +/* If there are no packets present in the queue (fr_authpkts) then we go to */ +/* sleep. */ +/* ------------------------------------------------------------------------ */ +int fr_authwait(data) +char *data; +{ + frauth_t auth, *au = &auth; + int error, len, i; + mb_t *m; + char *t; +#if defined(_KERNEL) && !defined(MENTAT) && !defined(linux) && \ + (!defined(__FreeBSD_version) || (__FreeBSD_version < 501000)) + SPL_INT(s); +#endif + +fr_authioctlloop: + error = fr_inobj(data, au, IPFOBJ_FRAUTH); + if (error != 0) + return error; + + /* + * XXX Locks are held below over calls to copyout...a better + * solution needs to be found so this isn't necessary. The situation + * we are trying to guard against here is an error in the copyout + * steps should not cause the packet to "disappear" from the queue. + */ + READ_ENTER(&ipf_auth); + + /* + * If fr_authnext is not equal to fr_authend it will be because there + * is a packet waiting to be delt with in the fr_authpkts array. We + * copy as much of that out to user space as requested. + */ + if ((fr_authnext != fr_authend) && fr_authpkts[fr_authnext]) { + error = fr_outobj(data, &fr_auth[fr_authnext], IPFOBJ_FRAUTH); + if (error != 0) + return error; + + if (auth.fra_len != 0 && auth.fra_buf != NULL) { + /* + * Copy packet contents out to user space if + * requested. Bail on an error. + */ + m = fr_authpkts[fr_authnext]; + len = MSGDSIZE(m); + if (len > auth.fra_len) + len = auth.fra_len; + auth.fra_len = len; + + for (t = auth.fra_buf; m && (len > 0); ) { + i = MIN(M_LEN(m), len); + error = copyoutptr(MTOD(m, char *), &t, i); + len -= i; + t += i; + if (error != 0) + return error; + m = m->m_next; + } + } + RWLOCK_EXIT(&ipf_auth); + if (error != 0) + return error; + + SPL_NET(s); + WRITE_ENTER(&ipf_auth); + fr_authnext++; + if (fr_authnext == fr_authsize) + fr_authnext = 0; + RWLOCK_EXIT(&ipf_auth); + SPL_X(s); + + return 0; + } + RWLOCK_EXIT(&ipf_auth); + + /* + * We exit ipf_global here because a program that enters in + * here will have a lock on it and goto sleep having this lock. + * If someone were to do an 'ipf -D' the system would then + * deadlock. The catch with releasing it here is that the + * caller of this function expects it to be held when we + * return so we have to reacquire it in here. + */ + RWLOCK_EXIT(&ipf_global); + + MUTEX_ENTER(&ipf_authmx); +#ifdef _KERNEL +# if SOLARIS + error = 0; + if (!cv_wait_sig(&ipfauthwait, &ipf_authmx.ipf_lk)) + error = EINTR; +# else /* SOLARIS */ +# ifdef __hpux + { + lock_t *l; + + l = get_sleep_lock(&fr_authnext); + error = sleep(&fr_authnext, PZERO+1); + spinunlock(l); + } +# else +# ifdef __osf__ + error = mpsleep(&fr_authnext, PSUSP|PCATCH, "fr_authnext", 0, + &ipf_authmx, MS_LOCK_SIMPLE); +# else + error = SLEEP(&fr_authnext, "fr_authnext"); +# endif /* __osf__ */ +# endif /* __hpux */ +# endif /* SOLARIS */ +#endif + MUTEX_EXIT(&ipf_authmx); + READ_ENTER(&ipf_global); + if (error == 0) + goto fr_authioctlloop; + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_authreply */ +/* Returns: int - 0 == success, else error */ +/* Parameters: data(I) - pointer to data from ioctl call */ +/* */ +/* This function is called by an application when it wants to return a */ +/* decision on a packet using the SIOCAUTHR ioctl. This is after it has */ +/* received information using an SIOCAUTHW. The decision returned in the */ +/* form of flags, the same as those used in each rule. */ +/* ------------------------------------------------------------------------ */ +int fr_authreply(data) +char *data; +{ + frauth_t auth, *au = &auth, *fra; + int error, i; + mb_t *m; + SPL_INT(s); + + error = fr_inobj(data, &auth, IPFOBJ_FRAUTH); + if (error != 0) + return error; + + SPL_NET(s); + WRITE_ENTER(&ipf_auth); + + i = au->fra_index; + fra = fr_auth + i; + error = 0; + + /* + * Check the validity of the information being returned with two simple + * checks. First, the auth index value should be within the size of + * the array and second the packet id being returned should also match. + */ + if ((i < 0) || (i >= fr_authsize) || + (fra->fra_info.fin_id != au->fra_info.fin_id)) { + RWLOCK_EXIT(&ipf_auth); + SPL_X(s); + return ESRCH; + } + + m = fr_authpkts[i]; + fra->fra_index = -2; + fra->fra_pass = au->fra_pass; + fr_authpkts[i] = NULL; + + RWLOCK_EXIT(&ipf_auth); + + /* + * Re-insert the packet back into the packet stream flowing through + * the kernel in a manner that will mean IPFilter sees the packet + * again. This is not the same as is done with fastroute, + * deliberately, as we want to resume the normal packet processing + * path for it. + */ +#ifdef _KERNEL + if ((m != NULL) && (au->fra_info.fin_out != 0)) { + error = ipf_inject(&fra->fra_info, m); + if (error != 0) { + error = ENOBUFS; + fr_authstats.fas_sendfail++; + } else { + fr_authstats.fas_sendok++; + } + } else if (m) { + error = ipf_inject(&fra->fra_info, m); + if (error != 0) { + error = ENOBUFS; + fr_authstats.fas_quefail++; + } else { + fr_authstats.fas_queok++; + } + } else { + error = EINVAL; + } + + /* + * If we experience an error which will result in the packet + * not being processed, make sure we advance to the next one. + */ + if (error == ENOBUFS) { + fr_authused--; + fra->fra_index = -1; + fra->fra_pass = 0; + if (i == fr_authstart) { + while (fra->fra_index == -1) { + i++; + if (i == fr_authsize) + i = 0; + fr_authstart = i; + if (i == fr_authend) + break; + } + if (fr_authstart == fr_authend) { + fr_authnext = 0; + fr_authstart = fr_authend = 0; + } + } + } +#endif /* _KERNEL */ + SPL_X(s); + + return 0; +} diff --git a/sys/contrib/ipfilter/netinet/ip_auth.h b/sys/contrib/ipfilter/netinet/ip_auth.h index 22c69b7..818497b 100644 --- a/sys/contrib/ipfilter/netinet/ip_auth.h +++ b/sys/contrib/ipfilter/netinet/ip_auth.h @@ -3,7 +3,7 @@ * * See the IPFILTER.LICENCE file for details on licencing. * - * $Id: ip_auth.h,v 2.16.2.2 2006/03/16 06:45:49 darrenr Exp $ + * $Id: ip_auth.h,v 2.16.2.3 2006/07/14 06:12:05 darrenr Exp $ * */ #ifndef __IP_AUTH_H__ @@ -27,7 +27,9 @@ typedef struct frauth { typedef struct frauthent { struct frentry fae_fr; struct frauthent *fae_next; + struct frauthent **fae_pnext; u_long fae_age; + int fae_ref; } frauthent_t; typedef struct fr_authstat { @@ -60,7 +62,7 @@ extern int fr_authflush __P((void)); extern mb_t **fr_authpkts; extern int fr_newauth __P((mb_t *, fr_info_t *)); extern int fr_preauthcmd __P((ioctlcmd_t, frentry_t *, frentry_t **)); -extern int fr_auth_ioctl __P((caddr_t, ioctlcmd_t, int)); +extern int fr_auth_ioctl __P((caddr_t, ioctlcmd_t, int, int, void *)); extern int fr_auth_waiting __P((void)); #endif /* __IP_AUTH_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_compat.h b/sys/contrib/ipfilter/netinet/ip_compat.h index 0a294cf..5dc1d44 100644 --- a/sys/contrib/ipfilter/netinet/ip_compat.h +++ b/sys/contrib/ipfilter/netinet/ip_compat.h @@ -4,7 +4,7 @@ * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ip_compat.h 1.8 1/14/96 - * $Id: ip_compat.h,v 2.142.2.36 2006/03/26 05:50:29 darrenr Exp $ + * $Id: ip_compat.h,v 2.142.2.48 2007/05/31 12:27:34 darrenr Exp $ */ #ifndef __IP_COMPAT_H__ @@ -238,11 +238,12 @@ typedef unsigned int u_32_t; # define MUTEX_EXIT(x) mutex_exit(&(x)->ipf_lk) # define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c)) # define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) -# define BCOPYIN(a,b,c) (void) copyin((caddr_t)(a), (caddr_t)(b), (c)) -# define BCOPYOUT(a,b,c) (void) copyout((caddr_t)(a), (caddr_t)(b), (c)) +# define BCOPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c)) +# define BCOPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) # define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,c,d) # define KFREE(x) kmem_free((char *)(x), sizeof(*(x))) # define KFREES(x,s) kmem_free((char *)(x), (s)) +# define SPL_SCHED(x) ; # define SPL_NET(x) ; # define SPL_IMP(x) ; # undef SPL_X @@ -415,13 +416,7 @@ typedef struct iplog_select_s { # define RW_DESTROY(x) # define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c)) # define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) -# if HPUXREV >= 1111 -# define BCOPYIN(a,b,c) 0; bcopy((caddr_t)(a), (caddr_t)(b), (c)) -# define BCOPYOUT(a,b,c) 0; bcopy((caddr_t)(a), (caddr_t)(b), (c)) -# else -# define BCOPYIN(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) -# define BCOPYOUT(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) -# endif +# define SPL_SCHED(x) ; # define SPL_NET(x) ; # define SPL_IMP(x) ; # undef SPL_X @@ -574,8 +569,6 @@ typedef struct { # define MTOD(m,t) mtod(m,t) # define COPYIN(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) # define COPYOUT(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) -# define BCOPYIN(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) -# define BCOPYOUT(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) # define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,c,d) # define SLEEP(id, n) sleep((id), PZERO+1) # define WAKEUP(id,x) wakeup(id+x) @@ -591,6 +584,7 @@ typedef struct { # define USE_SPL 1 # define SPL_IMP(x) (x) = splimp() # define SPL_NET(x) (x) = splnet() +# define SPL_SCHED(x) (x) = splsched() # define SPL_X(x) (void) splx(x) extern void m_copydata __P((struct mbuf *, int, int, caddr_t)); extern void m_copyback __P((struct mbuf *, int, int, caddr_t)); @@ -651,6 +645,7 @@ typedef struct mbuf mb_t; simple_unlock(&ipf_rw); } # define ATOMIC_DEC(x) { simple_lock(&ipf_rw); (x)--; \ simple_unlock(&ipf_rw); } +# define SPL_SCHED(x) ; # define SPL_NET(x) ; # define SPL_IMP(x) ; # undef SPL_X @@ -664,8 +659,6 @@ typedef struct mbuf mb_t; # define POLLWAKEUP(x) ; # define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c)) # define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) -# define BCOPYIN(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) -# define BCOPYOUT(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) # define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), M_PFILT, M_NOWAIT) # define KMALLOCS(a, b, c) MALLOC((a), b, (c), M_PFILT, \ ((c) > 4096) ? M_WAITOK : M_NOWAIT) @@ -718,6 +711,14 @@ typedef unsigned int u_32_t; /* N E T B S D */ /* ----------------------------------------------------------------------- */ #ifdef __NetBSD__ +# if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL) +# include "opt_ipfilter.h" +# endif +# if defined(_KERNEL) +# include +# else +# include +# endif # if defined(_KERNEL) && !defined(IPFILTER_LKM) # include "bpfilter.h" # if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 104110000) @@ -731,7 +732,14 @@ typedef unsigned int u_32_t; # endif # endif +# if (__NetBSD_Version__ >= 499000000) +typedef char * caddr_t; +# endif + # ifdef _KERNEL +# if (__NetBSD_Version__ >= 399001400) +# define KMALLOCS(a, b, c) (a) = (b)malloc((c), _M_IPF, M_NOWAIT) +# endif # define MSGDSIZE(x) mbufchainlen(x) # define M_LEN(x) (x)->m_len # define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL) @@ -739,8 +747,6 @@ typedef unsigned int u_32_t; # define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); } # define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c)) # define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) -# define BCOPYIN(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) -# define BCOPYOUT(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) typedef struct mbuf mb_t; # endif /* _KERNEL */ # if (NetBSD <= 1991011) && (NetBSD >= 199606) @@ -754,7 +760,6 @@ typedef struct mbuf mb_t; # define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \ ((struct ifnet *)fin->fin_ifp)->if_unit) & 7) # endif - typedef struct uio uio_t; typedef u_long ioctlcmd_t; typedef int minor_t; @@ -796,8 +801,6 @@ typedef u_int32_t u_32_t; # endif # define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c)) # define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) -# define BCOPYIN(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) -# define BCOPYOUT(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) # if (__FreeBSD_version >= 500043) # define NETBSD_PF @@ -813,7 +816,7 @@ typedef u_int32_t u_32_t; * with a WITNESS kernel, it generates LOR messages. */ # define KMUTEX_T struct mtx -# if 1 +# if (__FreeBSD_version < 700000) # define KRWLOCK_T struct mtx # else # define KRWLOCK_T struct sx @@ -857,7 +860,7 @@ typedef u_int32_t u_32_t; * for what we want to use them for, despite testing showing they work - * with a WITNESS kernel, it generates LOR messages. */ -# if 1 +# if (__FreeBSD_version < 700000) # define READ_ENTER(x) mtx_lock(&(x)->ipf_lk) # define WRITE_ENTER(x) mtx_lock(&(x)->ipf_lk) # define RWLOCK_EXIT(x) mtx_unlock(&(x)->ipf_lk) @@ -872,7 +875,7 @@ typedef u_int32_t u_32_t; # define RWLOCK_INIT(x, y) sx_init(&(x)->ipf_lk, (y)) # define RW_DESTROY(x) sx_destroy(&(x)->ipf_lk) # ifdef sx_unlock -# define RWLOCK_EXIT(x) sx_unlock(x) +# define RWLOCK_EXIT(x) sx_unlock(&(x)->ipf_lk) # else # define RWLOCK_EXIT(x) do { \ if ((x)->ipf_lk.sx_cnt < 0) \ @@ -889,15 +892,16 @@ typedef u_int32_t u_32_t; mtx_unlock(&ipf_rw.ipf_lk); } # define ATOMIC_INCL(x) atomic_add_long(&(x), 1) # define ATOMIC_INC64(x) ATOMIC_INC(x) -# define ATOMIC_INC32(x) atomic_add_32(&(x), 1) +# define ATOMIC_INC32(x) atomic_add_32((u_int *)&(x), 1) # define ATOMIC_INC16(x) atomic_add_16(&(x), 1) # define ATOMIC_DECL(x) atomic_add_long(&(x), -1) # define ATOMIC_DEC64(x) ATOMIC_DEC(x) -# define ATOMIC_DEC32(x) atomic_add_32(&(x), -1) +# define ATOMIC_DEC32(x) atomic_add_32((u_int *)&(x), -1) # define ATOMIC_DEC16(x) atomic_add_16(&(x), -1) # define SPL_X(x) ; # define SPL_NET(x) ; # define SPL_IMP(x) ; +# define SPL_SCHED(x) ; extern int in_cksum __P((struct mbuf *, int)); # endif /* __FreeBSD_version >= 500043 */ # define MSGDSIZE(x) mbufchainlen(x) @@ -955,8 +959,6 @@ typedef u_int32_t u_32_t; # endif # define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c)) # define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) -# define BCOPYIN(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) -# define BCOPYOUT(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) # define GETKTIME(x) microtime((struct timeval *)x) # define MSGDSIZE(x) mbufchainlen(x) # define M_LEN(x) (x)->m_len @@ -1058,7 +1060,7 @@ typedef unsigned int u_32_t; #if defined(linux) && !defined(OS_RECOGNISED) #include #include -# if LINUX >= 20600 +# if (LINUX >= 20600) && defined(_KERNEL) # define HDR_T_PRIVATE 1 # endif # undef USE_INET6 @@ -1071,15 +1073,17 @@ struct ip6_ext { # ifdef _KERNEL # define IPF_PANIC(x,y) if (x) { printf y; panic("ipf_panic"); } -# define BCOPYIN(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) -# define BCOPYOUT(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) # define COPYIN(a,b,c) copy_from_user((caddr_t)(b), (caddr_t)(a), (c)) # define COPYOUT(a,b,c) copy_to_user((caddr_t)(b), (caddr_t)(a), (c)) # define FREE_MB_T(m) kfree_skb(m) # define GETKTIME(x) do_gettimeofday((struct timeval *)x) -# define SLEEP(x,s) 0, interruptible_sleep_on(x##_linux) # define POLLWAKEUP(x) ; -# define WAKEUP(x,y) wake_up(x##_linux + y) +# ifdef wait_event_interruptible +# define SLEEP(x,s) wait_event_interruptible((*(x##_linux)), 0) +# else +# define SLEEP(x,s) 0, interruptible_sleep_on(x##_linux) +# endif +# define WAKEUP(x,y) wake_up(x##_linux + y) # define UIOMOVE(a,b,c,d) uiomove(a,b,c,d) # define USE_MUTEXES # define KRWLOCK_T rwlock_t @@ -1091,7 +1095,7 @@ struct ip6_ext { # define MUTEX_NUKE(x) bzero(&(x)->ipf_lk, sizeof((x)->ipf_lk)) # define READ_ENTER(x) ipf_read_enter(x) # define WRITE_ENTER(x) ipf_write_enter(x) -# define RWLOCK_INIT(x,y) rwlock_init(&(x)->ipf_lk) +# define RWLOCK_INIT(x,y) ipf_rw_init(x, y) # define RW_DESTROY(x) do { } while (0) # define RWLOCK_EXIT(x) ipf_rw_exit(x) # define MUTEX_DOWNGRADE(x) ipf_rw_downgrade(x) @@ -1111,6 +1115,7 @@ struct ip6_ext { MUTEX_EXIT(&ipf_rw) # define ATOMIC_DEC16(x) MUTEX_ENTER(&ipf_rw); (x)--; \ MUTEX_EXIT(&ipf_rw) +# define SPL_SCHED(x) do { } while (0) # define SPL_IMP(x) do { } while (0) # define SPL_NET(x) do { } while (0) # define SPL_X(x) do { } while (0) @@ -1260,6 +1265,7 @@ typedef u_int32_t u_32_t; MUTEX_EXIT(&ipf_rw); } # define ATOMIC_DEC(x) { MUTEX_ENTER(&ipf_rw); (x)--; \ MUTEX_EXIT(&ipf_rw); } +# define SPL_SCHED(x) x = splsched() # define SPL_NET(x) x = splnet() # define SPL_IMP(x) x = splimp() # undef SPL_X @@ -1273,8 +1279,6 @@ extern void* getifp __P((char *, int)); # define POLLWAKEUP(x) ; # define COPYIN(a,b,c) copyin((caddr_t)(a), (caddr_t)(b), (c)) # define COPYOUT(a,b,c) copyout((caddr_t)(a), (caddr_t)(b), (c)) -# define BCOPYIN(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) -# define BCOPYOUT(a,b,c) bcopy((caddr_t)(a), (caddr_t)(b), (c)) # define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), M_TEMP, M_NOWAIT) # define KMALLOCS(a, b, c) MALLOC((a), b, (c), M_TEMP, \ ((c) > 4096) ? M_WAITOK : M_NOWAIT) @@ -1351,7 +1355,7 @@ typedef struct { u_int eMm_magic; int eMm_held; int eMm_heldat; -#ifdef __hpux +#if defined(__hpux) || defined(__linux) char eMm_fill[8]; #endif } eMmutex_t; @@ -1410,6 +1414,7 @@ typedef union { extern void ipf_read_enter __P((ipfrwlock_t *)); extern void ipf_write_enter __P((ipfrwlock_t *)); extern void ipf_rw_exit __P((ipfrwlock_t *)); +extern void ipf_rw_init __P((ipfrwlock_t *, char *)); extern void ipf_rw_downgrade __P((ipfrwlock_t *)); #endif @@ -1438,6 +1443,7 @@ typedef struct mb_s { # define POLLWAKEUP(y) ; # define IPF_PANIC(x,y) ; # define PANIC(x,y) ; +# define SPL_SCHED(x) ; # define SPL_NET(x) ; # define SPL_IMP(x) ; # define SPL_X(x) ; @@ -1448,8 +1454,6 @@ typedef struct mb_s { # define GETIFP(x, v) get_unit(x,v) # define COPYIN(a,b,c) bcopywrap((a), (b), (c)) # define COPYOUT(a,b,c) bcopywrap((a), (b), (c)) -# define BCOPYIN(a,b,c) (bcopy((a), (b), (c)), 0) -# define BCOPYOUT(a,b,c) (bcopy((a), (b), (c)), 0) # define COPYDATA(m, o, l, b) bcopy(MTOD((mb_t *)m, char *) + (o), \ (b), (l)) # define COPYBACK(m, o, l, b) bcopy((b), \ @@ -1537,9 +1541,6 @@ typedef struct ip6_hdr ip6_t; #endif #if defined(_KERNEL) -# ifdef BSD -extern struct selinfo ipfselwait[]; -# endif # ifdef MENTAT # define COPYDATA mb_copydata # define COPYBACK mb_copyback @@ -1583,7 +1584,9 @@ MALLOC_DECLARE(M_IPFILTER); # endif /* M_PFIL */ # endif /* IPFILTER_M_IPFILTER */ # define KMALLOC(a, b) MALLOC((a), b, sizeof(*(a)), _M_IPF, M_NOWAIT) -# define KMALLOCS(a, b, c) MALLOC((a), b, (c), _M_IPF, M_NOWAIT) +# if !defined(KMALLOCS) +# define KMALLOCS(a, b, c) MALLOC((a), b, (c), _M_IPF, M_NOWAIT) +# endif # define KFREE(x) FREE((x), _M_IPF) # define KFREES(x,s) FREE((x), _M_IPF) # define UIOMOVE(a,b,c,d) uiomove(a,b,d) @@ -1601,6 +1604,7 @@ MALLOC_DECLARE(M_IPFILTER); # define SPL_IMP(x) x = splimp() # define SPL_NET(x) x = splnet() # endif /* NetBSD && (NetBSD <= 1991011) && (NetBSD >= 199407) */ +# define SPL_SCHED(x) x = splsched() # define SPL_X(x) (void) splx(x) # endif /* !USE_MUTEXES */ @@ -1615,8 +1619,6 @@ MALLOC_DECLARE(M_IPFILTER); # ifndef COPYIN # define COPYIN(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) # define COPYOUT(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) -# define BCOPYIN(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) -# define BCOPYOUT(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) # endif # ifndef KMALLOC @@ -1645,6 +1647,11 @@ extern char *fr_getifname __P((struct ifnet *, char *)); # define ASSERT(x) #endif +#ifndef BCOPYIN +# define BCOPYIN(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) +# define BCOPYOUT(a,b,c) (bcopy((caddr_t)(a), (caddr_t)(b), (c)), 0) +#endif + /* * Because the ctype(3) posix definition, if used "safely" in code everywhere, * would mean all normal code that walks through strings needed casts. Yuck. @@ -1721,9 +1728,6 @@ typedef struct tcpiphdr tcpiphdr_t; # define FR_GROUPLEN 16 #endif -#ifdef offsetof -# undef offsetof -#endif #ifndef offsetof # define offsetof(t,m) (int)((&((t *)0L)->m)) #endif @@ -1743,7 +1747,7 @@ typedef struct tcpiphdr tcpiphdr_t; # define IP_HL(x) (x)->ip_hl #endif #ifndef IP_HL_A -# define IP_HL_A(x,y) (x)->ip_hl = (y) +# define IP_HL_A(x,y) (x)->ip_hl = ((y) & 0xf) #endif #ifndef TCP_X2 # define TCP_X2(x) (x)->th_x2 @@ -2351,21 +2355,21 @@ typedef struct tcpiphdr tcpiphdr_t; /* * TCP States */ -#define IPF_TCPS_CLOSED 0 /* closed */ -#define IPF_TCPS_LISTEN 1 /* listening for connection */ -#define IPF_TCPS_SYN_SENT 2 /* active, have sent syn */ -#define IPF_TCPS_SYN_RECEIVED 3 /* have send and received syn */ -#define IPF_TCPS_HALF_ESTAB 4 /* for connections not fully "up" */ +#define IPF_TCPS_LISTEN 0 /* listening for connection */ +#define IPF_TCPS_SYN_SENT 1 /* active, have sent syn */ +#define IPF_TCPS_SYN_RECEIVED 2 /* have send and received syn */ +#define IPF_TCPS_HALF_ESTAB 3 /* for connections not fully "up" */ /* states < IPF_TCPS_ESTABLISHED are those where connections not established */ -#define IPF_TCPS_ESTABLISHED 5 /* established */ -#define IPF_TCPS_CLOSE_WAIT 6 /* rcvd fin, waiting for close */ +#define IPF_TCPS_ESTABLISHED 4 /* established */ +#define IPF_TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ /* states > IPF_TCPS_CLOSE_WAIT are those where user has closed */ -#define IPF_TCPS_FIN_WAIT_1 7 /* have closed, sent fin */ -#define IPF_TCPS_CLOSING 8 /* closed xchd FIN; await FIN ACK */ -#define IPF_TCPS_LAST_ACK 9 /* had fin and close; await FIN ACK */ +#define IPF_TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ +#define IPF_TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */ +#define IPF_TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */ /* states > IPF_TCPS_CLOSE_WAIT && < IPF_TCPS_FIN_WAIT_2 await ACK of FIN */ -#define IPF_TCPS_FIN_WAIT_2 10 /* have closed, fin is acked */ -#define IPF_TCPS_TIME_WAIT 11 /* in 2*msl quiet wait after close */ +#define IPF_TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ +#define IPF_TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */ +#define IPF_TCPS_CLOSED 11 /* closed */ #define IPF_TCP_NSTATES 12 #define TCP_MSL 120 diff --git a/sys/contrib/ipfilter/netinet/ip_fil.h b/sys/contrib/ipfilter/netinet/ip_fil.h index 5a13993..da710c1 100644 --- a/sys/contrib/ipfilter/netinet/ip_fil.h +++ b/sys/contrib/ipfilter/netinet/ip_fil.h @@ -4,7 +4,7 @@ * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ip_fil.h 1.35 6/5/96 - * $Id: ip_fil.h,v 2.170.2.29 2006/03/29 11:19:55 darrenr Exp $ + * $Id: ip_fil.h,v 2.170.2.45 2007/05/28 11:56:22 darrenr Exp $ */ #ifndef __IP_FIL_H__ @@ -43,12 +43,12 @@ # define SIOCZRLST _IOWR('r', 75, struct ipfobj) # define SIOCAUTHW _IOWR('r', 76, struct ipfobj) # define SIOCAUTHR _IOWR('r', 77, struct ipfobj) -# define SIOCATHST _IOWR('r', 78, struct ipfobj) +# define SIOCSTAT1 _IOWR('r', 78, struct ipfobj) # define SIOCSTLCK _IOWR('r', 79, u_int) # define SIOCSTPUT _IOWR('r', 80, struct ipfobj) # define SIOCSTGET _IOWR('r', 81, struct ipfobj) # define SIOCSTGSZ _IOWR('r', 82, struct ipfobj) -# define SIOCGFRST _IOWR('r', 83, struct ipfobj) +# define SIOCSTAT2 _IOWR('r', 83, struct ipfobj) # define SIOCSETLG _IOWR('r', 84, int) # define SIOCGETLG _IOWR('r', 85, int) # define SIOCFUNCL _IOWR('r', 86, struct ipfunc_resolve) @@ -56,6 +56,12 @@ # define SIOCIPFGET _IOWR('r', 88, struct ipfobj) # define SIOCIPFSET _IOWR('r', 89, struct ipfobj) # define SIOCIPFL6 _IOWR('r', 90, int) +# define SIOCIPFITER _IOWR('r', 91, struct ipfobj) +# define SIOCGENITER _IOWR('r', 92, struct ipfobj) +# define SIOCGTABL _IOWR('r', 93, struct ipfobj) +# define SIOCIPFDELTOK _IOWR('r', 94, int) +# define SIOCLOOKUPITER _IOWR('r', 95, struct ipfobj) +# define SIOCGTQTAB _IOWR('r', 96, struct ipfobj) #else # define SIOCADAFR _IOW(r, 60, struct ipfobj) # define SIOCRMAFR _IOW(r, 61, struct ipfobj) @@ -75,12 +81,12 @@ # define SIOCZRLST _IOWR(r, 75, struct ipfobj) # define SIOCAUTHW _IOWR(r, 76, struct ipfobj) # define SIOCAUTHR _IOWR(r, 77, struct ipfobj) -# define SIOCATHST _IOWR(r, 78, struct ipfobj) +# define SIOCSTAT1 _IOWR(r, 78, struct ipfobj) # define SIOCSTLCK _IOWR(r, 79, u_int) # define SIOCSTPUT _IOWR(r, 80, struct ipfobj) # define SIOCSTGET _IOWR(r, 81, struct ipfobj) # define SIOCSTGSZ _IOWR(r, 82, struct ipfobj) -# define SIOCGFRST _IOWR(r, 83, struct ipfobj) +# define SIOCSTAT2 _IOWR(r, 83, struct ipfobj) # define SIOCSETLG _IOWR(r, 84, int) # define SIOCGETLG _IOWR(r, 85, int) # define SIOCFUNCL _IOWR(r, 86, struct ipfunc_resolve) @@ -88,10 +94,18 @@ # define SIOCIPFGET _IOWR(r, 88, struct ipfobj) # define SIOCIPFSET _IOWR(r, 89, struct ipfobj) # define SIOCIPFL6 _IOWR(r, 90, int) +# define SIOCIPFITER _IOWR(r, 91, struct ipfobj) +# define SIOCGENITER _IOWR(r, 92, struct ipfobj) +# define SIOCGTABL _IOWR(r, 93, struct ipfobj) +# define SIOCIPFDELTOK _IOWR(r, 94, int) +# define SIOCLOOKUPITER _IOWR(r, 95, struct ipfobj) +# define SIOCGTQTAB _IOWR(r, 96, struct ipfobj) #endif #define SIOCADDFR SIOCADAFR #define SIOCDELFR SIOCRMAFR #define SIOCINSFR SIOCINAFR +#define SIOCATHST SIOCSTAT1 +#define SIOCGFRST SIOCSTAT2 struct ipscan; @@ -111,6 +125,11 @@ typedef union i6addr { struct in6_addr in6; void *vptr[2]; lookupfunc_t lptr[2]; + struct { + u_short type; + u_short subtype; + char label[12]; + } i6un; } i6addr_t; #else typedef union i6addr { @@ -118,12 +137,19 @@ typedef union i6addr { struct in_addr in4; void *vptr[2]; lookupfunc_t lptr[2]; + struct { + u_short type; + u_short subtype; + char label[12]; + } i6un; } i6addr_t; #endif #define in4_addr in4.s_addr -#define iplookupnum i6[0] -#define iplookuptype i6[1] +#define iplookupnum i6[1] +#define iplookupname i6un.label +#define iplookuptype i6un.type +#define iplookupsubtype i6un.subtype /* * NOTE: These DO overlap the above on 64bit systems and this IS recognised. */ @@ -249,8 +275,12 @@ typedef struct fr_ip { #define fi_daddr fi_dst.in4.s_addr #define fi_srcnum fi_src.iplookupnum #define fi_dstnum fi_dst.iplookupnum +#define fi_srcname fi_src.iplookupname +#define fi_dstname fi_dst.iplookupname #define fi_srctype fi_src.iplookuptype #define fi_dsttype fi_dst.iplookuptype +#define fi_srcsubtype fi_src.iplookupsubtype +#define fi_dstsubtype fi_dst.iplookupsubtype #define fi_srcptr fi_src.iplookupptr #define fi_dstptr fi_dst.iplookupptr #define fi_srcfunc fi_src.iplookupfunc @@ -299,6 +329,7 @@ typedef struct fr_info { void *fin_nat; void *fin_state; void *fin_nattag; + void *fin_exthdr; ip_t *fin_ip; mb_t **fin_mp; /* pointer to pointer to mbuf */ mb_t *fin_m; /* pointer to mbuf */ @@ -329,8 +360,8 @@ typedef struct fr_info { #define fin_dport fin_dat.fid_16[1] #define fin_ports fin_dat.fid_32 -#define IPF_IN 0 -#define IPF_OUT 1 +#define IPF_IN 0 +#define IPF_OUT 1 typedef struct frentry *(*ipfunc_t) __P((fr_info_t *, u_32_t *)); typedef int (*ipfuncinit_t) __P((struct frentry *)); @@ -440,9 +471,13 @@ typedef struct fripf { int fri_difpidx; /* index into fr_ifps[] to use when */ } fripf_t; -#define fri_dstnum fri_ip.fi_dstnum +#define fri_dlookup fri_mip.fi_dst +#define fri_slookup fri_mip.fi_src +#define fri_dstnum fri_mip.fi_dstnum #define fri_srcnum fri_mip.fi_srcnum -#define fri_dstptr fri_ip.fi_dstptr +#define fri_dstname fri_mip.fi_dstname +#define fri_srcname fri_mip.fi_srcname +#define fri_dstptr fri_mip.fi_dstptr #define fri_srcptr fri_mip.fi_srcptr #define FRI_NORMAL 0 /* Normal address */ @@ -468,6 +503,13 @@ typedef struct frentry { int fr_ref; /* reference count - for grouping */ int fr_statecnt; /* state count - for limit rules */ /* + * The line number from a file is here because we need to be able to + * match the rule generated with ``grep rule ipf.conf | ipf -rf -'' + * with the rule loaded using ``ipf -f ipf.conf'' - thus it can't be + * on the other side of fr_func. + */ + int fr_flineno; /* line number from conf file */ + /* * These are only incremented when a packet matches this rule and * it is the last match */ @@ -494,7 +536,6 @@ typedef struct frentry { int fr_dsize; int fr_pps; int fr_statemax; /* max reference count */ - int fr_flineno; /* line number from conf file */ u_32_t fr_type; u_32_t fr_flags; /* per-rule flags && options (see below) */ u_32_t fr_logtag; /* user defined log tag # */ @@ -554,8 +595,14 @@ typedef struct frentry { #define fr_smask fr_mip.fi_src.in4.s_addr #define fr_dstnum fr_ip.fi_dstnum #define fr_srcnum fr_ip.fi_srcnum +#define fr_dlookup fr_ip.fi_dst +#define fr_slookup fr_ip.fi_src +#define fr_dstname fr_ip.fi_dstname +#define fr_srcname fr_ip.fi_srcname #define fr_dsttype fr_ip.fi_dsttype #define fr_srctype fr_ip.fi_srctype +#define fr_dstsubtype fr_ip.fi_dstsubtype +#define fr_srcsubtype fr_ip.fi_srcsubtype #define fr_dstptr fr_mip.fi_dstptr #define fr_srcptr fr_mip.fi_srcptr #define fr_dstfunc fr_mip.fi_dstfunc @@ -1018,6 +1065,8 @@ typedef struct ipftq { /* checks its timeout queues. */ #define IPF_TTLVAL(x) (((x) / IPF_HZ_MULT) * IPF_HZ_DIVIDE) +typedef int (*ipftq_delete_fn_t)(void *); + /* * Structure to define address for pool lookups. */ @@ -1053,6 +1102,13 @@ typedef struct ipfobj { #define IPFOBJ_STATESTAT 11 /* struct ips_stat */ #define IPFOBJ_FRAUTH 12 /* struct frauth */ #define IPFOBJ_TUNEABLE 13 /* struct ipftune */ +#define IPFOBJ_NAT 14 /* struct nat */ +#define IPFOBJ_IPFITER 15 /* struct ipfruleiter */ +#define IPFOBJ_GENITER 16 /* struct ipfgeniter */ +#define IPFOBJ_GTABLE 17 /* struct ipftable */ +#define IPFOBJ_LOOKUPITER 18 /* struct ipflookupiter */ +#define IPFOBJ_STATETQTAB 19 /* struct ipftq [NSTATES] */ +#define IPFOBJ_COUNT 20 /* How many #defines are above this? */ typedef union ipftunevalptr { @@ -1065,7 +1121,7 @@ typedef union ipftunevalptr { typedef struct ipftuneable { ipftunevalptr_t ipft_una; - char *ipft_name; + const char *ipft_name; u_long ipft_min; u_long ipft_max; int ipft_sz; @@ -1104,6 +1160,66 @@ typedef struct ipftune { #define ipft_vshort ipft_un.ipftu_short #define ipft_vchar ipft_un.ipftu_char +/* + * + */ +typedef struct ipfruleiter { + int iri_inout; + char iri_group[FR_GROUPLEN]; + int iri_active; + int iri_nrules; + int iri_v; + frentry_t *iri_rule; +} ipfruleiter_t; + +/* + * Values for iri_inout + */ +#define F_IN 0 +#define F_OUT 1 +#define F_ACIN 2 +#define F_ACOUT 3 + + +typedef struct ipfgeniter { + int igi_type; + int igi_nitems; + void *igi_data; +} ipfgeniter_t; + +#define IPFGENITER_IPF 0 +#define IPFGENITER_NAT 1 +#define IPFGENITER_IPNAT 2 +#define IPFGENITER_FRAG 3 +#define IPFGENITER_AUTH 4 +#define IPFGENITER_STATE 5 +#define IPFGENITER_NATFRAG 6 +#define IPFGENITER_HOSTMAP 7 +#define IPFGENITER_LOOKUP 8 + +typedef struct ipftable { + int ita_type; + void *ita_table; +} ipftable_t; + +#define IPFTABLE_BUCKETS 1 + + +/* + * + */ +typedef struct ipftoken { + struct ipftoken *ipt_next; + struct ipftoken **ipt_pnext; + void *ipt_ctx; + void *ipt_data; + u_long ipt_die; + int ipt_type; + int ipt_uid; + int ipt_subtype; + int ipt_alive; +} ipftoken_t; + /* ** HPUX Port @@ -1162,11 +1278,22 @@ extern int iplclose __P((dev_t, int)); extern void m_freem __P((mb_t *)); extern int bcopywrap __P((void *, void *, size_t)); #else /* #ifndef _KERNEL */ +# ifdef BSD +# if (defined(__NetBSD__) && (__NetBSD_Version__ < 399000000)) || \ + defined(__osf__) || \ + (defined(__FreeBSD_version) && (__FreeBSD_version < 500043)) +# include +# else +# include +# endif +extern struct selinfo ipfselwait[IPL_LOGSIZE]; +# endif # if defined(__NetBSD__) && defined(PFIL_HOOKS) extern void ipfilterattach __P((int)); # endif extern int ipl_enable __P((void)); extern int ipl_disable __P((void)); +extern int ipf_inject __P((fr_info_t *, mb_t *)); # ifdef MENTAT extern int fr_check __P((struct ip *, int, void *, int, void *, mblk_t **)); @@ -1189,7 +1316,6 @@ extern int iplread __P((dev_t, uio_t *)); extern int iplwrite __P((dev_t, uio_t *)); extern int iplselect __P((dev_t, int)); # endif -extern int ipfsync __P((void)); extern int fr_qout __P((queue_t *, mblk_t *)); # else /* MENTAT */ extern int fr_check __P((struct ip *, int, void *, int, mb_t **)); @@ -1202,7 +1328,6 @@ extern int iplopen __P((dev_t *, int, int, cred_t *)); extern int iplclose __P((dev_t, int, int, cred_t *)); extern int iplread __P((dev_t, uio_t *, cred_t *)); extern int iplwrite __P((dev_t, uio_t *, cred_t *)); -extern int ipfsync __P((void)); extern int ipfilter_sgi_attach __P((void)); extern void ipfilter_sgi_detach __P((void)); extern void ipfilter_sgi_intfsync __P((void)); @@ -1221,7 +1346,15 @@ extern int iplioctl __P((struct cdev*, u_long, caddr_t, int, struct thread *)); extern int iplioctl __P((dev_t, u_long, caddr_t, int, struct thread *)); # endif /* __FreeBSD_version >= 502116 */ # else +# if (__NetBSD_Version__ >= 499001000) +extern int iplioctl __P((dev_t, u_long, void *, int, struct lwp *)); +# else +# if (__NetBSD_Version__ >= 399001400) +extern int iplioctl __P((dev_t, u_long, caddr_t, int, struct lwp *)); +# else extern int iplioctl __P((dev_t, u_long, caddr_t, int, struct proc *)); +# endif +# endif # endif /* __FreeBSD_version >= 500024 */ # else extern int iplioctl __P((dev_t, int, caddr_t, int, struct proc *)); @@ -1235,8 +1368,13 @@ extern int iplopen __P((dev_t, int, int, struct thread *)); extern int iplclose __P((dev_t, int, int, struct thread *)); # endif /* __FreeBSD_version >= 502116 */ # else +# if (__NetBSD_Version__ >= 399001400) +extern int iplopen __P((dev_t, int, int, struct lwp *)); +extern int iplclose __P((dev_t, int, int, struct lwp *)); +# else extern int iplopen __P((dev_t, int, int, struct proc *)); extern int iplclose __P((dev_t, int, int, struct proc *)); +# endif /* __NetBSD_Version__ >= 399001400 */ # endif /* __FreeBSD_version >= 500024 */ # else # ifdef linux @@ -1270,21 +1408,22 @@ extern ipfmutex_t ipl_mutex, ipf_authmx, ipf_rw, ipf_hostmap; extern ipfmutex_t ipf_timeoutlock, ipf_stinsert, ipf_natio, ipf_nat_new; extern ipfrwlock_t ipf_mutex, ipf_global, ip_poolrw, ipf_ipidfrag; extern ipfrwlock_t ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth; -extern ipfrwlock_t ipf_frcache; +extern ipfrwlock_t ipf_frcache, ipf_tokens; extern char *memstr __P((const char *, char *, size_t, size_t)); extern int count4bits __P((u_32_t)); extern int frrequest __P((int, ioctlcmd_t, caddr_t, int, int)); extern char *getifname __P((struct ifnet *)); -extern int iplattach __P((void)); -extern int ipldetach __P((void)); +extern int ipfattach __P((void)); +extern int ipfdetach __P((void)); extern u_short ipf_cksum __P((u_short *, int)); extern int copyinptr __P((void *, void *, size_t)); extern int copyoutptr __P((void *, void *, size_t)); extern int fr_fastroute __P((mb_t *, mb_t **, fr_info_t *, frdest_t *)); extern int fr_inobj __P((void *, void *, int)); extern int fr_inobjsz __P((void *, void *, int, int)); -extern int fr_ioctlswitch __P((int, void *, ioctlcmd_t, int)); +extern int fr_ioctlswitch __P((int, void *, ioctlcmd_t, int, int, void *)); +extern int fr_ipf_ioctl __P((caddr_t, ioctlcmd_t, int, int, void *)); extern int fr_ipftune __P((ioctlcmd_t, void *)); extern int fr_outobj __P((void *, void *, int)); extern int fr_outobjsz __P((void *, void *, int, int)); @@ -1294,7 +1433,7 @@ extern int fr_resolvefunc __P((void *)); extern void *fr_resolvenic __P((char *, int)); extern int fr_send_icmp_err __P((int, fr_info_t *, int)); extern int fr_send_reset __P((fr_info_t *)); -#if (__FreeBSD_version < 490000) || !defined(_KERNEL) +#if (__FreeBSD_version < 501000) || !defined(_KERNEL) extern int ppsratecheck __P((struct timeval *, int *, int)); #endif extern ipftq_t *fr_addtimeoutqueue __P((ipftq_t **, u_int)); @@ -1356,12 +1495,20 @@ extern int fr_matchicmpqueryreply __P((int, icmpinfo_t *, struct icmp *, int)); extern u_32_t fr_newisn __P((fr_info_t *)); extern u_short fr_nextipid __P((fr_info_t *)); +extern int ipf_queueflush __P((ipftq_delete_fn_t, ipftq_t *, ipftq_t *)); extern int fr_rulen __P((int, frentry_t *)); extern int fr_scanlist __P((fr_info_t *, u_32_t)); extern frentry_t *fr_srcgrpmap __P((fr_info_t *, u_32_t *)); extern int fr_tcpudpchk __P((fr_info_t *, frtuc_t *)); extern int fr_verifysrc __P((fr_info_t *fin)); extern int fr_zerostats __P((char *)); +extern ipftoken_t *ipf_findtoken __P((int, int, void *)); +extern int ipf_getnextrule __P((ipftoken_t *, void *)); +extern void ipf_expiretokens __P((void)); +extern void ipf_freetoken __P((ipftoken_t *)); +extern int ipf_deltoken __P((int,int, void *)); +extern int ipfsync __P((void)); +extern int ipf_genericiter __P((void *, int, void *)); extern int fr_running; extern u_long fr_frouteok[2]; @@ -1376,7 +1523,6 @@ extern int fr_update_ipid; extern int nat_logging; extern int ipstate_logging; extern int ipl_suppress; -extern int ipl_buffer_sz; extern int ipl_logmax; extern int ipl_logall; extern int ipl_logsize; diff --git a/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c b/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c index d361bea..02e0030 100644 --- a/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c +++ b/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c @@ -5,7 +5,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_freebsd.c,v 2.53.2.32 2006/03/25 13:03:01 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_fil_freebsd.c,v 2.53.2.46 2007/05/11 13:41:53 darrenr Exp $"; #endif #if defined(KERNEL) || defined(_KERNEL) @@ -55,11 +55,18 @@ static const char rcsid[] = "@(#)$Id: ip_fil_freebsd.c,v 2.53.2.32 2006/03/25 13 #endif #include #include -#include +#if __FreeBSD_version >= 500043 +# include +#else +# include +#endif #include #if __FreeBSD_version >= 300000 # include +# if __FreeBSD_version >= 500043 +# include +# endif # if !defined(IPFILTER_LKM) # include "opt_ipfilter.h" # endif @@ -124,7 +131,7 @@ static int fr_send_ip __P((fr_info_t *, mb_t *, mb_t **)); # ifdef USE_MUTEXES ipfmutex_t ipl_mutex, ipf_authmx, ipf_rw, ipf_stinsert; ipfmutex_t ipf_nat_new, ipf_natio, ipf_timeoutlock; -ipfrwlock_t ipf_mutex, ipf_global, ipf_ipidfrag, ipf_frcache; +ipfrwlock_t ipf_mutex, ipf_global, ipf_ipidfrag, ipf_frcache, ipf_tokens; ipfrwlock_t ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth; # endif int ipf_locks_done = 0; @@ -191,7 +198,7 @@ char *s; #endif /* IPFILTER_LKM */ -int iplattach() +int ipfattach() { #ifdef USE_SPL int s; @@ -213,11 +220,9 @@ int iplattach() } MUTEX_INIT(&ipf_rw, "ipf rw mutex"); - RWLOCK_INIT(&ipf_global, "ipf filter load/unload mutex"); MUTEX_INIT(&ipf_timeoutlock, "ipf timeout queue mutex"); - RWLOCK_INIT(&ipf_mutex, "ipf filter rwlock"); - RWLOCK_INIT(&ipf_frcache, "ipf cache rwlock"); RWLOCK_INIT(&ipf_ipidfrag, "ipf IP NAT-Frag rwlock"); + RWLOCK_INIT(&ipf_tokens, "ipf token rwlock"); ipf_locks_done = 1; if (fr_initialise() < 0) { @@ -324,7 +329,7 @@ pfil_error: * Disable the filter by removing the hooks from the IP input/output * stream. */ -int ipldetach() +int ipfdetach() { #ifdef USE_SPL int s; @@ -418,10 +423,8 @@ int ipldetach() if (ipf_locks_done == 1) { MUTEX_DESTROY(&ipf_timeoutlock); MUTEX_DESTROY(&ipf_rw); - RW_DESTROY(&ipf_mutex); - RW_DESTROY(&ipf_frcache); RW_DESTROY(&ipf_ipidfrag); - RW_DESTROY(&ipf_global); + RW_DESTROY(&ipf_tokens); ipf_locks_done = 0; } @@ -439,8 +442,14 @@ int iplioctl(dev, cmd, data, mode , p) # if (__FreeBSD_version >= 500024) struct thread *p; +# if (__FreeBSD_version >= 500043) +# define p_uid td_ucred->cr_ruid +# else +# define p_uid t_proc->p_cred->p_ruid +# endif # else struct proc *p; +# define p_uid p_cred->p_ruid # endif /* __FreeBSD_version >= 500024 */ # else ) @@ -454,11 +463,8 @@ ioctlcmd_t cmd; caddr_t data; int mode; { -#ifdef USE_SPL - int s; -#endif - int error = 0, unit = 0, tmp; - friostat_t fio; + int error = 0, unit = 0; + SPL_INT(s); #if (BSD >= 199306) && defined(_KERNEL) if ((securelevel >= 3) && (mode & FWRITE)) @@ -481,149 +487,12 @@ int mode; SPL_NET(s); READ_ENTER(&ipf_global); - error = fr_ioctlswitch(unit, data, cmd, mode); + error = fr_ioctlswitch(unit, data, cmd, mode, p->p_uid, p); if (error != -1) { RWLOCK_EXIT(&ipf_global); SPL_X(s); return error; } - error = 0; - - switch (cmd) - { - case FIONREAD : -#ifdef IPFILTER_LOG - BCOPYOUT(&iplused[IPL_LOGIPF], (caddr_t)data, - sizeof(iplused[IPL_LOGIPF])); -#endif - break; - case SIOCFRENB : - if (!(mode & FWRITE)) - error = EPERM; - else { - BCOPYIN(data, &tmp, sizeof(tmp)); - if (tmp) { - if (fr_running > 0) - error = 0; - else - error = iplattach(); - if (error == 0) - fr_running = 1; - else - (void) ipldetach(); - } else { - error = ipldetach(); - if (error == 0) - fr_running = -1; - } - } - break; - case SIOCIPFSET : - if (!(mode & FWRITE)) { - error = EPERM; - break; - } - case SIOCIPFGETNEXT : - case SIOCIPFGET : - error = fr_ipftune(cmd, data); - break; - case SIOCSETFF : - if (!(mode & FWRITE)) - error = EPERM; - else - BCOPYIN(data, &fr_flags, sizeof(fr_flags)); - break; - case SIOCGETFF : - BCOPYOUT(&fr_flags, data, sizeof(fr_flags)); - break; - case SIOCFUNCL : - error = fr_resolvefunc(data); - break; - case SIOCINAFR : - case SIOCRMAFR : - case SIOCADAFR : - case SIOCZRLST : - if (!(mode & FWRITE)) - error = EPERM; - else - error = frrequest(unit, cmd, data, fr_active, 1); - break; - case SIOCINIFR : - case SIOCRMIFR : - case SIOCADIFR : - if (!(mode & FWRITE)) - error = EPERM; - else - error = frrequest(unit, cmd, data, 1 - fr_active, 1); - break; - case SIOCSWAPA : - if (!(mode & FWRITE)) - error = EPERM; - else { - bzero((char *)frcache, sizeof(frcache[0]) * 2); - *(u_int *)data = fr_active; - fr_active = 1 - fr_active; - } - break; - case SIOCGETFS : - fr_getstat(&fio); - error = fr_outobj(data, &fio, IPFOBJ_IPFSTAT); - break; - case SIOCFRZST : - if (!(mode & FWRITE)) - error = EPERM; - else - error = fr_zerostats(data); - break; - case SIOCIPFFL : - if (!(mode & FWRITE)) - error = EPERM; - else { - BCOPYIN(data, &tmp, sizeof(tmp)); - tmp = frflush(unit, 4, tmp); - BCOPYOUT(&tmp, data, sizeof(tmp)); - } - break; -#ifdef USE_INET6 - case SIOCIPFL6 : - if (!(mode & FWRITE)) - error = EPERM; - else { - BCOPYIN(data, &tmp, sizeof(tmp)); - tmp = frflush(unit, 6, tmp); - BCOPYOUT(&tmp, data, sizeof(tmp)); - } - break; -#endif - case SIOCSTLCK : - BCOPYIN(data, &tmp, sizeof(tmp)); - fr_state_lock = tmp; - fr_nat_lock = tmp; - fr_frag_lock = tmp; - fr_auth_lock = tmp; - break; -#ifdef IPFILTER_LOG - case SIOCIPFFB : - if (!(mode & FWRITE)) - error = EPERM; - else - *(int *)data = ipflog_clear(unit); - break; -#endif /* IPFILTER_LOG */ - case SIOCGFRST : - error = fr_outobj(data, fr_fragstats(), IPFOBJ_FRAGSTAT); - break; - case SIOCFRSYN : - if (!(mode & FWRITE)) - error = EPERM; - else { - frsync(NULL); - } - break; - default : - error = EINVAL; - break; - } RWLOCK_EXIT(&ipf_global); SPL_X(s); @@ -752,6 +621,9 @@ register struct uio *uio; { u_int xmin = GET_MINOR(dev); + if (fr_running < 1) + return EIO; + if (xmin < 0) return ENXIO; @@ -788,6 +660,9 @@ dev_t dev; register struct uio *uio; { + if (fr_running < 1) + return EIO; + #ifdef IPFILTER_SYNC if (GET_MINOR(dev) == IPL_LOGSYNC) return ipfsync_write(uio); @@ -1145,7 +1020,7 @@ void # endif iplinit() { - if (iplattach() != 0) + if (ipfattach() != 0) printf("IP Filter failed to attach\n"); ip_init(); } @@ -1256,9 +1131,11 @@ frdest_t *fdp; /* * For input packets which are being "fastrouted", they won't * go back through output filtering and miss their chance to get - * NAT'd and counted. + * NAT'd and counted. Duplicated packets aren't considered to be + * part of the normal packet stream, so do not NAT them or pass + * them through stateful checking, etc. */ - if (fin->fin_out == 0) { + if ((fdp != &fr->fr_dif) && (fin->fin_out == 0)) { sifp = fin->fin_ifp; fin->fin_ifp = ifp; fin->fin_out = 1; @@ -1267,7 +1144,8 @@ frdest_t *fdp; if (!fr || !(fr->fr_flags & FR_RETMASK)) { u_32_t pass; - (void) fr_checkstate(fin, &pass); + if (fr_checkstate(fin, &pass) != NULL) + fr_statederef((ipstate_t **)&fin->fin_state); } switch (fr_checknatout(fin, NULL)) @@ -1275,6 +1153,7 @@ frdest_t *fdp; case 0 : break; case 1 : + fr_natderef((nat_t **)&fin->fin_nat); ip->ip_sum = 0; break; case -1 : @@ -1734,3 +1613,46 @@ int len; fin->fin_flx |= FI_COALESCE; return ip; } + + +int ipf_inject(fin, m) +fr_info_t *fin; +mb_t *m; +{ + int error = 0; + + if (fin->fin_out == 0) { +#if (__FreeBSD_version >= 501000) + netisr_dispatch(NETISR_IP, m); +#else + struct ifqueue *ifq; + + ifq = &ipintrq; + +# ifdef _IF_QFULL + if (_IF_QFULL(ifq)) +# else + if (IF_QFULL(ifq)) +# endif + { +# ifdef _IF_DROP + _IF_DROP(ifq); +# else + IF_DROP(ifq); +# endif + FREE_MB_T(m); + error = ENOBUFS; + } else { + IF_ENQUEUE(ifq, m); + } +#endif + } else { +#if (__FreeBSD_version >= 470102) + error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL); +#else + error = ip_output(m, NULL, NULL, IP_FORWARDING, NULL); +#endif + } + + return error; +} diff --git a/sys/contrib/ipfilter/netinet/ip_frag.c b/sys/contrib/ipfilter/netinet/ip_frag.c index 18360ce..df75a0d 100644 --- a/sys/contrib/ipfilter/netinet/ip_frag.c +++ b/sys/contrib/ipfilter/netinet/ip_frag.c @@ -100,20 +100,21 @@ extern struct timeout fr_slowtimer_ch; #if !defined(lint) static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.77.2.5 2006/02/26 08:26:54 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.77.2.9 2007/05/27 11:13:44 darrenr Exp $"; #endif -static ipfr_t *ipfr_list = NULL; -static ipfr_t **ipfr_tail = &ipfr_list; -static ipfr_t **ipfr_heads; +ipfr_t *ipfr_list = NULL; +ipfr_t **ipfr_tail = &ipfr_list; -static ipfr_t *ipfr_natlist = NULL; -static ipfr_t **ipfr_nattail = &ipfr_natlist; -static ipfr_t **ipfr_nattab; +ipfr_t *ipfr_natlist = NULL; +ipfr_t **ipfr_nattail = &ipfr_natlist; -static ipfr_t *ipfr_ipidlist = NULL; -static ipfr_t **ipfr_ipidtail = &ipfr_ipidlist; +ipfr_t *ipfr_ipidlist = NULL; +ipfr_t **ipfr_ipidtail = &ipfr_ipidlist; + +static ipfr_t **ipfr_heads; +static ipfr_t **ipfr_nattab; static ipfr_t **ipfr_ipidtab; static ipfrstat_t ipfr_stats; @@ -129,6 +130,7 @@ u_long fr_ticks = 0; static ipfr_t *ipfr_newfrag __P((fr_info_t *, u_32_t, ipfr_t **)); static ipfr_t *fr_fraglookup __P((fr_info_t *, ipfr_t **)); static void fr_fragdelete __P((ipfr_t *, ipfr_t ***)); +static void fr_fragfree __P((ipfr_t *)); /* ------------------------------------------------------------------------ */ @@ -305,6 +307,7 @@ ipfr_t *table[]; fra->ipfr_seen0 = 1; fra->ipfr_off = off + (fin->fin_dlen >> 3); fra->ipfr_pass = pass; + fra->ipfr_ref = 1; ipfr_stats.ifs_new++; ipfr_inuse++; return fra; @@ -685,11 +688,6 @@ void *ptr; static void fr_fragdelete(fra, tail) ipfr_t *fra, ***tail; { - frentry_t *fr; - - fr = fra->ipfr_rule; - if (fr != NULL) - (void)fr_derefrule(&fr); if (fra->ipfr_next) fra->ipfr_next->ipfr_prev = fra->ipfr_prev; @@ -700,7 +698,30 @@ ipfr_t *fra, ***tail; if (fra->ipfr_hnext) fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev; *fra->ipfr_hprev = fra->ipfr_hnext; + + if (fra->ipfr_rule != NULL) { + (void) fr_derefrule(&fra->ipfr_rule); + } + + if (fra->ipfr_ref <= 0) + fr_fragfree(fra); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_fragfree */ +/* Returns: Nil */ +/* Parameters: fra - pointer to frag structure to free */ +/* */ +/* Take care of the details associated with deleting an entry from the frag */ +/* cache. Currently this just means bumping stats correctly after freeing */ +/* ------------------------------------------------------------------------ */ +static void fr_fragfree(fra) +ipfr_t *fra; +{ KFREE(fra); + ipfr_stats.ifs_expire++; + ipfr_inuse--; } @@ -718,8 +739,10 @@ void fr_fragclear() nat_t *nat; WRITE_ENTER(&ipf_frag); - while ((fra = ipfr_list) != NULL) + while ((fra = ipfr_list) != NULL) { + fra->ipfr_ref--; fr_fragdelete(fra, &ipfr_tail); + } ipfr_tail = &ipfr_list; RWLOCK_EXIT(&ipf_frag); @@ -731,6 +754,7 @@ void fr_fragclear() if (nat->nat_data == fra) nat->nat_data = NULL; } + fra->ipfr_ref--; fr_fragdelete(fra, &ipfr_nattail); } ipfr_nattail = &ipfr_natlist; @@ -764,9 +788,8 @@ void fr_fragexpire() for (fp = &ipfr_list; ((fra = *fp) != NULL); ) { if (fra->ipfr_ttl > fr_ticks) break; + fra->ipfr_ref--; fr_fragdelete(fra, &ipfr_tail); - ipfr_stats.ifs_expire++; - ipfr_inuse--; } RWLOCK_EXIT(&ipf_frag); @@ -774,9 +797,8 @@ void fr_fragexpire() for (fp = &ipfr_ipidlist; ((fra = *fp) != NULL); ) { if (fra->ipfr_ttl > fr_ticks) break; + fra->ipfr_ref--; fr_fragdelete(fra, &ipfr_ipidtail); - ipfr_stats.ifs_expire++; - ipfr_inuse--; } RWLOCK_EXIT(&ipf_ipidfrag); @@ -786,23 +808,27 @@ void fr_fragexpire() * at the one to be free'd, NULL the reference from the NAT struct. * NOTE: We need to grab both mutex's early, and in this order so as * to prevent a deadlock if both try to expire at the same time. + * The extra if() statement here is because it locks out all NAT + * operations - no need to do that if there are no entries in this + * list, right? */ - WRITE_ENTER(&ipf_nat); - WRITE_ENTER(&ipf_natfrag); - for (fp = &ipfr_natlist; ((fra = *fp) != NULL); ) { - if (fra->ipfr_ttl > fr_ticks) - break; - nat = fra->ipfr_data; - if (nat != NULL) { - if (nat->nat_data == fra) - nat->nat_data = NULL; + if (ipfr_natlist != NULL) { + WRITE_ENTER(&ipf_nat); + WRITE_ENTER(&ipf_natfrag); + for (fp = &ipfr_natlist; ((fra = *fp) != NULL); ) { + if (fra->ipfr_ttl > fr_ticks) + break; + nat = fra->ipfr_data; + if (nat != NULL) { + if (nat->nat_data == fra) + nat->nat_data = NULL; + } + fra->ipfr_ref--; + fr_fragdelete(fra, &ipfr_nattail); } - fr_fragdelete(fra, &ipfr_nattail); - ipfr_stats.ifs_expire++; - ipfr_inuse--; + RWLOCK_EXIT(&ipf_natfrag); + RWLOCK_EXIT(&ipf_nat); } - RWLOCK_EXIT(&ipf_natfrag); - RWLOCK_EXIT(&ipf_nat); SPL_X(s); } @@ -825,6 +851,7 @@ int fr_slowtimer() { READ_ENTER(&ipf_global); + ipf_expiretokens(); fr_fragexpire(); fr_timeoutstate(); fr_natexpire(); @@ -858,3 +885,106 @@ done: # endif } #endif /* !SOLARIS && !defined(__hpux) && !defined(__sgi) */ + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_nextfrag */ +/* Returns: int - 0 == success, else error */ +/* Parameters: token(I) - pointer to token information for this caller */ +/* itp(I) - pointer to generic iterator from caller */ +/* top(I) - top of the fragment list */ +/* tail(I) - tail of the fragment list */ +/* lock(I) - fragment cache lock */ +/* */ +/* This function is used to interate through the list of entries in the */ +/* fragment cache. It increases the reference count on the one currently */ +/* being returned so that the caller can come back and resume from it later.*/ +/* */ +/* This function is used for both the NAT fragment cache as well as the ipf */ +/* fragment cache - hence the reason for passing in top, tail and lock. */ +/* ------------------------------------------------------------------------ */ +int fr_nextfrag(token, itp, top, tail +#ifdef USE_MUTEXES +, lock +#endif +) +ipftoken_t *token; +ipfgeniter_t *itp; +ipfr_t **top, ***tail; +#ifdef USE_MUTEXES +ipfrwlock_t *lock; +#endif +{ + ipfr_t *frag, *next, zero; + int error = 0; + + frag = token->ipt_data; + if (frag == (ipfr_t *)-1) { + ipf_freetoken(token); + return ESRCH; + } + + READ_ENTER(lock); + if (frag == NULL) + next = *top; + else + next = frag->ipfr_next; + + if (next != NULL) { + ATOMIC_INC(next->ipfr_ref); + token->ipt_data = next; + } else { + bzero(&zero, sizeof(zero)); + next = &zero; + token->ipt_data = (void *)-1; + } + RWLOCK_EXIT(lock); + + if (frag != NULL) { + WRITE_ENTER(lock); + frag->ipfr_ref--; + if (frag->ipfr_ref <= 0) + fr_fragfree(frag); + RWLOCK_EXIT(lock); + } + + error = COPYOUT(next, itp->igi_data, sizeof(*next)); + if (error != 0) + error = EFAULT; + + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_fragderef */ +/* Returns: Nil */ +/* Parameters: frp(IO) - pointer to fragment structure to deference */ +/* lock(I) - lock associated with the fragment */ +/* */ +/* This function dereferences a fragment structure (ipfr_t). The pointer */ +/* passed in will always be reset back to NULL, even if the structure is */ +/* not freed, to enforce the notion that the caller is no longer entitled */ +/* to use the pointer it is dropping the reference to. */ +/* ------------------------------------------------------------------------ */ +void fr_fragderef(frp +#ifdef USE_MUTEXES +, lock +#endif +) +ipfr_t **frp; +#ifdef USE_MUTEXES +ipfrwlock_t *lock; +#endif +{ + ipfr_t *fra; + + fra = *frp; + *frp = NULL; + + WRITE_ENTER(lock); + fra->ipfr_ref--; + if (fra->ipfr_ref <= 0) + fr_fragfree(fra); + RWLOCK_EXIT(lock); +} diff --git a/sys/contrib/ipfilter/netinet/ip_frag.h b/sys/contrib/ipfilter/netinet/ip_frag.h index 07b841c..d3e89005 100644 --- a/sys/contrib/ipfilter/netinet/ip_frag.h +++ b/sys/contrib/ipfilter/netinet/ip_frag.h @@ -4,7 +4,7 @@ * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ip_frag.h 1.5 3/24/96 - * $Id: ip_frag.h,v 2.23.2.2 2005/06/10 18:02:37 darrenr Exp $ + * $Id: ip_frag.h,v 2.23.2.5 2006/12/23 11:11:47 darrenr Exp $ */ #ifndef __IP_FRAG_H__ @@ -16,6 +16,16 @@ typedef struct ipfr { struct ipfr *ipfr_hnext, **ipfr_hprev; struct ipfr *ipfr_next, **ipfr_prev; void *ipfr_data; + frentry_t *ipfr_rule; + u_long ipfr_ttl; + int ipfr_ref; + u_short ipfr_off; + u_short ipfr_seen0; + /* + * All of the fields, from ipfr_ifp to ipfr_pass, are compared + * using bcmp to see if an identical entry is present. It is + * therefore important for this set to remain together. + */ void *ipfr_ifp; struct in_addr ipfr_src; struct in_addr ipfr_dst; @@ -26,10 +36,6 @@ typedef struct ipfr { u_char ipfr_p; u_char ipfr_tos; u_32_t ipfr_pass; - u_short ipfr_off; - u_char ipfr_ttl; - u_char ipfr_seen0; - frentry_t *ipfr_rule; } ipfr_t; @@ -49,6 +55,8 @@ typedef struct ipfrstat { #define IPFR_CMPSZ (offsetof(ipfr_t, ipfr_pass) - \ offsetof(ipfr_t, ipfr_ifp)) +extern ipfr_t *ipfr_list, **ipfr_tail; +extern ipfr_t *ipfr_natlist, **ipfr_nattail; extern int ipfr_size; extern int fr_ipfrttl; extern int fr_frag_lock; @@ -64,6 +72,15 @@ extern nat_t *fr_nat_knownfrag __P((fr_info_t *)); extern int fr_ipid_newfrag __P((fr_info_t *, u_32_t)); extern u_32_t fr_ipid_knownfrag __P((fr_info_t *)); +#ifdef USE_MUTEXES +extern void fr_fragderef __P((ipfr_t **, ipfrwlock_t *)); +extern int fr_nextfrag __P((ipftoken_t *, ipfgeniter_t *, ipfr_t **, \ + ipfr_t ***, ipfrwlock_t *)); +#else +extern void fr_fragderef __P((ipfr_t **)); +extern int fr_nextfrag __P((ipftoken_t *, ipfgeniter_t *, ipfr_t **, \ + ipfr_t ***)); +#endif extern void fr_forget __P((void *)); extern void fr_forgetnat __P((void *)); diff --git a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c index e72d6fe..c352027 100644 --- a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c @@ -6,7 +6,7 @@ * Simple FTP transparent proxy for in-kernel use. For use with the NAT * code. * - * $Id: ip_ftp_pxy.c,v 2.88.2.19 2006/04/01 10:14:53 darrenr Exp $ + * $Id: ip_ftp_pxy.c,v 2.88.2.22 2007/05/10 09:30:39 darrenr Exp $ */ #define IPF_FTP_PROXY @@ -368,24 +368,11 @@ int dlen; } (void) fr_addstate(&fi, NULL, SI_W_DPORT); if (fi.fin_state != NULL) - fr_statederef(&fi, (ipstate_t **)&fi.fin_state); + fr_statederef((ipstate_t **)&fi.fin_state); } ip->ip_len = slen; ip->ip_src = swip; ip->ip_dst = swip2; - } else { - ipstate_t *is; - - nat_update(&fi, nat2, nat->nat_ptr); - READ_ENTER(&ipf_state); - is = nat2->nat_state; - if (is != NULL) { - MUTEX_ENTER(&is->is_lock); - (void)fr_tcp_age(&is->is_sti, &fi, ips_tqtqb, - is->is_flags); - MUTEX_EXIT(&is->is_lock); - } - RWLOCK_EXIT(&ipf_state); } return APR_INC(inc); } @@ -730,25 +717,12 @@ u_int data_ip; } (void) fr_addstate(&fi, NULL, sflags); if (fi.fin_state != NULL) - fr_statederef(&fi, (ipstate_t **)&fi.fin_state); + fr_statederef((ipstate_t **)&fi.fin_state); } ip->ip_len = slen; ip->ip_src = swip; ip->ip_dst = swip2; - } else { - ipstate_t *is; - - nat_update(&fi, nat2, nat->nat_ptr); - READ_ENTER(&ipf_state); - is = nat2->nat_state; - if (is != NULL) { - MUTEX_ENTER(&is->is_lock); - (void)fr_tcp_age(&is->is_sti, &fi, ips_tqtqb, - is->is_flags); - MUTEX_EXIT(&is->is_lock); - } - RWLOCK_EXIT(&ipf_state); } return inc; } @@ -1141,8 +1115,8 @@ int rv; f->ftps_seq[1] = thseq + 1 - seqoff; } else { if (ippr_ftp_debug > 1) { - printf("FIN: thseq %x seqoff %d ftps_seq %x\n", - thseq, seqoff, f->ftps_seq[0]); + printf("FIN: thseq %x seqoff %d ftps_seq %x %x\n", + thseq, seqoff, f->ftps_seq[0], f->ftps_seq[1]); } return APR_ERR(1); } diff --git a/sys/contrib/ipfilter/netinet/ip_htable.c b/sys/contrib/ipfilter/netinet/ip_htable.c index 92ed8d5..e5a0ad2 100644 --- a/sys/contrib/ipfilter/netinet/ip_htable.c +++ b/sys/contrib/ipfilter/netinet/ip_htable.c @@ -51,7 +51,7 @@ struct file; /* END OF INCLUDES */ #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_htable.c,v 2.34.2.4 2005/11/13 15:38:37 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_htable.c,v 2.34.2.9 2007/02/02 23:06:16 darrenr Exp $"; #endif #ifdef IPFILTER_LOOKUP @@ -101,30 +101,36 @@ iplookupop_t *op; char name[FR_GROUPLEN]; int err, i, unit; - KMALLOC(iph, iphtable_t *); - if (iph == NULL) { - ipht_nomem[op->iplo_unit]++; - return ENOMEM; - } + unit = op->iplo_unit; + if ((op->iplo_arg & IPHASH_ANON) == 0) + iph = fr_existshtable(unit, op->iplo_name); + else + iph = NULL; - err = COPYIN(op->iplo_struct, iph, sizeof(*iph)); - if (err != 0) { - KFREE(iph); - return EFAULT; + if (iph == NULL) { + KMALLOC(iph, iphtable_t *); + if (iph == NULL) { + ipht_nomem[op->iplo_unit]++; + return ENOMEM; + } + err = COPYIN(op->iplo_struct, iph, sizeof(*iph)); + if (err != 0) { + KFREE(iph); + return EFAULT; + } + } else { + if ((iph->iph_flags & IPHASH_DELETE) == 0) + return EEXIST; } - unit = op->iplo_unit; if (iph->iph_unit != unit) { - KFREE(iph); + if ((iph->iph_flags & IPHASH_DELETE) == 0) { + KFREE(iph); + } return EINVAL; } - if ((op->iplo_arg & IPHASH_ANON) == 0) { - if (fr_findhtable(op->iplo_unit, op->iplo_name) != NULL) { - KFREE(iph); - return EEXIST; - } - } else { + if ((op->iplo_arg & IPHASH_ANON) != 0) { i = IPHASH_ANON; do { i++; @@ -145,24 +151,33 @@ iplookupop_t *op; iph->iph_type |= IPHASH_ANON; } - KMALLOCS(iph->iph_table, iphtent_t **, - iph->iph_size * sizeof(*iph->iph_table)); - if (iph->iph_table == NULL) { - KFREE(iph); - ipht_nomem[unit]++; - return ENOMEM; - } + if ((iph->iph_flags & IPHASH_DELETE) == 0) { + KMALLOCS(iph->iph_table, iphtent_t **, + iph->iph_size * sizeof(*iph->iph_table)); + if (iph->iph_table == NULL) { + if ((iph->iph_flags & IPHASH_DELETE) == 0) { + KFREE(iph); + } + ipht_nomem[unit]++; + return ENOMEM; + } - bzero((char *)iph->iph_table, iph->iph_size * sizeof(*iph->iph_table)); - iph->iph_masks = 0; + bzero((char *)iph->iph_table, + iph->iph_size * sizeof(*iph->iph_table)); + iph->iph_masks = 0; + iph->iph_list = NULL; - iph->iph_next = ipf_htables[unit]; - iph->iph_pnext = &ipf_htables[unit]; - if (ipf_htables[unit] != NULL) - ipf_htables[unit]->iph_pnext = &iph->iph_next; - ipf_htables[unit] = iph; + iph->iph_ref = 1; + iph->iph_next = ipf_htables[unit]; + iph->iph_pnext = &ipf_htables[unit]; + if (ipf_htables[unit] != NULL) + ipf_htables[unit]->iph_pnext = &iph->iph_next; + ipf_htables[unit] = iph; - ipf_nhtables[unit]++; + ipf_nhtables[unit]++; + } + + iph->iph_flags &= ~IPHASH_DELETE; return 0; } @@ -170,22 +185,24 @@ iplookupop_t *op; /* */ -int fr_removehtable(op) -iplookupop_t *op; +int fr_removehtable(unit, name) +int unit; +char *name; { iphtable_t *iph; - - iph = fr_findhtable(op->iplo_unit, op->iplo_name); + iph = fr_findhtable(unit, name); if (iph == NULL) return ESRCH; - if (iph->iph_unit != op->iplo_unit) { + if (iph->iph_unit != unit) { return EINVAL; } if (iph->iph_ref != 0) { - return EBUSY; + (void) fr_clearhtable(iph); + iph->iph_flags |= IPHASH_DELETE; + return 0; } fr_delhtable(iph); @@ -194,40 +211,106 @@ iplookupop_t *op; } -void fr_delhtable(iph) +int fr_clearhtable(iph) iphtable_t *iph; { iphtent_t *ipe; - int i; - for (i = 0; i < iph->iph_size; i++) - while ((ipe = iph->iph_table[i]) != NULL) - if (fr_delhtent(iph, ipe) != 0) - return; + while ((ipe = iph->iph_list) != NULL) + if (fr_delhtent(iph, ipe) != 0) + return 1; + return 0; +} + - *iph->iph_pnext = iph->iph_next; +int fr_delhtable(iph) +iphtable_t *iph; +{ + + if (fr_clearhtable(iph) != 0) + return 1; + + if (iph->iph_pnext != NULL) + *iph->iph_pnext = iph->iph_next; if (iph->iph_next != NULL) iph->iph_next->iph_pnext = iph->iph_pnext; ipf_nhtables[iph->iph_unit]--; + return fr_derefhtable(iph); +} + + +/* + * Delete an entry from a hash table. + */ +int fr_delhtent(iph, ipe) +iphtable_t *iph; +iphtent_t *ipe; +{ + + if (ipe->ipe_phnext != NULL) + *ipe->ipe_phnext = ipe->ipe_hnext; + if (ipe->ipe_hnext != NULL) + ipe->ipe_hnext->ipe_phnext = ipe->ipe_phnext; + + if (ipe->ipe_pnext != NULL) + *ipe->ipe_pnext = ipe->ipe_next; + if (ipe->ipe_next != NULL) + ipe->ipe_next->ipe_pnext = ipe->ipe_pnext; + + switch (iph->iph_type & ~IPHASH_ANON) + { + case IPHASH_GROUPMAP : + if (ipe->ipe_group != NULL) + fr_delgroup(ipe->ipe_group, IPL_LOGIPF, fr_active); + break; + + default : + ipe->ipe_ptr = NULL; + ipe->ipe_value = 0; + break; + } + + return fr_derefhtent(ipe); +} + + +int fr_derefhtable(iph) +iphtable_t *iph; +{ + int refs; + + iph->iph_ref--; + refs = iph->iph_ref; + if (iph->iph_ref == 0) { KFREES(iph->iph_table, iph->iph_size * sizeof(*iph->iph_table)); KFREE(iph); } + + return refs; } -void fr_derefhtable(iph) -iphtable_t *iph; +int fr_derefhtent(ipe) +iphtent_t *ipe; { - iph->iph_ref--; - if (iph->iph_ref == 0) - fr_delhtable(iph); + + ipe->ipe_ref--; + if (ipe->ipe_ref == 0) { + ipf_nhtnodes[ipe->ipe_unit]--; + + KFREE(ipe); + + return 0; + } + + return ipe->ipe_ref; } -iphtable_t *fr_findhtable(unit, name) +iphtable_t *fr_existshtable(unit, name) int unit; char *name; { @@ -240,6 +323,20 @@ char *name; } +iphtable_t *fr_findhtable(unit, name) +int unit; +char *name; +{ + iphtable_t *iph; + + iph = fr_existshtable(unit, name); + if ((iph != NULL) && (iph->iph_flags & IPHASH_DELETE) == 0) + return iph; + + return NULL; +} + + size_t fr_flushhtable(op) iplookupflush_t *op; { @@ -252,8 +349,11 @@ iplookupflush_t *op; for (i = 0; i <= IPL_LOGMAX; i++) { if (op->iplf_unit == i || op->iplf_unit == IPL_LOGALL) { while ((iph = ipf_htables[i]) != NULL) { - fr_delhtable(iph); - freed++; + if (fr_delhtable(iph) == 0) { + freed++; + } else { + iph->iph_flags |= IPHASH_DELETE; + } } } } @@ -285,13 +385,20 @@ iphtent_t *ipeo; hv = IPE_HASH_FN(ipe->ipe_addr.in4_addr, ipe->ipe_mask.in4_addr, iph->iph_size); - ipe->ipe_ref = 0; - ipe->ipe_next = iph->iph_table[hv]; - ipe->ipe_pnext = iph->iph_table + hv; + ipe->ipe_ref = 1; + ipe->ipe_hnext = iph->iph_table[hv]; + ipe->ipe_phnext = iph->iph_table + hv; if (iph->iph_table[hv] != NULL) - iph->iph_table[hv]->ipe_pnext = &ipe->ipe_next; + iph->iph_table[hv]->ipe_phnext = &ipe->ipe_hnext; iph->iph_table[hv] = ipe; + + ipe->ipe_next = iph->iph_list; + ipe->ipe_pnext = &iph->iph_list; + if (ipe->ipe_next != NULL) + ipe->ipe_next->ipe_pnext = &ipe->ipe_next; + iph->iph_list = ipe; + if ((bits >= 0) && (bits != 32)) iph->iph_masks |= 1 << bits; @@ -309,44 +416,8 @@ iphtent_t *ipeo; break; } - ipf_nhtnodes[iph->iph_unit]++; - - return 0; -} - - -/* - * Delete an entry from a hash table. - */ -int fr_delhtent(iph, ipe) -iphtable_t *iph; -iphtent_t *ipe; -{ - - if (ipe->ipe_ref != 0) - return EBUSY; - - - *ipe->ipe_pnext = ipe->ipe_next; - if (ipe->ipe_next != NULL) - ipe->ipe_next->ipe_pnext = ipe->ipe_pnext; - - switch (iph->iph_type & ~IPHASH_ANON) - { - case IPHASH_GROUPMAP : - if (ipe->ipe_group != NULL) - fr_delgroup(ipe->ipe_group, IPL_LOGIPF, fr_active); - break; - - default : - ipe->ipe_ptr = NULL; - ipe->ipe_value = 0; - break; - } - - KFREE(ipe); - - ipf_nhtnodes[iph->iph_unit]--; + ipe->ipe_unit = iph->iph_unit; + ipf_nhtnodes[ipe->ipe_unit]++; return 0; } @@ -377,22 +448,22 @@ void *tptr, *aptr; /* ------------------------------------------------------------------------ */ /* Function: fr_iphmfindip */ /* Returns: int - 0 == +ve match, -1 == error, 1 == -ve/no match */ -/* Parameters: tptr(I) - pointer to the pool to search */ -/* version(I) - IP protocol version (4 or 6) */ -/* aptr(I) - pointer to address information */ +/* Parameters: tptr(I) - pointer to the pool to search */ +/* ipversion(I) - IP protocol version (4 or 6) */ +/* aptr(I) - pointer to address information */ /* */ /* Search the hash table for a given address and return a search result. */ /* ------------------------------------------------------------------------ */ -int fr_iphmfindip(tptr, version, aptr) +int fr_iphmfindip(tptr, ipversion, aptr) void *tptr, *aptr; -int version; +int ipversion; { struct in_addr *addr; iphtable_t *iph; iphtent_t *ipe; int rval; - if (version != 4) + if (ipversion != 4) return -1; if (tptr == NULL || aptr == NULL) @@ -426,7 +497,7 @@ struct in_addr *addr; maskloop: ips = ntohl(addr->s_addr) & msk; hv = IPE_HASH_FN(ips, msk, iph->iph_size); - for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_next) { + for (ipe = iph->iph_table[hv]; (ipe != NULL); ipe = ipe->ipe_hnext) { if (ipe->ipe_mask.in4_addr != msk || ipe->ipe_addr.in4_addr != ips) { continue; @@ -449,4 +520,133 @@ maskloop: return ipe; } + +int fr_htable_getnext(token, ilp) +ipftoken_t *token; +ipflookupiter_t *ilp; +{ + iphtent_t *node, zn, *nextnode; + iphtable_t *iph, zp, *nextiph; + int err; + + err = 0; + iph = NULL; + node = NULL; + nextiph = NULL; + nextnode = NULL; + + READ_ENTER(&ip_poolrw); + + switch (ilp->ili_otype) + { + case IPFLOOKUPITER_LIST : + iph = token->ipt_data; + if (iph == NULL) { + nextiph = ipf_htables[(int)ilp->ili_unit]; + } else { + nextiph = iph->iph_next; + } + + if (nextiph != NULL) { + ATOMIC_INC(nextiph->iph_ref); + if (nextiph->iph_next == NULL) + token->ipt_alive = 0; + } else { + bzero((char *)&zp, sizeof(zp)); + nextiph = &zp; + } + break; + + case IPFLOOKUPITER_NODE : + node = token->ipt_data; + if (node == NULL) { + iph = fr_findhtable(ilp->ili_unit, ilp->ili_name); + if (iph == NULL) + err = ESRCH; + else { + nextnode = iph->iph_list; + } + } else { + nextnode = node->ipe_next; + } + + if (nextnode != NULL) { + ATOMIC_INC(nextnode->ipe_ref); + if (nextnode->ipe_next == NULL) + token->ipt_alive = 0; + } else { + bzero((char *)&zn, sizeof(zn)); + nextnode = &zn; + } + break; + default : + err = EINVAL; + break; + } + + RWLOCK_EXIT(&ip_poolrw); + if (err != 0) + return err; + + switch (ilp->ili_otype) + { + case IPFLOOKUPITER_LIST : + if (iph != NULL) { + WRITE_ENTER(&ip_poolrw); + fr_derefhtable(iph); + RWLOCK_EXIT(&ip_poolrw); + } + token->ipt_data = nextiph; + err = COPYOUT(nextiph, ilp->ili_data, sizeof(*nextiph)); + if (err != 0) + err = EFAULT; + break; + + case IPFLOOKUPITER_NODE : + if (node != NULL) { + WRITE_ENTER(&ip_poolrw); + fr_derefhtent(node); + RWLOCK_EXIT(&ip_poolrw); + } + token->ipt_data = nextnode; + err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode)); + if (err != 0) + err = EFAULT; + break; + } + + return err; +} + + +void fr_htable_iterderef(otype, unit, data) +u_int otype; +int unit; +void *data; +{ + + if (data == NULL) + return; + + if (unit < 0 || unit > IPL_LOGMAX) + return; + + switch (otype) + { + case IPFLOOKUPITER_LIST : + WRITE_ENTER(&ip_poolrw); + fr_derefhtable((iphtable_t *)data); + RWLOCK_EXIT(&ip_poolrw); + break; + + case IPFLOOKUPITER_NODE : + WRITE_ENTER(&ip_poolrw); + fr_derefhtent((iphtent_t *)data); + RWLOCK_EXIT(&ip_poolrw); + break; + default : + break; + } +} + #endif /* IPFILTER_LOOKUP */ diff --git a/sys/contrib/ipfilter/netinet/ip_htable.h b/sys/contrib/ipfilter/netinet/ip_htable.h index ebee58d..2c08812 100644 --- a/sys/contrib/ipfilter/netinet/ip_htable.h +++ b/sys/contrib/ipfilter/netinet/ip_htable.h @@ -5,10 +5,12 @@ typedef struct iphtent_s { struct iphtent_s *ipe_next, **ipe_pnext; + struct iphtent_s *ipe_hnext, **ipe_phnext; void *ipe_ptr; i6addr_t ipe_addr; i6addr_t ipe_mask; int ipe_ref; + int ipe_unit; union { char ipeu_char[16]; u_long ipeu_long; @@ -26,6 +28,7 @@ typedef struct iphtable_s { ipfrwlock_t iph_rwlock; struct iphtable_s *iph_next, **iph_pnext; struct iphtent_s **iph_table; + struct iphtent_s *iph_list; size_t iph_size; /* size of hash table */ u_long iph_seed; /* hashing seed */ u_32_t iph_flags; @@ -39,6 +42,7 @@ typedef struct iphtable_s { /* iph_type */ #define IPHASH_LOOKUP 0 #define IPHASH_GROUPMAP 1 +#define IPHASH_DELETE 2 #define IPHASH_ANON 0x80000000 @@ -53,17 +57,22 @@ typedef struct iphtstat_s { extern iphtable_t *ipf_htables[IPL_LOGSIZE]; +extern iphtable_t *fr_existshtable __P((int, char *)); +extern int fr_clearhtable __P((iphtable_t *)); extern void fr_htable_unload __P((void)); extern int fr_newhtable __P((iplookupop_t *)); extern iphtable_t *fr_findhtable __P((int, char *)); -extern int fr_removehtable __P((iplookupop_t *)); +extern int fr_removehtable __P((int, char *)); extern size_t fr_flushhtable __P((iplookupflush_t *)); extern int fr_addhtent __P((iphtable_t *, iphtent_t *)); extern int fr_delhtent __P((iphtable_t *, iphtent_t *)); -extern void fr_derefhtable __P((iphtable_t *)); -extern void fr_delhtable __P((iphtable_t *)); +extern int fr_derefhtable __P((iphtable_t *)); +extern int fr_derefhtent __P((iphtent_t *)); +extern int fr_delhtable __P((iphtable_t *)); extern void *fr_iphmfindgroup __P((void *, void *)); extern int fr_iphmfindip __P((void *, int, void *)); extern int fr_gethtablestat __P((iplookupop_t *)); +extern int fr_htable_getnext __P((ipftoken_t *, ipflookupiter_t *)); +extern void fr_htable_iterderef __P((u_int, int, void *)); #endif /* __IP_HTABLE_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c b/sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c index 93cf070..e88a6b9 100644 --- a/sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_ipsec_pxy.c @@ -6,7 +6,7 @@ * Simple ISAKMP transparent proxy for in-kernel use. For use with the NAT * code. * - * $Id: ip_ipsec_pxy.c,v 2.20.2.7 2005/08/20 13:48:22 darrenr Exp $ + * $Id: ip_ipsec_pxy.c,v 2.20.2.8 2006/07/14 06:12:14 darrenr Exp $ * */ #define IPF_IPSEC_PROXY @@ -177,7 +177,7 @@ nat_t *nat; ipsec->ipsc_state = fr_addstate(&fi, &ipsec->ipsc_state, SI_WILDP); if (fi.fin_state != NULL) - fr_statederef(&fi, (ipstate_t **)&fi.fin_state); + fr_statederef((ipstate_t **)&fi.fin_state); } ip->ip_p = p & 0xff; return 0; @@ -256,7 +256,7 @@ nat_t *nat; &ipsec->ipsc_state, SI_WILDP); if (fi.fin_state != NULL) - fr_statederef(&fi, (ipstate_t **)&fi.fin_state); + fr_statederef((ipstate_t **)&fi.fin_state); } ip->ip_p = p; } diff --git a/sys/contrib/ipfilter/netinet/ip_irc_pxy.c b/sys/contrib/ipfilter/netinet/ip_irc_pxy.c index 0aa5710..5bb252a 100644 --- a/sys/contrib/ipfilter/netinet/ip_irc_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_irc_pxy.c @@ -3,7 +3,7 @@ * * See the IPFILTER.LICENCE file for details on licencing. * - * $Id: ip_irc_pxy.c,v 2.39.2.5 2005/12/04 23:39:27 darrenr Exp $ + * $Id: ip_irc_pxy.c,v 2.39.2.6 2006/07/14 06:12:14 darrenr Exp $ */ #define IPF_IRC_PROXY @@ -415,7 +415,7 @@ nat_t *nat; (void) fr_addstate(&fi, NULL, SI_W_DPORT); if (fi.fin_state != NULL) - fr_statederef(&fi, (ipstate_t **)&fi.fin_state); + fr_statederef((ipstate_t **)&fi.fin_state); } ip->ip_src = swip; } diff --git a/sys/contrib/ipfilter/netinet/ip_log.c b/sys/contrib/ipfilter/netinet/ip_log.c index 5508557..2a0c72e 100644 --- a/sys/contrib/ipfilter/netinet/ip_log.c +++ b/sys/contrib/ipfilter/netinet/ip_log.c @@ -3,7 +3,7 @@ * * See the IPFILTER.LICENCE file for details on licencing. * - * $Id: ip_log.c,v 2.75.2.11 2006/03/26 13:50:47 darrenr Exp $ + * $Id: ip_log.c,v 2.75.2.15 2007/02/03 00:49:30 darrenr Exp $ */ #include #if defined(KERNEL) || defined(_KERNEL) @@ -14,7 +14,11 @@ #endif #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ defined(_KERNEL) -# include "opt_ipfilter_log.h" +# if (__NetBSD_Version__ < 399001400) +# include "opt_ipfilter_log.h" +# else +# include "opt_ipfilter.h" +# endif #endif #if defined(__FreeBSD__) && !defined(IPFILTER_LKM) # if defined(_KERNEL) @@ -147,7 +151,7 @@ extern int selwait; # if defined(linux) && defined(_KERNEL) wait_queue_head_t iplh_linux[IPL_LOGSIZE]; # endif -# if SOLARIS +# if SOLARIS && defined(_KERNEL) extern kcondvar_t iplwait; extern struct pollhead iplpollhead[IPL_LOGSIZE]; # endif @@ -156,7 +160,6 @@ iplog_t **iplh[IPL_LOGSIZE], *iplt[IPL_LOGSIZE], *ipll[IPL_LOGSIZE]; int iplused[IPL_LOGSIZE]; static fr_info_t iplcrc[IPL_LOGSIZE]; int ipl_suppress = 1; -int ipl_buffer_sz; int ipl_logmax = IPL_LOGMAX; int ipl_logall = 0; int ipl_log_init = 0; @@ -259,8 +262,11 @@ u_int flags; struct ifnet *ifp; # endif /* SOLARIS || __hpux */ - ipfl.fl_nattag.ipt_num[0] = 0; m = fin->fin_m; + if (m == NULL) + return -1; + + ipfl.fl_nattag.ipt_num[0] = 0; ifp = fin->fin_ifp; hlen = fin->fin_hlen; /* diff --git a/sys/contrib/ipfilter/netinet/ip_lookup.c b/sys/contrib/ipfilter/netinet/ip_lookup.c index 3c7eb5f..12b1f4a 100644 --- a/sys/contrib/ipfilter/netinet/ip_lookup.c +++ b/sys/contrib/ipfilter/netinet/ip_lookup.c @@ -34,9 +34,6 @@ struct file; #endif #include #if (defined(__osf__) || defined(AIX) || defined(__hpux) || defined(__sgi)) && defined(_KERNEL) -# ifdef __osf__ -# include -# endif # include "radix_ipf_local.h" # define _RADIX_H_ #endif @@ -61,7 +58,7 @@ struct file; /* END OF INCLUDES */ #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_lookup.c,v 2.35.2.8 2005/11/13 15:35:45 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_lookup.c,v 2.35.2.15 2007/05/26 13:05:13 darrenr Exp $"; #endif #ifdef IPFILTER_LOOKUP @@ -129,10 +126,11 @@ void ip_lookup_unload() /* involves just calling another function to handle the specifics of each */ /* command. */ /* ------------------------------------------------------------------------ */ -int ip_lookup_ioctl(data, cmd, mode) +int ip_lookup_ioctl(data, cmd, mode, uid, ctx) caddr_t data; ioctlcmd_t cmd; -int mode; +int mode, uid; +void *ctx; { int err; SPL_INT(s); @@ -182,6 +180,10 @@ int mode; RWLOCK_EXIT(&ip_poolrw); break; + case SIOCLOOKUPITER : + err = ip_lookup_iterate(data, uid, ctx); + break; + default : err = EINVAL; break; @@ -210,8 +212,13 @@ caddr_t data; ip_pool_t *p; int err; - err = 0; - BCOPYIN(data, &op, sizeof(op)); + err = BCOPYIN(data, &op, sizeof(op)); + if (err != 0) + return EFAULT; + + if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) + return EINVAL; + op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; switch (op.iplo_type) @@ -283,6 +290,9 @@ caddr_t data; err = 0; BCOPYIN(data, &op, sizeof(op)); + if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) + return EINVAL; + op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; switch (op.iplo_type) @@ -341,8 +351,12 @@ caddr_t data; iplookupop_t op; int err; - err = 0; - BCOPYIN(data, &op, sizeof(op)); + err = BCOPYIN(data, &op, sizeof(op)); + if (err != 0) + return EFAULT; + + if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) + return EINVAL; op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; @@ -371,8 +385,10 @@ caddr_t data; * For anonymous pools, copy back the operation struct because in the * case of success it will contain the new table's name. */ - if ((err == 0) && ((op.iplo_arg & IPOOL_ANON) != 0)) { - BCOPYOUT(&op, data, sizeof(op)); + if ((err == 0) && ((op.iplo_arg & LOOKUP_ANON) != 0)) { + err = BCOPYOUT(&op, data, sizeof(op)); + if (err != 0) + err = EFAULT; } return err; @@ -393,11 +409,14 @@ caddr_t data; iplookupop_t op; int err; - BCOPYIN(data, &op, sizeof(op)); - op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; + err = BCOPYIN(data, &op, sizeof(op)); + if (err != 0) + return EFAULT; - if (op.iplo_arg & IPLT_ANON) - op.iplo_arg &= IPLT_ANON; + if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) + return EINVAL; + + op.iplo_name[sizeof(op.iplo_name) - 1] = '\0'; /* * create a new pool - fail if one already exists with @@ -406,11 +425,11 @@ caddr_t data; switch (op.iplo_type) { case IPLT_POOL : - err = ip_pool_destroy(&op); + err = ip_pool_destroy(op.iplo_unit, op.iplo_name); break; case IPLT_HASH : - err = fr_removehtable(&op); + err = fr_removehtable(op.iplo_unit, op.iplo_name); break; default : @@ -434,8 +453,12 @@ caddr_t data; iplookupop_t op; int err; - err = 0; - BCOPYIN(data, &op, sizeof(op)); + err = BCOPYIN(data, &op, sizeof(op)); + if (err != 0) + return EFAULT; + + if (op.iplo_unit < 0 || op.iplo_unit > IPL_LOGMAX) + return EINVAL; switch (op.iplo_type) { @@ -469,15 +492,16 @@ caddr_t data; int err, unit, num, type; iplookupflush_t flush; - err = 0; - BCOPYIN(data, &flush, sizeof(flush)); - - flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0'; + err = BCOPYIN(data, &flush, sizeof(flush)); + if (err != 0) + return EFAULT; unit = flush.iplf_unit; if ((unit < 0 || unit > IPL_LOGMAX) && (unit != IPLT_ALL)) return EINVAL; + flush.iplf_name[sizeof(flush.iplf_name) - 1] = '\0'; + type = flush.iplf_type; err = EINVAL; num = 0; @@ -494,12 +518,23 @@ caddr_t data; if (err == 0) { flush.iplf_count = num; - err = COPYOUT(&flush, data, sizeof(flush)); + err = BCOPYOUT(&flush, data, sizeof(flush)); + if (err != 0) + err = EFAULT; } return err; } +/* ------------------------------------------------------------------------ */ +/* Function: ip_lookup_delref */ +/* Returns: void */ +/* Parameters: type(I) - table type to operate on */ +/* ptr(I) - pointer to object to remove reference for */ +/* */ +/* This function organises calling the correct deref function for a given */ +/* type of object being passed into it. */ +/* ------------------------------------------------------------------------ */ void ip_lookup_deref(type, ptr) int type; void *ptr; @@ -522,13 +557,102 @@ void *ptr; } +/* ------------------------------------------------------------------------ */ +/* Function: ip_lookup_iterate */ +/* Returns: int - 0 = success, else error */ +/* Parameters: data(I) - pointer to data from ioctl call */ +/* */ +/* Decodes ioctl request to step through either hash tables or pools. */ +/* ------------------------------------------------------------------------ */ +int ip_lookup_iterate(data, uid, ctx) +void *data; +int uid; +void *ctx; +{ + ipflookupiter_t iter; + ipftoken_t *token; + int err; + SPL_INT(s); + + err = fr_inobj(data, &iter, IPFOBJ_LOOKUPITER); + if (err != 0) + return err; + + if (iter.ili_unit < 0 || iter.ili_unit > IPL_LOGMAX) + return EINVAL; + + if (iter.ili_ival != IPFGENITER_LOOKUP) + return EINVAL; + + SPL_SCHED(s); + token = ipf_findtoken(iter.ili_key, uid, ctx); + if (token == NULL) { + RWLOCK_EXIT(&ipf_tokens); + SPL_X(s); + return ESRCH; + } + + switch (iter.ili_type) + { + case IPLT_POOL : + err = ip_pool_getnext(token, &iter); + break; + case IPLT_HASH : + err = fr_htable_getnext(token, &iter); + break; + default : + err = EINVAL; + break; + } + RWLOCK_EXIT(&ipf_tokens); + SPL_X(s); + + return err; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: iplookup_iterderef */ +/* Returns: int - 0 = success, else error */ +/* Parameters: data(I) - pointer to data from ioctl call */ +/* */ +/* Decodes ioctl request to remove a particular hash table or pool and */ +/* calls the relevant function to do the cleanup. */ +/* ------------------------------------------------------------------------ */ +void ip_lookup_iterderef(type, data) +u_32_t type; +void *data; +{ + iplookupiterkey_t key; + + key.ilik_key = type; + + if (key.ilik_unstr.ilik_ival != IPFGENITER_LOOKUP) + return; + + switch (key.ilik_unstr.ilik_type) + { + case IPLT_HASH : + fr_htable_iterderef((u_int)key.ilik_unstr.ilik_otype, + (int)key.ilik_unstr.ilik_unit, data); + break; + case IPLT_POOL : + ip_pool_iterderef((u_int)key.ilik_unstr.ilik_otype, + (int)key.ilik_unstr.ilik_unit, data); + break; + } +} + + + #else /* IPFILTER_LOOKUP */ /*ARGSUSED*/ -int ip_lookup_ioctl(data, cmd, mode) +int ip_lookup_ioctl(data, cmd, mode, uid, ctx) caddr_t data; ioctlcmd_t cmd; -int mode; +int mode, uid; +void *ctx; { return EIO; } diff --git a/sys/contrib/ipfilter/netinet/ip_lookup.h b/sys/contrib/ipfilter/netinet/ip_lookup.h index 953dde1..4b90655 100644 --- a/sys/contrib/ipfilter/netinet/ip_lookup.h +++ b/sys/contrib/ipfilter/netinet/ip_lookup.h @@ -33,6 +33,9 @@ typedef struct iplookupop { void *iplo_struct; } iplookupop_t; +#define LOOKUP_ANON 0x80000000 + + typedef struct iplookupflush { int iplf_type; /* IPLT_* */ int iplf_unit; /* IPL_LOG* */ @@ -55,9 +58,39 @@ typedef struct iplookuplink { #define IPLT_ANON 0x80000000 + +typedef union { + struct iplookupiterkey { + char ilik_ival; + u_char ilik_type; /* IPLT_* */ + u_char ilik_otype; + char ilik_unit; /* IPL_LOG* */ + } ilik_unstr; + u_32_t ilik_key; +} iplookupiterkey_t; + +typedef struct ipflookupiter { + int ili_nitems; + iplookupiterkey_t ili_lkey; + char ili_name[FR_GROUPLEN]; + void *ili_data; +} ipflookupiter_t; + +#define ili_key ili_lkey.ilik_key +#define ili_ival ili_lkey.ilik_unstr.ilik_ival +#define ili_unit ili_lkey.ilik_unstr.ilik_unit +#define ili_type ili_lkey.ilik_unstr.ilik_type +#define ili_otype ili_lkey.ilik_unstr.ilik_otype + +#define IPFLOOKUPITER_LIST 0 +#define IPFLOOKUPITER_NODE 1 + + extern int ip_lookup_init __P((void)); -extern int ip_lookup_ioctl __P((caddr_t, ioctlcmd_t, int)); +extern int ip_lookup_ioctl __P((caddr_t, ioctlcmd_t, int, int, void *)); extern void ip_lookup_unload __P((void)); extern void ip_lookup_deref __P((int, void *)); +extern int ip_lookup_iterate __P((void *, int, void *)); +extern void ip_lookup_iterderef __P((u_32_t, void *)); #endif /* __IP_LOOKUP_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_nat.c b/sys/contrib/ipfilter/netinet/ip_nat.c index af73ebf..554fbc8 100644 --- a/sys/contrib/ipfilter/netinet/ip_nat.c +++ b/sys/contrib/ipfilter/netinet/ip_nat.c @@ -14,9 +14,17 @@ #include #include #include +#if defined(_KERNEL) && defined(__NetBSD_Version__) && \ + (__NetBSD_Version__ >= 399002000) +# include +#endif #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ defined(_KERNEL) -# include "opt_ipfilter_log.h" +#if defined(__NetBSD_Version__) && (__NetBSD_Version__ < 399001400) +# include "opt_ipfilter_log.h" +# else +# include "opt_ipfilter.h" +# endif #endif #if !defined(_KERNEL) # include @@ -107,7 +115,7 @@ extern struct ifnet vpnif; #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.195.2.56 2006/04/01 10:15:34 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.195.2.87 2007/05/31 10:17:17 darrenr Exp $"; #endif @@ -145,14 +153,17 @@ u_int fr_nat_maxbucket = 0, fr_nat_maxbucket_reset = 1; u_32_t nat_masks = 0; u_32_t rdr_masks = 0; +u_long nat_last_force_flush = 0; ipnat_t **nat_rules = NULL; ipnat_t **rdr_rules = NULL; -hostmap_t **maptable = NULL; +hostmap_t **ipf_hm_maptable = NULL; +hostmap_t *ipf_hm_maplist = NULL; ipftq_t nat_tqb[IPF_TCP_NSTATES]; ipftq_t nat_udptq; ipftq_t nat_icmptq; ipftq_t nat_iptq; ipftq_t *nat_utqe = NULL; +int fr_nat_doflush = 0; #ifdef IPFILTER_LOG int nat_logging = 1; #else @@ -169,6 +180,7 @@ int fr_nat_init = 0; extern int pfil_delayed_copy; #endif +static int nat_flush_entry __P((void *)); static int nat_flushtable __P((void)); static int nat_clearlist __P((void)); static void nat_addnat __P((struct ipnat *)); @@ -179,13 +191,13 @@ static void nat_delnat __P((struct ipnat *)); static int fr_natgetent __P((caddr_t)); static int fr_natgetsz __P((caddr_t)); static int fr_natputent __P((caddr_t, int)); +static int nat_extraflush __P((int)); static void nat_tabmove __P((nat_t *)); static int nat_match __P((fr_info_t *, ipnat_t *)); static INLINE int nat_newmap __P((fr_info_t *, nat_t *, natinfo_t *)); static INLINE int nat_newrdr __P((fr_info_t *, nat_t *, natinfo_t *)); static hostmap_t *nat_hostmap __P((ipnat_t *, struct in_addr, struct in_addr, struct in_addr, u_32_t)); -static void nat_hostmapdel __P((struct hostmap *)); static int nat_icmpquerytype4 __P((int)); static int nat_siocaddnat __P((ipnat_t *, ipnat_t **, int)); static void nat_siocdelnat __P((ipnat_t *, ipnat_t **, int)); @@ -195,6 +207,8 @@ static int nat_resolverule __P((ipnat_t *)); static nat_t *fr_natclone __P((fr_info_t *, nat_t *)); static void nat_mssclamp __P((tcphdr_t *, u_32_t, fr_info_t *, u_short *)); static int nat_wildok __P((nat_t *, int, int, int, int)); +static int nat_getnext __P((ipftoken_t *, ipfgeniter_t *)); +static int nat_iterator __P((ipftoken_t *, ipfgeniter_t *)); /* ------------------------------------------------------------------------ */ @@ -232,11 +246,14 @@ int fr_natinit() else return -4; - KMALLOCS(maptable, hostmap_t **, sizeof(hostmap_t *) * ipf_hostmap_sz); - if (maptable != NULL) - bzero((char *)maptable, sizeof(hostmap_t *) * ipf_hostmap_sz); + KMALLOCS(ipf_hm_maptable, hostmap_t **, \ + sizeof(hostmap_t *) * ipf_hostmap_sz); + if (ipf_hm_maptable != NULL) + bzero((char *)ipf_hm_maptable, + sizeof(hostmap_t *) * ipf_hostmap_sz); else return -5; + ipf_hm_maplist = NULL; KMALLOCS(nat_stats.ns_bucketlen[0], u_long *, ipf_nattable_sz * sizeof(u_long)); @@ -436,7 +453,7 @@ u_32_t port; hv += src.s_addr; hv += dst.s_addr; hv %= HOSTMAP_SIZE; - for (hm = maptable[hv]; hm; hm = hm->hm_next) + for (hm = ipf_hm_maptable[hv]; hm; hm = hm->hm_next) if ((hm->hm_srcip.s_addr == src.s_addr) && (hm->hm_dstip.s_addr == dst.s_addr) && ((np == NULL) || (np == hm->hm_ipnat)) && @@ -450,11 +467,16 @@ u_32_t port; KMALLOC(hm, hostmap_t *); if (hm) { - hm->hm_next = maptable[hv]; - hm->hm_pnext = maptable + hv; - if (maptable[hv] != NULL) - maptable[hv]->hm_pnext = &hm->hm_next; - maptable[hv] = hm; + hm->hm_next = ipf_hm_maplist; + hm->hm_pnext = &ipf_hm_maplist; + if (ipf_hm_maplist != NULL) + ipf_hm_maplist->hm_pnext = &hm->hm_next; + ipf_hm_maplist = hm; + hm->hm_hnext = ipf_hm_maptable[hv]; + hm->hm_phnext = ipf_hm_maptable + hv; + if (ipf_hm_maptable[hv] != NULL) + ipf_hm_maptable[hv]->hm_phnext = &hm->hm_hnext; + ipf_hm_maptable[hv] = hm; hm->hm_ipnat = np; hm->hm_srcip = src; hm->hm_dstip = dst; @@ -467,19 +489,27 @@ u_32_t port; /* ------------------------------------------------------------------------ */ -/* Function: nat_hostmapdel */ +/* Function: fr_hostmapdel */ /* Returns: Nil */ -/* Parameters: hm(I) - pointer to hostmap structure */ +/* Parameters: hmp(I) - pointer to hostmap structure pointer */ /* Write Locks: ipf_nat */ /* */ /* Decrement the references to this hostmap structure by one. If this */ /* reaches zero then remove it and free it. */ /* ------------------------------------------------------------------------ */ -static void nat_hostmapdel(hm) -struct hostmap *hm; +void fr_hostmapdel(hmp) +struct hostmap **hmp; { + struct hostmap *hm; + + hm = *hmp; + *hmp = NULL; + hm->hm_ref--; if (hm->hm_ref == 0) { + if (hm->hm_hnext) + hm->hm_hnext->hm_phnext = hm->hm_phnext; + *hm->hm_phnext = hm->hm_hnext; if (hm->hm_next) hm->hm_next->hm_pnext = hm->hm_pnext; *hm->hm_pnext = hm->hm_next; @@ -609,18 +639,30 @@ u_32_t n; /* */ /* Processes an ioctl call made to operate on the IP Filter NAT device. */ /* ------------------------------------------------------------------------ */ -int fr_nat_ioctl(data, cmd, mode) +int fr_nat_ioctl(data, cmd, mode, uid, ctx) ioctlcmd_t cmd; caddr_t data; -int mode; +int mode, uid; +void *ctx; { ipnat_t *nat, *nt, *n = NULL, **np = NULL; int error = 0, ret, arg, getlock; ipnat_t natd; + SPL_INT(s); #if (BSD >= 199306) && defined(_KERNEL) - if ((securelevel >= 2) && (mode & FWRITE)) +# if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 399002000) + if ((mode & FWRITE) && + kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_FIREWALL, + KAUTH_REQ_NETWORK_FIREWALL_FW, + NULL, NULL, NULL)) { return EPERM; + } +# else + if ((securelevel >= 2) && (mode & FWRITE)) { + return EPERM; + } +# endif #endif #if defined(__osf__) && defined(_KERNEL) @@ -643,9 +685,6 @@ int mode; } else { error = fr_inobj(data, &natd, IPFOBJ_IPNAT); } - - } else if (cmd == (ioctlcmd_t)SIOCIPFFL) { /* SIOCFLNAT & SIOCCNATL */ - BCOPYIN(data, &arg, sizeof(arg)); } if (error != 0) @@ -667,9 +706,13 @@ int mode; } MUTEX_ENTER(&ipf_natio); for (np = &nat_list; ((n = *np) != NULL); np = &n->in_next) - if (!bcmp((char *)&nat->in_flags, (char *)&n->in_flags, - IPN_CMPSIZ)) + if (bcmp((char *)&nat->in_flags, (char *)&n->in_flags, + IPN_CMPSIZ) == 0) { + if (nat->in_redir == NAT_REDIRECT && + nat->in_pnext != n->in_pnext) + continue; break; + } } switch (cmd) @@ -683,25 +726,37 @@ int mode; error = EPERM; else { tmp = ipflog_clear(IPL_LOGNAT); - BCOPYOUT((char *)&tmp, (char *)data, sizeof(tmp)); + error = BCOPYOUT((char *)&tmp, (char *)data, + sizeof(tmp)); + if (error != 0) + error = EFAULT; } break; } + case SIOCSETLG : if (!(mode & FWRITE)) error = EPERM; else { - BCOPYIN((char *)data, (char *)&nat_logging, - sizeof(nat_logging)); + error = BCOPYIN((char *)data, (char *)&nat_logging, + sizeof(nat_logging)); + if (error != 0) + error = EFAULT; } break; + case SIOCGETLG : - BCOPYOUT((char *)&nat_logging, (char *)data, - sizeof(nat_logging)); + error = BCOPYOUT((char *)&nat_logging, (char *)data, + sizeof(nat_logging)); + if (error != 0) + error = EFAULT; break; + case FIONREAD : arg = iplused[IPL_LOGNAT]; - BCOPYOUT(&arg, data, sizeof(arg)); + error = BCOPYOUT(&arg, data, sizeof(arg)); + if (error != 0) + error = EFAULT; break; #endif case SIOCADNAT : @@ -722,6 +777,7 @@ int mode; if (error == 0) nt = NULL; break; + case SIOCRMNAT : if (!(mode & FWRITE)) { error = EPERM; @@ -739,11 +795,13 @@ int mode; MUTEX_EXIT(&ipf_natio); n = NULL; break; + case SIOCGNATS : nat_stats.ns_table[0] = nat_table[0]; nat_stats.ns_table[1] = nat_table[1]; nat_stats.ns_list = nat_list; - nat_stats.ns_maptable = maptable; + nat_stats.ns_maptable = ipf_hm_maptable; + nat_stats.ns_maplist = ipf_hm_maplist; nat_stats.ns_nattab_sz = ipf_nattable_sz; nat_stats.ns_nattab_max = ipf_nattable_max; nat_stats.ns_rultab_sz = ipf_natrules_sz; @@ -751,8 +809,10 @@ int mode; nat_stats.ns_hostmap_sz = ipf_hostmap_sz; nat_stats.ns_instances = nat_instances; nat_stats.ns_apslist = ap_sess_list; + nat_stats.ns_ticks = fr_ticks; error = fr_outobj(data, &nat_stats, IPFOBJ_NATSTAT); break; + case SIOCGNATL : { natlookup_t nl; @@ -773,6 +833,7 @@ int mode; } break; } + case SIOCIPFFL : /* old SIOCFLNAT & SIOCCNATL */ if (!(mode & FWRITE)) { error = EPERM; @@ -781,23 +842,31 @@ int mode; if (getlock) { WRITE_ENTER(&ipf_nat); } - error = 0; - if (arg == 0) - ret = nat_flushtable(); - else if (arg == 1) - ret = nat_clearlist(); - else - error = EINVAL; + + error = BCOPYIN(data, &arg, sizeof(arg)); + if (error != 0) + error = EFAULT; + else { + if (arg == 0) + ret = nat_flushtable(); + else if (arg == 1) + ret = nat_clearlist(); + else + ret = nat_extraflush(arg); + } + if (getlock) { RWLOCK_EXIT(&ipf_nat); } if (error == 0) { - BCOPYOUT(&ret, data, sizeof(ret)); + error = BCOPYOUT(&ret, data, sizeof(ret)); } break; + case SIOCPROXY : - error = appr_ioctl(data, cmd, mode); + error = appr_ioctl(data, cmd, mode, ctx); break; + case SIOCSTLCK : if (!(mode & FWRITE)) { error = EPERM; @@ -805,6 +874,7 @@ int mode; fr_lock(data, &fr_nat_lock); } break; + case SIOCSTPUT : if ((mode & FWRITE) != 0) { error = fr_natputent(data, getlock); @@ -812,6 +882,7 @@ int mode; error = EACCES; } break; + case SIOCSTGSZ : if (fr_nat_lock) { if (getlock) { @@ -824,6 +895,7 @@ int mode; } else error = EACCES; break; + case SIOCSTGET : if (fr_nat_lock) { if (getlock) { @@ -836,12 +908,46 @@ int mode; } else error = EACCES; break; + + case SIOCGENITER : + { + ipfgeniter_t iter; + ipftoken_t *token; + + SPL_SCHED(s); + error = fr_inobj(data, &iter, IPFOBJ_GENITER); + if (error == 0) { + token = ipf_findtoken(iter.igi_type, uid, ctx); + if (token != NULL) { + error = nat_iterator(token, &iter); + } + RWLOCK_EXIT(&ipf_tokens); + } + SPL_X(s); + break; + } + + case SIOCIPFDELTOK : + error = BCOPYIN((caddr_t)data, (caddr_t)&arg, sizeof(arg)); + if (error == 0) { + SPL_SCHED(s); + error = ipf_deltoken(arg, uid, ctx); + SPL_X(s); + } else { + error = EFAULT; + } + break; + + case SIOCGTQTAB : + error = fr_outobj(data, nat_tqb, IPFOBJ_STATETQTAB); + break; + default : error = EINVAL; break; } done: - if (nt) + if (nt != NULL) KFREE(nt); return error; } @@ -969,6 +1075,8 @@ int getlock; n->in_flags &= ~IPN_NOTSRC; nat_addnat(n); } + MUTEX_INIT(&n->in_lock, "ipnat rule lock"); + n = NULL; nat_stats.ns_rules++; #if SOLARIS @@ -1093,7 +1201,8 @@ caddr_t data; nat_t *nat, *n; natget_t ng; - BCOPYIN(data, &ng, sizeof(ng)); + if (BCOPYIN(data, &ng, sizeof(ng)) != 0) + return EFAULT; nat = ng.ng_ptr; if (!nat) { @@ -1103,7 +1212,8 @@ caddr_t data; * Empty list so the size returned is 0. Simple. */ if (nat == NULL) { - BCOPYOUT(&ng, data, sizeof(ng)); + if (BCOPYOUT(&ng, data, sizeof(ng)) != 0) + return EFAULT; return 0; } } else { @@ -1130,7 +1240,8 @@ caddr_t data; ng.ng_sz += aps->aps_psiz; } - BCOPYOUT(&ng, data, sizeof(ng)); + if (BCOPYOUT(&ng, data, sizeof(ng)) != 0) + return EFAULT; return 0; } @@ -1280,12 +1391,12 @@ int getlock; aps = NULL; nat = NULL; ipnn = NULL; + fr = NULL; /* * New entry, copy in the rest of the NAT entry if it's size is more * than just the nat_t structure. */ - fr = NULL; if (ipn.ipn_dsize > sizeof(ipn)) { if (ipn.ipn_dsize > 81920) { error = ENOMEM; @@ -1354,8 +1465,8 @@ int getlock; */ bzero((char *)&fin, sizeof(fin)); fin.fin_p = nat->nat_p; - fin.fin_ifp = nat->nat_ifps[0]; if (nat->nat_dir == NAT_OUTBOUND) { + fin.fin_ifp = nat->nat_ifps[0]; fin.fin_data[0] = ntohs(nat->nat_oport); fin.fin_data[1] = ntohs(nat->nat_outport); if (getlock) { @@ -1371,6 +1482,7 @@ int getlock; goto junkput; } } else if (nat->nat_dir == NAT_INBOUND) { + fin.fin_ifp = nat->nat_ifps[0]; fin.fin_data[0] = ntohs(nat->nat_outport); fin.fin_data[1] = ntohs(nat->nat_oport); if (getlock) { @@ -1498,7 +1610,7 @@ int getlock; junkput: if (fr != NULL) - fr_derefrule(&fr); + (void) fr_derefrule(&fr); if ((ipnn != NULL) && (ipnn != &ipn)) { KFREES(ipnn, ipn.ipn_dsize); @@ -1580,13 +1692,18 @@ int logtype; nat->nat_me = NULL; } - fr_deletequeueentry(&nat->nat_tqe); + if (nat->nat_tqe.tqe_ifq != NULL) + fr_deletequeueentry(&nat->nat_tqe); + + if (logtype == NL_EXPIRE) + nat_stats.ns_expire++; nat->nat_ref--; if (nat->nat_ref > 0) { MUTEX_EXIT(&ipf_nat_new); return; } + /* * At this point, nat_ref can be either 0 or -1 */ @@ -1597,10 +1714,10 @@ int logtype; #endif if (nat->nat_fr != NULL) - (void)fr_derefrule(&nat->nat_fr); + (void) fr_derefrule(&nat->nat_fr); if (nat->nat_hm != NULL) - nat_hostmapdel(nat->nat_hm); + fr_hostmapdel(&nat->nat_hm); /* * If there is an active reference from the nat entry to its parent @@ -1609,18 +1726,7 @@ int logtype; */ ipn = nat->nat_ptr; if (ipn != NULL) { - ipn->in_space++; - ipn->in_use--; - if (ipn->in_use == 0 && (ipn->in_flags & IPN_DELETE)) { - if (ipn->in_apr) - appr_free(ipn->in_apr); - KFREE(ipn); - nat_stats.ns_rules--; -#if SOLARIS - if (nat_stats.ns_rules == 0) - pfil_delayed_copy = 1; -#endif - } + fr_ipnatderef(&ipn); } MUTEX_DESTROY(&nat->nat_lock); @@ -1776,8 +1882,7 @@ natinfo_t *ni; if (hm != NULL) in.s_addr = hm->hm_mapip.s_addr; } else if ((l == 1) && (hm != NULL)) { - nat_hostmapdel(hm); - hm = NULL; + fr_hostmapdel(&hm); } in.s_addr = ntohl(in.s_addr); @@ -1998,10 +2103,12 @@ nat_t *nat; natinfo_t *ni; { u_short nport, dport, sport; - struct in_addr in; + struct in_addr in, inb; + u_short sp, dp; hostmap_t *hm; u_32_t flags; ipnat_t *np; + nat_t *natl; int move; move = 1; @@ -2111,6 +2218,23 @@ natinfo_t *ni; in.s_addr = ntohl(fin->fin_daddr); } + /* + * Check to see if this redirect mapping already exists and if + * it does, return "failure" (allowing it to be created will just + * cause one or both of these "connections" to stop working.) + */ + inb.s_addr = htonl(in.s_addr); + sp = fin->fin_data[0]; + dp = fin->fin_data[1]; + fin->fin_data[1] = fin->fin_data[0]; + fin->fin_data[0] = ntohs(nport); + natl = nat_outlookup(fin, flags & ~(SI_WILDP|NAT_SEARCH), + (u_int)fin->fin_p, inb, fin->fin_src); + fin->fin_data[0] = sp; + fin->fin_data[1] = dp; + if (natl != NULL) + return -1; + nat->nat_inip.s_addr = htonl(in.s_addr); nat->nat_outip = fin->fin_dst; nat->nat_oip = fin->fin_src; @@ -2194,6 +2318,7 @@ int direction; if (nat_stats.ns_inuse >= ipf_nattable_max) { nat_stats.ns_memfail++; + fr_nat_doflush = 1; return NULL; } @@ -2204,6 +2329,8 @@ int direction; ni.nai_np = np; ni.nai_nflags = nflags; ni.nai_flags = flags; + ni.nai_dport = 0; + ni.nai_sport = 0; /* Give me a new nat */ KMALLOC(nat, nat_t *); @@ -2247,6 +2374,7 @@ int direction; bzero((char *)nat, sizeof(*nat)); nat->nat_flags = flags; + nat->nat_redir = np->in_redir; if ((flags & NAT_SLAVE) == 0) { MUTEX_ENTER(&ipf_nat_new); @@ -2359,7 +2487,7 @@ int direction; badnat: nat_stats.ns_badnat++; if ((hm = nat->nat_hm) != NULL) - nat_hostmapdel(hm); + fr_hostmapdel(&hm); KFREE(nat); nat = NULL; done: @@ -2686,9 +2814,9 @@ u_int *nflags; int dir; { u_32_t sum1, sum2, sumd, sumd2; - struct in_addr in; + struct in_addr a1, a2; + int flags, dlen, odst; icmphdr_t *icmp; - int flags, dlen; u_short *csump; tcphdr_t *tcp; nat_t *nat; @@ -2739,33 +2867,7 @@ int dir; /* * Step 1 * Fix the IP addresses in the offending IP packet. You also need - * to adjust the IP header checksum of that offending IP packet - * and the ICMP checksum of the ICMP error message itself. - * - * Unfortunately, for UDP and TCP, the IP addresses are also contained - * in the pseudo header that is used to compute the UDP resp. TCP - * checksum. So, we must compensate that as well. Even worse, the - * change in the UDP and TCP checksums require yet another - * adjustment of the ICMP checksum of the ICMP error message. - */ - - if (oip->ip_dst.s_addr == nat->nat_oip.s_addr) { - sum1 = LONG_SUM(ntohl(oip->ip_src.s_addr)); - in = nat->nat_inip; - oip->ip_src = in; - } else { - sum1 = LONG_SUM(ntohl(oip->ip_dst.s_addr)); - in = nat->nat_outip; - oip->ip_dst = in; - } - - sum2 = LONG_SUM(ntohl(in.s_addr)); - - CALC_SUMD(sum1, sum2, sumd); - - /* - * Fix IP checksum of the offending IP packet to adjust for - * the change in the IP address. + * to adjust the IP header checksum of that offending IP packet. * * Normally, you would expect that the ICMP checksum of the * ICMP error message needs to be adjusted as well for the @@ -2777,184 +2879,122 @@ int dir; * the IP address is x, then the delta for ip_sum is minus x), * so no change in the icmp_cksum is necessary. * - * Be careful that nat_dir refers to the direction of the - * offending IP packet (oip), not to its ICMP response (icmp) + * Inbound ICMP + * ------------ + * MAP rule, SRC=a,DST=b -> SRC=c,DST=b + * - response to outgoing packet (a,b)=>(c,b) (OIP_SRC=c,OIP_DST=b) + * - OIP_SRC(c)=nat_outip, OIP_DST(b)=nat_oip + * + * RDR rule, SRC=a,DST=b -> SRC=a,DST=c + * - response to outgoing packet (c,a)=>(b,a) (OIP_SRC=b,OIP_DST=a) + * - OIP_SRC(b)=nat_outip, OIP_DST(a)=nat_oip + * + * Outbound ICMP + * ------------- + * MAP rule, SRC=a,DST=b -> SRC=c,DST=b + * - response to incoming packet (b,c)=>(b,a) (OIP_SRC=b,OIP_DST=a) + * - OIP_SRC(a)=nat_oip, OIP_DST(c)=nat_inip + * + * RDR rule, SRC=a,DST=b -> SRC=a,DST=c + * - response to incoming packet (a,b)=>(a,c) (OIP_SRC=a,OIP_DST=c) + * - OIP_SRC(a)=nat_oip, OIP_DST(c)=nat_inip + * */ - fix_datacksum(&oip->ip_sum, sumd); - /* Fix icmp cksum : IP Addr + Cksum */ - sumd2 = (sumd >> 16); + odst = (oip->ip_dst.s_addr == nat->nat_oip.s_addr) ? 1 : 0; + if (odst == 1) { + a1.s_addr = ntohl(nat->nat_inip.s_addr); + a2.s_addr = ntohl(oip->ip_src.s_addr); + oip->ip_src.s_addr = htonl(a1.s_addr); + } else { + a1.s_addr = ntohl(nat->nat_outip.s_addr); + a2.s_addr = ntohl(oip->ip_dst.s_addr); + oip->ip_dst.s_addr = htonl(a1.s_addr); + } - /* - * Fix UDP pseudo header checksum to compensate for the - * IP address change. - */ - if ((oip->ip_p == IPPROTO_UDP) && (dlen >= 8) && (*csump != 0)) { - /* - * The UDP checksum is optional, only adjust it - * if it has been set. - */ - sum1 = ntohs(*csump); - fix_datacksum(csump, sumd); - sum2 = ntohs(*csump); + sumd = a2.s_addr - a1.s_addr; + if (sumd != 0) { + if (a1.s_addr > a2.s_addr) + sumd--; + sumd = ~sumd; - /* - * Fix ICMP checksum to compensate the UDP - * checksum adjustment. - */ - sumd2 = sumd << 1; - CALC_SUMD(sum1, sum2, sumd); - sumd2 += sumd; + fix_datacksum(&oip->ip_sum, sumd); } + sumd2 = sumd; + sum1 = 0; + sum2 = 0; + /* - * Fix TCP pseudo header checksum to compensate for the - * IP address change. Before we can do the change, we - * must make sure that oip is sufficient large to hold - * the TCP checksum (normally it does not!). - * 18 = offsetof(tcphdr_t, th_sum) + 2 + * Fix UDP pseudo header checksum to compensate for the + * IP address change. */ - else if (oip->ip_p == IPPROTO_TCP && dlen >= 18) { - sum1 = ntohs(*csump); - fix_datacksum(csump, sumd); - sum2 = ntohs(*csump); - - /* - * Fix ICMP checksum to compensate the TCP - * checksum adjustment. - */ - sumd2 = sumd << 1; - CALC_SUMD(sum1, sum2, sumd); - sumd2 += sumd; - } else { - if (nat->nat_dir == NAT_OUTBOUND) - sumd2 = ~sumd2; - else - sumd2 = ~sumd2 + 1; - } - if (((flags & IPN_TCPUDP) != 0) && (dlen >= 4)) { - int mode = 0; - /* * Step 2 : * For offending TCP/UDP IP packets, translate the ports as * well, based on the NAT specification. Of course such - * a change must be reflected in the ICMP checksum as well. - * - * Advance notice : Now it becomes complicated :-) + * a change may be reflected in the ICMP checksum as well. * * Since the port fields are part of the TCP/UDP checksum * of the offending IP packet, you need to adjust that checksum * as well... except that the change in the port numbers should - * be offset by the checksum change, so we only need to change - * the ICMP checksum if we only change the ports. - * - * To further complicate: the TCP checksum is not in the first - * 8 bytes of the offending ip packet, so it most likely is not - * available. Some OSses like Solaris return enough bytes to - * include the TCP checksum. So we have to check if the - * ip->ip_len actually holds the TCP checksum of the oip! + * be offset by the checksum change. However, the TCP/UDP + * checksum will also need to change if there has been an + * IP address change. */ + if (odst == 1) { + sum1 = ntohs(nat->nat_inport); + sum2 = ntohs(tcp->th_sport); - if (nat->nat_oport == tcp->th_dport) { - if (tcp->th_sport != nat->nat_inport) { - mode = 1; - sum1 = ntohs(nat->nat_inport); - sum2 = ntohs(tcp->th_sport); - } - } else if (tcp->th_sport == nat->nat_oport) { - mode = 2; + tcp->th_sport = htons(sum1); + } else { sum1 = ntohs(nat->nat_outport); sum2 = ntohs(tcp->th_dport); - } - if (mode == 1) { - /* - * Fix ICMP checksum to compensate port adjustment. - */ - tcp->th_sport = htons(sum1); + tcp->th_dport = htons(sum1); + } + sumd += sum1 - sum2; + if (sumd != 0 || sumd2 != 0) { /* - * Fix udp checksum to compensate port adjustment. - * NOTE : the offending IP packet flows the other - * direction compared to the ICMP message. + * At this point, sumd is the delta to apply to the + * TCP/UDP header, given the changes in both the IP + * address and the ports and sumd2 is the delta to + * apply to the ICMP header, given the IP address + * change delta that may need to be applied to the + * TCP/UDP checksum instead. * - * The UDP checksum is optional, only adjust it if - * it has been set. + * If we will both the IP and TCP/UDP checksums + * then the ICMP checksum changes by the address + * delta applied to the TCP/UDP checksum. If we + * do not change the TCP/UDP checksum them we + * apply the delta in ports to the ICMP checksum. */ if (oip->ip_p == IPPROTO_UDP) { - sumd = sum1 - sum2; - if ((dlen >= 8) && (*csump != 0)) { fix_datacksum(csump, sumd); } else { - sumd2 += sumd; + sumd2 = sum1 - sum2; + if (sum2 > sum1) + sumd2--; } - } - - /* - * Fix TCP checksum (if present) to compensate port - * adjustment. NOTE : the offending IP packet flows - * the other direction compared to the ICMP message. - */ - if (oip->ip_p == IPPROTO_TCP) { - sumd = sum1 - sum2; - + } else if (oip->ip_p == IPPROTO_TCP) { if (dlen >= 18) { fix_datacksum(csump, sumd); } else { - sumd = sum2 - sum1 + 1; - sumd2 += sumd; - } - } - } else if (mode == 2) { - /* - * Fix ICMP checksum to compensate port adjustment. - */ - tcp->th_dport = htons(sum1); - - /* - * Fix UDP checksum to compensate port adjustment. - * NOTE : the offending IP packet flows the other - * direction compared to the ICMP message. - * - * The UDP checksum is optional, only adjust - * it if it has been set. - */ - if (oip->ip_p == IPPROTO_UDP) { - sumd = sum1 - sum2; - - if ((dlen >= 8) && (*csump != 0)) { - fix_datacksum(csump, sumd); - } else { - sumd2 += sumd; + sumd2 = sum2 - sum1; + if (sum1 > sum2) + sumd2--; } } - /* - * Fix TCP checksum (if present) to compensate port - * adjustment. NOTE : the offending IP packet flows - * the other direction compared to the ICMP message. - */ - if (oip->ip_p == IPPROTO_TCP) { - sumd = sum1 - sum2; - - if (dlen >= 18) { - fix_datacksum(csump, sumd); - } else { - if (nat->nat_dir == NAT_INBOUND) - sumd = sum2 - sum1; - else - sumd = sum2 - sum1 + 1; - sumd2 += sumd; - } + if (sumd2 != 0) { + sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); + sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); + sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); + fix_incksum(fin, &icmp->icmp_cksum, sumd2); } } - if (sumd2 != 0) { - sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); - sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16); - fix_incksum(fin, &icmp->icmp_cksum, sumd2); - } } else if (((flags & IPN_ICMPQUERY) != 0) && (dlen >= 8)) { icmphdr_t *orgicmp; @@ -2964,7 +3004,7 @@ int dir; */ orgicmp = (icmphdr_t *)dp; - if (nat->nat_dir == NAT_OUTBOUND) { + if (odst == 1) { if (orgicmp->icmp_id != nat->nat_inport) { /* @@ -3632,9 +3672,11 @@ u_32_t *passp; natfailed = 0; fr = fin->fin_fr; sifp = fin->fin_ifp; - if ((fr != NULL) && !(fr->fr_flags & FR_DUP) && - fr->fr_tif.fd_ifp && fr->fr_tif.fd_ifp != (void *)-1) - fin->fin_ifp = fr->fr_tif.fd_ifp; + if (fr != NULL) { + ifp = fr->fr_tifs[fin->fin_rev].fd_ifp; + if ((ifp != NULL) && (ifp != (void *)-1)) + fin->fin_ifp = ifp; + } ifp = fin->fin_ifp; if (!(fin->fin_flx & FI_SHORT) && (fin->fin_off == 0)) { @@ -3746,6 +3788,7 @@ maskloop: MUTEX_ENTER(&nat->nat_lock); nat->nat_ref++; MUTEX_EXIT(&nat->nat_lock); + nat->nat_touched = fr_ticks; fin->fin_nat = nat; } } else @@ -4039,8 +4082,8 @@ maskloop: MUTEX_ENTER(&nat->nat_lock); nat->nat_ref++; MUTEX_EXIT(&nat->nat_lock); + nat->nat_touched = fr_ticks; fin->fin_nat = nat; - fin->fin_state = nat->nat_state; } } else rval = natfailed; @@ -4284,9 +4327,9 @@ void fr_natunload() KFREES(rdr_rules, sizeof(ipnat_t *) * ipf_rdrrules_sz); rdr_rules = NULL; } - if (maptable != NULL) { - KFREES(maptable, sizeof(hostmap_t *) * ipf_hostmap_sz); - maptable = NULL; + if (ipf_hm_maptable != NULL) { + KFREES(ipf_hm_maptable, sizeof(hostmap_t *) * ipf_hostmap_sz); + ipf_hm_maptable = NULL; } if (nat_stats.ns_bucketlen[0] != NULL) { KFREES(nat_stats.ns_bucketlen[0], @@ -4365,6 +4408,11 @@ void fr_natexpire() } } + if (fr_nat_doflush != 0) { + nat_extraflush(2); + fr_nat_doflush = 0; + } + RWLOCK_EXIT(&ipf_nat); SPL_X(s); } @@ -4574,6 +4622,35 @@ void *ifp; /* ------------------------------------------------------------------------ */ +/* Function: fr_ipnatderef */ +/* Returns: Nil */ +/* Parameters: isp(I) - pointer to pointer to NAT rule */ +/* Write Locks: ipf_nat */ +/* */ +/* ------------------------------------------------------------------------ */ +void fr_ipnatderef(inp) +ipnat_t **inp; +{ + ipnat_t *in; + + in = *inp; + *inp = NULL; + in->in_space++; + in->in_use--; + if (in->in_use == 0 && (in->in_flags & IPN_DELETE)) { + if (in->in_apr) + appr_free(in->in_apr); + KFREE(in); + nat_stats.ns_rules--; +#if SOLARIS + if (nat_stats.ns_rules == 0) + pfil_delayed_copy = 1; +#endif + } +} + + +/* ------------------------------------------------------------------------ */ /* Function: fr_natderef */ /* Returns: Nil */ /* Parameters: isp(I) - pointer to pointer to NAT table entry */ @@ -4854,3 +4931,407 @@ int rev; fr_queueappend(&nat->nat_tqe, nifq, nat); return; } + + +/* ------------------------------------------------------------------------ */ +/* Function: nat_getnext */ +/* Returns: int - 0 == ok, else error */ +/* Parameters: t(I) - pointer to ipftoken structure */ +/* itp(I) - pointer to ipfgeniter_t structure */ +/* */ +/* Fetch the next nat/ipnat structure pointer from the linked list and */ +/* copy it out to the storage space pointed to by itp_data. The next item */ +/* in the list to look at is put back in the ipftoken struture. */ +/* If we call ipf_freetoken, the accompanying pointer is set to NULL because*/ +/* ipf_freetoken will call a deref function for us and we dont want to call */ +/* that twice (second time would be in the second switch statement below. */ +/* ------------------------------------------------------------------------ */ +static int nat_getnext(t, itp) +ipftoken_t *t; +ipfgeniter_t *itp; +{ + hostmap_t *hm, *nexthm = NULL, zerohm; + ipnat_t *ipn, *nextipnat = NULL, zeroipn; + nat_t *nat, *nextnat = NULL, zeronat; + int error = 0, count; + ipftoken_t *freet; + char *dst; + + freet = NULL; + + READ_ENTER(&ipf_nat); + + switch (itp->igi_type) + { + case IPFGENITER_HOSTMAP : + hm = t->ipt_data; + if (hm == NULL) { + nexthm = ipf_hm_maplist; + } else { + nexthm = hm->hm_next; + } + break; + + case IPFGENITER_IPNAT : + ipn = t->ipt_data; + if (ipn == NULL) { + nextipnat = nat_list; + } else { + nextipnat = ipn->in_next; + } + break; + + case IPFGENITER_NAT : + nat = t->ipt_data; + if (nat == NULL) { + nextnat = nat_instances; + } else { + nextnat = nat->nat_next; + } + break; + default : + RWLOCK_EXIT(&ipf_nat); + return EINVAL; + } + + dst = itp->igi_data; + for (count = itp->igi_nitems; count > 0; count--) { + switch (itp->igi_type) + { + case IPFGENITER_HOSTMAP : + if (nexthm != NULL) { + if (nexthm->hm_next == NULL) { + freet = t; + count = 1; + hm = NULL; + } + if (count == 1) { + ATOMIC_INC32(nexthm->hm_ref); + } + } else { + bzero(&zerohm, sizeof(zerohm)); + nexthm = &zerohm; + count = 1; + } + break; + + case IPFGENITER_IPNAT : + if (nextipnat != NULL) { + if (nextipnat->in_next == NULL) { + freet = t; + count = 1; + ipn = NULL; + } + if (count == 1) { + MUTEX_ENTER(&nextipnat->in_lock); + nextipnat->in_use++; + MUTEX_EXIT(&nextipnat->in_lock); + } + } else { + bzero(&zeroipn, sizeof(zeroipn)); + nextipnat = &zeroipn; + count = 1; + } + break; + + case IPFGENITER_NAT : + if (nextnat != NULL) { + if (nextnat->nat_next == NULL) { + count = 1; + freet = t; + nat = NULL; + } + if (count == 1) { + MUTEX_ENTER(&nextnat->nat_lock); + nextnat->nat_ref++; + MUTEX_EXIT(&nextnat->nat_lock); + } + } else { + bzero(&zeronat, sizeof(zeronat)); + nextnat = &zeronat; + count = 1; + } + break; + default : + break; + } + RWLOCK_EXIT(&ipf_nat); + + if (freet != NULL) { + ipf_freetoken(freet); + freet = NULL; + } + + switch (itp->igi_type) + { + case IPFGENITER_HOSTMAP : + if (hm != NULL) { + WRITE_ENTER(&ipf_nat); + fr_hostmapdel(&hm); + RWLOCK_EXIT(&ipf_nat); + } + t->ipt_data = nexthm; + error = COPYOUT(nexthm, dst, sizeof(*nexthm)); + if (error != 0) + error = EFAULT; + else + dst += sizeof(*nexthm); + break; + + case IPFGENITER_IPNAT : + if (ipn != NULL) + fr_ipnatderef(&ipn); + t->ipt_data = nextipnat; + error = COPYOUT(nextipnat, dst, sizeof(*nextipnat)); + if (error != 0) + error = EFAULT; + else + dst += sizeof(*nextipnat); + break; + + case IPFGENITER_NAT : + if (nat != NULL) + fr_natderef(&nat); + t->ipt_data = nextnat; + error = COPYOUT(nextnat, dst, sizeof(*nextnat)); + if (error != 0) + error = EFAULT; + else + dst += sizeof(*nextnat); + break; + } + + if ((count == 1) || (error != 0)) + break; + + READ_ENTER(&ipf_nat); + + switch (itp->igi_type) + { + case IPFGENITER_HOSTMAP : + hm = nexthm; + nexthm = hm->hm_next; + break; + + case IPFGENITER_IPNAT : + ipn = nextipnat; + nextipnat = ipn->in_next; + break; + + case IPFGENITER_NAT : + nat = nextnat; + nextnat = nat->nat_next; + break; + default : + break; + } + } + + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: nat_iterator */ +/* Returns: int - 0 == ok, else error */ +/* Parameters: token(I) - pointer to ipftoken structure */ +/* itp(I) - pointer to ipfgeniter_t structure */ +/* */ +/* This function acts as a handler for the SIOCGENITER ioctls that use a */ +/* generic structure to iterate through a list. There are three different */ +/* linked lists of NAT related information to go through: NAT rules, active */ +/* NAT mappings and the NAT fragment cache. */ +/* ------------------------------------------------------------------------ */ +static int nat_iterator(token, itp) +ipftoken_t *token; +ipfgeniter_t *itp; +{ + int error; + + if (itp->igi_data == NULL) + return EFAULT; + + token->ipt_subtype = itp->igi_type; + + switch (itp->igi_type) + { + case IPFGENITER_HOSTMAP : + case IPFGENITER_IPNAT : + case IPFGENITER_NAT : + error = nat_getnext(token, itp); + break; + + case IPFGENITER_NATFRAG : +#ifdef USE_MUTEXES + error = fr_nextfrag(token, itp, &ipfr_natlist, + &ipfr_nattail, &ipf_natfrag); +#else + error = fr_nextfrag(token, itp, &ipfr_natlist, &ipfr_nattail); +#endif + break; + default : + error = EINVAL; + break; + } + + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: nat_extraflush */ +/* Returns: int - 0 == success, -1 == failure */ +/* Parameters: which(I) - how to flush the active NAT table */ +/* Write Locks: ipf_nat */ +/* */ +/* Flush nat tables. Three actions currently defined: */ +/* which == 0 : flush all nat table entries */ +/* which == 1 : flush TCP connections which have started to close but are */ +/* stuck for some reason. */ +/* which == 2 : flush TCP connections which have been idle for a long time, */ +/* starting at > 4 days idle and working back in successive half-*/ +/* days to at most 12 hours old. If this fails to free enough */ +/* slots then work backwards in half hour slots to 30 minutes. */ +/* If that too fails, then work backwards in 30 second intervals */ +/* for the last 30 minutes to at worst 30 seconds idle. */ +/* ------------------------------------------------------------------------ */ +static int nat_extraflush(which) +int which; +{ + ipftq_t *ifq, *ifqnext; + nat_t *nat, **natp; + ipftqent_t *tqn; + int removed; + SPL_INT(s); + + removed = 0; + + SPL_NET(s); + + switch (which) + { + case 0 : + /* + * Style 0 flush removes everything... + */ + for (natp = &nat_instances; ((nat = *natp) != NULL); ) { + nat_delete(nat, NL_FLUSH); + removed++; + } + break; + + case 1 : + /* + * Since we're only interested in things that are closing, + * we can start with the appropriate timeout queue. + */ + for (ifq = nat_tqb + IPF_TCPS_CLOSE_WAIT; ifq != NULL; + ifq = ifq->ifq_next) { + + for (tqn = ifq->ifq_head; tqn != NULL; ) { + nat = tqn->tqe_parent; + tqn = tqn->tqe_next; + if (nat->nat_p != IPPROTO_TCP) + break; + nat_delete(nat, NL_EXPIRE); + removed++; + } + } + + /* + * Also need to look through the user defined queues. + */ + for (ifq = nat_utqe; ifq != NULL; ifq = ifqnext) { + ifqnext = ifq->ifq_next; + for (tqn = ifq->ifq_head; tqn != NULL; ) { + nat = tqn->tqe_parent; + tqn = tqn->tqe_next; + if (nat->nat_p != IPPROTO_TCP) + continue; + + if ((nat->nat_tcpstate[0] > + IPF_TCPS_ESTABLISHED) && + (nat->nat_tcpstate[1] > + IPF_TCPS_ESTABLISHED)) { + nat_delete(nat, NL_EXPIRE); + removed++; + } + } + } + break; + + /* + * Args 5-11 correspond to flushing those particular states + * for TCP connections. + */ + case IPF_TCPS_CLOSE_WAIT : + case IPF_TCPS_FIN_WAIT_1 : + case IPF_TCPS_CLOSING : + case IPF_TCPS_LAST_ACK : + case IPF_TCPS_FIN_WAIT_2 : + case IPF_TCPS_TIME_WAIT : + case IPF_TCPS_CLOSED : + tqn = nat_tqb[which].ifq_head; + while (tqn != NULL) { + nat = tqn->tqe_parent; + tqn = tqn->tqe_next; + nat_delete(nat, NL_FLUSH); + removed++; + } + break; + + default : + if (which < 30) + break; + + /* + * Take a large arbitrary number to mean the number of seconds + * for which which consider to be the maximum value we'll allow + * the expiration to be. + */ + which = IPF_TTLVAL(which); + for (natp = &nat_instances; ((nat = *natp) != NULL); ) { + if (fr_ticks - nat->nat_touched > which) { + nat_delete(nat, NL_FLUSH); + removed++; + } else + natp = &nat->nat_next; + } + break; + } + + if (which != 2) { + SPL_X(s); + return removed; + } + + /* + * Asked to remove inactive entries because the table is full. + */ + if (fr_ticks - nat_last_force_flush > IPF_TTLVAL(5)) { + nat_last_force_flush = fr_ticks; + removed = ipf_queueflush(nat_flush_entry, nat_tqb, nat_utqe); + } + + SPL_X(s); + return removed; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: nat_flush_entry */ +/* Returns: 0 - always succeeds */ +/* Parameters: entry(I) - pointer to NAT entry */ +/* Write Locks: ipf_nat */ +/* */ +/* This function is a stepping stone between ipf_queueflush() and */ +/* nat_dlete(). It is used so we can provide a uniform interface via the */ +/* ipf_queueflush() function. Since the nat_delete() function returns void */ +/* we translate that to mean it always succeeds in deleting something. */ +/* ------------------------------------------------------------------------ */ +static int nat_flush_entry(entry) +void *entry; +{ + nat_delete(entry, NL_FLUSH); + return 0; +} diff --git a/sys/contrib/ipfilter/netinet/ip_nat.h b/sys/contrib/ipfilter/netinet/ip_nat.h index 68396cd..d478942 100644 --- a/sys/contrib/ipfilter/netinet/ip_nat.h +++ b/sys/contrib/ipfilter/netinet/ip_nat.h @@ -4,7 +4,7 @@ * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ip_nat.h 1.5 2/4/96 - * $Id: ip_nat.h,v 2.90.2.11 2005/06/18 02:41:32 darrenr Exp $ + * $Id: ip_nat.h,v 2.90.2.17 2007/05/11 10:19:11 darrenr Exp $ */ #ifndef __IP_NAT_H__ @@ -121,6 +121,7 @@ typedef struct nat { int nat_hv[2]; char nat_ifnames[2][LIFNAMSIZ]; int nat_rev; /* 0 = forward, 1 = reverse */ + int nat_redir; /* copy of in_redir */ } nat_t; #define nat_inip nat_inip6.in4 @@ -133,6 +134,8 @@ typedef struct nat { #define nat_seq nat_un.nat_uni.ici_seq #define nat_id nat_un.nat_uni.ici_id #define nat_tcpstate nat_tqe.tqe_state +#define nat_die nat_tqe.tqe_die +#define nat_touched nat_tqe.tqe_touched /* * Values for nat_dir @@ -149,7 +152,7 @@ typedef struct nat { #define NAT_ICMPQUERY 0x0008 /* IPN_ICMPQUERY */ #define NAT_SEARCH 0x0010 #define NAT_SLAVE 0x0020 /* Slave connection for a proxy */ -#define NAT_NOTRULEPORT 0x0040 +#define NAT_NOTRULEPORT 0x0040 /* Don't use the port # in the NAT rule */ #define NAT_TCPUDP (NAT_TCP|NAT_UDP) #define NAT_TCPUDPICMP (NAT_TCP|NAT_UDP|NAT_ICMPERR) @@ -168,6 +171,7 @@ typedef struct nat { #define NAT_DEBUG 0x800000 typedef struct ipnat { + ipfmutex_t in_lock; struct ipnat *in_next; /* NAT rule list next */ struct ipnat *in_rnext; /* rdr rule hash next */ struct ipnat **in_prnext; /* prior rdr next ptr */ @@ -293,25 +297,6 @@ typedef struct natget { } natget_t; -#undef tr_flags -typedef struct nattrpnt { - struct in_addr tr_dstip; /* real destination IP# */ - struct in_addr tr_srcip; /* real source IP# */ - struct in_addr tr_locip; /* local source IP# */ - u_int tr_flags; - int tr_expire; - u_short tr_dstport; /* real destination port# */ - u_short tr_srcport; /* real source port# */ - u_short tr_locport; /* local source port# */ - struct nattrpnt *tr_hnext; - struct nattrpnt **tr_phnext; - struct nattrpnt *tr_next; - struct nattrpnt **tr_pnext; /* previous next */ -} nattrpnt_t; - -#define TN_CMPSIZ offsetof(nattrpnt_t, tr_hnext) - - /* * This structure gets used to help NAT sessions keep the same NAT rule (and * thus translation for IP address) when: @@ -319,6 +304,8 @@ typedef struct nattrpnt { * (b) different IP add */ typedef struct hostmap { + struct hostmap *hm_hnext; + struct hostmap **hm_phnext; struct hostmap *hm_next; struct hostmap **hm_pnext; struct ipnat *hm_ipnat; @@ -370,8 +357,9 @@ typedef struct natstat { u_int ns_trpntab_sz; u_int ns_hostmap_sz; nat_t *ns_instances; - nattrpnt_t *ns_trpntlist; + hostmap_t *ns_maplist; u_long *ns_bucketlen[2]; + u_long ns_ticks; } natstat_t; typedef struct natlog { @@ -424,6 +412,7 @@ extern u_int ipf_hostmap_sz; extern u_int fr_nat_maxbucket; extern u_int fr_nat_maxbucket_reset; extern int fr_nat_lock; +extern int fr_nat_doflush; extern void fr_natsync __P((void *)); extern u_long fr_defnatage; extern u_long fr_defnaticmpage; @@ -441,7 +430,7 @@ extern natstat_t nat_stats; #if defined(__OpenBSD__) extern void nat_ifdetach __P((void *)); #endif -extern int fr_nat_ioctl __P((caddr_t, ioctlcmd_t, int)); +extern int fr_nat_ioctl __P((caddr_t, ioctlcmd_t, int, int, void *)); extern int fr_natinit __P((void)); extern nat_t *nat_new __P((fr_info_t *, ipnat_t *, nat_t **, u_int, int)); extern nat_t *nat_outlookup __P((fr_info_t *, u_int, u_int, struct in_addr, @@ -466,9 +455,11 @@ extern void fr_natexpire __P((void)); extern void nat_log __P((struct nat *, u_int)); extern void fix_incksum __P((fr_info_t *, u_short *, u_32_t)); extern void fix_outcksum __P((fr_info_t *, u_short *, u_32_t)); +extern void fr_ipnatderef __P((ipnat_t **)); extern void fr_natderef __P((nat_t **)); extern u_short *nat_proto __P((fr_info_t *, nat_t *, u_int)); extern void nat_update __P((fr_info_t *, nat_t *, ipnat_t *)); extern void fr_setnatqueue __P((nat_t *, int)); +extern void fr_hostmapdel __P((hostmap_t **)); #endif /* __IP_NAT_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_pool.c b/sys/contrib/ipfilter/netinet/ip_pool.c index 3d19afb..b7e9946 100644 --- a/sys/contrib/ipfilter/netinet/ip_pool.c +++ b/sys/contrib/ipfilter/netinet/ip_pool.c @@ -55,9 +55,6 @@ struct file; #if defined(_KERNEL) && (defined(__osf__) || defined(AIX) || \ defined(__hpux) || defined(__sgi)) -# ifdef __osf__ -# include -# endif # include "radix_ipf_local.h" # define _RADIX_H_ #endif @@ -78,7 +75,7 @@ static int rn_freenode __P((struct radix_node *, void *)); #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_pool.c,v 2.55.2.15 2005/11/13 15:38:37 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_pool.c,v 2.55.2.20 2007/05/31 12:27:35 darrenr Exp $"; #endif #ifdef IPFILTER_LOOKUP @@ -90,6 +87,9 @@ static const char rcsid[] = "@(#)$Id: ip_pool.c,v 2.55.2.15 2005/11/13 15:38:37 # define RADIX_NODE_HEAD_UNLOCK(x) ; # endif +static void ip_pool_clearnodes __P((ip_pool_t *)); +static void *ip_pool_exists __P((int, char *)); + ip_pool_stat_t ipoolstat; ipfrwlock_t ip_poolrw; @@ -137,7 +137,7 @@ main(argc, argv) strcpy(op.iplo_name, "0"); if (ip_pool_create(&op) == 0) - ipo = ip_pool_find(0, "0"); + ipo = ip_pool_exists(0, "0"); a.adf_addr.in4.s_addr = 0x0a010203; b.adf_addr.in4.s_addr = 0xffffffff; @@ -262,18 +262,14 @@ int ip_pool_init() void ip_pool_fini() { ip_pool_t *p, *q; - iplookupop_t op; int i; ASSERT(rw_read_locked(&ipf_global.ipf_lk) == 0); for (i = 0; i <= IPL_LOGMAX; i++) { for (q = ip_pool_list[i]; (p = q) != NULL; ) { - op.iplo_unit = i; - (void)strncpy(op.iplo_name, p->ipo_name, - sizeof(op.iplo_name)); q = p->ipo_next; - (void) ip_pool_destroy(&op); + (void) ip_pool_destroy(i, p->ipo_name); } } @@ -307,8 +303,8 @@ iplookupop_t *op; stats.ipls_list[i] = ip_pool_list[i]; } else if (unit >= 0 && unit < IPL_LOGSIZE) { if (op->iplo_name[0] != '\0') - stats.ipls_list[unit] = ip_pool_find(unit, - op->iplo_name); + stats.ipls_list[unit] = ip_pool_exists(unit, + op->iplo_name); else stats.ipls_list[unit] = ip_pool_list[unit]; } else @@ -319,16 +315,15 @@ iplookupop_t *op; } - /* ------------------------------------------------------------------------ */ -/* Function: ip_pool_find */ +/* Function: ip_pool_exists */ /* Returns: int - 0 = success, else error */ /* Parameters: ipo(I) - pointer to the pool getting the new node. */ /* */ /* Find a matching pool inside the collection of pools for a particular */ /* device, indicated by the unit number. */ /* ------------------------------------------------------------------------ */ -void *ip_pool_find(unit, name) +static void *ip_pool_exists(unit, name) int unit; char *name; { @@ -342,6 +337,29 @@ char *name; /* ------------------------------------------------------------------------ */ +/* Function: ip_pool_find */ +/* Returns: int - 0 = success, else error */ +/* Parameters: ipo(I) - pointer to the pool getting the new node. */ +/* */ +/* Find a matching pool inside the collection of pools for a particular */ +/* device, indicated by the unit number. If it is marked for deletion then */ +/* pretend it does not exist. */ +/* ------------------------------------------------------------------------ */ +void *ip_pool_find(unit, name) +int unit; +char *name; +{ + ip_pool_t *p; + + p = ip_pool_exists(unit, name); + if ((p != NULL) && (p->ipo_flags & IPOOL_DELETE)) + return NULL; + + return p; +} + + +/* ------------------------------------------------------------------------ */ /* Function: ip_pool_findeq */ /* Returns: int - 0 = success, else error */ /* Parameters: ipo(I) - pointer to the pool getting the new node. */ @@ -375,9 +393,9 @@ addrfamily_t *addr, *mask; /* */ /* Search the pool for a given address and return a search result. */ /* ------------------------------------------------------------------------ */ -int ip_pool_search(tptr, version, dptr) +int ip_pool_search(tptr, ipversion, dptr) void *tptr; -int version; +int ipversion; void *dptr; { struct radix_node *rn; @@ -397,11 +415,11 @@ void *dptr; bzero(&v, sizeof(v)); v.adf_len = offsetof(addrfamily_t, adf_addr); - if (version == 4) { + if (ipversion == 4) { v.adf_len += sizeof(addr->in4); v.adf_addr.in4 = addr->in4; #ifdef USE_INET6 - } else if (version == 6) { + } else if (ipversion == 6) { v.adf_len += sizeof(addr->in6); v.adf_addr.in6 = addr->in6; #endif @@ -475,6 +493,7 @@ int info; return ENOMEM; } + x->ipn_ref = 1; x->ipn_next = ipo->ipo_list; x->ipn_pnext = &ipo->ipo_list; if (ipo->ipo_list != NULL) @@ -498,6 +517,10 @@ int info; /* when being inserted - assume this has already been done. If the pool is */ /* marked as being anonymous, give it a new, unique, identifier. Call any */ /* other functions required to initialise the structure. */ +/* */ +/* If the structure is flagged for deletion then reset the flag and return, */ +/* as this likely means we've tried to free a pool that is in use (flush) */ +/* and now want to repopulate it with "new" data. */ /* ------------------------------------------------------------------------ */ int ip_pool_create(op) iplookupop_t *op; @@ -508,23 +531,37 @@ iplookupop_t *op; ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0); - KMALLOC(h, ip_pool_t *); - if (h == NULL) - return ENOMEM; - bzero(h, sizeof(*h)); + unit = op->iplo_unit; - if (rn_inithead((void **)&h->ipo_head, - offsetof(addrfamily_t, adf_addr) << 3) == 0) { - KFREE(h); - return ENOMEM; - } + if ((op->iplo_arg & LOOKUP_ANON) == 0) + h = ip_pool_exists(unit, op->iplo_name); + else + h = NULL; - unit = op->iplo_unit; + if (h != NULL) { + if ((h->ipo_flags & IPOOL_DELETE) != 0) { + h->ipo_flags &= ~IPOOL_DELETE; + return 0; + } + return EEXIST; + } else { + KMALLOC(h, ip_pool_t *); + if (h == NULL) + return ENOMEM; + bzero(h, sizeof(*h)); + + if (rn_inithead((void **)&h->ipo_head, + offsetof(addrfamily_t, adf_addr) << 3) == 0) { + KFREE(h); + return ENOMEM; + } + } - if ((op->iplo_arg & IPOOL_ANON) != 0) { + if ((op->iplo_arg & LOOKUP_ANON) != 0) { ip_pool_t *p; - poolnum = IPOOL_ANON; + h->ipo_flags |= IPOOL_ANON; + poolnum = LOOKUP_ANON; #if defined(SNPRINTF) && defined(_KERNEL) SNPRINTF(name, sizeof(name), "%x", poolnum); @@ -549,19 +586,21 @@ iplookupop_t *op; (void)strncpy(h->ipo_name, name, sizeof(h->ipo_name)); (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name)); } else { - (void) strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name)); + (void)strncpy(h->ipo_name, op->iplo_name, sizeof(h->ipo_name)); } - h->ipo_ref = 1; - h->ipo_list = NULL; - h->ipo_unit = unit; - h->ipo_next = ip_pool_list[unit]; - if (ip_pool_list[unit] != NULL) - ip_pool_list[unit]->ipo_pnext = &h->ipo_next; - h->ipo_pnext = &ip_pool_list[unit]; - ip_pool_list[unit] = h; - - ipoolstat.ipls_pools++; + if ((h->ipo_flags & IPOOL_DELETE) == 0) { + h->ipo_ref = 1; + h->ipo_list = NULL; + h->ipo_unit = unit; + h->ipo_next = ip_pool_list[unit]; + if (ip_pool_list[unit] != NULL) + ip_pool_list[unit]->ipo_pnext = &h->ipo_next; + h->ipo_pnext = &ip_pool_list[unit]; + ip_pool_list[unit] = h; + + ipoolstat.ipls_pools++; + } return 0; } @@ -574,36 +613,26 @@ iplookupop_t *op; /* ipe(I) - address being deleted as a node */ /* Locks: WRITE(ip_poolrw) */ /* */ -/* Add another node to the pool given by ipo. The three parameters passed */ -/* in (addr, mask, info) shold all be stored in the node. */ +/* Remove a node from the pool given by ipo. */ /* ------------------------------------------------------------------------ */ int ip_pool_remove(ipo, ipe) ip_pool_t *ipo; ip_pool_node_t *ipe; { - ip_pool_node_t **ipp, *n; ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0); - for (ipp = &ipo->ipo_list; (n = *ipp) != NULL; ipp = &n->ipn_next) { - if (ipe == n) { - *n->ipn_pnext = n->ipn_next; - if (n->ipn_next) - n->ipn_next->ipn_pnext = n->ipn_pnext; - break; - } - } - - if (n == NULL) - return ENOENT; + if (ipe->ipn_pnext != NULL) + *ipe->ipn_pnext = ipe->ipn_next; + if (ipe->ipn_next != NULL) + ipe->ipn_next->ipn_pnext = ipe->ipn_pnext; RADIX_NODE_HEAD_LOCK(ipo->ipo_head); - ipo->ipo_head->rnh_deladdr(&n->ipn_addr, &n->ipn_mask, + ipo->ipo_head->rnh_deladdr(&ipe->ipn_addr, &ipe->ipn_mask, ipo->ipo_head); RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); - KFREE(n); - ipoolstat.ipls_nodes--; + ip_pool_node_deref(ipe); return 0; } @@ -616,23 +645,28 @@ ip_pool_node_t *ipe; /* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ /* */ /* Search for a pool using paramters passed in and if it's not otherwise */ -/* busy, free it. */ +/* busy, free it. If it is busy, clear all of its nodes, mark it for being */ +/* deleted and return an error saying it is busy. */ /* */ -/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */ +/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */ /* may not be initialised, we can't use an ASSERT to enforce the locking */ /* assertion that one of the two (ip_poolrw,ipf_global) is held. */ /* ------------------------------------------------------------------------ */ -int ip_pool_destroy(op) -iplookupop_t *op; +int ip_pool_destroy(unit, name) +int unit; +char *name; { ip_pool_t *ipo; - ipo = ip_pool_find(op->iplo_unit, op->iplo_name); + ipo = ip_pool_exists(unit, name); if (ipo == NULL) return ESRCH; - if (ipo->ipo_ref != 1) - return EBUSY; + if (ipo->ipo_ref != 1) { + ip_pool_clearnodes(ipo); + ipo->ipo_flags |= IPOOL_DELETE; + return 0; + } ip_pool_free(ipo); return 0; @@ -648,7 +682,7 @@ iplookupop_t *op; /* Free all pools associated with the device that matches the unit number */ /* passed in with operation. */ /* */ -/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */ +/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */ /* may not be initialised, we can't use an ASSERT to enforce the locking */ /* assertion that one of the two (ip_poolrw,ipf_global) is held. */ /* ------------------------------------------------------------------------ */ @@ -669,7 +703,7 @@ iplookupflush_t *fp; (void)strncpy(op.iplo_name, p->ipo_name, sizeof(op.iplo_name)); q = p->ipo_next; - err = ip_pool_destroy(&op); + err = ip_pool_destroy(op.iplo_unit, op.iplo_name); if (err == 0) num++; else @@ -690,13 +724,37 @@ iplookupflush_t *fp; /* all of the address information stored in it, including any tree data */ /* structures also allocated. */ /* */ -/* NOTE: Because this function is called out of ipldetach() where ip_poolrw */ +/* NOTE: Because this function is called out of ipfdetach() where ip_poolrw */ /* may not be initialised, we can't use an ASSERT to enforce the locking */ /* assertion that one of the two (ip_poolrw,ipf_global) is held. */ /* ------------------------------------------------------------------------ */ void ip_pool_free(ipo) ip_pool_t *ipo; { + + ip_pool_clearnodes(ipo); + + if (ipo->ipo_next != NULL) + ipo->ipo_next->ipo_pnext = ipo->ipo_pnext; + *ipo->ipo_pnext = ipo->ipo_next; + rn_freehead(ipo->ipo_head); + KFREE(ipo); + + ipoolstat.ipls_pools--; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ip_pool_clearnodes */ +/* Returns: void */ +/* Parameters: ipo(I) - pointer to pool structure */ +/* Locks: WRITE(ip_poolrw) or WRITE(ipf_global) */ +/* */ +/* Deletes all nodes stored in a pool structure. */ +/* ------------------------------------------------------------------------ */ +static void ip_pool_clearnodes(ipo) +ip_pool_t *ipo; +{ ip_pool_node_t *n; RADIX_NODE_HEAD_LOCK(ipo->ipo_head); @@ -715,13 +773,6 @@ ip_pool_t *ipo; RADIX_NODE_HEAD_UNLOCK(ipo->ipo_head); ipo->ipo_list = NULL; - if (ipo->ipo_next != NULL) - ipo->ipo_next->ipo_pnext = ipo->ipo_pnext; - *ipo->ipo_pnext = ipo->ipo_next; - rn_freehead(ipo->ipo_head); - KFREE(ipo); - - ipoolstat.ipls_pools--; } @@ -741,8 +792,179 @@ ip_pool_t *ipo; ASSERT(rw_read_locked(&ip_poolrw.ipf_lk) == 0); ipo->ipo_ref--; + if (ipo->ipo_ref == 0) ip_pool_free(ipo); + + else if ((ipo->ipo_ref == 1) && (ipo->ipo_flags & IPOOL_DELETE)) + ip_pool_destroy(ipo->ipo_unit, ipo->ipo_name); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ip_pool_node_deref */ +/* Returns: void */ +/* Parameters: ipn(I) - pointer to pool structure */ +/* Locks: WRITE(ip_poolrw) */ +/* */ +/* Drop a reference to the pool node passed in and if we're the last, free */ +/* it all up and adjust the stats accordingly. */ +/* ------------------------------------------------------------------------ */ +void ip_pool_node_deref(ipn) +ip_pool_node_t *ipn; +{ + + ipn->ipn_ref--; + + if (ipn->ipn_ref == 0) { + KFREE(ipn); + ipoolstat.ipls_nodes--; + } +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ip_pool_getnext */ +/* Returns: void */ +/* Parameters: token(I) - pointer to pool structure */ +/* Parameters: ilp(IO) - pointer to pool iterating structure */ +/* */ +/* ------------------------------------------------------------------------ */ +int ip_pool_getnext(token, ilp) +ipftoken_t *token; +ipflookupiter_t *ilp; +{ + ip_pool_node_t *node, zn, *nextnode; + ip_pool_t *ipo, zp, *nextipo; + int err; + + err = 0; + node = NULL; + nextnode = NULL; + ipo = NULL; + nextipo = NULL; + + READ_ENTER(&ip_poolrw); + + switch (ilp->ili_otype) + { + case IPFLOOKUPITER_LIST : + ipo = token->ipt_data; + if (ipo == NULL) { + nextipo = ip_pool_list[(int)ilp->ili_unit]; + } else { + nextipo = ipo->ipo_next; + } + + if (nextipo != NULL) { + ATOMIC_INC(nextipo->ipo_ref); + if (nextipo->ipo_next == NULL) + token->ipt_alive = 0; + } else { + bzero((char *)&zp, sizeof(zp)); + nextipo = &zp; + } + break; + + case IPFLOOKUPITER_NODE : + node = token->ipt_data; + if (node == NULL) { + ipo = ip_pool_exists(ilp->ili_unit, ilp->ili_name); + if (ipo == NULL) + err = ESRCH; + else { + nextnode = ipo->ipo_list; + ipo = NULL; + } + } else { + nextnode = node->ipn_next; + } + + if (nextnode != NULL) { + ATOMIC_INC(nextnode->ipn_ref); + if (nextnode->ipn_next == NULL) + token->ipt_alive = 0; + } else { + bzero((char *)&zn, sizeof(zn)); + nextnode = &zn; + } + break; + default : + err = EINVAL; + break; + } + + RWLOCK_EXIT(&ip_poolrw); + + if (err != 0) + return err; + + switch (ilp->ili_otype) + { + case IPFLOOKUPITER_LIST : + if (ipo != NULL) { + WRITE_ENTER(&ip_poolrw); + ip_pool_deref(ipo); + RWLOCK_EXIT(&ip_poolrw); + } + token->ipt_data = nextipo; + err = COPYOUT(nextipo, ilp->ili_data, sizeof(*nextipo)); + if (err != 0) + err = EFAULT; + break; + + case IPFLOOKUPITER_NODE : + if (node != NULL) { + WRITE_ENTER(&ip_poolrw); + ip_pool_node_deref(node); + RWLOCK_EXIT(&ip_poolrw); + } + token->ipt_data = nextnode; + err = COPYOUT(nextnode, ilp->ili_data, sizeof(*nextnode)); + if (err != 0) + err = EFAULT; + break; + } + + return err; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: ip_pool_iterderef */ +/* Returns: void */ +/* Parameters: ipn(I) - pointer to pool structure */ +/* Locks: WRITE(ip_poolrw) */ +/* */ +/* ------------------------------------------------------------------------ */ +void ip_pool_iterderef(otype, unit, data) +u_int otype; +int unit; +void *data; +{ + + if (data == NULL) + return; + + if (unit < 0 || unit > IPL_LOGMAX) + return; + + switch (otype) + { + case IPFLOOKUPITER_LIST : + WRITE_ENTER(&ip_poolrw); + ip_pool_deref((ip_pool_t *)data); + RWLOCK_EXIT(&ip_poolrw); + break; + + case IPFLOOKUPITER_NODE : + WRITE_ENTER(&ip_poolrw); + ip_pool_node_deref((ip_pool_node_t *)data); + RWLOCK_EXIT(&ip_poolrw); + break; + default : + break; + } } @@ -780,5 +1002,4 @@ rn_freehead(rnh) Free(rnh); } # endif - #endif /* IPFILTER_LOOKUP */ diff --git a/sys/contrib/ipfilter/netinet/ip_pool.h b/sys/contrib/ipfilter/netinet/ip_pool.h index 3731fe9..927276f 100644 --- a/sys/contrib/ipfilter/netinet/ip_pool.h +++ b/sys/contrib/ipfilter/netinet/ip_pool.h @@ -3,7 +3,7 @@ * * See the IPFILTER.LICENCE file for details on licencing. * - * $Id: ip_pool.h,v 2.26.2.3 2005/06/12 07:18:27 darrenr Exp $ + * $Id: ip_pool.h,v 2.26.2.5 2007/01/14 14:06:12 darrenr Exp $ */ #ifndef __IP_POOL_H__ @@ -35,8 +35,9 @@ typedef struct ip_pool_node { addrfamily_t ipn_addr; addrfamily_t ipn_mask; int ipn_info; - char ipn_name[FR_GROUPLEN]; - u_long ipn_hits; + int ipn_ref; +char ipn_name[FR_GROUPLEN]; +u_long ipn_hits; struct ip_pool_node *ipn_next, **ipn_pnext; } ip_pool_node_t; @@ -53,7 +54,8 @@ typedef struct ip_pool_s { char ipo_name[FR_GROUPLEN]; } ip_pool_t; -#define IPOOL_ANON 0x80000000 +#define IPOOL_DELETE 0x01 +#define IPOOL_ANON 0x02 typedef struct ip_pool_stat { @@ -73,13 +75,16 @@ extern void ip_pool_fini __P((void)); extern int ip_pool_create __P((iplookupop_t *)); extern int ip_pool_insert __P((ip_pool_t *, i6addr_t *, i6addr_t *, int)); extern int ip_pool_remove __P((ip_pool_t *, ip_pool_node_t *)); -extern int ip_pool_destroy __P((iplookupop_t *)); +extern int ip_pool_destroy __P((int, char *)); extern void ip_pool_free __P((ip_pool_t *)); extern void ip_pool_deref __P((ip_pool_t *)); +extern void ip_pool_node_deref __P((ip_pool_node_t *)); extern void *ip_pool_find __P((int, char *)); extern ip_pool_node_t *ip_pool_findeq __P((ip_pool_t *, addrfamily_t *, addrfamily_t *)); extern int ip_pool_flush __P((iplookupflush_t *)); extern int ip_pool_statistics __P((iplookupop_t *)); +extern int ip_pool_getnext __P((ipftoken_t *, ipflookupiter_t *)); +extern void ip_pool_iterderef __P((u_int, int, void *)); #endif /* __IP_POOL_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_pptp_pxy.c b/sys/contrib/ipfilter/netinet/ip_pptp_pxy.c index 2ef2e17..3924d4b 100644 --- a/sys/contrib/ipfilter/netinet/ip_pptp_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_pptp_pxy.c @@ -4,7 +4,7 @@ * Simple PPTP transparent proxy for in-kernel use. For use with the NAT * code. * - * $Id: ip_pptp_pxy.c,v 2.10.2.13 2006/03/17 10:40:05 darrenr Exp $ + * $Id: ip_pptp_pxy.c,v 2.10.2.15 2006/10/31 12:11:23 darrenr Exp $ * */ #define IPF_PPTP_PROXY @@ -78,6 +78,9 @@ void ippr_pptp_fini() /* * Setup for a new PPTP proxy. + * + * NOTE: The printf's are broken up with %s in them to prevent them being + * optimised into puts statements on FreeBSD (this doesn't exist in the kernel) */ int ippr_pptp_new(fin, aps, nat) fr_info_t *fin; @@ -220,7 +223,7 @@ pptp_pxy_t *pptp; pptp->pptp_state = fr_addstate(&fi, &pptp->pptp_state, 0); if (fi.fin_state != NULL) - fr_statederef(&fi, (ipstate_t **)&fi.fin_state); + fr_statederef((ipstate_t **)&fi.fin_state); } ip->ip_p = p; return; diff --git a/sys/contrib/ipfilter/netinet/ip_proxy.c b/sys/contrib/ipfilter/netinet/ip_proxy.c index 8fdd98c..96eb172 100644 --- a/sys/contrib/ipfilter/netinet/ip_proxy.c +++ b/sys/contrib/ipfilter/netinet/ip_proxy.c @@ -103,7 +103,7 @@ struct file; /* END OF INCLUDES */ #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 2.62.2.16 2006/03/29 11:19:56 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 2.62.2.20 2007/05/31 12:27:36 darrenr Exp $"; #endif static int appr_fixseqack __P((fr_info_t *, ip_t *, ap_session_t *, int )); @@ -121,7 +121,7 @@ aproxy_t *ap_proxylist = NULL; aproxy_t ap_proxies[] = { #ifdef IPF_FTP_PROXY { NULL, "ftp", (char)IPPROTO_TCP, 0, 0, ippr_ftp_init, ippr_ftp_fini, - ippr_ftp_new, NULL, ippr_ftp_in, ippr_ftp_out, NULL }, + ippr_ftp_new, NULL, ippr_ftp_in, ippr_ftp_out, NULL, NULL }, #endif #ifdef IPF_IRC_PROXY { NULL, "irc", (char)IPPROTO_TCP, 0, 0, ippr_irc_init, ippr_irc_fini, @@ -155,9 +155,9 @@ aproxy_t ap_proxies[] = { #endif #ifdef IPF_H323_PROXY { NULL, "h323", (char)IPPROTO_TCP, 0, 0, ippr_h323_init, ippr_h323_fini, - ippr_h323_new, ippr_h323_del, ippr_h323_in, NULL, NULL }, + ippr_h323_new, ippr_h323_del, ippr_h323_in, NULL, NULL, NULL }, { NULL, "h245", (char)IPPROTO_TCP, 0, 0, NULL, NULL, - ippr_h245_new, NULL, NULL, ippr_h245_out, NULL }, + ippr_h245_new, NULL, NULL, ippr_h245_out, NULL, NULL }, #endif #ifdef IPF_RPCB_PROXY # if 0 @@ -169,7 +169,7 @@ aproxy_t ap_proxies[] = { ippr_rpcb_init, ippr_rpcb_fini, ippr_rpcb_new, ippr_rpcb_del, ippr_rpcb_in, ippr_rpcb_out, NULL, NULL }, #endif - { NULL, "", '\0', 0, 0, NULL, NULL, NULL, NULL } + { NULL, "", '\0', 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL } }; /* @@ -191,7 +191,7 @@ aproxy_t *ap; return -1; } - for (a = ap_proxylist; a->apr_p; a = a->apr_next) + for (a = ap_proxylist; (a != NULL); a = a->apr_next) if ((a->apr_p == ap->apr_p) && !strncmp(a->apr_label, ap->apr_label, sizeof(ap->apr_label))) { @@ -288,10 +288,11 @@ ipnat_t *nat; } -int appr_ioctl(data, cmd, mode) +int appr_ioctl(data, cmd, mode, ctx) caddr_t data; ioctlcmd_t cmd; int mode; +void *ctx; { ap_ctl_t ctl; caddr_t ptr; @@ -813,7 +814,7 @@ int inc; if (ipf_proxy_debug > 8) printf("appr_fixseqack: seq %x ack %x\n", - ntohl(tcp->th_seq), ntohl(tcp->th_ack)); + (u_32_t)ntohl(tcp->th_seq), (u_32_t)ntohl(tcp->th_ack)); return ch ? 2 : 0; } diff --git a/sys/contrib/ipfilter/netinet/ip_proxy.h b/sys/contrib/ipfilter/netinet/ip_proxy.h index 1e0bede..e370022 100644 --- a/sys/contrib/ipfilter/netinet/ip_proxy.h +++ b/sys/contrib/ipfilter/netinet/ip_proxy.h @@ -3,7 +3,7 @@ * * See the IPFILTER.LICENCE file for details on licencing. * - * $Id: ip_proxy.h,v 2.31.2.3 2005/06/18 02:41:33 darrenr Exp $ + * $Id: ip_proxy.h,v 2.31.2.5 2007/04/16 21:06:52 darrenr Exp $ */ #ifndef __IP_PROXY_H__ @@ -440,6 +440,7 @@ extern ap_session_t *ap_sess_tab[AP_SESS_SIZE]; extern ap_session_t *ap_sess_list; extern aproxy_t ap_proxies[]; extern int ippr_ftp_pasvonly; +extern int ipf_proxy_debug; extern int appr_add __P((aproxy_t *)); extern int appr_ctl __P((ap_ctl_t *)); @@ -453,6 +454,6 @@ extern void aps_free __P((ap_session_t *)); extern int appr_check __P((fr_info_t *, struct nat *)); extern aproxy_t *appr_lookup __P((u_int, char *)); extern int appr_new __P((fr_info_t *, struct nat *)); -extern int appr_ioctl __P((caddr_t, ioctlcmd_t, int)); +extern int appr_ioctl __P((caddr_t, ioctlcmd_t, int, void *)); #endif /* __IP_PROXY_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c b/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c index a81e12d..76e8b9f 100644 --- a/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c @@ -3,7 +3,7 @@ * * See the IPFILTER.LICENCE file for details on licencing. * - * $Id: ip_raudio_pxy.c,v 1.40.2.3 2005/02/04 10:22:55 darrenr Exp $ + * $Id: ip_raudio_pxy.c,v 1.40.2.4 2006/07/14 06:12:17 darrenr Exp $ */ #define IPF_RAUDIO_PROXY @@ -304,7 +304,7 @@ nat_t *nat; (void) fr_addstate(&fi, NULL, (sp ? 0 : SI_W_SPORT)); if (fi.fin_state != NULL) - fr_statederef(&fi, (ipstate_t **)&fi.fin_state); + fr_statederef((ipstate_t **)&fi.fin_state); } } @@ -324,7 +324,7 @@ nat_t *nat; (void) fr_addstate(&fi, NULL, SI_W_DPORT); if (fi.fin_state != NULL) - fr_statederef(&fi, (ipstate_t **)&fi.fin_state); + fr_statederef((ipstate_t **)&fi.fin_state); } } diff --git a/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c b/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c index c93207e..0af3f9b 100644 --- a/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c @@ -3,7 +3,7 @@ * * See the IPFILTER.LICENCE file for details on licencing. * - * $Id: ip_rcmd_pxy.c,v 1.41.2.6 2006/04/01 10:14:54 darrenr Exp $ + * $Id: ip_rcmd_pxy.c,v 1.41.2.7 2006/07/14 06:12:18 darrenr Exp $ * * Simple RCMD transparent proxy for in-kernel use. For use with the NAT * code. @@ -204,7 +204,7 @@ nat_t *nat; } (void) fr_addstate(&fi, NULL, SI_W_DPORT); if (fi.fin_state != NULL) - fr_statederef(&fi, (ipstate_t **)&fi.fin_state); + fr_statederef((ipstate_t **)&fi.fin_state); } ip->ip_len = slen; ip->ip_src = swip; diff --git a/sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c b/sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c index 112e4da..4350bf4 100644 --- a/sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_rpcb_pxy.c @@ -37,7 +37,7 @@ * o The enclosed hack of STREAMS support is pretty sick and most likely * broken. * - * $Id: ip_rpcb_pxy.c,v 2.25.2.3 2005/02/04 10:22:56 darrenr Exp $ + * $Id: ip_rpcb_pxy.c,v 2.25.2.6 2007/01/17 11:34:54 darrenr Exp $ */ #define IPF_RPCB_PROXY @@ -290,6 +290,7 @@ ippr_rpcb_out(fin, aps, nat) /* Perform basic variable initialization. */ rs = (rpcb_session_t *)aps->aps_data; + rx = NULL; m = fin->fin_m; off = (char *)fin->fin_dp - (char *)fin->fin_ip; @@ -307,6 +308,8 @@ ippr_rpcb_out(fin, aps, nat) COPYDATA(m, off, dlen, (caddr_t)&rm->rm_msgbuf); rm->rm_buflen = dlen; + rx = NULL; /* XXX gcc */ + /* Send off to decode reply. */ rv = ippr_rpcb_decoderep(fin, nat, rs, rm, &rx); @@ -1156,6 +1159,8 @@ ippr_rpcb_getnat(fin, nat, proto, port) /* Generate dummy fr_info */ bcopy((char *)fin, (char *)&fi, sizeof(fi)); + fi.fin_state = NULL; + fi.fin_nat = NULL; fi.fin_out = 0; fi.fin_src = fin->fin_dst; fi.fin_dst = nat->nat_outip; @@ -1191,8 +1196,9 @@ ippr_rpcb_getnat(fin, nat, proto, port) * no use for this lock, so simply unlock it if necessary. */ is = fr_stlookup(&fi, &tcp, NULL); - if (is != NULL) + if (is != NULL) { RWLOCK_EXIT(&ipf_state); + } RWLOCK_EXIT(&ipf_nat); @@ -1271,7 +1277,7 @@ ippr_rpcb_getnat(fin, nat, proto, port) return(-1); } if (fi.fin_state != NULL) - fr_statederef(&fi, (ipstate_t **)&fi.fin_state); + fr_statederef((ipstate_t **)&fi.fin_state); } return(0); diff --git a/sys/contrib/ipfilter/netinet/ip_scan.c b/sys/contrib/ipfilter/netinet/ip_scan.c index 13a5a60..ad37216 100644 --- a/sys/contrib/ipfilter/netinet/ip_scan.c +++ b/sys/contrib/ipfilter/netinet/ip_scan.c @@ -58,7 +58,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_scan.c,v 2.40.2.6 2006/03/26 23:06:49 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_scan.c,v 2.40.2.9 2007/03/13 09:42:05 darrenr Exp $"; #endif #ifdef IPFILTER_SCAN /* endif at bottom of file */ @@ -115,8 +115,10 @@ caddr_t data; return ENOMEM; err = copyinptr(data, isc, sizeof(*isc)); - if (err) + if (err) { + KFREE(isc); return err; + } WRITE_ENTER(&ipsc_rwlock); @@ -230,20 +232,17 @@ struct ipstate *is; fr = is->is_rule; if (fr) { i = fr->fr_isc; - if (!i || (i != (ipscan_t *)-1)) { + if ((i != NULL) && (i != (ipscan_t *)-1)) { is->is_isc = i; - if (i) { - ATOMIC_INC32(i->ipsc_sref); - if (i->ipsc_clen) - is->is_flags |= IS_SC_CLIENT; - else - is->is_flags |= IS_SC_MATCHC; - if (i->ipsc_slen) - is->is_flags |= IS_SC_SERVER; - else - is->is_flags |= IS_SC_MATCHS; - } else - is->is_flags |= (IS_SC_CLIENT|IS_SC_SERVER); + ATOMIC_INC32(i->ipsc_sref); + if (i->ipsc_clen) + is->is_flags |= IS_SC_CLIENT; + else + is->is_flags |= IS_SC_MATCHC; + if (i->ipsc_slen) + is->is_flags |= IS_SC_SERVER; + else + is->is_flags |= IS_SC_MATCHS; } } RWLOCK_EXIT(&ipsc_rwlock); @@ -568,10 +567,11 @@ ipstate_t *is; } -int fr_scan_ioctl(data, cmd, mode) +int fr_scan_ioctl(data, cmd, mode, uid, ctx) caddr_t data; ioctlcmd_t cmd; -int mode; +int mode, uid; +void *ctx; { ipscanstat_t ipscs; int err = 0; diff --git a/sys/contrib/ipfilter/netinet/ip_scan.h b/sys/contrib/ipfilter/netinet/ip_scan.h index d857453..4772d28 100644 --- a/sys/contrib/ipfilter/netinet/ip_scan.h +++ b/sys/contrib/ipfilter/netinet/ip_scan.h @@ -4,7 +4,7 @@ * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ip_fil.h 1.35 6/5/96 - * $Id: ip_scan.h,v 2.9.2.1 2005/06/12 07:18:29 darrenr Exp $ + * $Id: ip_scan.h,v 2.9.2.2 2006/07/14 06:12:19 darrenr Exp $ */ #ifndef __IP_SCAN_H__ @@ -94,7 +94,7 @@ typedef struct ipscanstat { } ipscanstat_t; -extern int fr_scan_ioctl __P((caddr_t, ioctlcmd_t, int)); +extern int fr_scan_ioctl __P((caddr_t, ioctlcmd_t, int, int, void *)); extern int ipsc_init __P((void)); extern int ipsc_attachis __P((struct ipstate *)); extern int ipsc_attachfr __P((struct frentry *)); diff --git a/sys/contrib/ipfilter/netinet/ip_state.c b/sys/contrib/ipfilter/netinet/ip_state.c index 32aa805..774dff3 100644 --- a/sys/contrib/ipfilter/netinet/ip_state.c +++ b/sys/contrib/ipfilter/netinet/ip_state.c @@ -15,7 +15,11 @@ #include #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \ defined(_KERNEL) -# include "opt_ipfilter_log.h" +# if (__NetBSD_Version__ < 399001400) +# include "opt_ipfilter_log.h" +# else +# include "opt_ipfilter.h" +# endif #endif #if defined(_KERNEL) && defined(__FreeBSD_version) && \ (__FreeBSD_version >= 400000) && !defined(KLD_MODULE) @@ -107,7 +111,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.41 2006/04/01 10:16:28 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.186.2.69 2007/05/26 13:05:14 darrenr Exp $"; #endif static ipstate_t **ips_table = NULL; @@ -123,8 +127,9 @@ static ipstate_t *fr_matchsrcdst __P((fr_info_t *, ipstate_t *, i6addr_t *, i6addr_t *, tcphdr_t *, u_32_t)); static ipstate_t *fr_checkicmpmatchingstate __P((fr_info_t *)); static int fr_state_flush __P((int, int)); +static int fr_state_flush_entry __P((void *)); static ips_stat_t *fr_statetstats __P((void)); -static void fr_delstate __P((ipstate_t *, int)); +static int fr_delstate __P((ipstate_t *, int)); static int fr_state_remove __P((caddr_t)); static void fr_ipsmove __P((ipstate_t *, u_int)); static int fr_tcpstate __P((fr_info_t *, tcphdr_t *, ipstate_t *)); @@ -133,6 +138,8 @@ static ipstate_t *fr_stclone __P((fr_info_t *, tcphdr_t *, ipstate_t *)); static void fr_fixinisn __P((fr_info_t *, ipstate_t *)); static void fr_fixoutisn __P((fr_info_t *, ipstate_t *)); static void fr_checknewisn __P((fr_info_t *, ipstate_t *)); +static int fr_stateiter __P((ipftoken_t *, ipfgeniter_t *)); +static int fr_stgettable __P((char *)); int fr_stputent __P((caddr_t)); int fr_stgetent __P((caddr_t)); @@ -143,9 +150,10 @@ int fr_stgetent __P((caddr_t)); u_long fr_tcpidletimeout = FIVE_DAYS, fr_tcpclosewait = IPF_TTLVAL(2 * TCP_MSL), - fr_tcplastack = IPF_TTLVAL(2 * TCP_MSL), + fr_tcplastack = IPF_TTLVAL(30), fr_tcptimeout = IPF_TTLVAL(2 * TCP_MSL), - fr_tcpclosed = IPF_TTLVAL(60), + fr_tcptimewait = IPF_TTLVAL(2 * TCP_MSL), + fr_tcpclosed = IPF_TTLVAL(30), fr_tcphalfclosed = IPF_TTLVAL(2 * 3600), /* 2 hours */ fr_udptimeout = IPF_TTLVAL(120), fr_udpacktimeout = IPF_TTLVAL(12), @@ -165,6 +173,7 @@ ipftq_t ips_tqtqb[IPF_TCP_NSTATES], ips_iptq, ips_icmptq, ips_icmpacktq, + ips_deletetq, *ips_utqe = NULL; #ifdef IPFILTER_LOG int ipstate_logging = 1; @@ -239,6 +248,7 @@ int fr_stateinit() fr_state_maxbucket *= 2; } + ips_stats.iss_tcptab = ips_tqtqb; fr_sttab_init(ips_tqtqb); ips_tqtqb[IPF_TCP_NSTATES - 1].ifq_next = &ips_udptq; ips_udptq.ifq_ttl = (u_long)fr_udptimeout; @@ -270,7 +280,13 @@ int fr_stateinit() ips_iptq.ifq_head = NULL; ips_iptq.ifq_tail = &ips_iptq.ifq_head; MUTEX_INIT(&ips_iptq.ifq_lock, "ipftq ip tab"); - ips_iptq.ifq_next = NULL; + ips_iptq.ifq_next = &ips_deletetq; + ips_deletetq.ifq_ttl = (u_long)1; + ips_deletetq.ifq_ref = 1; + ips_deletetq.ifq_head = NULL; + ips_deletetq.ifq_tail = &ips_deletetq.ifq_head; + MUTEX_INIT(&ips_deletetq.ifq_lock, "state delete queue"); + ips_deletetq.ifq_next = NULL; RWLOCK_INIT(&ipf_state, "ipf IP state rwlock"); MUTEX_INIT(&ipf_stinsert, "ipf state insert mutex"); @@ -295,7 +311,7 @@ void fr_stateunload() ipstate_t *is; while ((is = ips_list) != NULL) - fr_delstate(is, 0); + fr_delstate(is, ISL_UNLOAD); /* * Proxy timeout queues are not cleaned here because although they @@ -321,6 +337,7 @@ void fr_stateunload() MUTEX_DESTROY(&ips_udpacktq.ifq_lock); MUTEX_DESTROY(&ips_icmpacktq.ifq_lock); MUTEX_DESTROY(&ips_iptq.ifq_lock); + MUTEX_DESTROY(&ips_deletetq.ifq_lock); } if (ips_table != NULL) { @@ -414,12 +431,14 @@ caddr_t data; /* */ /* Processes an ioctl call made to operate on the IP Filter state device. */ /* ------------------------------------------------------------------------ */ -int fr_state_ioctl(data, cmd, mode) +int fr_state_ioctl(data, cmd, mode, uid, ctx) caddr_t data; ioctlcmd_t cmd; -int mode; +int mode, uid; +void *ctx; { int arg, ret, error = 0; + SPL_INT(s); switch (cmd) { @@ -429,29 +448,37 @@ int mode; case SIOCDELST : error = fr_state_remove(data); break; + /* * Flush the state table */ case SIOCIPFFL : - BCOPYIN(data, (char *)&arg, sizeof(arg)); - if (arg == 0 || arg == 1) { + error = BCOPYIN(data, (char *)&arg, sizeof(arg)); + if (error != 0) { + error = EFAULT; + } else { WRITE_ENTER(&ipf_state); ret = fr_state_flush(arg, 4); RWLOCK_EXIT(&ipf_state); - BCOPYOUT((char *)&ret, data, sizeof(ret)); - } else - error = EINVAL; + error = BCOPYOUT((char *)&ret, data, sizeof(ret)); + if (error != 0) + error = EFAULT; + } break; + #ifdef USE_INET6 case SIOCIPFL6 : - BCOPYIN(data, (char *)&arg, sizeof(arg)); - if (arg == 0 || arg == 1) { + error = BCOPYIN(data, (char *)&arg, sizeof(arg)); + if (error != 0) { + error = EFAULT; + } else { WRITE_ENTER(&ipf_state); ret = fr_state_flush(arg, 6); RWLOCK_EXIT(&ipf_state); - BCOPYOUT((char *)&ret, data, sizeof(ret)); - } else - error = EINVAL; + error = BCOPYOUT((char *)&ret, data, sizeof(ret)); + if (error != 0) + error = EFAULT; + } break; #endif #ifdef IPFILTER_LOG @@ -465,9 +492,12 @@ int mode; int tmp; tmp = ipflog_clear(IPL_LOGSTATE); - BCOPYOUT((char *)&tmp, data, sizeof(tmp)); + error = BCOPYOUT((char *)&tmp, data, sizeof(tmp)); + if (error != 0) + error = EFAULT; } break; + /* * Turn logging of state information on/off. */ @@ -475,31 +505,41 @@ int mode; if (!(mode & FWRITE)) error = EPERM; else { - BCOPYIN((char *)data, (char *)&ipstate_logging, - sizeof(ipstate_logging)); + error = BCOPYIN((char *)data, (char *)&ipstate_logging, + sizeof(ipstate_logging)); + if (error != 0) + error = EFAULT; } break; + /* * Return the current state of logging. */ case SIOCGETLG : - BCOPYOUT((char *)&ipstate_logging, (char *)data, - sizeof(ipstate_logging)); + error = BCOPYOUT((char *)&ipstate_logging, (char *)data, + sizeof(ipstate_logging)); + if (error != 0) + error = EFAULT; break; + /* * Return the number of bytes currently waiting to be read. */ case FIONREAD : arg = iplused[IPL_LOGSTATE]; /* returned in an int */ - BCOPYOUT((char *)&arg, data, sizeof(arg)); + error = BCOPYOUT((char *)&arg, data, sizeof(arg)); + if (error != 0) + error = EFAULT; break; #endif + /* * Get the current state statistics. */ case SIOCGETFS : error = fr_outobj(data, fr_statetstats(), IPFOBJ_STATESTAT); break; + /* * Lock/Unlock the state table. (Locking prevents any changes, which * means no packets match). @@ -511,6 +551,7 @@ int mode; fr_lock(data, &fr_state_lock); } break; + /* * Add an entry to the current state table. */ @@ -521,6 +562,7 @@ int mode; } error = fr_stputent(data); break; + /* * Get a state table entry. */ @@ -531,6 +573,56 @@ int mode; } error = fr_stgetent(data); break; + + /* + * Return a copy of the hash table bucket lengths + */ + case SIOCSTAT1 : + error = BCOPYOUT(ips_stats.iss_bucketlen, data, + fr_statesize * sizeof(u_long)); + if (error != 0) + error = EFAULT; + break; + + case SIOCGENITER : + { + ipftoken_t *token; + ipfgeniter_t iter; + + error = fr_inobj(data, &iter, IPFOBJ_GENITER); + if (error != 0) + break; + + SPL_SCHED(s); + token = ipf_findtoken(IPFGENITER_STATE, uid, ctx); + if (token != NULL) + error = fr_stateiter(token, &iter); + else + error = ESRCH; + RWLOCK_EXIT(&ipf_tokens); + SPL_X(s); + break; + } + + case SIOCGTABL : + error = fr_stgettable(data); + break; + + case SIOCIPFDELTOK : + error = BCOPYIN(data, (char *)&arg, sizeof(arg)); + if (error != 0) { + error = EFAULT; + } else { + SPL_SCHED(s); + error = ipf_deltoken(arg, uid, ctx); + SPL_X(s); + } + break; + + case SIOCGTQTAB : + error = fr_outobj(data, ips_tqtqb, IPFOBJ_STATETQTAB); + break; + default : error = EINVAL; break; @@ -670,7 +762,8 @@ caddr_t data; fr->fr_data = NULL; fr->fr_type = FR_T_NONE; - fr_resolvedest(&fr->fr_tif, fr->fr_v); + fr_resolvedest(&fr->fr_tifs[0], fr->fr_v); + fr_resolvedest(&fr->fr_tifs[1], fr->fr_v); fr_resolvedest(&fr->fr_dif, fr->fr_v); /* @@ -819,7 +912,6 @@ u_int flags; frentry_t *fr; tcphdr_t *tcp; grehdr_t *gre; - void *ifp; int out; if (fr_state_lock || @@ -841,7 +933,7 @@ u_int flags; */ fr = fin->fin_fr; if (fr != NULL) { - if ((ips_num == fr_statemax) && (fr->fr_statemax == 0)) { + if ((ips_num >= fr_statemax) && (fr->fr_statemax == 0)) { ATOMIC_INCL(ips_stats.iss_max); fr_state_doflush = 1; return NULL; @@ -849,7 +941,6 @@ u_int flags; if ((fr->fr_statemax != 0) && (fr->fr_statecnt >= fr->fr_statemax)) { ATOMIC_INCL(ips_stats.iss_maxref); - fr_state_doflush = 1; return NULL; } } @@ -1084,30 +1175,41 @@ u_int flags; is->is_tag = fr->fr_logtag; + /* + * The name '-' is special for network interfaces and causes + * a NULL name to be present, always, allowing packets to + * match it, regardless of their interface. + */ + if ((fin->fin_ifp == NULL) || + (fr->fr_ifnames[out << 1][0] == '-' && + fr->fr_ifnames[out << 1][1] == '\0')) { + is->is_ifp[out << 1] = fr->fr_ifas[0]; + strncpy(is->is_ifname[out << 1], fr->fr_ifnames[0], + sizeof(fr->fr_ifnames[0])); + } else { + is->is_ifp[out << 1] = fin->fin_ifp; + COPYIFNAME(fin->fin_ifp, is->is_ifname[out << 1]); + } + is->is_ifp[(out << 1) + 1] = fr->fr_ifas[1]; + strncpy(is->is_ifname[(out << 1) + 1], fr->fr_ifnames[1], + sizeof(fr->fr_ifnames[1])); + is->is_ifp[(1 - out) << 1] = fr->fr_ifas[2]; - is->is_ifp[((1 - out) << 1) + 1] = fr->fr_ifas[3]; + strncpy(is->is_ifname[((1 - out) << 1)], fr->fr_ifnames[2], + sizeof(fr->fr_ifnames[2])); - if (((ifp = fr->fr_ifas[1]) != NULL) && - (ifp != (void *)-1)) { - COPYIFNAME(ifp, is->is_ifname[(out << 1) + 1]); - } - if (((ifp = fr->fr_ifas[2]) != NULL) && - (ifp != (void *)-1)) { - COPYIFNAME(ifp, is->is_ifname[(1 - out) << 1]); - } - if (((ifp = fr->fr_ifas[3]) != NULL) && - (ifp != (void *)-1)) { - COPYIFNAME(ifp, is->is_ifname[((1 - out) << 1) + 1]); - } + is->is_ifp[((1 - out) << 1) + 1] = fr->fr_ifas[3]; + strncpy(is->is_ifname[((1 - out) << 1) + 1], fr->fr_ifnames[3], + sizeof(fr->fr_ifnames[3])); } else { pass = fr_flags; is->is_tag = FR_NOLOGTAG; - } - is->is_ifp[out << 1] = fin->fin_ifp; - if (fin->fin_ifp != NULL) { - COPYIFNAME(fin->fin_ifp, is->is_ifname[out << 1]); + if (fin->fin_ifp != NULL) { + is->is_ifp[out << 1] = fin->fin_ifp; + COPYIFNAME(fin->fin_ifp, is->is_ifname[out << 1]); + } } /* @@ -1324,6 +1426,22 @@ ipstate_t *is; tdata = &is->is_tcp.ts_data[source]; MUTEX_ENTER(&is->is_lock); + + /* + * If a SYN packet is received for a connection that is on the way out + * but hasn't yet departed then advance this session along the way. + */ + if ((tcp->th_flags & TH_OPENING) == TH_SYN) { + if ((is->is_state[0] > IPF_TCPS_ESTABLISHED) && + (is->is_state[1] > IPF_TCPS_ESTABLISHED)) { + is->is_state[!source] = IPF_TCPS_CLOSED; + fr_movequeue(&is->is_sti, is->is_sti.tqe_ifq, + &ips_deletetq); + MUTEX_ENTER(&is->is_lock); + return 0; + } + } + if (fr_tcpinwindow(fin, fdata, tdata, tcp, is->is_flags)) { #ifdef IPFILTER_SCAN if (is->is_flags & (IS_SC_CLIENT|IS_SC_SERVER)) { @@ -1356,21 +1474,16 @@ ipstate_t *is; if (flags == (TH_SYN|TH_ACK)) { is->is_s0[source] = ntohl(tcp->th_ack); is->is_s0[!source] = ntohl(tcp->th_seq) + 1; - if ((TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2)) && - (tdata->td_winflags & TCP_WSCALE_SEEN)) { + if ((TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2))) { if (fr_tcpoptions(fin, tcp, fdata) == -1) fin->fin_flx |= FI_BAD; - if (!(fdata->td_winflags & TCP_WSCALE_SEEN)) { - fdata->td_winscale = 0; - tdata->td_winscale = 0; - } } if ((fin->fin_out != 0) && (is->is_pass & FR_NEWISN)) fr_checknewisn(fin, is); } else if (flags == TH_SYN) { is->is_s0[source] = ntohl(tcp->th_seq) + 1; if ((TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2))) { - if (fr_tcpoptions(fin, tcp, tdata) == -1) + if (fr_tcpoptions(fin, tcp, fdata) == -1) fin->fin_flx |= FI_BAD; } @@ -1379,8 +1492,9 @@ ipstate_t *is; } ret = 1; - } else + } else { fin->fin_flx |= FI_OOW; + } MUTEX_EXIT(&is->is_lock); return ret; } @@ -1477,17 +1591,8 @@ int flags; * the receiver also does window scaling) */ if (!(tcpflags & TH_SYN) && (fdata->td_winflags & TCP_WSCALE_FIRST)) { - if (tdata->td_winflags & TCP_WSCALE_SEEN) { - fdata->td_winflags &= ~TCP_WSCALE_FIRST; - fdata->td_maxwin = win; - } else { - fdata->td_winscale = 0; - fdata->td_winflags &= ~(TCP_WSCALE_FIRST| - TCP_WSCALE_SEEN); - tdata->td_winscale = 0; - tdata->td_winflags &= ~(TCP_WSCALE_FIRST| - TCP_WSCALE_SEEN); - } + fdata->td_winflags &= ~TCP_WSCALE_FIRST; + fdata->td_maxwin = win; } end = seq + dsize; @@ -1530,7 +1635,7 @@ int flags; (SEQ_GE(seq, fdata->td_end - maxwin)) && /* XXX what about big packets */ #define MAXACKWINDOW 66000 - (-ackskew <= (MAXACKWINDOW << fdata->td_winscale)) && + (-ackskew <= (MAXACKWINDOW)) && ( ackskew <= (MAXACKWINDOW << fdata->td_winscale))) { inseq = 1; /* @@ -1576,6 +1681,8 @@ int flags; } } + /* TRACE(inseq, fdata, tdata, seq, end, ack, ackskew, win, maxwin) */ + if (inseq) { /* if ackskew < 0 then this should be due to fragmented * packets. There is no way to know the length of the @@ -1733,9 +1840,9 @@ u_32_t cmask; * If the interface for this 'direction' is set, make sure it matches. * An interface name that is not set matches any, as does a name of *. */ - if ((is->is_ifp[idx] == NULL && - (*is->is_ifname[idx] == '\0' || *is->is_ifname[idx] == '*')) || - is->is_ifp[idx] == ifp) + if ((is->is_ifp[idx] == ifp) || (is->is_ifp[idx] == NULL && + (*is->is_ifname[idx] == '\0' || *is->is_ifname[idx] == '-' || + *is->is_ifname[idx] == '*'))) ret = 1; if (ret == 0) @@ -2005,7 +2112,7 @@ fr_info_t *fin; # endif } #endif - bcopy((char *)fin, (char *)&ofin, sizeof(fin)); + bcopy((char *)fin, (char *)&ofin, sizeof(*fin)); /* * in the IPv4 case we must zero the i6addr union otherwise @@ -2035,7 +2142,6 @@ fr_info_t *fin; ofin.fin_ip = oip; ofin.fin_m = NULL; /* if dereferenced, panic XXX */ ofin.fin_mp = NULL; /* if dereferenced, panic XXX */ - ofin.fin_plen = fin->fin_dlen - ICMPERR_ICMPHLEN; (void) fr_makefrip(IP_HL(oip) << 2, oip, &ofin); ofin.fin_ifp = fin->fin_ifp; ofin.fin_out = !fin->fin_out; @@ -2295,6 +2401,13 @@ icmp6again: hvm = DOUBLE_HASH(hv); for (isp = &ips_table[hvm]; ((is = *isp) != NULL); ) { isp = &is->is_hnext; + /* + * If a connection is about to be deleted, no packets + * are allowed to match it. + */ + if (is->is_sti.tqe_ifq == &ips_deletetq) + continue; + if ((is->is_p != pr) || (is->is_v != v)) continue; is = fr_matchsrcdst(fin, is, &src, &dst, NULL, FI_CMP); @@ -2624,8 +2737,6 @@ matched: fin->fin_rule = is->is_rulen; pass = is->is_pass; fr_updatestate(fin, is, ifq); - if (fin->fin_out == 1) - fin->fin_nat = is->is_nat[fin->fin_rev]; fin->fin_state = is; is->is_touched = fr_ticks; @@ -2761,7 +2872,7 @@ void *ifp; /* ------------------------------------------------------------------------ */ /* Function: fr_delstate */ -/* Returns: Nil */ +/* Returns: int - 0 = entry deleted, else reference count on struct */ /* Parameters: is(I) - pointer to state structure to delete */ /* why(I) - if not 0, log reason why it was deleted */ /* Write Locks: ipf_state */ @@ -2770,7 +2881,7 @@ void *ifp; /* and timeout queue lists. Make adjustments to hash table statistics and */ /* global counters as required. */ /* ------------------------------------------------------------------------ */ -static void fr_delstate(is, why) +static int fr_delstate(is, why) ipstate_t *is; int why; { @@ -2781,16 +2892,6 @@ int why; * Since we want to delete this, remove it from the state table, * where it can be found & used, first. */ - if (is->is_pnext != NULL) { - *is->is_pnext = is->is_next; - - if (is->is_next != NULL) - is->is_next->is_pnext = is->is_pnext; - - is->is_pnext = NULL; - is->is_next = NULL; - } - if (is->is_phnext != NULL) { *is->is_phnext = is->is_hnext; if (is->is_hnext != NULL) @@ -2818,7 +2919,8 @@ int why; /* * Next, remove it from the timeout queue it is in. */ - fr_deletequeueentry(&is->is_sti); + if (is->is_sti.tqe_ifq != NULL) + fr_deletequeueentry(&is->is_sti); if (is->is_me != NULL) { *is->is_me = NULL; @@ -2827,11 +2929,15 @@ int why; /* * If it is still in use by something else, do not go any further, - * but note that at this point it is now an orphan. + * but note that at this point it is now an orphan. How can this + * be? fr_state_flush() calls fr_delete() directly because it wants + * to empty the table out and if something has a hold on a state + * entry (such as ipfstat), it'll do the deref path that'll bring + * us back here to do the real delete & free. */ is->is_ref--; if (is->is_ref > 0) - return; + return is->is_ref; if (is->is_tqehead[0] != NULL) { if (fr_deletetimeoutqueue(is->is_tqehead[0]) == 0) @@ -2850,6 +2956,19 @@ int why; (void) ipsc_detachis(is); #endif + /* + * Now remove it from the linked list of known states + */ + if (is->is_pnext != NULL) { + *is->is_pnext = is->is_next; + + if (is->is_next != NULL) + is->is_next->is_pnext = is->is_pnext; + + is->is_pnext = NULL; + is->is_next = NULL; + } + if (ipstate_logging != 0 && why != 0) ipstate_log(is, why); @@ -2860,12 +2979,14 @@ int why; if (is->is_rule != NULL) { is->is_rule->fr_statecnt--; - (void)fr_derefrule(&is->is_rule); + (void) fr_derefrule(&is->is_rule); } MUTEX_DESTROY(&is->is_lock); KFREE(is); ips_num--; + + return 0; } @@ -2951,42 +3072,115 @@ int which, proto; ipftq_t *ifq, *ifqnext; ipftqent_t *tqe, *tqn; ipstate_t *is, **isp; - int delete, removed; - long try, maxtick; - u_long interval; + int removed; SPL_INT(s); removed = 0; SPL_NET(s); - for (isp = &ips_list; ((is = *isp) != NULL); ) { - delete = 0; - if ((proto != 0) && (is->is_v != proto)) { - isp = &is->is_next; - continue; + switch (which) + { + case 0 : + /* + * Style 0 flush removes everything... + */ + for (isp = &ips_list; ((is = *isp) != NULL); ) { + if ((proto != 0) && (is->is_v != proto)) { + isp = &is->is_next; + continue; + } + if (fr_delstate(is, ISL_FLUSH) == 0) + removed++; + else + isp = &is->is_next; } + break; - switch (which) - { - case 0 : - delete = 1; - break; - case 1 : - case 2 : - if (is->is_p != IPPROTO_TCP) - break; - if ((is->is_state[0] != IPF_TCPS_ESTABLISHED) || - (is->is_state[1] != IPF_TCPS_ESTABLISHED)) - delete = 1; - break; + case 1 : + /* + * Since we're only interested in things that are closing, + * we can start with the appropriate timeout queue. + */ + for (ifq = ips_tqtqb + IPF_TCPS_CLOSE_WAIT; ifq != NULL; + ifq = ifq->ifq_next) { + + for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { + tqn = tqe->tqe_next; + is = tqe->tqe_parent; + if (is->is_p != IPPROTO_TCP) + break; + if (fr_delstate(is, ISL_EXPIRE) == 0) + removed++; + } + } + + /* + * Also need to look through the user defined queues. + */ + for (ifq = ips_utqe; ifq != NULL; ifq = ifqnext) { + ifqnext = ifq->ifq_next; + for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { + tqn = tqe->tqe_next; + is = tqe->tqe_parent; + if (is->is_p != IPPROTO_TCP) + continue; + + if ((is->is_state[0] > IPF_TCPS_ESTABLISHED) && + (is->is_state[1] > IPF_TCPS_ESTABLISHED)) { + if (fr_delstate(is, ISL_EXPIRE) == 0) + removed++; + } + } } + break; - if (delete) { - fr_delstate(is, ISL_FLUSH); - removed++; - } else + case 2 : + break; + + /* + * Args 5-11 correspond to flushing those particular states + * for TCP connections. + */ + case IPF_TCPS_CLOSE_WAIT : + case IPF_TCPS_FIN_WAIT_1 : + case IPF_TCPS_CLOSING : + case IPF_TCPS_LAST_ACK : + case IPF_TCPS_FIN_WAIT_2 : + case IPF_TCPS_TIME_WAIT : + case IPF_TCPS_CLOSED : + tqn = ips_tqtqb[which].ifq_head; + while (tqn != NULL) { + tqe = tqn; + tqn = tqe->tqe_next; + is = tqe->tqe_parent; + if (fr_delstate(is, ISL_FLUSH) == 0) + removed++; + } + break; + + default : + if (which < 30) + break; + + /* + * Take a large arbitrary number to mean the number of seconds + * for which which consider to be the maximum value we'll allow + * the expiration to be. + */ + which = IPF_TTLVAL(which); + for (isp = &ips_list; ((is = *isp) != NULL); ) { + if ((proto == 0) || (is->is_v == proto)) { + if (fr_ticks - is->is_touched > which) { + if (fr_delstate(is, ISL_FLUSH) == 0) { + removed++; + continue; + } + } + } isp = &is->is_next; + } + break; } if (which != 2) { @@ -2995,83 +3189,35 @@ int which, proto; } /* - * Asked to remove inactive entries because the table is full, try - * again, 3 times, if first attempt failed with a different criteria - * each time. The order tried in must be in decreasing age. - * Another alternative is to implement random drop and drop N entries - * at random until N have been freed up. + * Asked to remove inactive entries because the table is full. */ - if (fr_ticks - ips_last_force_flush < IPF_TTLVAL(5)) - goto force_flush_skipped; - ips_last_force_flush = fr_ticks; - - if (fr_ticks > IPF_TTLVAL(43200)) - interval = IPF_TTLVAL(43200); - else if (fr_ticks > IPF_TTLVAL(1800)) - interval = IPF_TTLVAL(1800); - else if (fr_ticks > IPF_TTLVAL(30)) - interval = IPF_TTLVAL(30); - else - interval = IPF_TTLVAL(10); - try = fr_ticks - (fr_ticks - interval); - if (try < 0) - goto force_flush_skipped; - - while (removed == 0) { - maxtick = fr_ticks - interval; - if (maxtick < 0) - break; - - while (try < maxtick) { - for (ifq = ips_tqtqb; ifq != NULL; - ifq = ifq->ifq_next) { - for (tqn = ifq->ifq_head; - ((tqe = tqn) != NULL); ) { - if (tqe->tqe_die > try) - break; - tqn = tqe->tqe_next; - is = tqe->tqe_parent; - fr_delstate(is, ISL_EXPIRE); - removed++; - } - } - - for (ifq = ips_utqe; ifq != NULL; ifq = ifqnext) { - ifqnext = ifq->ifq_next; - - for (tqn = ifq->ifq_head; - ((tqe = tqn) != NULL); ) { - if (tqe->tqe_die > try) - break; - tqn = tqe->tqe_next; - is = tqe->tqe_parent; - fr_delstate(is, ISL_EXPIRE); - removed++; - } - } - if (try + interval > maxtick) - break; - try += interval; - } - - if (removed == 0) { - if (interval == IPF_TTLVAL(43200)) { - interval = IPF_TTLVAL(1800); - } else if (interval == IPF_TTLVAL(1800)) { - interval = IPF_TTLVAL(30); - } else if (interval == IPF_TTLVAL(30)) { - interval = IPF_TTLVAL(10); - } else { - break; - } - } + if (fr_ticks - ips_last_force_flush > IPF_TTLVAL(5)) { + ips_last_force_flush = fr_ticks; + removed = ipf_queueflush(fr_state_flush_entry, ips_tqtqb, + ips_utqe); } -force_flush_skipped: + SPL_X(s); return removed; } +/* ------------------------------------------------------------------------ */ +/* Function: fr_state_flush_entry */ +/* Returns: int - 0 = entry deleted, else not deleted */ +/* Parameters: entry(I) - pointer to state structure to delete */ +/* Write Locks: ipf_state */ +/* */ +/* This function is a stepping stone between ipf_queueflush() and */ +/* fr_delstate(). It is used so we can provide a uniform interface via the */ +/* ipf_queueflush() function. */ +/* ------------------------------------------------------------------------ */ +static int fr_state_flush_entry(entry) +void *entry; +{ + return fr_delstate(entry, ISL_FLUSH); +} + /* ------------------------------------------------------------------------ */ /* Function: fr_tcp_age */ @@ -3101,6 +3247,25 @@ force_flush_skipped: /* dir == 0 : a packet from source to dest */ /* dir == 1 : a packet from dest to source */ /* */ +/* A typical procession for a connection is as follows: */ +/* */ +/* +--------------+-------------------+ */ +/* | Side '0' | Side '1' | */ +/* +--------------+-------------------+ */ +/* | 0 -> 1 (SYN) | | */ +/* | | 0 -> 2 (SYN-ACK) | */ +/* | 1 -> 3 (ACK) | | */ +/* | | 2 -> 4 (ACK-PUSH) | */ +/* | 3 -> 4 (ACK) | | */ +/* | ... | ... | */ +/* | | 4 -> 6 (FIN-ACK) | */ +/* | 4 -> 5 (ACK) | | */ +/* | | 6 -> 6 (ACK-PUSH) | */ +/* | 5 -> 5 (ACK) | | */ +/* | 5 -> 8 (FIN) | | */ +/* | | 6 -> 10 (ACK) | */ +/* +--------------+-------------------+ */ +/* */ /* Locking: it is assumed that the parent of the tqe structure is locked. */ /* ------------------------------------------------------------------------ */ int fr_tcp_age(tqe, fin, tqtab, flags) @@ -3132,16 +3297,16 @@ int flags; switch (nstate) { - case IPF_TCPS_CLOSED: /* 0 */ + case IPF_TCPS_LISTEN: /* 0 */ if ((tcpflags & TH_OPENING) == TH_OPENING) { /* * 'dir' received an S and sends SA in - * response, CLOSED -> SYN_RECEIVED + * response, LISTEN -> SYN_RECEIVED */ nstate = IPF_TCPS_SYN_RECEIVED; rval = 1; } else if ((tcpflags & TH_OPENING) == TH_SYN) { - /* 'dir' sent S, CLOSED -> SYN_SENT */ + /* 'dir' sent S, LISTEN -> SYN_SENT */ nstate = IPF_TCPS_SYN_SENT; rval = 1; } @@ -3160,7 +3325,7 @@ int flags; */ switch (ostate) { - case IPF_TCPS_CLOSED : + case IPF_TCPS_LISTEN : case IPF_TCPS_SYN_RECEIVED : nstate = IPF_TCPS_HALF_ESTAB; rval = 1; @@ -3181,11 +3346,7 @@ int flags; */ break; - case IPF_TCPS_LISTEN: /* 1 */ - /* NOT USED */ - break; - - case IPF_TCPS_SYN_SENT: /* 2 */ + case IPF_TCPS_SYN_SENT: /* 1 */ if ((tcpflags & ~(TH_ECN|TH_CWR)) == TH_SYN) { /* * A retransmitted SYN packet. We do not reset @@ -3226,7 +3387,7 @@ int flags; } break; - case IPF_TCPS_SYN_RECEIVED: /* 3 */ + case IPF_TCPS_SYN_RECEIVED: /* 2 */ if ((tcpflags & (TH_SYN|TH_FIN|TH_ACK)) == TH_ACK) { /* * we see an A from 'dir' which was in @@ -3255,7 +3416,7 @@ int flags; } break; - case IPF_TCPS_HALF_ESTAB: /* 4 */ + case IPF_TCPS_HALF_ESTAB: /* 3 */ if (tcpflags & TH_FIN) { nstate = IPF_TCPS_FIN_WAIT_1; rval = 1; @@ -3270,7 +3431,7 @@ int flags; */ switch (ostate) { - case IPF_TCPS_CLOSED : + case IPF_TCPS_LISTEN : case IPF_TCPS_SYN_SENT : case IPF_TCPS_SYN_RECEIVED : rval = 1; @@ -3286,7 +3447,7 @@ int flags; } break; - case IPF_TCPS_ESTABLISHED: /* 5 */ + case IPF_TCPS_ESTABLISHED: /* 4 */ rval = 1; if (tcpflags & TH_FIN) { /* @@ -3294,7 +3455,11 @@ int flags; * this gives us a half-closed connection; * ESTABLISHED -> FIN_WAIT_1 */ - nstate = IPF_TCPS_FIN_WAIT_1; + if (ostate == IPF_TCPS_FIN_WAIT_1) { + nstate = IPF_TCPS_CLOSING; + } else { + nstate = IPF_TCPS_FIN_WAIT_1; + } } else if (tcpflags & TH_ACK) { /* * an ACK, should we exclude other flags here? @@ -3319,7 +3484,7 @@ int flags; } break; - case IPF_TCPS_CLOSE_WAIT: /* 6 */ + case IPF_TCPS_CLOSE_WAIT: /* 5 */ rval = 1; if (tcpflags & TH_FIN) { /* @@ -3337,7 +3502,7 @@ int flags; } break; - case IPF_TCPS_FIN_WAIT_1: /* 7 */ + case IPF_TCPS_FIN_WAIT_1: /* 6 */ rval = 1; if ((tcpflags & TH_ACK) && ostate > IPF_TCPS_CLOSE_WAIT) { @@ -3365,11 +3530,14 @@ int flags; } break; - case IPF_TCPS_CLOSING: /* 8 */ - /* NOT USED */ + case IPF_TCPS_CLOSING: /* 7 */ + if ((tcpflags & (TH_FIN|TH_ACK)) == TH_ACK) { + nstate = IPF_TCPS_TIME_WAIT; + } + rval = 1; break; - case IPF_TCPS_LAST_ACK: /* 9 */ + case IPF_TCPS_LAST_ACK: /* 8 */ if (tcpflags & TH_ACK) { if ((tcpflags & TH_PUSH) || dlen) /* @@ -3388,17 +3556,30 @@ int flags; */ break; - case IPF_TCPS_FIN_WAIT_2: /* 10 */ + case IPF_TCPS_FIN_WAIT_2: /* 9 */ + /* NOT USED */ +#if 0 rval = 1; - if ((tcpflags & TH_OPENING) == TH_OPENING) + if ((tcpflags & TH_OPENING) == TH_OPENING) { nstate = IPF_TCPS_SYN_RECEIVED; - else if (tcpflags & TH_SYN) + } else if (tcpflags & TH_SYN) { nstate = IPF_TCPS_SYN_SENT; + } else if ((tcpflags & (TH_FIN|TH_ACK)) != 0) { + nstate = IPF_TCPS_TIME_WAIT; + } +#endif break; - case IPF_TCPS_TIME_WAIT: /* 11 */ + case IPF_TCPS_TIME_WAIT: /* 10 */ /* we're in 2MSL timeout now */ - rval = 1; + rval = 2; + if (ostate == IPF_TCPS_LAST_ACK) { + nstate = IPF_TCPS_CLOSED; + } + break; + + case IPF_TCPS_CLOSED: /* 11 */ + rval = 2; break; default : @@ -3551,7 +3732,7 @@ fr_info_t *fin; if (fin->fin_plen < sizeof(*oip6)) return NULL; - bcopy((char *)fin, (char *)&ofin, sizeof(fin)); + bcopy((char *)fin, (char *)&ofin, sizeof(*fin)); ofin.fin_v = 6; ofin.fin_ifp = fin->fin_ifp; ofin.fin_out = !fin->fin_out; @@ -3572,7 +3753,6 @@ fr_info_t *fin; oip6->ip6_plen = fin->fin_dlen - ICMPERR_ICMPHLEN; ofin.fin_flx = FI_NOCKSUM; ofin.fin_ip = (ip_t *)oip6; - ofin.fin_plen = oip6->ip6_plen; (void) fr_makefrip(sizeof(*oip6), (ip_t *)oip6, &ofin); ofin.fin_flx &= ~(FI_BAD|FI_SHORT); oip6->ip6_plen = savelen; @@ -3719,7 +3899,7 @@ ipftq_t *tqp; tqp[IPF_TCPS_CLOSING].ifq_ttl = fr_tcptimeout; tqp[IPF_TCPS_LAST_ACK].ifq_ttl = fr_tcplastack; tqp[IPF_TCPS_FIN_WAIT_2].ifq_ttl = fr_tcpclosewait; - tqp[IPF_TCPS_TIME_WAIT].ifq_ttl = fr_tcptimeout; + tqp[IPF_TCPS_TIME_WAIT].ifq_ttl = fr_tcptimewait; tqp[IPF_TCPS_HALF_ESTAB].ifq_ttl = fr_tcptimeout; } @@ -3765,40 +3945,11 @@ ipftq_t *tqp; /* dir == 0 : a packet from source to dest */ /* dir == 1 : a packet from dest to source */ /* ------------------------------------------------------------------------ */ -void fr_statederef(fin, isp) -fr_info_t *fin; +void fr_statederef(isp) ipstate_t **isp; { - ipstate_t *is = *isp; -#if 0 - int nstate, ostate, dir, eol; - - eol = 0; /* End-of-the-line flag. */ - dir = fin->fin_rev; - ostate = is->is_state[1 - dir]; - nstate = is->is_state[dir]; - /* - * Determine whether this packet is local or routed. State entries - * with us as the destination will have an interface list of - * int1,-,-,int1. Entries with us as the origin run as -,int1,int1,-. - */ - if ((fin->fin_p == IPPROTO_TCP) && (fin->fin_out == 0)) { - if ((strcmp(is->is_ifname[0], is->is_ifname[3]) == 0) && - (strcmp(is->is_ifname[1], is->is_ifname[2]) == 0)) { - if ((dir == 0) && - (strcmp(is->is_ifname[1], "-") == 0) && - (strcmp(is->is_ifname[0], "-") != 0)) { - eol = 1; - } else if ((dir == 1) && - (strcmp(is->is_ifname[0], "-") == 0) && - (strcmp(is->is_ifname[1], "-") != 0)) { - eol = 1; - } - } - } -#endif + ipstate_t *is; - fin = fin; /* LINT */ is = *isp; *isp = NULL; WRITE_ENTER(&ipf_state); @@ -3807,15 +3958,8 @@ ipstate_t **isp; is->is_ref++; /* To counter ref-- in fr_delstate() */ fr_delstate(is, ISL_EXPIRE); #ifndef _KERNEL -#if 0 - } else if (((fin->fin_out == 1) || (eol == 1)) && - ((ostate == IPF_TCPS_LAST_ACK) && - (nstate == IPF_TCPS_TIME_WAIT))) { - ; -#else } else if ((is->is_sti.tqe_state[0] > IPF_TCPS_ESTABLISHED) || (is->is_sti.tqe_state[1] > IPF_TCPS_ESTABLISHED)) { -#endif fr_delstate(is, ISL_ORPHAN); #endif } @@ -3890,3 +4034,120 @@ int rev; fr_queueappend(&is->is_sti, nifq, is); return; } + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_stateiter */ +/* Returns: int - 0 == success, else error */ +/* Parameters: token(I) - pointer to ipftoken structure */ +/* itp(I) - pointer to ipfgeniter structure */ +/* */ +/* This function handles the SIOCGENITER ioctl for the state tables and */ +/* walks through the list of entries in the state table list (ips_list.) */ +/* ------------------------------------------------------------------------ */ +static int fr_stateiter(token, itp) +ipftoken_t *token; +ipfgeniter_t *itp; +{ + ipstate_t *is, *next, zero; + int error, count; + char *dst; + + if (itp->igi_data == NULL) + return EFAULT; + + if (itp->igi_nitems == 0) + return ENOSPC; + + if (itp->igi_type != IPFGENITER_STATE) + return EINVAL; + + is = token->ipt_data; + if (is == (void *)-1) { + ipf_freetoken(token); + return ESRCH; + } + + error = 0; + dst = itp->igi_data; + + READ_ENTER(&ipf_state); + if (is == NULL) { + next = ips_list; + } else { + next = is->is_next; + } + + for (count = itp->igi_nitems; count > 0; count--) { + if (next != NULL) { + /* + * If we find a state entry to use, bump its + * reference count so that it can be used for + * is_next when we come back. + */ + MUTEX_ENTER(&next->is_lock); + next->is_ref++; + MUTEX_EXIT(&next->is_lock); + token->ipt_data = next; + } else { + bzero(&zero, sizeof(zero)); + next = &zero; + token->ipt_data = (void *)-1; + count = 1; + } + RWLOCK_EXIT(&ipf_state); + + /* + * If we had a prior pointer to a state entry, release it. + */ + if (is != NULL) { + fr_statederef(&is); + } + + /* + * This should arguably be via fr_outobj() so that the state + * structure can (if required) be massaged going out. + */ + error = COPYOUT(next, dst, sizeof(*next)); + if (error != 0) + error = EFAULT; + if ((count == 1) || (error != 0)) + break; + + dst += sizeof(*next); + READ_ENTER(&ipf_state); + is = next; + next = is->is_next; + } + + return error; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: fr_stgettable */ +/* Returns: int - 0 = success, else error */ +/* Parameters: data(I) - pointer to ioctl data */ +/* */ +/* This function handles ioctl requests for tables of state information. */ +/* At present the only table it deals with is the hash bucket statistics. */ +/* ------------------------------------------------------------------------ */ +static int fr_stgettable(data) +char *data; +{ + ipftable_t table; + int error; + + error = fr_inobj(data, &table, IPFOBJ_GTABLE); + if (error != 0) + return error; + + if (table.ita_type != IPFTABLE_BUCKETS) + return EINVAL; + + error = COPYOUT(ips_stats.iss_bucketlen, table.ita_table, + fr_statesize * sizeof(u_long)); + if (error != 0) + error = EFAULT; + return error; +} diff --git a/sys/contrib/ipfilter/netinet/ip_state.h b/sys/contrib/ipfilter/netinet/ip_state.h index 7167f15..e19df1e 100644 --- a/sys/contrib/ipfilter/netinet/ip_state.h +++ b/sys/contrib/ipfilter/netinet/ip_state.h @@ -4,7 +4,7 @@ * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ip_state.h 1.3 1/12/96 (C) 1995 Darren Reed - * $Id: ip_state.h,v 2.68.2.5 2005/08/20 13:48:25 darrenr Exp $ + * $Id: ip_state.h,v 2.68.2.8 2007/05/11 10:44:14 darrenr Exp $ */ #ifndef __IP_STATE_H__ #define __IP_STATE_H__ @@ -39,7 +39,6 @@ typedef struct ipstate { struct ipstate **is_me; void *is_ifp[4]; void *is_sync; - struct nat *is_nat[2]; frentry_t *is_rule; struct ipftq *is_tqehead[2]; struct ipscan *is_isc; @@ -187,6 +186,7 @@ typedef struct ipslog { #define ISL_INTERMEDIATE 0xfffc #define ISL_KILLED 0xfffb #define ISL_ORPHAN 0xfffa +#define ISL_UNLOAD 0xfff9 typedef struct ips_stat { @@ -213,6 +213,7 @@ typedef struct ips_stat { ipstate_t **iss_table; ipstate_t *iss_list; u_long *iss_bucketlen; + ipftq_t *iss_tcptab; } ips_stat_t; @@ -248,12 +249,12 @@ extern int fr_tcpinwindow __P((struct fr_info *, struct tcpdata *, struct tcpdata *, tcphdr_t *, int)); extern void fr_stateunload __P((void)); extern void ipstate_log __P((struct ipstate *, u_int)); -extern int fr_state_ioctl __P((caddr_t, ioctlcmd_t, int)); +extern int fr_state_ioctl __P((caddr_t, ioctlcmd_t, int, int, void *)); extern void fr_stinsert __P((struct ipstate *, int)); extern void fr_sttab_init __P((struct ipftq *)); extern void fr_sttab_destroy __P((struct ipftq *)); extern void fr_updatestate __P((fr_info_t *, ipstate_t *, ipftq_t *)); -extern void fr_statederef __P((fr_info_t *, ipstate_t **)); +extern void fr_statederef __P((ipstate_t **)); extern void fr_setstatequeue __P((ipstate_t *, int)); #endif /* __IP_STATE_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_sync.c b/sys/contrib/ipfilter/netinet/ip_sync.c index b5b811b..c2eff0e 100644 --- a/sys/contrib/ipfilter/netinet/ip_sync.c +++ b/sys/contrib/ipfilter/netinet/ip_sync.c @@ -96,7 +96,7 @@ struct file; /* END OF INCLUDES */ #if !defined(lint) -static const char rcsid[] = "@(#)$Id: ip_sync.c,v 2.40.2.7 2006/03/19 14:59:39 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_sync.c,v 2.40.2.8 2006/07/14 06:12:20 darrenr Exp $"; #endif #define SYNC_STATETABSZ 256 @@ -995,10 +995,11 @@ synclist_t *sl; /* This function currently does not handle any ioctls and so just returns */ /* EINVAL on all occasions. */ /* ------------------------------------------------------------------------ */ -int fr_sync_ioctl(data, cmd, mode) +int fr_sync_ioctl(data, cmd, mode, uid, ctx) caddr_t data; ioctlcmd_t cmd; -int mode; +int mode, uid; +void *ctx; { return EINVAL; } diff --git a/sys/contrib/ipfilter/netinet/ip_sync.h b/sys/contrib/ipfilter/netinet/ip_sync.h index 76862f7..8104db3 100644 --- a/sys/contrib/ipfilter/netinet/ip_sync.h +++ b/sys/contrib/ipfilter/netinet/ip_sync.h @@ -4,7 +4,7 @@ * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ip_fil.h 1.35 6/5/96 - * $Id: ip_sync.h,v 2.11.2.3 2006/03/19 14:59:39 darrenr Exp $ + * $Id: ip_sync.h,v 2.11.2.4 2006/07/14 06:12:20 darrenr Exp $ */ #ifndef __IP_SYNC_H__ @@ -102,16 +102,16 @@ typedef struct syncupdent { /* 28 or 32 bytes */ extern synclogent_t synclog[SYNCLOG_SZ]; -extern int fr_sync_ioctl __P((caddr_t, ioctlcmd_t, int)); -extern synclist_t *ipfsync_new __P((int, fr_info_t *, void *)); -extern void ipfsync_del __P((synclist_t *)); -extern void ipfsync_update __P((int, fr_info_t *, synclist_t *)); -extern int ipfsync_init __P((void)); -extern int ipfsync_nat __P((synchdr_t *sp, void *data)); -extern int ipfsync_state __P((synchdr_t *sp, void *data)); -extern int ipfsync_read __P((struct uio *uio)); -extern int ipfsync_write __P((struct uio *uio)); -extern int ipfsync_canread __P((void)); -extern int ipfsync_canwrite __P((void)); +extern int fr_sync_ioctl __P((caddr_t, ioctlcmd_t, int, int, void *)); +extern synclist_t *ipfsync_new __P((int, fr_info_t *, void *)); +extern void ipfsync_del __P((synclist_t *)); +extern void ipfsync_update __P((int, fr_info_t *, synclist_t *)); +extern int ipfsync_init __P((void)); +extern int ipfsync_nat __P((synchdr_t *sp, void *data)); +extern int ipfsync_state __P((synchdr_t *sp, void *data)); +extern int ipfsync_read __P((struct uio *uio)); +extern int ipfsync_write __P((struct uio *uio)); +extern int ipfsync_canread __P((void)); +extern int ipfsync_canwrite __P((void)); #endif /* IP_SYNC */ diff --git a/sys/contrib/ipfilter/netinet/ipl.h b/sys/contrib/ipfilter/netinet/ipl.h index 28b9e0c..2bc9a1d 100644 --- a/sys/contrib/ipfilter/netinet/ipl.h +++ b/sys/contrib/ipfilter/netinet/ipl.h @@ -4,14 +4,14 @@ * See the IPFILTER.LICENCE file for details on licencing. * * @(#)ipl.h 1.21 6/5/96 - * $Id: ipl.h,v 2.52.2.14 2006/04/01 20:09:42 darrenr Exp $ + * $Id: ipl.h,v 2.52.2.25 2007/05/31 11:40:43 darrenr Exp $ */ #ifndef __IPL_H__ #define __IPL_H__ -#define IPL_VERSION "IP Filter: v4.1.13" +#define IPL_VERSION "IP Filter: v4.1.23" -#define IPFILTER_VERSION 4011300 +#define IPFILTER_VERSION 4012300 #endif diff --git a/sys/contrib/ipfilter/netinet/mlfk_ipl.c b/sys/contrib/ipfilter/netinet/mlfk_ipl.c index e4c5ccb..3f04235 100644 --- a/sys/contrib/ipfilter/netinet/mlfk_ipl.c +++ b/sys/contrib/ipfilter/netinet/mlfk_ipl.c @@ -30,8 +30,6 @@ #include #include -extern struct selinfo ipfselwait[IPL_LOGSIZE]; - #if __FreeBSD_version >= 502116 static struct cdev *ipf_devs[IPL_LOGSIZE]; #else @@ -98,8 +96,8 @@ SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_chksrc, CTLFLAG_RW, &fr_chksrc, 0, ""); SYSCTL_IPF(_net_inet_ipf, OID_AUTO, fr_minttl, CTLFLAG_RW, &fr_minttl, 0, ""); #define CDEV_MAJOR 79 -#if __FreeBSD_version >= 501000 -# include +#include +#if __FreeBSD_version >= 500043 # include static int iplpoll(struct cdev *dev, int events, struct thread *td); @@ -114,12 +112,16 @@ static struct cdevsw ipl_cdevsw = { .d_write = iplwrite, .d_ioctl = iplioctl, .d_name = "ipl", +# if __FreeBSD_version >= 500043 .d_poll = iplpoll, +# endif # if __FreeBSD_version < 600000 .d_maj = CDEV_MAJOR, # endif }; #else +static int iplpoll(dev_t dev, int events, struct proc *p); + static struct cdevsw ipl_cdevsw = { /* open */ iplopen, /* close */ iplclose, @@ -137,7 +139,9 @@ static struct cdevsw ipl_cdevsw = { # if (__FreeBSD_version < 500043) /* bmaj */ -1, # endif +# if (__FreeBSD_version > 430000) /* kqfilter */ NULL +# endif }; #endif @@ -173,9 +177,17 @@ ipf_modload() char *defpass, *c, *str; int i, j, error; - error = iplattach(); - if (error) + RWLOCK_INIT(&ipf_global, "ipf filter load/unload mutex"); + RWLOCK_INIT(&ipf_mutex, "ipf filter rwlock"); + RWLOCK_INIT(&ipf_frcache, "ipf cache rwlock"); + + error = ipfattach(); + if (error) { + RW_DESTROY(&ipf_global); + RW_DESTROY(&ipf_mutex); + RW_DESTROY(&ipf_frcache); return error; + } for (i = 0; i < IPL_LOGSIZE; i++) ipf_devs[i] = NULL; @@ -225,12 +237,16 @@ ipf_modunload() return EBUSY; if (fr_running >= 0) { - error = ipldetach(); + error = ipfdetach(); if (error != 0) return error; } else error = 0; + RW_DESTROY(&ipf_global); + RW_DESTROY(&ipf_mutex); + RW_DESTROY(&ipf_frcache); + fr_running = -2; for (i = 0; ipf_devfiles[i]; i++) { @@ -284,9 +300,12 @@ sysctl_ipf_int ( SYSCTL_HANDLER_ARGS ) #endif -#if __FreeBSD_version >= 501000 static int +#if __FreeBSD_version >= 500043 iplpoll(struct cdev *dev, int events, struct thread *td) +#else +iplpoll(dev_t dev, int events, struct proc *td) +#endif { u_int xmin = GET_MINOR(dev); int revents; @@ -329,4 +348,3 @@ iplpoll(struct cdev *dev, int events, struct thread *td) return revents; } -#endif -- cgit v1.1