diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c index 29e4aacb4b82..703ff76e5c99 100644 --- a/sys/contrib/ipfilter/netinet/fil.c +++ b/sys/contrib/ipfilter/netinet/fil.c @@ -34,7 +34,9 @@ #else # include #endif -#include +#if !defined(_AIX51) +# include +#endif #if defined(_KERNEL) # include # include @@ -74,6 +76,9 @@ struct file; # include #endif #if !defined(_KERNEL) && defined(__FreeBSD__) +# if (__FreeBSD_version >= 504000) +# undef _RADIX_H_ +# endif # include "radix_ipf.h" #endif #include @@ -88,7 +93,7 @@ struct file; # include #endif #include -#if !defined(__sgi) || defined(_KERNEL) +#if (!defined(__sgi) && !defined(AIX)) || defined(_KERNEL) # include # include #endif @@ -176,6 +181,7 @@ int fr_update_ipid = 0; u_short fr_ip_id = 0; int fr_chksrc = 0; /* causes a system crash if enabled */ int fr_minttl = 4; +int fr_icmpminfragmtu = 68; u_long fr_frouteok[2] = {0, 0}; u_long fr_userifqs = 0; u_long fr_badcoalesces[2] = {0, 0}; @@ -221,6 +227,7 @@ static int frflushlist __P((int, minor_t, int *, frentry_t **)); static ipfunc_t fr_findfunc __P((ipfunc_t)); static frentry_t *fr_firewall __P((fr_info_t *, u_32_t *)); static int fr_funcinit __P((frentry_t *fr)); +static INLINE void frpr_ah __P((fr_info_t *)); static INLINE void frpr_esp __P((fr_info_t *)); static INLINE void frpr_gre __P((fr_info_t *)); static INLINE void frpr_udp __P((fr_info_t *)); @@ -229,15 +236,15 @@ static INLINE void frpr_icmp __P((fr_info_t *)); static INLINE void frpr_ipv4hdr __P((fr_info_t *)); static INLINE int frpr_pullup __P((fr_info_t *, int)); static INLINE void frpr_short __P((fr_info_t *, int)); -static INLINE void frpr_tcpcommon __P((fr_info_t *)); -static INLINE void frpr_udpcommon __P((fr_info_t *)); -static INLINE int fr_updateipid __P((fr_info_t *)); +static INLINE int frpr_tcpcommon __P((fr_info_t *)); +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 *)); #endif static void frsynclist __P((frentry_t *, void *)); -static ipftuneable_t *fr_findtunebyname __P((char *)); +static ipftuneable_t *fr_findtunebyname __P((const char *)); static ipftuneable_t *fr_findtunebycookie __P((void *, void **)); @@ -280,6 +287,7 @@ struct optlist ip6exthdr[] = { { IPPROTO_AH, 0x000020 }, { IPPROTO_NONE, 0x000040 }, { IPPROTO_DSTOPTS, 0x000080 }, + { IPPROTO_MOBILITY, 0x000100 }, { 0, 0 } }; #endif @@ -331,15 +339,20 @@ static ipfunc_resolve_t fr_availfuncs[] = { * adding more code to a growing switch statement. */ #ifdef USE_INET6 +static INLINE int frpr_ah6 __P((fr_info_t *)); +static INLINE void frpr_esp6 __P((fr_info_t *)); +static INLINE void frpr_gre6 __P((fr_info_t *)); static INLINE void frpr_udp6 __P((fr_info_t *)); static INLINE void frpr_tcp6 __P((fr_info_t *)); static INLINE void frpr_icmp6 __P((fr_info_t *)); -static INLINE void frpr_ipv6hdr __P((fr_info_t *)); +static INLINE int frpr_ipv6hdr __P((fr_info_t *)); static INLINE void frpr_short6 __P((fr_info_t *, int)); static INLINE int frpr_hopopts6 __P((fr_info_t *)); +static INLINE int frpr_mobility6 __P((fr_info_t *)); static INLINE int frpr_routing6 __P((fr_info_t *)); static INLINE int frpr_dstopts6 __P((fr_info_t *)); -static INLINE int frpr_fragment6 __P((fr_info_t *)); +static INLINE void frpr_fragment6 __P((fr_info_t *)); +static INLINE int frpr_ipv6exthdr __P((fr_info_t *, int, int)); /* ------------------------------------------------------------------------ */ @@ -352,37 +365,32 @@ static INLINE int frpr_fragment6 __P((fr_info_t *)); /* for IPv6 and marks the packet with FI_SHORT if so. See function comment */ /* for frpr_short() for more details. */ /* ------------------------------------------------------------------------ */ -static INLINE void frpr_short6(fin, min) +static INLINE void frpr_short6(fin, xmin) fr_info_t *fin; -int min; +int xmin; { - fr_ip_t *fi = &fin->fin_fi; - int off; - off = fin->fin_off; - if (off == 0) { - if (fin->fin_plen < fin->fin_hlen + min) - fi->fi_flx |= FI_SHORT; - } else if (off < min) { - fi->fi_flx |= FI_SHORT; - } + if (fin->fin_dlen < xmin) + fin->fin_flx |= FI_SHORT; } /* ------------------------------------------------------------------------ */ /* Function: frpr_ipv6hdr */ -/* Returns: void */ +/* Returns: int - 0 = IPv6 packet intact, -1 = packet lost */ /* Parameters: fin(I) - pointer to packet information */ /* */ /* IPv6 Only */ /* Copy values from the IPv6 header into the fr_info_t struct and call the */ -/* per-protocol analyzer if it exists. */ +/* per-protocol analyzer if it exists. In validating the packet, a protocol*/ +/* analyzer may pullup or free the packet itself so we need to be vigiliant */ +/* of that possibility arising. */ /* ------------------------------------------------------------------------ */ -static INLINE void frpr_ipv6hdr(fin) +static INLINE int frpr_ipv6hdr(fin) fr_info_t *fin; { - int p, go = 1, i, hdrcount, coalesced; ip6_t *ip6 = (ip6_t *)fin->fin_ip; + int p, go = 1, i, hdrcount; fr_ip_t *fi = &fin->fin_fi; fin->fin_off = 0; @@ -392,7 +400,6 @@ fr_info_t *fin; fi->fi_secmsk = 0; fi->fi_auth = 0; - coalesced = (fin->fin_flx & FI_COALESCE) ? 1 : 0; p = ip6->ip6_nxt; fi->fi_ttl = ip6->ip6_hlim; fi->fi_src.in6 = ip6->ip6_src; @@ -419,48 +426,35 @@ fr_info_t *fin; break; case IPPROTO_GRE : - frpr_gre(fin); + frpr_gre6(fin); go = 0; break; case IPPROTO_HOPOPTS : - /* - * Actually, hop by hop header is only allowed right - * after IPv6 header! - */ - if (hdrcount != 0) - fin->fin_flx |= FI_BAD; - - if (coalesced == 0) { - coalesced = fr_coalesce(fin); - if (coalesced != 1) - return; - } p = frpr_hopopts6(fin); break; + case IPPROTO_MOBILITY : + p = frpr_mobility6(fin); + break; + case IPPROTO_DSTOPTS : - if (coalesced == 0) { - coalesced = fr_coalesce(fin); - if (coalesced != 1) - return; - } p = frpr_dstopts6(fin); break; case IPPROTO_ROUTING : - if (coalesced == 0) { - coalesced = fr_coalesce(fin); - if (coalesced != 1) - return; - } p = frpr_routing6(fin); break; - case IPPROTO_ESP : - frpr_esp(fin); - /*FALLTHROUGH*/ case IPPROTO_AH : + p = frpr_ah6(fin); + break; + + case IPPROTO_ESP : + frpr_esp6(fin); + go = 0; + break; + case IPPROTO_IPV6 : for (i = 0; ip6exthdr[i].ol_bit != 0; i++) if (ip6exthdr[i].ol_val == p) { @@ -475,12 +469,8 @@ fr_info_t *fin; break; case IPPROTO_FRAGMENT : - if (coalesced == 0) { - coalesced = fr_coalesce(fin); - if (coalesced != 1) - return; - } - p = frpr_fragment6(fin); + frpr_fragment6(fin); + go = 0; break; default : @@ -494,9 +484,9 @@ fr_info_t *fin; * extension headers (go != 0), the entire header may not have * been pulled up when the code gets to this point. This is * only done for "go != 0" because the other header handlers - * will all pullup their complete header and the other - * indicator of an incomplete header is that this eas just an - * extension header. + * will all pullup their complete header. The other indicator + * of an incomplete packet is that this was just an extension + * header. */ if ((go != 0) && (p != IPPROTO_NONE) && (frpr_pullup(fin, 0) == -1)) { @@ -505,19 +495,32 @@ fr_info_t *fin; } } fi->fi_p = p; + + /* + * Some of the above functions, like frpr_esp6(), can call fr_pullup + * and destroy whatever packet was here. The caller of this function + * expects us to return -1 if there is a problem with fr_pullup. + */ + if (fin->fin_m == NULL) + return -1; + + return 0; } /* ------------------------------------------------------------------------ */ -/* Function: frpr_hopopts6 */ +/* Function: frpr_ipv6exthdr */ /* Returns: int - value of the next header or IPPROTO_NONE if error */ -/* Parameters: fin(I) - pointer to packet information */ +/* Parameters: fin(I) - pointer to packet information */ +/* multiple(I) - flag indicating yes/no if multiple occurances */ +/* of this extension header are allowed. */ +/* proto(I) - protocol number for this extension header */ /* */ /* IPv6 Only */ -/* This is function checks pending hop by hop options extension header */ /* ------------------------------------------------------------------------ */ -static INLINE int frpr_hopopts6(fin) +static INLINE int frpr_ipv6exthdr(fin, multiple, proto) fr_info_t *fin; +int multiple, proto; { struct ip6_ext *hdr; u_short shift; @@ -542,8 +545,15 @@ fr_info_t *fin; } for (i = 0; ip6exthdr[i].ol_bit != 0; i++) - if (ip6exthdr[i].ol_val == IPPROTO_HOPOPTS) { - fin->fin_optmsk |= ip6exthdr[i].ol_bit; + if (ip6exthdr[i].ol_val == proto) { + /* + * Most IPv6 extension headers are only allowed once. + */ + if ((multiple == 0) && + ((fin->fin_optmsk & ip6exthdr[i].ol_bit) != 0)) + fin->fin_flx |= FI_BAD; + else + fin->fin_optmsk |= ip6exthdr[i].ol_bit; break; } @@ -554,6 +564,36 @@ fr_info_t *fin; } +/* ------------------------------------------------------------------------ */ +/* Function: frpr_hopopts6 */ +/* Returns: int - value of the next header or IPPROTO_NONE if error */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv6 Only */ +/* This is function checks pending hop by hop options extension header */ +/* ------------------------------------------------------------------------ */ +static INLINE int frpr_hopopts6(fin) +fr_info_t *fin; +{ + return frpr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_mobility6 */ +/* Returns: int - value of the next header or IPPROTO_NONE if error */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv6 Only */ +/* This is function checks the IPv6 mobility extension header */ +/* ------------------------------------------------------------------------ */ +static INLINE int frpr_mobility6(fin) +fr_info_t *fin; +{ + return frpr_ipv6exthdr(fin, 0, IPPROTO_MOBILITY); +} + + /* ------------------------------------------------------------------------ */ /* Function: frpr_routing6 */ /* Returns: int - value of the next header or IPPROTO_NONE if error */ @@ -566,100 +606,67 @@ static INLINE int frpr_routing6(fin) fr_info_t *fin; { struct ip6_ext *hdr; - u_short shift; - int i; + int shift; - fin->fin_flx |= FI_V6EXTHDR; - - /* 8 is default length of extension hdr */ - if ((fin->fin_dlen - 8) < 0) { - fin->fin_flx |= FI_SHORT; + if (frpr_ipv6exthdr(fin, 0, IPPROTO_ROUTING) == IPPROTO_NONE) return IPPROTO_NONE; - } - if (frpr_pullup(fin, 8) == -1) - return IPPROTO_NONE; hdr = fin->fin_dp; - shift = 8 + (hdr->ip6e_len << 3); /* * Nasty extension header length? */ - if ((shift > fin->fin_dlen) || (shift < sizeof(struct ip6_hdr)) || + if ((shift < sizeof(struct ip6_hdr)) || ((shift - sizeof(struct ip6_hdr)) & 15)) { 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; return IPPROTO_NONE; } - for (i = 0; ip6exthdr[i].ol_bit != 0; i++) - if (ip6exthdr[i].ol_val == IPPROTO_ROUTING) { - fin->fin_optmsk |= ip6exthdr[i].ol_bit; - break; - } - - fin->fin_dp = (char *)fin->fin_dp + shift; - fin->fin_dlen -= shift; - return hdr->ip6e_nxt; } /* ------------------------------------------------------------------------ */ /* Function: frpr_fragment6 */ -/* Returns: int - value of the next header or IPPROTO_NONE if error */ +/* Returns: void */ /* Parameters: fin(I) - pointer to packet information */ /* */ /* IPv6 Only */ /* Examine the IPv6 fragment header and extract fragment offset information.*/ +/* */ +/* We don't know where the transport layer header (or whatever is next is), */ +/* as it could be behind destination options (amongst others). Because */ +/* there is no fragment cache, there is no knowledge about whether or not an*/ +/* upper layer header has been seen (or where it ends) and thus we are not */ +/* able to continue processing beyond this header with any confidence. */ /* ------------------------------------------------------------------------ */ -static INLINE int frpr_fragment6(fin) +static INLINE void frpr_fragment6(fin) fr_info_t *fin; { struct ip6_frag *frag; - struct ip6_ext *hdr; - int i; - fin->fin_flx |= (FI_FRAG|FI_V6EXTHDR); + fin->fin_flx |= FI_FRAG; - /* 8 is default length of extension hdr */ - if ((fin->fin_dlen - 8) < 0) { - fin->fin_flx |= FI_SHORT; - return IPPROTO_NONE; - } - - /* - * Only one frgament header is allowed per IPv6 packet but it need - * not be the first nor last (not possible in some cases.) - */ - for (i = 0; ip6exthdr[i].ol_bit != 0; i++) - if (ip6exthdr[i].ol_val == IPPROTO_FRAGMENT) - break; - - if (fin->fin_optmsk & ip6exthdr[i].ol_bit) { - fin->fin_flx |= FI_BAD; - return IPPROTO_NONE; - } - - fin->fin_optmsk |= ip6exthdr[i].ol_bit; + if (frpr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT) == IPPROTO_NONE) + return; if (frpr_pullup(fin, sizeof(*frag)) == -1) - return IPPROTO_NONE; - hdr = fin->fin_dp; - - /* - * Length must be zero, i.e. it has no length. - */ - if (hdr->ip6e_len != 0) { - fin->fin_flx |= FI_BAD; - return IPPROTO_NONE; - } - - if ((int)(fin->fin_dlen - sizeof(*frag)) < 0) { - fin->fin_flx |= FI_SHORT; - return IPPROTO_NONE; - } + return; frag = fin->fin_dp; + /* + * Fragment but no fragmentation info set? Bad packet... + */ + if (frag->ip6f_offlg == 0) { + fin->fin_flx |= FI_BAD; + return; + } + fin->fin_off = frag->ip6f_offlg & IP6F_OFF_MASK; fin->fin_off <<= 3; if (fin->fin_off != 0) @@ -667,8 +674,6 @@ fr_info_t *fin; fin->fin_dp = (char *)fin->fin_dp + sizeof(*frag); fin->fin_dlen -= sizeof(*frag); - - return frag->ip6f_nxt; } @@ -684,34 +689,7 @@ fr_info_t *fin; static INLINE int frpr_dstopts6(fin) fr_info_t *fin; { - struct ip6_ext *hdr; - u_short shift; - int i; - - /* 8 is default length of extension hdr */ - if ((fin->fin_dlen - 8) < 0) { - fin->fin_flx |= FI_SHORT; - return IPPROTO_NONE; - } - - if (frpr_pullup(fin, 8) == -1) - return IPPROTO_NONE; - hdr = fin->fin_dp; - - shift = 8 + (hdr->ip6e_len << 3); - if (shift > fin->fin_dlen) { /* Nasty extension header length? */ - fin->fin_flx |= FI_BAD; - return IPPROTO_NONE; - } - - for (i = 0; ip6exthdr[i].ol_bit != 0; i++) - if (ip6exthdr[i].ol_val == IPPROTO_DSTOPTS) - break; - fin->fin_optmsk |= ip6exthdr[i].ol_bit; - fin->fin_dp = (char *)fin->fin_dp + shift; - fin->fin_dlen -= shift; - - return hdr->ip6e_nxt; + return frpr_ipv6exthdr(fin, 1, IPPROTO_DSTOPTS); } @@ -761,7 +739,7 @@ fr_info_t *fin; } } - frpr_short(fin, minicmpsz); + frpr_short6(fin, minicmpsz); } @@ -772,16 +750,16 @@ fr_info_t *fin; /* */ /* IPv6 Only */ /* Analyse the packet for IPv6/UDP properties. */ +/* Is not expected to be called for fragmented packets. */ /* ------------------------------------------------------------------------ */ static INLINE void frpr_udp6(fin) fr_info_t *fin; { - fr_checkv6sum(fin); + frpr_short6(fin, sizeof(struct udphdr)); - frpr_short(fin, sizeof(struct udphdr)); - - frpr_udpcommon(fin); + if (frpr_udpcommon(fin) == 0) + fr_checkv6sum(fin); } @@ -792,16 +770,86 @@ fr_info_t *fin; /* */ /* IPv6 Only */ /* Analyse the packet for IPv6/TCP properties. */ +/* Is not expected to be called for fragmented packets. */ /* ------------------------------------------------------------------------ */ static INLINE void frpr_tcp6(fin) fr_info_t *fin; { - fr_checkv6sum(fin); + frpr_short6(fin, sizeof(struct tcphdr)); - frpr_short(fin, sizeof(struct tcphdr)); + if (frpr_tcpcommon(fin) == 0) + fr_checkv6sum(fin); +} - frpr_tcpcommon(fin); + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_esp6 */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv6 Only */ +/* Analyse the packet for ESP properties. */ +/* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ +/* even though the newer ESP packets must also have a sequence number that */ +/* is 32bits as well, it is not possible(?) to determine the version from a */ +/* simple packet header. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_esp6(fin) +fr_info_t *fin; +{ + + frpr_short6(fin, sizeof(grehdr_t)); + + (void) frpr_pullup(fin, 8); +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_ah6 */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* IPv6 Only */ +/* Analyse the packet for AH properties. */ +/* The minimum length is taken to be the combination of all fields in the */ +/* header being present and no authentication data (null algorithm used.) */ +/* ------------------------------------------------------------------------ */ +static INLINE int frpr_ah6(fin) +fr_info_t *fin; +{ + authhdr_t *ah; + + frpr_short6(fin, 12); + + if (frpr_pullup(fin, sizeof(*ah)) == -1) + return IPPROTO_NONE; + + ah = (authhdr_t *)fin->fin_dp; + return ah->ah_next; +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_gre6 */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* Analyse the packet for GRE properties. */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_gre6(fin) +fr_info_t *fin; +{ + grehdr_t *gre; + + frpr_short6(fin, sizeof(grehdr_t)); + + if (frpr_pullup(fin, sizeof(grehdr_t)) == -1) + return; + + gre = fin->fin_dp; + if (GRE_REV(gre->gr_flags) == 1) + fin->fin_data[0] = gre->gr_call; } #endif /* USE_INET6 */ @@ -839,28 +887,25 @@ int plen; /* ------------------------------------------------------------------------ */ /* Function: frpr_short */ /* Returns: void */ -/* Parameters: fin(I) - pointer to packet information */ -/* min(I) - minimum header size */ +/* Parameters: fin(I) - pointer to packet information */ +/* xmin(I) - minimum header size */ /* */ -/* Check if a packet is "short" as defined by min. The rule we are */ +/* Check if a packet is "short" as defined by xmin. The rule we are */ /* applying here is that the packet must not be fragmented within the layer */ /* 4 header. That is, it must not be a fragment that has its offset set to */ /* start within the layer 4 header (hdrmin) or if it is at offset 0, the */ /* entire layer 4 header must be present (min). */ /* ------------------------------------------------------------------------ */ -static INLINE void frpr_short(fin, min) +static INLINE void frpr_short(fin, xmin) fr_info_t *fin; -int min; +int xmin; { - fr_ip_t *fi = &fin->fin_fi; - int off; - off = fin->fin_off; - if (off == 0) { - if (fin->fin_plen < fin->fin_hlen + min) - fi->fi_flx |= FI_SHORT; - } else if (off < min) { - fi->fi_flx |= FI_SHORT; + if (fin->fin_off == 0) { + if (fin->fin_dlen < xmin) + fin->fin_flx |= FI_SHORT; + } else if (fin->fin_off < xmin) { + fin->fin_flx |= FI_SHORT; } } @@ -873,7 +918,7 @@ int min; /* IPv4 Only */ /* Do a sanity check on the packet for ICMP (v4). In nearly all cases, */ /* except extrememly bad packets, both type and code will be present. */ -/* The expected minimum size of an ICMP packet is very much dependant on */ +/* The expected minimum size of an ICMP packet is very much dependent on */ /* the type of it. */ /* */ /* XXX - other ICMP sanity checks? */ @@ -883,13 +928,17 @@ fr_info_t *fin; { int minicmpsz = sizeof(struct icmp); icmphdr_t *icmp; + ip_t *oip; + + if (fin->fin_off != 0) { + frpr_short(fin, ICMPERR_ICMPHLEN); + return; + } if (frpr_pullup(fin, ICMPERR_ICMPHLEN) == -1) return; - fr_checkv4sum(fin); - - if (!fin->fin_off && (fin->fin_dlen > 1)) { + if (fin->fin_dlen > 1) { icmp = fin->fin_dp; fin->fin_data[0] = *(u_short *)icmp; @@ -923,13 +972,27 @@ fr_info_t *fin; * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+) */ case ICMP_UNREACH : +#ifdef icmp_nextmtu + if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG) { + if (icmp->icmp_nextmtu < fr_icmpminfragmtu) + fin->fin_flx |= FI_BAD; + } +#endif case ICMP_SOURCEQUENCH : case ICMP_REDIRECT : case ICMP_TIMXCEED : case ICMP_PARAMPROB : + fin->fin_flx |= FI_ICMPERR; if (fr_coalesce(fin) != 1) return; - fin->fin_flx |= FI_ICMPERR; + /* + * ICMP error packets should not be generated for IP + * packets that are a fragment that isn't the first + * fragment. + */ + oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN); + if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0) + fin->fin_flx |= FI_BAD; break; default : break; @@ -940,12 +1003,14 @@ fr_info_t *fin; } frpr_short(fin, minicmpsz); + + fr_checkv4sum(fin); } /* ------------------------------------------------------------------------ */ /* Function: frpr_tcpcommon */ -/* Returns: void */ +/* Returns: int - 0 = header ok, 1 = bad packet, -1 = buffer error */ /* Parameters: fin(I) - pointer to packet information */ /* */ /* TCP header sanity checking. Look for bad combinations of TCP flags, */ @@ -953,20 +1018,18 @@ fr_info_t *fin; /* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is */ /* valid and mark the packet as bad if not. */ /* ------------------------------------------------------------------------ */ -static INLINE void frpr_tcpcommon(fin) +static INLINE int frpr_tcpcommon(fin) fr_info_t *fin; { int flags, tlen; tcphdr_t *tcp; - fr_ip_t *fi; - fi = &fin->fin_fi; - fi->fi_flx |= FI_TCPUDP; + fin->fin_flx |= FI_TCPUDP; if (fin->fin_off != 0) - return; + return 0; if (frpr_pullup(fin, sizeof(*tcp)) == -1) - return; + return -1; tcp = fin->fin_dp; if (fin->fin_dlen > 3) { @@ -974,8 +1037,8 @@ fr_info_t *fin; fin->fin_dport = ntohs(tcp->th_dport); } - if ((fi->fi_flx & FI_SHORT) != 0) - return; + if ((fin->fin_flx & FI_SHORT) != 0) + return 1; /* * Use of the TCP data offset *must* result in a value that is at @@ -984,7 +1047,7 @@ fr_info_t *fin; tlen = TCP_OFF(tcp) << 2; if (tlen < sizeof(tcphdr_t)) { fin->fin_flx |= FI_BAD; - return; + return 1; } flags = tcp->th_flags; @@ -1038,10 +1101,10 @@ fr_info_t *fin; * then that might add some weight to adding this... */ if (tlen == sizeof(tcphdr_t)) - return; + return 0; if (frpr_pullup(fin, tlen) == -1) - return; + return -1; #if 0 ip = fin->fin_ip; @@ -1080,31 +1143,31 @@ fr_info_t *fin; s += ol; } #endif /* 0 */ + + return 0; } /* ------------------------------------------------------------------------ */ /* Function: frpr_udpcommon */ -/* Returns: void */ +/* Returns: int - 0 = header ok, 1 = bad packet */ /* Parameters: fin(I) - pointer to packet information */ /* */ /* Extract the UDP source and destination ports, if present. If compiled */ /* with IPFILTER_CKSUM, check to see if the UDP checksum is valid. */ /* ------------------------------------------------------------------------ */ -static INLINE void frpr_udpcommon(fin) +static INLINE int frpr_udpcommon(fin) fr_info_t *fin; { udphdr_t *udp; - fr_ip_t *fi; - fi = &fin->fin_fi; - fi->fi_flx |= FI_TCPUDP; + fin->fin_flx |= FI_TCPUDP; if (!fin->fin_off && (fin->fin_dlen > 3)) { if (frpr_pullup(fin, sizeof(*udp)) == -1) { - fi->fi_flx |= FI_SHORT; - return; + fin->fin_flx |= FI_SHORT; + return 1; } udp = fin->fin_dp; @@ -1112,6 +1175,8 @@ fr_info_t *fin; fin->fin_sport = ntohs(udp->uh_sport); fin->fin_dport = ntohs(udp->uh_dport); } + + return 0; } @@ -1127,11 +1192,10 @@ static INLINE void frpr_tcp(fin) fr_info_t *fin; { - fr_checkv4sum(fin); - frpr_short(fin, sizeof(tcphdr_t)); - frpr_tcpcommon(fin); + if (frpr_tcpcommon(fin) == 0) + fr_checkv4sum(fin); } @@ -1147,11 +1211,10 @@ static INLINE void frpr_udp(fin) fr_info_t *fin; { - fr_checkv4sum(fin); - frpr_short(fin, sizeof(udphdr_t)); - frpr_udpcommon(fin); + if (frpr_udpcommon(fin) == 0) + fr_checkv4sum(fin); } @@ -1169,15 +1232,42 @@ fr_info_t *fin; static INLINE void frpr_esp(fin) fr_info_t *fin; { - if (frpr_pullup(fin, 8) == -1) + + if (fin->fin_off == 0) { + frpr_short(fin, 8); + (void) frpr_pullup(fin, 8); + } + +} + + +/* ------------------------------------------------------------------------ */ +/* Function: frpr_ah */ +/* Returns: void */ +/* Parameters: fin(I) - pointer to packet information */ +/* */ +/* Analyse the packet for AH properties. */ +/* The minimum length is taken to be the combination of all fields in the */ +/* header being present and no authentication data (null algorithm used.) */ +/* ------------------------------------------------------------------------ */ +static INLINE void frpr_ah(fin) +fr_info_t *fin; +{ + authhdr_t *ah; + int len; + + frpr_short(fin, sizeof(*ah)); + + if (((fin->fin_flx & FI_SHORT) != 0) || (fin->fin_off != 0)) return; - if (fin->fin_v == 4) - frpr_short(fin, 8); -#ifdef USE_INET6 - else if (fin->fin_v == 6) - frpr_short6(fin, sizeof(grehdr_t)); -#endif + if (frpr_pullup(fin, sizeof(*ah)) == -1) + return; + + ah = (authhdr_t *)fin->fin_dp; + + len = (ah->ah_plen + 2) << 2; + frpr_short(fin, len); } @@ -1193,18 +1283,19 @@ fr_info_t *fin; { grehdr_t *gre; - if (frpr_pullup(fin, sizeof(grehdr_t)) == -1) + frpr_short(fin, sizeof(*gre)); + + if (fin->fin_off != 0) return; - if (fin->fin_v == 4) - frpr_short(fin, sizeof(grehdr_t)); -#ifdef USE_INET6 - else if (fin->fin_v == 6) - frpr_short6(fin, sizeof(grehdr_t)); -#endif - gre = fin->fin_dp; - if (GRE_REV(gre->gr_flags) == 1) - fin->fin_data[0] = gre->gr_call; + if (frpr_pullup(fin, sizeof(*gre)) == -1) + return; + + if (fin->fin_off == 0) { + gre = fin->fin_dp; + if (GRE_REV(gre->gr_flags) == 1) + fin->fin_data[0] = gre->gr_call; + } } @@ -1260,12 +1351,6 @@ fr_info_t *fin; * set packet attribute flags based on the offset and * calculate the byte offset that it represents. */ - if ((off & IP_MF) != 0) { - fi->fi_flx |= FI_FRAG; - if (fin->fin_dlen == 0) - fi->fi_flx |= FI_BAD; - } - off &= IP_MF|IP_OFFMASK; if (off != 0) { fi->fi_flx |= FI_FRAG; @@ -1273,7 +1358,17 @@ fr_info_t *fin; if (off != 0) { fin->fin_flx |= FI_FRAGBODY; off <<= 3; - if (off + fin->fin_dlen > 0xffff) { + if ((off + fin->fin_dlen > 65535) || + (fin->fin_dlen == 0) || (fin->fin_dlen & 7)) { + /* + * The length of the packet, starting at its + * offset cannot exceed 65535 (0xffff) as the + * length of an IP packet is only 16 bits. + * + * Any fragment that isn't the last fragment + * must have a length greater than 0 and it + * must be an even multiple of 8. + */ fi->fi_flx |= FI_BAD; } } @@ -1294,6 +1389,9 @@ fr_info_t *fin; case IPPROTO_ICMP : frpr_icmp(fin); break; + case IPPROTO_AH : + frpr_ah(fin); + break; case IPPROTO_ESP : frpr_esp(fin); break; @@ -1422,8 +1520,10 @@ fr_info_t *fin; if (v == 4) frpr_ipv4hdr(fin); #ifdef USE_INET6 - else if (v == 6) - frpr_ipv6hdr(fin); + else if (v == 6) { + if (frpr_ipv6hdr(fin) == -1) + return -1; + } #endif if (fin->fin_ip == NULL) return -1; @@ -1551,6 +1651,7 @@ frtuc_t *ft; } + /* ------------------------------------------------------------------------ */ /* Function: fr_ipfcheck */ /* Returns: int - 0 == match, 1 == no match */ @@ -1756,7 +1857,7 @@ u_32_t pass; { int rulen, portcmp, off, logged, skip; struct frentry *fr, *fnext; - u_32_t passt; + u_32_t passt, passo; /* * Do not allow nesting deeper than 16 levels. @@ -1824,15 +1925,13 @@ u_32_t pass; case FR_T_BPFOPC|FR_T_BUILTIN : { u_char *mc; - int wlen; if (*fin->fin_mp == NULL) continue; if (fin->fin_v != fr->fr_v) continue; mc = (u_char *)fin->fin_m; - wlen = fin->fin_dlen + fin->fin_hlen; - if (!bpf_filter(fr->fr_data, mc, wlen, 0)) + if (!bpf_filter(fr->fr_data, mc, fin->fin_plen, 0)) continue; break; } @@ -1914,6 +2013,7 @@ u_32_t pass; } #endif /* IPFILTER_LOG */ fr->fr_bytes += (U_QUAD_T)fin->fin_plen; + passo = pass; if (FR_ISSKIP(passt)) skip = fr->fr_arg; else if ((passt & FR_LOGMASK) != FR_LOG) @@ -1936,8 +2036,29 @@ u_32_t pass; if (fin->fin_flx & FI_DONTCACHE) logged = 1; } - if (pass & FR_QUICK) + + if (pass & FR_QUICK) { + /* + * Finally, if we've asked to track state for this + * packet, set it up. Add state for "quick" rules + * here so that if the action fails we can consider + * the rule to "not match" and keep on processing + * filter rules. + */ + if ((pass & FR_KEEPSTATE) && + !(fin->fin_flx & FI_STATE)) { + int out = fin->fin_out; + + if (fr_addstate(fin, NULL, 0) != NULL) { + ATOMIC_INCL(frstats[out].fr_ads); + } else { + ATOMIC_INCL(frstats[out].fr_bads); + pass = passo; + continue; + } + } break; + } } if (logged) fin->fin_flx |= FI_DONTCACHE; @@ -2022,18 +2143,22 @@ u_32_t *passp; * the result as if it were from the ACL's. */ fc = &frcache[out][CACHE_HASH(fin)]; + READ_ENTER(&ipf_frcache); if (!bcmp((char *)fin, (char *)fc, FI_CSIZE)) { /* - * copy cached data so we can unlock the mutex - * earlier. + * copy cached data so we can unlock the mutexes earlier. */ bcopy((char *)fc, (char *)fin, FI_COPYSIZE); + RWLOCK_EXIT(&ipf_frcache); ATOMIC_INCL(frstats[out].fr_chit); + if ((fr = fin->fin_fr) != NULL) { ATOMIC_INC64(fr->fr_hits); pass = fr->fr_flags; } } else { + RWLOCK_EXIT(&ipf_frcache); + #ifdef USE_INET6 if (fin->fin_v == 6) fin->fin_fr = ipfilter6[out][fr_active]; @@ -2042,9 +2167,13 @@ u_32_t *passp; fin->fin_fr = ipfilter[out][fr_active]; if (fin->fin_fr != NULL) pass = fr_scanlist(fin, fr_pass); + if (((pass & FR_KEEPSTATE) == 0) && - ((fin->fin_flx & FI_DONTCACHE) == 0)) + ((fin->fin_flx & FI_DONTCACHE) == 0)) { + WRITE_ENTER(&ipf_frcache); bcopy((char *)fin, (char *)fc, FI_COPYSIZE); + RWLOCK_EXIT(&ipf_frcache); + } if ((pass & FR_NOMATCH)) { ATOMIC_INCL(frstats[out].fr_nom); } @@ -2139,7 +2268,7 @@ u_32_t *passp; /* User space: */ /* -1 == packet blocked */ /* 1 == packet not matched */ -/* -2 == requires authantication */ +/* -2 == requires authentication */ /* Kernel: */ /* > 0 == filter error # for packet */ /* Parameters: ip(I) - pointer to start of IPv4/6 packet */ @@ -2189,6 +2318,7 @@ int out; #ifdef USE_INET6 ip6_t *ip6; #endif + SPL_INT(s); /* * The first part of fr_check() deals with making sure that what goes @@ -2228,6 +2358,10 @@ int out; if ((m->m_flags & M_MCAST) != 0) fin->fin_flx |= FI_MBCAST|FI_MULTICAST; # endif +# if defined(M_MLOOP) + if ((m->m_flags & M_MLOOP) != 0) + fin->fin_flx |= FI_MBCAST|FI_MULTICAST; +# endif # if defined(M_BCAST) if ((m->m_flags & M_BCAST) != 0) fin->fin_flx |= FI_MBCAST|FI_BROADCAST; @@ -2264,11 +2398,13 @@ int out; fin->fin_out = out; fin->fin_ifp = ifp; fin->fin_error = ENETUNREACH; - fin->fin_hlen = (u_short )hlen; + fin->fin_hlen = (u_short)hlen; fin->fin_dp = (char *)ip + hlen; fin->fin_ipoff = (char *)ip - MTOD(m, char *); + SPL_NET(s); + #ifdef USE_INET6 if (v == 6) { ATOMIC_INCL(frstats[out].fr_ipv6); @@ -2281,7 +2417,7 @@ int out; fin->fin_plen = ntohs(ip6->ip6_plen); if (fin->fin_plen == 0) { pass = FR_BLOCK|FR_NOMATCH; - goto filtered; + goto finished; } fin->fin_plen += sizeof(ip6_t); } else @@ -2294,8 +2430,10 @@ int out; fin->fin_plen = ip->ip_len; } - if (fr_makefrip(hlen, ip, fin) == -1) + if (fr_makefrip(hlen, ip, fin) == -1) { + pass = FR_BLOCK|FR_NOMATCH; goto finished; + } /* * For at least IPv6 packets, if a m_pullup() fails then this pointer @@ -2389,22 +2527,31 @@ int out; } #endif - if (fin->fin_state != NULL) + if (fin->fin_state != NULL) { fr_statederef(fin, (ipstate_t **)&fin->fin_state); + fin->fin_state = NULL; + } - if (fin->fin_nat != NULL) + if (fin->fin_nat != NULL) { fr_natderef((nat_t **)&fin->fin_nat); + fin->fin_nat = NULL; + } /* - * Only allow FR_DUP to work if a rule matched - it makes no sense to - * set FR_DUP as a "default" as there are no instructions about where - * to send the packet. Use fin_m here because it may have changed - * (without an update of 'm') in prior processing. + * Up the reference on fr_lock and exit ipf_mutex. fr_fastroute + * only frees up the lock on ipf_global and the generation of a + * packet below could cause a recursive call into IPFilter. + * Hang onto the filter rule just in case someone decides to remove + * or flush it in the meantime. */ - if ((fr != NULL) && (pass & FR_DUP)) { - mc = M_DUPLICATE(fin->fin_m); + if (fr != NULL) { + MUTEX_ENTER(&fr->fr_lock); + fr->fr_ref++; + MUTEX_EXIT(&fr->fr_lock); } + RWLOCK_EXIT(&ipf_mutex); + if (pass & (FR_RETRST|FR_RETICMP)) { /* * Should we return an ICMP packet to indicate error @@ -2426,7 +2573,8 @@ int out; ATOMIC_INCL(frstats[0].fr_ret); } else if (((pass & FR_RETMASK) == FR_RETRST) && !(fin->fin_flx & FI_SHORT)) { - if (fr_send_reset(fin) == 0) { + if (((fin->fin_flx & FI_OOW) != 0) || + (fr_send_reset(fin) == 0)) { ATOMIC_INCL(frstats[1].fr_ret); } } @@ -2442,13 +2590,7 @@ int out; * instructions about what to do with a packet. * Once we're finished return to our caller, freeing the packet if * we are dropping it (* BSD ONLY *). - * Reassign m from fin_m as we may have a new buffer, now. */ -#if defined(USE_INET6) || (defined(__sgi) && defined(_KERNEL)) -filtered: -#endif - m = fin->fin_m; - if (fr != NULL) { frdest_t *fdp; @@ -2459,26 +2601,26 @@ int out; * For fastroute rule, no destioation interface defined * so pass NULL as the frdest_t parameter */ - (void) fr_fastroute(m, mp, fin, NULL); + (void) fr_fastroute(fin->fin_m, mp, fin, NULL); m = *mp = NULL; } else if ((fdp->fd_ifp != NULL) && (fdp->fd_ifp != (struct ifnet *)-1)) { /* this is for to rules: */ - (void) fr_fastroute(m, mp, fin, fdp); + (void) fr_fastroute(fin->fin_m, mp, fin, fdp); m = *mp = NULL; } /* * Generate a duplicated packet. */ - if (mc != NULL) - (void) fr_fastroute(mc, &mc, fin, &fr->fr_dif); - } + if ((pass & FR_DUP) != 0) { + mc = M_DUPLICATE(fin->fin_m); + if (mc != NULL) + (void) fr_fastroute(mc, &mc, fin, &fr->fr_dif); + } - /* - * This late because the likes of fr_fastroute() use fin_fr. - */ - RWLOCK_EXIT(&ipf_mutex); + (void) fr_derefrule(&fr); + } finished: if (!FR_ISPASS(pass)) { @@ -2492,12 +2634,14 @@ int out; #if defined(_KERNEL) && defined(__sgi) if ((fin->fin_hbuf != NULL) && (mtod(fin->fin_m, struct ip *) != fin->fin_ip)) { - COPYBACK(m, 0, fin->fin_plen, fin->fin_hbuf); + COPYBACK(fin->fin_m, 0, fin->fin_plen, fin->fin_hbuf); } #endif } + SPL_X(s); RWLOCK_EXIT(&ipf_global); + #ifdef _KERNEL # if defined(OpenBSD) && OpenBSD >= 200311 if (FR_ISPASS(pass) && (v == 4)) { @@ -2890,7 +3034,7 @@ void *l4hdr; #if defined(_KERNEL) && ( ((BSD < 199103) && !defined(MENTAT)) || \ - defined(__sgi) ) && !defined(linux) + defined(__sgi) ) && !defined(linux) && !defined(_AIX51) /* * Copyright (c) 1982, 1986, 1988, 1991, 1993 * The Regents of the University of California. All rights reserved. @@ -2920,7 +3064,7 @@ void *l4hdr; * SUCH DAMAGE. * * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 - * Id: fil.c,v 2.243.2.57 2005/03/28 10:47:50 darrenr Exp + * $Id: fil.c,v 2.243.2.70 2005/12/07 08:15:16 darrenr Exp $ */ /* * Copy data from an mbuf chain starting "off" bytes from the beginning, @@ -2989,7 +3133,7 @@ m_copyback(m0, off, len, cp) m = m->m_next; } while (len > 0) { - mlen = min (m->m_len - off, len); + mlen = min(m->m_len - off, len); bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); cp += mlen; len -= mlen; @@ -3038,7 +3182,7 @@ frgroup_t ***fgpp; frgroup_t *fg, **fgp; /* - * Which list of groups to search in is dependant on which list of + * Which list of groups to search in is dependent on which list of * rules are being operated on. */ fgp = &ipfgroups[unit][set]; @@ -3331,7 +3475,8 @@ int proto, flags; /* slen bytes. */ /* ------------------------------------------------------------------------ */ char *memstr(src, dst, slen, dlen) -char *src, *dst; +const char *src; +char *dst; int slen, dlen; { char *s = NULL; @@ -4105,7 +4250,6 @@ caddr_t data; break; #endif default : - break; } break; @@ -4300,7 +4444,7 @@ caddr_t data; } else f = fp; if (f != NULL) { - if (fg != NULL && fg->fg_head!= NULL ) + if (fg != NULL && fg->fg_head != NULL) fg->fg_head->fr_ref++; if (fp != f) bcopy((char *)fp, (char *)f, @@ -4967,7 +5111,7 @@ ipftq_t *oifq, *nifq; /* the fragment cache for non-leading fragments. If a non-leading fragment */ /* has no match in the cache, return an error. */ /* ------------------------------------------------------------------------ */ -static INLINE int fr_updateipid(fin) +static int fr_updateipid(fin) fr_info_t *fin; { u_short id, ido, sums; @@ -5019,7 +5163,7 @@ char *buffer; { static char namebuf[LIFNAMSIZ]; # if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \ - defined(__sgi) || defined(linux) || \ + defined(__sgi) || defined(linux) || defined(_AIX51) || \ (defined(sun) && !defined(__SVR4) && !defined(__svr4__)) int unit, space; char temp[20]; @@ -5031,7 +5175,7 @@ char *buffer; (void) strncpy(buffer, ifp->if_name, LIFNAMSIZ); buffer[LIFNAMSIZ - 1] = '\0'; # if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \ - defined(__sgi) || \ + defined(__sgi) || defined(_AIX51) || \ (defined(sun) && !defined(__SVR4) && !defined(__svr4__)) for (s = buffer; *s; s++) ; @@ -5644,6 +5788,10 @@ ipftuneable_t ipf_tuneables[] = { sizeof(fr_update_ipid), 0 }, { { &fr_chksrc }, "fr_chksrc", 0, 1, sizeof(fr_chksrc), 0 }, + { { &fr_minttl }, "fr_minttl", 0, 1, + sizeof(fr_minttl), 0 }, + { { &fr_icmpminfragmtu }, "fr_icmpminfragmtu", 0, 1, + sizeof(fr_icmpminfragmtu), 0 }, { { &fr_pass }, "fr_pass", 0, 0xffffffff, sizeof(fr_pass), 0 }, /* state */ @@ -5789,7 +5937,7 @@ void *cookie, **next; /* to the matching structure. */ /* ------------------------------------------------------------------------ */ static ipftuneable_t *fr_findtunebyname(name) -char *name; +const char *name; { ipftuneable_t *ta; @@ -6180,31 +6328,6 @@ int v; } -/* ------------------------------------------------------------------------ */ -/* Function: fr_icmp4errortype */ -/* Returns: int - 1 == success, 0 == failure */ -/* Parameters: icmptype(I) - ICMP type number */ -/* */ -/* Tests to see if the ICMP type number passed is an error type or not. */ -/* ------------------------------------------------------------------------ */ -int fr_icmp4errortype(icmptype) -int icmptype; -{ - - switch (icmptype) - { - case ICMP_SOURCEQUENCH : - case ICMP_PARAMPROB : - case ICMP_REDIRECT : - case ICMP_TIMXCEED : - case ICMP_UNREACH : - return 1; - default: - return 0; - } -} - - /* ------------------------------------------------------------------------ */ /* Function: fr_resolvenic */ /* Returns: void* - NULL = wildcard name, -1 = failed to find NIC, else */ diff --git a/sys/contrib/ipfilter/netinet/ip_auth.c b/sys/contrib/ipfilter/netinet/ip_auth.c index a5e5c58018c2..c4341df4be6b 100644 --- a/sys/contrib/ipfilter/netinet/ip_auth.c +++ b/sys/contrib/ipfilter/netinet/ip_auth.c @@ -370,9 +370,7 @@ int mode; #if defined(_KERNEL) && !defined(MENTAT) && !defined(linux) && \ (!defined(__FreeBSD_version) || (__FreeBSD_version < 501000)) struct ifqueue *ifq; -# ifdef USE_SPL - int s; -# endif /* USE_SPL */ + SPL_INT(s); #endif frauth_t auth, *au = &auth, *fra; int i, error = 0, len; @@ -509,7 +507,7 @@ int mode; # ifdef MENTAT error = !putq(fra->fra_q, m); # else /* MENTAT */ -# ifdef linux +# if defined(linux) || defined(AIX) # else # if (defined(_BSDI_VERSION) && _BSDI_VERSION >= 199802) || \ (defined(__OpenBSD__)) || \ @@ -530,12 +528,12 @@ int mode; # ifdef MENTAT error = !putq(fra->fra_q, m); # else /* MENTAT */ -# ifdef linux +# if defined(linux) || defined(AIX) # else -# if __FreeBSD_version >= 501000 +# if (__FreeBSD_version >= 501000) netisr_dispatch(NETISR_IP, m); # else -# if IRIX >= 60516 +# if (IRIX >= 60516) ifq = &((struct ifnet *)fra->fra_info.fin_ifp)->if_snd; # else ifq = &ipintrq; @@ -666,9 +664,7 @@ void fr_authexpire() register frauthent_t *fae, **faep; register frentry_t *fr, **frp; mb_t *m; -# if !defined(MENAT) && defined(_KERNEL) && defined(USE_SPL) - int s; -# endif + SPL_INT(s); if (fr_auth_lock) return; @@ -717,9 +713,7 @@ frentry_t *fr, **frptr; { frauthent_t *fae, **faep; int error = 0; -# if !defined(MENAT) && defined(_KERNEL) && defined(USE_SPL) - int s; -#endif + SPL_INT(s); if ((cmd != SIOCADAFR) && (cmd != SIOCRMAFR)) return EIO; diff --git a/sys/contrib/ipfilter/netinet/ip_compat.h b/sys/contrib/ipfilter/netinet/ip_compat.h index 1bd24ff80a51..1709e30da5f7 100644 --- a/sys/contrib/ipfilter/netinet/ip_compat.h +++ b/sys/contrib/ipfilter/netinet/ip_compat.h @@ -1121,6 +1121,7 @@ extern mb_t *m_pullup __P((mb_t *, int)); # define mbuf sk_buff # define mtod(m, t) ((t)(m)->data) +# define m_data data # define m_len len # define m_next next # define M_DUPLICATE(m) skb_clone((m), in_interrupt() ? GFP_ATOMIC : \ @@ -1205,6 +1206,115 @@ typedef u_int32_t u_32_t; #endif +/* ----------------------------------------------------------------------- */ +/* A I X */ +/* ----------------------------------------------------------------------- */ +#if defined(_AIX51) +# undef MENTAT + +# include +# include + +# ifdef _KERNEL +# define rw_read_locked(x) 0 +# include +# include +# define KMUTEX_T simple_lock_t +# define KRWLOCK_T complex_lock_t +# define USE_MUTEXES 1 +# define USE_SPL 1 +# define READ_ENTER(x) lock_read((x)->ipf_lk) +# define WRITE_ENTER(x) lock_write((x)->ipf_lk) +# define MUTEX_DOWNGRADE(x) lock_write_to_read((x)->ipf_lk) +# define RWLOCK_INIT(x, y) lock_alloc(&(x)->ipf_lk, \ + LOCK_ALLOC_PIN, \ + (u_short)y, 0); \ + lock_init((x)->ipf_lk, TRUE) +# define RWLOCK_EXIT(x) lock_done((x)->ipf_lk) +# define RW_DESTROY(x) lock_free(&(x)->ipf_lk) +# define MUTEX_ENTER(x) simple_lock((x)->ipf_lk) +# define MUTEX_INIT(x, y) lock_alloc(&(x)->ipf_lk, \ + LOCK_ALLOC_PIN, \ + (u_short)y, 0); \ + simple_lock_init((x)->ipf_lk) +# define MUTEX_DESTROY(x) lock_free(&(x)->ipf_lk) +# define MUTEX_EXIT(x) simple_unlock((x)->ipf_lk) +# define MUTEX_NUKE(x) bzero(&(x)->ipf_lk, sizeof((x)->ipf_lk)) +# define ATOMIC_INC64(x) { MUTEX_ENTER(&ipf_rw); (x)++; \ + MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_DEC64(x) { MUTEX_ENTER(&ipf_rw); (x)--; \ + MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_INC32(x) { MUTEX_ENTER(&ipf_rw); (x)++; \ + MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_DEC32(x) { MUTEX_ENTER(&ipf_rw); (x)--; \ + MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_INCL(x) { MUTEX_ENTER(&ipf_rw); (x)++; \ + MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_DECL(x) { MUTEX_ENTER(&ipf_rw); (x)--; \ + MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_INC(x) { MUTEX_ENTER(&ipf_rw); (x)++; \ + MUTEX_EXIT(&ipf_rw); } +# define ATOMIC_DEC(x) { MUTEX_ENTER(&ipf_rw); (x)--; \ + MUTEX_EXIT(&ipf_rw); } +# define SPL_NET(x) x = splnet() +# define SPL_IMP(x) x = splimp() +# undef SPL_X +# define SPL_X(x) splx(x) +# define UIOMOVE(a,b,c,d) uiomove((caddr_t)a,b,c,d) +extern void* getifp __P((char *, int)); +# define GETIFP(n, v) getifp(n, v) +# define GET_MINOR minor +# define SLEEP(id, n) sleepx((id), PZERO+1, 0) +# define WAKEUP(id,x) wakeup(id) +# 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) +# define KFREE(x) FREE((x), M_TEMP) +# define KFREES(x,s) FREE((x), M_TEMP) +# define MSGDSIZE(x) mbufchainlen(x) +# define M_LEN(x) (x)->m_len +# define M_DUPLICATE(x) m_copy((x), 0, M_COPYALL) +# define GETKTIME(x) +# define CACHE_HASH(x) ((IFNAME(fin->fin_ifp)[0] + \ + ((struct ifnet *)fin->fin_ifp)->if_unit) & 7) +# define IPF_PANIC(x,y) +typedef struct mbuf mb_t; +# endif /* _KERNEL */ + +/* + * These are from's Solaris' #defines for little endian. + */ +#if !defined(IP6F_MORE_FRAG) +# define IP6F_MORE_FRAG 0x0100 +#endif +#if !defined(IP6F_RESERVED_MASK) +# define IP6F_RESERVED_MASK 0x0600 +#endif +#if !defined(IP6F_OFF_MASK) +# define IP6F_OFF_MASK 0xf8ff +#endif + +struct ip6_ext { + u_char ip6e_nxt; + u_char ip6e_len; +}; + +typedef int ioctlcmd_t; +typedef int minor_t; +/* + * Really, any arch where sizeof(long) != sizeof(int). + */ +typedef unsigned int u_32_t; +# define U_32_T 1 + +# define OS_RECOGNISED 1 +#endif /* _AIX51 */ + + #ifndef OS_RECOGNISED #error ip_compat.h does not recognise this platform/OS. #endif @@ -1220,11 +1330,11 @@ typedef u_int32_t u_32_t; * For BSD kernels, if bpf is in the kernel, enable ipfilter to use bpf in * filter rules. */ -#if !defined(IPFILTER_BPF) && \ - ((defined(NBPF) && NBPF > 0) || \ - (defined(NBPFILTER) && NBPFILTER > 0) || \ - (defined(DEV_BPF) && DEV_BPF >0)) -# define IPFILTER_BPF +#if !defined(IPFILTER_BPF) +# if (defined(NBPF) && (NBPF > 0)) || (defined(DEV_BPF) && (DEV_BPF > 0)) || \ + (defined(NBPFILTER) && (NBPFILTER > 0)) +# define IPFILTER_BPF +# endif #endif /* @@ -1292,10 +1402,10 @@ typedef union { #endif #if defined(linux) && defined(_KERNEL) -extern INLINE void ipf_read_enter __P((ipfrwlock_t *)); -extern INLINE void ipf_write_enter __P((ipfrwlock_t *)); -extern INLINE void ipf_rw_exit __P((ipfrwlock_t *)); -extern INLINE void ipf_rw_downgrade __P((ipfrwlock_t *)); +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_downgrade __P((ipfrwlock_t *)); #endif /* @@ -1315,6 +1425,7 @@ typedef struct mb_s { # define M_LEN(x) (x)->mb_len # define M_DUPLICATE(x) (x) # define GETKTIME(x) gettimeofday((struct timeval *)(x), NULL) +# undef MTOD # define MTOD(m, t) ((t)(m)->mb_buf) # define FREE_MB_T(x) # define SLEEP(x,y) 1; @@ -1329,8 +1440,8 @@ typedef struct mb_s { # define KFREE(x) free(x) # define KFREES(x,s) free(x) # define GETIFP(x, v) get_unit(x,v) -# define COPYIN(a,b,c) (bcopy((a), (b), (c)), 0) -# define COPYOUT(a,b,c) (bcopy((a), (b), (c)), 0) +# 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), \ @@ -1565,6 +1676,12 @@ extern char *fr_getifname __P((struct ifnet *, char *)); # define ATOMIC_DEC(x) (x)-- #endif +#if defined(USE_SPL) && defined(_KERNEL) +# define SPL_INT(x) int x +#else +# define SPL_INT(x) +#endif + /* * If there are no atomic operations for bit sizes defined, define them to all * use a generic one that works for all sizes. @@ -2039,9 +2156,10 @@ typedef struct tcpiphdr tcpiphdr_t; #ifndef IPPROTO_DSTOPTS # define IPPROTO_DSTOPTS 60 #endif -#ifndef IPPROTO_FRAGMENT -# define IPPROTO_FRAGMENT 44 +#ifndef IPPROTO_MOBILITY +# define IPPROTO_MOBILITY 135 #endif + #ifndef ICMP_ROUTERADVERT # define ICMP_ROUTERADVERT 9 #endif @@ -2275,7 +2393,7 @@ typedef struct tcpiphdr tcpiphdr_t; /* * ICMP error replies have an IP header (20 bytes), 8 bytes of ICMP data, * another IP header and then 64 bits of data, totalling 56. Of course, - * the last 64 bits is dependant on that being available. + * the last 64 bits is dependent on that being available. */ #define ICMPERR_ICMPHLEN 8 #define ICMPERR_IPICMPHLEN (20 + 8) diff --git a/sys/contrib/ipfilter/netinet/ip_fil.h b/sys/contrib/ipfilter/netinet/ip_fil.h index eb50a8e498c1..a061edef6700 100644 --- a/sys/contrib/ipfilter/netinet/ip_fil.h +++ b/sys/contrib/ipfilter/netinet/ip_fil.h @@ -25,7 +25,7 @@ # endif #endif -#if defined(__STDC__) || defined(__GNUC__) +#if defined(__STDC__) || defined(__GNUC__) || defined(_AIX51) # define SIOCADAFR _IOW('r', 60, struct ipfobj) # define SIOCRMAFR _IOW('r', 61, struct ipfobj) # define SIOCSETFF _IOW('r', 62, u_int) @@ -905,6 +905,7 @@ typedef struct tcpdata { #define TCP_WSCALE_SEEN 0x00000001 #define TCP_WSCALE_FIRST 0x00000002 +#define TCP_SACK_PERMIT 0x00000004 typedef struct tcpinfo { @@ -914,6 +915,9 @@ typedef struct tcpinfo { } tcpinfo_t; +/* + * Structures to define a GRE header as seen in a packet. + */ struct grebits { u_32_t grb_C:1; u_32_t grb_R:1; @@ -948,7 +952,9 @@ typedef struct grehdr { #define gr_A gr_bits.grb_A #define gr_ver gr_bits.grb_ver - +/* + * GRE information tracked by "keep state" + */ typedef struct greinfo { u_short gs_call[2]; u_short gs_flags; @@ -958,6 +964,20 @@ typedef struct greinfo { #define GRE_REV(x) ((ntohs(x) >> 13) & 7) +/* + * Format of an Authentication header + */ +typedef struct authhdr { + u_char ah_next; + u_char ah_plen; + u_short ah_reserved; + u_32_t ah_spi; + u_32_t ah_seq; + /* Following the sequence number field is 0 or more bytes of */ + /* authentication data, as specified by ah_plen - RFC 2402. */ +} authhdr_t; + + /* * Timeout tail queue list member */ @@ -1240,8 +1260,9 @@ 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 char *memstr __P((char *, char *, int, int)); +extern char *memstr __P((const char *, char *, int, int)); extern int count4bits __P((u_32_t)); extern int frrequest __P((int, ioctlcmd_t, caddr_t, int, int)); extern char *getifname __P((struct ifnet *)); @@ -1314,7 +1335,6 @@ extern void fr_fixskip __P((frentry_t **, frentry_t *, int)); extern void fr_forgetifp __P((void *)); extern frentry_t *fr_getrulen __P((int, char *, u_32_t)); extern void fr_getstat __P((struct friostat *)); -extern int fr_icmp4errortype __P((int)); extern int fr_ifpaddr __P((int, int, void *, struct in_addr *, struct in_addr *)); extern int fr_initialise __P((void)); diff --git a/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c b/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c index 6c87f544101a..0e8125160f3f 100644 --- a/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c +++ b/sys/contrib/ipfilter/netinet/ip_fil_freebsd.c @@ -7,7 +7,7 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ip_fil.c 2.41 6/5/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)Id: ip_fil_freebsd.c,v 2.53.2.25 2005/02/01 03:15:56 darrenr Exp"; +static const char rcsid[] = "@(#)$Id: ip_fil_freebsd.c,v 2.53.2.27 2005/08/20 13:48:19 darrenr Exp $"; #endif #if defined(KERNEL) || defined(_KERNEL) @@ -125,7 +125,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; +ipfrwlock_t ipf_mutex, ipf_global, ipf_ipidfrag, ipf_frcache; ipfrwlock_t ipf_frag, ipf_state, ipf_nat, ipf_natfrag, ipf_auth; # endif int ipf_locks_done = 0; @@ -147,6 +147,19 @@ int (*fr_checkp) __P((ip_t *ip, int hlen, void *ifp, int out, mb_t **mp)); #endif /* __FreeBSD_version >= 500011 */ +#if (__FreeBSD_version >= 502103) +static eventhandler_tag ipf_arrivetag, ipf_departtag, ipf_clonetag; + +static void ipf_ifevent(void *arg); + +static void ipf_ifevent(arg) +void *arg; +{ + frsync(NULL); +} +#endif + + #if (__FreeBSD_version >= 501108) && defined(_KERNEL) static int @@ -203,6 +216,7 @@ int iplattach() 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"); ipf_locks_done = 1; @@ -271,6 +285,18 @@ int iplattach() } # endif # endif + +#if (__FreeBSD_version >= 502103) + ipf_arrivetag = EVENTHANDLER_REGISTER(ifnet_arrival_event, \ + ipf_ifevent, NULL, \ + EVENTHANDLER_PRI_ANY); + ipf_departtag = EVENTHANDLER_REGISTER(ifnet_departure_event, \ + ipf_ifevent, NULL, \ + EVENTHANDLER_PRI_ANY); + ipf_clonetag = EVENTHANDLER_REGISTER(if_clone_event, ipf_ifevent, \ + NULL, EVENTHANDLER_PRI_ANY); +#endif + if (fr_checkp != fr_check) { fr_savep = fr_checkp; fr_checkp = fr_check; @@ -315,6 +341,18 @@ int ipldetach() if (fr_control_forwarding & 2) ipforwarding = 0; +#if (__FreeBSD_version >= 502103) + if (ipf_arrivetag != NULL) { + EVENTHANDLER_DEREGISTER(ifnet_arrival_event, ipf_arrivetag); + } + if (ipf_departtag != NULL) { + EVENTHANDLER_DEREGISTER(ifnet_departure_event, ipf_departtag); + } + if (ipf_clonetag != NULL) { + EVENTHANDLER_DEREGISTER(if_clone_event, ipf_clonetag); + } +#endif + SPL_NET(s); #if (__FreeBSD_version >= 300000) @@ -380,6 +418,7 @@ int ipldetach() MUTEX_DESTROY(&ipf_timeoutlock); MUTEX_DESTROY(&ipf_rw); RW_DESTROY(&ipf_mutex); + RW_DESTROY(&ipf_frcache); RW_DESTROY(&ipf_ipidfrag); RW_DESTROY(&ipf_global); ipf_locks_done = 0; @@ -421,7 +460,7 @@ int mode; friostat_t fio; #if (BSD >= 199306) && defined(_KERNEL) - if ((securelevel >= 2) && (mode & FWRITE)) + if ((securelevel >= 3) && (mode & FWRITE)) return EPERM; #endif diff --git a/sys/contrib/ipfilter/netinet/ip_frag.c b/sys/contrib/ipfilter/netinet/ip_frag.c index bcc22283f5be..f1754cab61f8 100644 --- a/sys/contrib/ipfilter/netinet/ip_frag.c +++ b/sys/contrib/ipfilter/netinet/ip_frag.c @@ -47,7 +47,7 @@ struct file; # endif #endif #if !defined(__SVR4) && !defined(__svr4__) -# if defined(_KERNEL) && !defined(__sgi) +# if defined(_KERNEL) && !defined(__sgi) && !defined(AIX) # include # endif #else @@ -238,7 +238,7 @@ ipfr_t *table[]; ip = fin->fin_ip; if (pass & FR_FRSTRICT) - if ((ip->ip_off & IP_OFFMASK) != 0) + if (fin->fin_off != 0) return NULL; frag.ipfr_p = ip->ip_p; @@ -278,8 +278,16 @@ ipfr_t *table[]; return NULL; } - if ((fra->ipfr_rule = fin->fin_fr) != NULL) - fin->fin_fr->fr_ref++; + fra->ipfr_rule = fin->fin_fr; + if (fra->ipfr_rule != NULL) { + + frentry_t *fr; + + fr = fin->fin_fr; + MUTEX_ENTER(&fr->fr_lock); + fr->fr_ref++; + MUTEX_EXIT(&fr->fr_lock); + } /* * Insert the fragment into the fragment table, copy the struct used @@ -747,9 +755,7 @@ void fr_fragexpire() { ipfr_t **fp, *fra; nat_t *nat; -#if defined(USE_SPL) && defined(_KERNEL) - int s; -#endif + SPL_INT(s); if (fr_frag_lock) return; @@ -815,7 +821,7 @@ void fr_fragexpire() /* expectation of this being called twice per second. */ /* ------------------------------------------------------------------------ */ #if !defined(_KERNEL) || (!SOLARIS && !defined(__hpux) && !defined(__sgi) && \ - !defined(__osf__)) + !defined(__osf__) && !defined(linux)) # if defined(_KERNEL) && ((BSD >= 199103) || defined(__sgi)) void fr_slowtimer __P((void *ptr)) # else diff --git a/sys/contrib/ipfilter/netinet/ip_frag.h b/sys/contrib/ipfilter/netinet/ip_frag.h index 519899976879..88b588277cb5 100644 --- a/sys/contrib/ipfilter/netinet/ip_frag.h +++ b/sys/contrib/ipfilter/netinet/ip_frag.h @@ -81,7 +81,11 @@ extern void fr_slowtimer __P((void)); extern void fr_slowtimer __P((void *)); # endif #else +# if defined(linux) && defined(_KERNEL) +extern void fr_slowtimer __P((long)); +# else extern int fr_slowtimer __P((void)); +# endif #endif #endif /* __IP_FRAG_H__ */ diff --git a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c index 91a48c0fbfc0..9e628a692ada 100644 --- a/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_ftp_pxy.c @@ -474,9 +474,10 @@ int dlen; { u_int a1, a2, a3, a4, data_ip; char newbuf[IPF_FTPBUFSZ]; - char *s, *brackets[2]; + const char *brackets[2]; u_short a5, a6; ftpside_t *f; + char *s; if (ippr_ftp_forcepasv != 0 && ftp->ftp_side[0].ftps_cmds != FTPXY_C_PASV) { diff --git a/sys/contrib/ipfilter/netinet/ip_htable.c b/sys/contrib/ipfilter/netinet/ip_htable.c index d1769b75607b..aaecaa63f52d 100644 --- a/sys/contrib/ipfilter/netinet/ip_htable.c +++ b/sys/contrib/ipfilter/netinet/ip_htable.c @@ -53,7 +53,7 @@ struct file; /* END OF INCLUDES */ #if !defined(lint) -static const char rcsid[] = "@(#)Id: ip_htable.c,v 2.34.2.2 2004/10/17 15:49:15 darrenr Exp"; +static const char rcsid[] = "@(#)$Id: ip_htable.c,v 2.34.2.4 2005/11/13 15:38:37 darrenr Exp $"; #endif #ifdef IPFILTER_LOOKUP @@ -141,12 +141,9 @@ iplookupop_t *op; sizeof(oiph->iph_name)) == 0) break; } while (oiph != NULL); + (void)strncpy(iph->iph_name, name, sizeof(iph->iph_name)); - err = COPYOUT(iph, op->iplo_struct, sizeof(*iph)); - if (err != 0) { - KFREE(iph); - return EFAULT; - } + (void)strncpy(op->iplo_name, name, sizeof(op->iplo_name)); iph->iph_type |= IPHASH_ANON; } diff --git a/sys/contrib/ipfilter/netinet/ip_log.c b/sys/contrib/ipfilter/netinet/ip_log.c index e42469de56af..36901ac679b6 100644 --- a/sys/contrib/ipfilter/netinet/ip_log.c +++ b/sys/contrib/ipfilter/netinet/ip_log.c @@ -419,9 +419,7 @@ int *types, cnt; iplog_t *ipl; size_t len; int i; -# if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) - int s; -# endif + SPL_INT(s); /* * Check to see if this log record has a CRC which matches the last @@ -541,9 +539,7 @@ struct uio *uio; size_t dlen, copied; int error = 0; iplog_t *ipl; -# if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) - int s; -# endif + SPL_INT(s); /* * Sanity checks. Make sure the minor # is valid and we're copying @@ -655,9 +651,7 @@ minor_t unit; { iplog_t *ipl; int used; -# if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) - int s; -# endif + SPL_INT(s); SPL_NET(s); MUTEX_ENTER(&ipl_mutex); diff --git a/sys/contrib/ipfilter/netinet/ip_nat.c b/sys/contrib/ipfilter/netinet/ip_nat.c index 83464d416619..1b69f853077c 100644 --- a/sys/contrib/ipfilter/netinet/ip_nat.c +++ b/sys/contrib/ipfilter/netinet/ip_nat.c @@ -37,7 +37,9 @@ struct file; #else # include #endif -#include +#if !defined(AIX) +# include +#endif #if !defined(linux) # include #endif @@ -187,15 +189,15 @@ 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 INLINE int nat_icmpquerytype4 __P((int)); +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)); -static INLINE int nat_finalise __P((fr_info_t *, nat_t *, natinfo_t *, +static int nat_finalise __P((fr_info_t *, nat_t *, natinfo_t *, tcphdr_t *, nat_t **, int)); static void 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 INLINE int nat_wildok __P((nat_t *, int, int, int, int)); +static int nat_wildok __P((nat_t *, int, int, int, int)); /* ------------------------------------------------------------------------ */ @@ -800,10 +802,14 @@ int mode; error = appr_ioctl(data, cmd, mode); break; case SIOCSTLCK : - fr_lock(data, &fr_nat_lock); + if (!(mode & FWRITE)) { + error = EPERM; + } else { + fr_lock(data, &fr_nat_lock); + } break; case SIOCSTPUT : - if (fr_nat_lock) { + if ((mode & FWRITE) != 0) { error = fr_natputent(data, getlock); } else { error = EACCES; @@ -1347,8 +1353,15 @@ int getlock; fin.fin_data[0] = ntohs(nat->nat_oport); fin.fin_data[1] = ntohs(nat->nat_outport); fin.fin_ifp = nat->nat_ifps[1]; - if (nat_inlookup(&fin, 0, fin.fin_p, nat->nat_oip, - nat->nat_inip) != NULL) { + if (getlock) { + READ_ENTER(&ipf_nat); + } + n = nat_inlookup(&fin, 0, fin.fin_p, nat->nat_oip, + nat->nat_inip); + if (getlock) { + RWLOCK_EXIT(&ipf_nat); + } + if (n != NULL) { error = EEXIST; goto junkput; } @@ -1356,8 +1369,15 @@ int getlock; fin.fin_data[0] = ntohs(nat->nat_outport); fin.fin_data[1] = ntohs(nat->nat_oport); fin.fin_ifp = nat->nat_ifps[0]; - if (nat_outlookup(&fin, 0, fin.fin_p, nat->nat_outip, - nat->nat_oip) != NULL) { + if (getlock) { + READ_ENTER(&ipf_nat); + } + n = nat_outlookup(&fin, 0, fin.fin_p, nat->nat_outip, + nat->nat_oip); + if (getlock) { + RWLOCK_EXIT(&ipf_nat); + } + if (n != NULL) { error = EEXIST; goto junkput; } @@ -1421,7 +1441,9 @@ int getlock; MUTEX_NUKE(&fr->fr_lock); MUTEX_INIT(&fr->fr_lock, "nat-filter rule lock"); } else { - READ_ENTER(&ipf_nat); + if (getlock) { + READ_ENTER(&ipf_nat); + } for (n = nat_instances; n; n = n->nat_next) if (n->nat_fr == fr) break; @@ -1431,7 +1453,9 @@ int getlock; fr->fr_ref++; MUTEX_EXIT(&fr->fr_lock); } - RWLOCK_EXIT(&ipf_nat); + if (getlock) { + RWLOCK_EXIT(&ipf_nat); + } if (!n) { error = ESRCH; @@ -1982,8 +2006,8 @@ natinfo_t *ni; * packet might match a different one to the previous connection but * we want the same destination to be used. */ - if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == - (IPN_ROUNDR|IPN_STICKY)) { + if (((np->in_flags & (IPN_ROUNDR|IPN_SPLIT)) != 0) && + ((np->in_flags & IPN_STICKY) != 0)) { hm = nat_hostmap(NULL, fin->fin_src, fin->fin_dst, in, (u_32_t)dport); if (hm != NULL) { @@ -2004,7 +2028,7 @@ natinfo_t *ni; in.s_addr = np->in_nip; if ((np->in_flags & (IPN_ROUNDR|IPN_STICKY)) == IPN_STICKY) { - hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, + hm = nat_hostmap(NULL, fin->fin_src, fin->fin_dst, in, (u_32_t)dport); if (hm != NULL) { in.s_addr = hm->hm_mapip.s_addr; @@ -2077,6 +2101,9 @@ natinfo_t *ni; nat->nat_inip.s_addr = htonl(in.s_addr); nat->nat_outip = fin->fin_dst; nat->nat_oip = fin->fin_src; + if ((nat->nat_hm == NULL) && ((np->in_flags & IPN_STICKY) != 0)) + nat->nat_hm = nat_hostmap(np, fin->fin_src, fin->fin_dst, in, + (u_32_t)dport); ni->nai_sum1 = LONG_SUM(ntohl(fin->fin_daddr)) + ntohs(dport); ni->nai_sum2 = LONG_SUM(in.s_addr) + ntohs(nport); @@ -2338,7 +2365,7 @@ int direction; /* for both IPv4 and IPv6. */ /* ------------------------------------------------------------------------ */ /*ARGSUSED*/ -static INLINE int nat_finalise(fin, nat, ni, tcp, natsave, direction) +static int nat_finalise(fin, nat, ni, tcp, natsave, direction) fr_info_t *fin; nat_t *nat; natinfo_t *ni; @@ -2363,8 +2390,6 @@ int direction; nat->nat_ptr = np; nat->nat_p = fin->fin_p; nat->nat_mssclamp = np->in_mssclamp; - fr = fin->fin_fr; - nat->nat_fr = fr; if ((np->in_apr != NULL) && ((ni->nai_flags & NAT_SLAVE) == 0)) if (appr_new(fin, nat) == -1) @@ -2374,6 +2399,8 @@ int direction; if (nat_logging) nat_log(nat, (u_int)np->in_redir); np->in_use++; + fr = fin->fin_fr; + nat->nat_fr = fr; if (fr != NULL) { MUTEX_ENTER(&fr->fr_lock); fr->fr_ref++; @@ -2515,8 +2542,7 @@ int dir; * Only a basic IP header (no options) should be with an ICMP error * header. Also, if it's not an error type, then return. */ - if ((fin->fin_hlen != sizeof(ip_t)) || - !fr_icmp4errortype(type)) + if ((fin->fin_hlen != sizeof(ip_t)) || !(fin->fin_flx & FI_ICMPERR)) return NULL; /* @@ -3806,8 +3832,15 @@ u_32_t nflags; CALC_SUMD(s1, s2, sumd); fix_outcksum(fin, &fin->fin_ip->ip_sum, sumd); } -#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || defined(linux) +#if !defined(_KERNEL) || defined(MENTAT) || defined(__sgi) || \ + defined(linux) || defined(BRIDGE_IPF) else { + /* + * Strictly speaking, this isn't necessary on BSD + * kernels because they do checksum calculation after + * this code has run BUT if ipfilter is being used + * to do NAT as a bridge, that code doesn't exist. + */ if (nat->nat_dir == NAT_OUTBOUND) fix_outcksum(fin, &fin->fin_ip->ip_sum, nat->nat_ipsumd); @@ -4316,9 +4349,7 @@ void fr_natexpire() { ipftq_t *ifq, *ifqnext; ipftqent_t *tqe, *tqn; -#if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) - int s; -#endif + SPL_INT(s); int i; SPL_NET(s); @@ -4373,9 +4404,7 @@ void *ifp; ipnat_t *n; nat_t *nat; void *ifp2; -#if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) - int s; -#endif + SPL_INT(s); if (fr_running <= 0) return; @@ -4457,7 +4486,7 @@ void *ifp; /* Tests to see if the ICMP type number passed is a query/response type or */ /* not. */ /* ------------------------------------------------------------------------ */ -static INLINE int nat_icmpquerytype4(icmptype) +static int nat_icmpquerytype4(icmptype) int icmptype; { @@ -4610,9 +4639,20 @@ nat_t *nat; MUTEX_NUKE(&clone->nat_lock); + clone->nat_aps = NULL; + /* + * Initialize all these so that nat_delete() doesn't cause a crash. + */ + clone->nat_tqe.tqe_pnext = NULL; + clone->nat_tqe.tqe_next = NULL; + clone->nat_tqe.tqe_ifq = NULL; + clone->nat_tqe.tqe_parent = clone; + clone->nat_flags &= ~SI_CLONE; clone->nat_flags |= SI_CLONED; + if (clone->nat_hm) + clone->nat_hm->hm_ref++; if (nat_insert(clone, fin->fin_rev) == -1) { KFREE(clone); @@ -4631,14 +4671,13 @@ nat_t *nat; MUTEX_EXIT(&fr->fr_lock); } - /* * Because the clone is created outside the normal loop of things and * TCP has special needs in terms of state, initialise the timeout * state of the new NAT from here. */ if (clone->nat_p == IPPROTO_TCP) { - (void) fr_tcp_age(&clone->nat_tqe, fin, nat_tqb, \ + (void) fr_tcp_age(&clone->nat_tqe, fin, nat_tqb, clone->nat_flags); } #ifdef IPFILTER_SYNC @@ -4663,7 +4702,7 @@ nat_t *nat; /* Use NAT entry and packet direction to determine which combination of */ /* wildcard flags should be used. */ /* ------------------------------------------------------------------------ */ -static INLINE int nat_wildok(nat, sport, dport, flags, dir) +static int nat_wildok(nat, sport, dport, flags, dir) nat_t *nat; int sport; int dport; diff --git a/sys/contrib/ipfilter/netinet/ip_nat.h b/sys/contrib/ipfilter/netinet/ip_nat.h index b30ac7f02947..e1bec966abb4 100644 --- a/sys/contrib/ipfilter/netinet/ip_nat.h +++ b/sys/contrib/ipfilter/netinet/ip_nat.h @@ -17,18 +17,16 @@ #define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) #endif -#if defined(__STDC__) || defined(__GNUC__) +#if defined(__STDC__) || defined(__GNUC__) || defined(_AIX51) #define SIOCADNAT _IOW('r', 60, struct ipfobj) #define SIOCRMNAT _IOW('r', 61, struct ipfobj) #define SIOCGNATS _IOWR('r', 62, struct ipfobj) #define SIOCGNATL _IOWR('r', 63, struct ipfobj) -/* SIOCPROXY _IOWR('r', 64, struct ap_control) */ #else #define SIOCADNAT _IOW(r, 60, struct ipfobj) #define SIOCRMNAT _IOW(r, 61, struct ipfobj) #define SIOCGNATS _IOWR(r, 62, struct ipfobj) #define SIOCGNATL _IOWR(r, 63, struct ipfobj) -/* SIOCPROXY _IOWR(r, 64, struct ap_control) */ #endif #undef LARGE_NAT /* define this if you're setting up a system to NAT @@ -298,6 +296,7 @@ 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# */ diff --git a/sys/contrib/ipfilter/netinet/ip_proxy.c b/sys/contrib/ipfilter/netinet/ip_proxy.c index 1336b0e642c0..8141eaa700fc 100644 --- a/sys/contrib/ipfilter/netinet/ip_proxy.c +++ b/sys/contrib/ipfilter/netinet/ip_proxy.c @@ -16,7 +16,9 @@ #include #include #include -#include +#if !defined(AIX) +# include +#endif #if !defined(_KERNEL) && !defined(__KERNEL__) # include # include @@ -35,7 +37,8 @@ struct file; #include #if defined(_KERNEL) # if !defined(__NetBSD__) && !defined(sun) && !defined(__osf__) && \ - !defined(__OpenBSD__) && !defined(__hpux) && !defined(__sgi) + !defined(__OpenBSD__) && !defined(__hpux) && !defined(__sgi) && \ + !defined(AIX) # include # endif # include @@ -93,12 +96,7 @@ struct file; #if defined(_KERNEL) # include "netinet/ip_irc_pxy.c" # include "netinet/ip_raudio_pxy.c" -# ifdef IPFILTER_H323 -# include "netinet/ip_h323_pxy.c" -# endif -# ifdef IPFILTER_PRO -# include "netinet/ip_msnrpc_pxy.c" -# endif +# include "netinet/ip_h323_pxy.c" # include "netinet/ip_netbios_pxy.c" #endif #include "netinet/ip_ipsec_pxy.c" @@ -107,7 +105,7 @@ struct file; /* END OF INCLUDES */ #if !defined(lint) -static const char rcsid[] = "@(#)Id: ip_proxy.c,v 2.62.2.12 2005/03/03 14:28:24 darrenr Exp"; +static const char rcsid[] = "@(#)$Id: ip_proxy.c,v 2.62.2.14 2005/06/18 02:41:33 darrenr Exp $"; #endif static int appr_fixseqack __P((fr_info_t *, ip_t *, ap_session_t *, int )); diff --git a/sys/contrib/ipfilter/netinet/ip_proxy.h b/sys/contrib/ipfilter/netinet/ip_proxy.h index ae4826dff754..71c1b816cbc1 100644 --- a/sys/contrib/ipfilter/netinet/ip_proxy.h +++ b/sys/contrib/ipfilter/netinet/ip_proxy.h @@ -16,7 +16,7 @@ #define SOLARIS (defined(sun) && (defined(__svr4__) || defined(__SVR4))) #endif -#if defined(__STDC__) || defined(__GNUC__) +#if defined(__STDC__) || defined(__GNUC__) || defined(_AIX51) #define SIOCPROXY _IOWR('r', 64, struct ap_control) #else #define SIOCPROXY _IOWR(r, 64, struct ap_control) diff --git a/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c b/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c index d24519f824e4..607fd742f537 100644 --- a/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_raudio_pxy.c @@ -6,7 +6,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.3 2005/02/04 10:22:55 darrenr Exp $ */ #define IPF_RAUDIO_PROXY diff --git a/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c b/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c index 540b837dfeff..01b2d89602e4 100644 --- a/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c +++ b/sys/contrib/ipfilter/netinet/ip_rcmd_pxy.c @@ -5,7 +5,7 @@ * * See the IPFILTER.LICENCE file for details on licencing. * - * Id: ip_rcmd_pxy.c,v 1.41.2.4 2005/02/04 10:22:55 darrenr Exp + * $Id: ip_rcmd_pxy.c,v 1.41.2.5 2005/10/02 04:20:07 darrenr Exp $ * * Simple RCMD transparent proxy for in-kernel use. For use with the NAT * code. @@ -154,6 +154,8 @@ nat_t *nat; * other way. */ bcopy((char *)fin, (char *)&fi, sizeof(fi)); + fi.fin_state = NULL; + fi.fin_nat = NULL; fi.fin_flx |= FI_IGNORE; fi.fin_data[0] = sp; fi.fin_data[1] = 0; diff --git a/sys/contrib/ipfilter/netinet/ip_state.c b/sys/contrib/ipfilter/netinet/ip_state.c index 7c1b3119d075..ab42da09c03b 100644 --- a/sys/contrib/ipfilter/netinet/ip_state.c +++ b/sys/contrib/ipfilter/netinet/ip_state.c @@ -109,7 +109,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.29 2005/03/28 10:47:54 darrenr Exp"; +static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.186.2.36 2005/12/04 22:25:36 darrenr Exp $"; #endif static ipstate_t **ips_table = NULL; @@ -507,13 +507,17 @@ int mode; * means no packets match). */ case SIOCSTLCK : - fr_lock(data, &fr_state_lock); + if (!(mode & FWRITE)) { + error = EPERM; + } else { + fr_lock(data, &fr_state_lock); + } break; /* * Add an entry to the current state table. */ case SIOCSTPUT : - if (!fr_state_lock) { + if (!fr_state_lock || !(mode &FWRITE)) { error = EACCES; break; } @@ -635,6 +639,7 @@ caddr_t data; if (fr == NULL) { READ_ENTER(&ipf_state); fr_stinsert(isn, 0); + MUTEX_EXIT(&isn->is_lock); RWLOCK_EXIT(&ipf_state); return 0; } @@ -682,6 +687,7 @@ caddr_t data; } READ_ENTER(&ipf_state); fr_stinsert(isn, 0); + MUTEX_EXIT(&isn->is_lock); RWLOCK_EXIT(&ipf_state); } else { @@ -689,6 +695,7 @@ caddr_t data; for (is = ips_list; is; is = is->is_next) if (is->is_rule == fr) { fr_stinsert(isn, 0); + MUTEX_EXIT(&isn->is_lock); break; } @@ -716,6 +723,7 @@ caddr_t data; /* to pointers and adjusts running stats for the hash table as appropriate. */ /* */ /* Locking: it is assumed that some kind of lock on ipf_state is held. */ +/* Exits with is_lock initialised and held. */ /* ------------------------------------------------------------------------ */ void fr_stinsert(is, rev) ipstate_t *is; @@ -780,7 +788,6 @@ int rev; MUTEX_EXIT(&ipf_stinsert); fr_setstatequeue(is, rev); - MUTEX_EXIT(&is->is_lock); } @@ -830,6 +837,7 @@ u_int flags; * to it, then schedule an automatic flush in case we can clear out * some "dead old wood". */ + MUTEX_ENTER(&fr->fr_lock); if ((fr != NULL) && (fr->fr_statemax != 0) && (fr->fr_statecnt >= fr->fr_statemax)) { MUTEX_EXIT(&fr->fr_lock); @@ -837,6 +845,8 @@ u_int flags; fr_state_doflush = 1; return NULL; } + fr->fr_statecnt++; + MUTEX_EXIT(&fr->fr_lock); pass = (fr == NULL) ? 0 : fr->fr_flags; @@ -979,9 +989,9 @@ u_int flags; TH_SYN && (TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2))) { if (fr_tcpoptions(fin, tcp, - &is->is_tcp.ts_data[0])) - is->is_swinflags = TCP_WSCALE_SEEN| - TCP_WSCALE_FIRST; + &is->is_tcp.ts_data[0]) == -1) { + fin->fin_flx |= FI_BAD; + } } if ((fin->fin_out != 0) && (pass & FR_NEWISN) != 0) { @@ -1038,16 +1048,16 @@ u_int flags; break; } if (is != NULL) - return NULL; + goto cantaddstate; if (ips_stats.iss_bucketlen[hv] >= fr_state_maxbucket) { ATOMIC_INCL(ips_stats.iss_bucketfull); - return NULL; + goto cantaddstate; } KMALLOC(is, ipstate_t *); if (is == NULL) { ATOMIC_INCL(ips_stats.iss_nomem); - return NULL; + goto cantaddstate; } bcopy((char *)&ips, (char *)is, sizeof(*is)); /* @@ -1124,8 +1134,14 @@ u_int flags; * this may change. */ is->is_v = fin->fin_v; - is->is_opt = fin->fin_optmsk; - is->is_optmsk = 0xffffffff; + is->is_opt[0] = fin->fin_optmsk; + is->is_optmsk[0] = 0xffffffff; + is->is_optmsk[1] = 0xffffffff; + if (is->is_v == 6) { + is->is_opt[0] &= ~0x8; + is->is_optmsk[0] &= ~0x8; + is->is_optmsk[1] &= ~0x8; + } is->is_sec = fin->fin_secmsk; is->is_secmsk = 0xffff; is->is_auth = fin->fin_auth; @@ -1150,13 +1166,14 @@ u_int flags; * timer on it as we'll never see an error if it fails to * connect. */ - MUTEX_ENTER(&is->is_lock); (void) fr_tcp_age(&is->is_sti, fin, ips_tqtqb, is->is_flags); MUTEX_EXIT(&is->is_lock); #ifdef IPFILTER_SCAN if ((is->is_flags & SI_CLONE) == 0) (void) ipsc_attachis(is); #endif + } else { + MUTEX_EXIT(&is->is_lock); } #ifdef IPFILTER_SYNC if ((is->is_flags & IS_STATESYNC) && ((is->is_flags & SI_CLONE) == 0)) @@ -1173,12 +1190,21 @@ u_int flags; (void) fr_newfrag(fin, pass ^ FR_KEEPSTATE); return is; + +cantaddstate: + if (fr != NULL) { + MUTEX_ENTER(&fr->fr_lock); + fr->fr_statecnt--; + MUTEX_EXIT(&fr->fr_lock); + } + return NULL; } /* ------------------------------------------------------------------------ */ /* Function: fr_tcpoptions */ -/* Returns: int - 1 == packet matches state entry, 0 == it does not */ +/* Returns: int - 1 == packet matches state entry, 0 == it does not, */ +/* -1 == packet has bad TCP options data */ /* Parameters: fin(I) - pointer to packet information */ /* tcp(I) - pointer to TCP packet header */ /* td(I) - pointer to TCP data held as part of the state */ @@ -1195,13 +1221,14 @@ tcpdata_t *td; char buf[64], *s, opt; mb_t *m = NULL; - off = fin->fin_hlen + sizeof(*tcp); - len = (TCP_OFF(tcp) << 2) - sizeof(*tcp); - if (fin->fin_plen < off + len) + len = (TCP_OFF(tcp) << 2); + if (fin->fin_dlen < len) return 0; + len -= sizeof(*tcp); + + off = fin->fin_plen - fin->fin_dlen + sizeof(*tcp) + fin->fin_ipoff; m = fin->fin_m; - off += fin->fin_ipoff; mlen = MSGDSIZE(m) - off; if (len > mlen) { len = mlen; @@ -1239,7 +1266,10 @@ tcpdata_t *td; else if (i < 0) i = 0; td->td_winscale = i; - } + td->td_winflags |= TCP_WSCALE_SEEN| + TCP_WSCALE_FIRST; + } else + retval = -1; break; case TCPOPT_MAXSEG : /* @@ -1251,7 +1281,14 @@ tcpdata_t *td; i <<= 8; i += (int)*(s + 3); td->td_maxseg = i; - } + } else + retval = -1; + break; + case TCPOPT_SACK_PERMITTED : + if (ol == TCPOLEN_SACK_PERMITTED) + td->td_winflags |= TCP_SACK_PERMIT; + else + retval = -1; break; } } @@ -1322,24 +1359,22 @@ ipstate_t *is; 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_winscale) { - if (fr_tcpoptions(fin, tcp, fdata)) { - fdata->td_winflags = TCP_WSCALE_SEEN| - TCP_WSCALE_FIRST; - } else { - if (!fdata->td_winscale) - tdata->td_winscale = 0; + (tdata->td_winflags & TCP_WSCALE_SEEN)) { + 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)) { - tdata->td_winflags = TCP_WSCALE_SEEN| - TCP_WSCALE_FIRST; - } + if ((TCP_OFF(tcp) > (sizeof(tcphdr_t) >> 2))) { + if (fr_tcpoptions(fin, tcp, tdata) == -1) + fin->fin_flx |= FI_BAD; + } if ((fin->fin_out != 0) && (is->is_pass & FR_NEWISN)) fr_checknewisn(fin, is); @@ -1410,6 +1445,7 @@ int flags; tcp_seq seq, ack, end; int ackskew, tcpflags; u_32_t win, maxwin; + int dsize, inseq; /* * Find difference between last checked packet and this packet. @@ -1421,9 +1457,28 @@ int flags; win = ntohs(tcp->th_win); else win = ntohs(tcp->th_win) << fdata->td_winscale; +#if 0 + /* + * XXX - This is a kludge is here because IPFilter doesn't track SACK + * options in TCP packets. This is not a trivial to do if one is to + * consider the performance impact of it. So instead, if the + * receiver has said SACK is ok, double the allowed window size. + * This is disabled for testing of another workaround for a problem + * with Microsoft Windows - see below. + */ + if ((tdata->td_winflags & TCP_SACK_PERMIT) != 0) + win *= 2; +#endif + + /* + * A window of 0 produces undesirable behaviour from this function. + */ if (win == 0) win = 1; + dsize = fin->fin_dlen - (TCP_OFF(tcp) << 2) + + ((tcpflags & TH_SYN) ? 1 : 0) + ((tcpflags & TH_FIN) ? 1 : 0); + /* * if window scaling is present, the scaling is only allowed * for windows not in the first SYN packet. In that packet the @@ -1441,14 +1496,15 @@ int flags; fdata->td_maxwin = win; } else { fdata->td_winscale = 0; - fdata->td_winflags = 0; + fdata->td_winflags &= ~(TCP_WSCALE_FIRST| + TCP_WSCALE_SEEN); tdata->td_winscale = 0; - tdata->td_winflags = 0; + tdata->td_winflags &= ~(TCP_WSCALE_FIRST| + TCP_WSCALE_SEEN); } } - end = seq + fin->fin_dlen - (TCP_OFF(tcp) << 2) + - ((tcpflags & TH_SYN) ? 1 : 0) + ((tcpflags & TH_FIN) ? 1 : 0); + end = seq + dsize; if ((fdata->td_end == 0) && (!(flags & IS_TCPFSM) || @@ -1456,7 +1512,7 @@ int flags; /* * Must be a (outgoing) SYN-ACK in reply to a SYN. */ - fdata->td_end = end; + fdata->td_end = end - 1; fdata->td_maxwin = 1; fdata->td_maxend = end + win; } @@ -1469,9 +1525,6 @@ int flags; ack = tdata->td_end; } - if (seq == end) - seq = end = fdata->td_end; - maxwin = tdata->td_maxwin; ackskew = tdata->td_end - ack; @@ -1486,16 +1539,25 @@ int flags; #define SEQ_GE(a,b) ((int)((a) - (b)) >= 0) #define SEQ_GT(a,b) ((int)((a) - (b)) > 0) - if ( -#if defined(_KERNEL) - (SEQ_GE(fdata->td_maxend, end)) && + inseq = 0; + if ((SEQ_GE(fdata->td_maxend, end)) && (SEQ_GE(seq, fdata->td_end - maxwin)) && -#endif /* XXX what about big packets */ #define MAXACKWINDOW 66000 (-ackskew <= (MAXACKWINDOW << fdata->td_winscale)) && ( ackskew <= (MAXACKWINDOW << fdata->td_winscale))) { + inseq = 1; + /* + * Microsoft Windows will send the next packet to the right of the + * window if SACK is in use. + */ + } else if ((seq == fdata->td_maxend) && (ackskew == 0) && + (fdata->td_winflags & TCP_SACK_PERMIT) && + (tdata->td_winflags & TCP_SACK_PERMIT)) { + inseq = 1; + } + if (inseq) { /* if ackskew < 0 then this should be due to fragmented * packets. There is no way to know the length of the * total packet in advance. @@ -1584,8 +1646,7 @@ ipstate_t *is; clone->is_flags &= ~SI_CLONE; clone->is_flags |= SI_CLONED; fr_stinsert(clone, fin->fin_rev); - MUTEX_ENTER(&clone->is_lock); - clone->is_ref = 1; + clone->is_ref = 2; if (clone->is_p == IPPROTO_TCP) { (void) fr_tcp_age(&clone->is_sti, fin, ips_tqtqb, clone->is_flags); @@ -1770,7 +1831,7 @@ u_32_t cmask; * Match up any flags set from IP options. */ if ((cflx && (flx != (cflx & cmask))) || - ((fin->fin_optmsk & is->is_optmsk) != is->is_opt) || + ((fin->fin_optmsk & is->is_optmsk[rev]) != is->is_opt[rev]) || ((fin->fin_secmsk & is->is_secmsk) != is->is_sec) || ((fin->fin_auth & is->is_authmsk) != is->is_auth)) return NULL; @@ -1787,9 +1848,12 @@ u_32_t cmask; if ((flags & (SI_W_SPORT|SI_W_DPORT))) { if ((flags & SI_CLONE) != 0) { - is = fr_stclone(fin, tcp, is); - if (is == NULL) + ipstate_t *clone; + + clone = fr_stclone(fin, tcp, is); + if (clone == NULL) return NULL; + is = clone; } else { ATOMIC_DECL(ips_stats.iss_wild); } @@ -1820,8 +1884,14 @@ u_32_t cmask; ret = -1; - if (is->is_flx[out][rev] == 0) + if (is->is_flx[out][rev] == 0) { is->is_flx[out][rev] = flx; + is->is_opt[rev] = fin->fin_optmsk; + if (is->is_v == 6) { + is->is_opt[rev] &= ~0x8; + is->is_optmsk[rev] &= ~0x8; + } + } /* * Check if the interface name for this "direction" is set and if not, @@ -1867,21 +1937,16 @@ fr_info_t *fin; /* * Does it at least have the return (basic) IP header ? + * Is it an actual recognised ICMP error type? * Only a basic IP header (no options) should be with * an ICMP error header. */ if ((fin->fin_v != 4) || (fin->fin_hlen != sizeof(ip_t)) || - (fin->fin_plen < ICMPERR_MINPKTLEN)) + (fin->fin_plen < ICMPERR_MINPKTLEN) || + !(fin->fin_flx & FI_ICMPERR)) return NULL; ic = fin->fin_dp; type = ic->icmp_type; - /* - * If it's not an error type, then return - */ - if ((type != ICMP_UNREACH) && (type != ICMP_SOURCEQUENCH) && - (type != ICMP_REDIRECT) && (type != ICMP_TIMXCEED) && - (type != ICMP_PARAMPROB)) - return NULL; oip = (ip_t *)((char *)ic + ICMPERR_ICMPHLEN); /* @@ -1944,7 +2009,7 @@ fr_info_t *fin; */ savelen = oip->ip_len; oip->ip_len = len; - oip->ip_off = htons(oip->ip_off); + oip->ip_off = ntohs(oip->ip_off); ofin.fin_flx = FI_NOCKSUM; ofin.fin_v = 4; @@ -1972,8 +2037,6 @@ fr_info_t *fin; switch (oip->ip_p) { case IPPROTO_ICMP : - icmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2)); - /* * an ICMP error can only be generated as a result of an * ICMP query, not as the response on an ICMP error @@ -1981,15 +2044,13 @@ fr_info_t *fin; * XXX theoretically ICMP_ECHOREP and the other reply's are * ICMP query's as well, but adding them here seems strange XXX */ - if ((icmp->icmp_type != ICMP_ECHO) && - (icmp->icmp_type != ICMP_TSTAMP) && - (icmp->icmp_type != ICMP_IREQ) && - (icmp->icmp_type != ICMP_MASKREQ)) + if ((ofin.fin_flx & FI_ICMPERR) != 0) return NULL; /* * perform a lookup of the ICMP packet in the state table */ + icmp = (icmphdr_t *)((char *)oip + (IP_HL(oip) << 2)); hv = (pr = oip->ip_p); src.in4 = oip->ip_src; hv += src.in4.s_addr; @@ -2008,10 +2069,6 @@ fr_info_t *fin; is = fr_matchsrcdst(&ofin, is, &src, &dst, NULL, FI_ICMPCMP); if (is != NULL) { - if ((is->is_pass & FR_NOICMPERR) != 0) { - RWLOCK_EXIT(&ipf_state); - return NULL; - } /* * i : the index of this packet (the icmp * unreachable) @@ -2774,6 +2831,11 @@ int why; if (ipstate_logging != 0 && why != 0) ipstate_log(is, why); + if (is->is_p == IPPROTO_TCP) + ips_stats.iss_fin++; + else + ips_stats.iss_expire++; + if (is->is_rule != NULL) { is->is_rule->fr_statecnt--; (void)fr_derefrule(&is->is_rule); @@ -2800,9 +2862,7 @@ void fr_timeoutstate() ipftq_t *ifq, *ifqnext; ipftqent_t *tqe, *tqn; ipstate_t *is; -#if defined(USE_SPL) && defined(_KERNEL) - int s; -#endif + SPL_INT(s); SPL_NET(s); WRITE_ENTER(&ipf_state); @@ -2872,9 +2932,7 @@ int which, proto; int delete, removed; long try, maxtick; u_long interval; -#if defined(_KERNEL) && !defined(MENTAT) && defined(USE_SPL) - int s; -#endif + SPL_INT(s); removed = 0; @@ -2903,10 +2961,6 @@ int which, proto; } if (delete) { - if (is->is_p == IPPROTO_TCP) - ips_stats.iss_fin++; - else - ips_stats.iss_expire++; fr_delstate(is, ISL_FLUSH); removed++; } else @@ -3042,7 +3096,7 @@ int flags; rval = 0; dir = fin->fin_rev; tcpflags = tcp->th_flags; - dlen = fin->fin_plen - fin->fin_hlen - (TCP_OFF(tcp) << 2); + dlen = fin->fin_dlen - (TCP_OFF(tcp) << 2); if (tcpflags & TH_RST) { if (!(tcpflags & TH_PUSH) && !dlen) @@ -3180,13 +3234,34 @@ int flags; break; case IPF_TCPS_HALF_ESTAB: /* 4 */ - if (ostate >= IPF_TCPS_HALF_ESTAB) { - if ((tcpflags & TH_ACKMASK) == TH_ACK) { + if (tcpflags & TH_FIN) { + nstate = IPF_TCPS_FIN_WAIT_1; + rval = 1; + } else if ((tcpflags & TH_ACKMASK) == TH_ACK) { + /* + * If we've picked up a connection in mid + * flight, we could be looking at a follow on + * packet from the same direction as the one + * that created this state. Recognise it but + * do not advance the entire connection's + * state. + */ + switch (ostate) + { + case IPF_TCPS_CLOSED : + case IPF_TCPS_SYN_SENT : + case IPF_TCPS_SYN_RECEIVED : + rval = 1; + break; + case IPF_TCPS_HALF_ESTAB : + case IPF_TCPS_ESTABLISHED : nstate = IPF_TCPS_ESTABLISHED; rval = 1; + break; + default : + break; } } - break; case IPF_TCPS_ESTABLISHED: /* 5 */ @@ -3316,9 +3391,6 @@ int flags; (u_long)tcp, tcpflags, (u_long)tqe, nstate, ostate); # endif -# ifdef DIAGNOSTIC - panic("invalid TCP state"); -# endif #else abort(); #endif @@ -3442,20 +3514,16 @@ fr_info_t *fin; /* * Does it at least have the return (basic) IP header ? + * Is it an actual recognised ICMP error type? * Only a basic IP header (no options) should be with * an ICMP error header. */ - if ((fin->fin_v != 6) || (fin->fin_plen < ICMP6ERR_MINPKTLEN)) + if ((fin->fin_v != 6) || (fin->fin_plen < ICMP6ERR_MINPKTLEN) || + !(fin->fin_flx & FI_ICMPERR)) return NULL; ic6 = fin->fin_dp; type = ic6->icmp6_type; - /* - * If it's not an error type, then return - */ - if ((type != ICMP6_DST_UNREACH) && (type != ICMP6_PACKET_TOO_BIG) && - (type != ICMP6_TIME_EXCEEDED) && (type != ICMP6_PARAM_PROB)) - return NULL; oip6 = (ip6_t *)((char *)ic6 + ICMPERR_ICMPHLEN); if (fin->fin_plen < sizeof(*oip6)) diff --git a/sys/contrib/ipfilter/netinet/ip_state.h b/sys/contrib/ipfilter/netinet/ip_state.h index 5e3fe87854f5..9c457cfcfbb1 100644 --- a/sys/contrib/ipfilter/netinet/ip_state.h +++ b/sys/contrib/ipfilter/netinet/ip_state.h @@ -12,7 +12,7 @@ #ifndef __IP_STATE_H__ #define __IP_STATE_H__ -#if defined(__STDC__) || defined(__GNUC__) +#if defined(__STDC__) || defined(__GNUC__) || defined(_AIX51) # define SIOCDELST _IOW('r', 61, struct ipfobj) #else # define SIOCDELST _IOW(r, 61, struct ipfobj) @@ -61,8 +61,8 @@ typedef struct ipstate { u_char is_v; u_32_t is_hv; u_32_t is_tag; - u_32_t is_opt; /* packet options set */ - u_32_t is_optmsk; /* " " mask */ + u_32_t is_opt[2]; /* packet options set */ + u_32_t is_optmsk[2]; /* " " mask */ u_short is_sec; /* security options set */ u_short is_secmsk; /* " " mask */ u_short is_auth; /* authentication options set */ diff --git a/sys/contrib/ipfilter/netinet/ip_sync.c b/sys/contrib/ipfilter/netinet/ip_sync.c index a091b5380da7..e96b65135f43 100644 --- a/sys/contrib/ipfilter/netinet/ip_sync.c +++ b/sys/contrib/ipfilter/netinet/ip_sync.c @@ -98,7 +98,7 @@ struct file; /* END OF INCLUDES */ #if !defined(lint) -static const char rcsid[] = "@(#)Id: ip_sync.c,v 2.40.2.3 2005/02/18 13:06:29 darrenr Exp"; +static const char rcsid[] = "@(#)$Id: ip_sync.c,v 2.40.2.5 2005/09/04 12:51:12 darrenr Exp $"; #endif #define SYNC_STATETABSZ 256 @@ -231,8 +231,10 @@ ipstate_t *ips; ips->is_die = htonl(ips->is_die); ips->is_pass = htonl(ips->is_pass); ips->is_flags = htonl(ips->is_flags); - ips->is_opt = htonl(ips->is_opt); - ips->is_optmsk = htonl(ips->is_optmsk); + ips->is_opt[0] = htonl(ips->is_opt[0]); + ips->is_opt[1] = htonl(ips->is_opt[1]); + ips->is_optmsk[0] = htonl(ips->is_optmsk[0]); + ips->is_optmsk[1] = htonl(ips->is_optmsk[1]); ips->is_sec = htons(ips->is_sec); ips->is_secmsk = htons(ips->is_secmsk); ips->is_auth = htons(ips->is_auth); @@ -246,8 +248,10 @@ ipstate_t *ips; ips->is_die = ntohl(ips->is_die); ips->is_pass = ntohl(ips->is_pass); ips->is_flags = ntohl(ips->is_flags); - ips->is_opt = ntohl(ips->is_opt); - ips->is_optmsk = ntohl(ips->is_optmsk); + ips->is_opt[0] = ntohl(ips->is_opt[0]); + ips->is_opt[1] = ntohl(ips->is_opt[1]); + ips->is_optmsk[0] = ntohl(ips->is_optmsk[0]); + ips->is_optmsk[1] = ntohl(ips->is_optmsk[1]); ips->is_sec = ntohs(ips->is_sec); ips->is_secmsk = ntohs(ips->is_secmsk); ips->is_auth = ntohs(ips->is_auth); diff --git a/sys/contrib/ipfilter/netinet/ipl.h b/sys/contrib/ipfilter/netinet/ipl.h index 364423c918df..906b2ef6f47f 100644 --- a/sys/contrib/ipfilter/netinet/ipl.h +++ b/sys/contrib/ipfilter/netinet/ipl.h @@ -13,8 +13,8 @@ #ifndef __IPL_H__ #define __IPL_H__ -#define IPL_VERSION "IP Filter: v4.1.8" +#define IPL_VERSION "IP Filter: v4.1.10" -#define IPFILTER_VERSION 4010800 +#define IPFILTER_VERSION 4011000 #endif diff --git a/sys/contrib/ipfilter/netinet/mlfk_ipl.c b/sys/contrib/ipfilter/netinet/mlfk_ipl.c index 2869697465ff..3c232661cada 100644 --- a/sys/contrib/ipfilter/netinet/mlfk_ipl.c +++ b/sys/contrib/ipfilter/netinet/mlfk_ipl.c @@ -103,6 +103,7 @@ static struct cdevsw ipl_cdevsw = { .d_open = iplopen, .d_close = iplclose, .d_read = iplread, + .d_write = iplwrite, .d_ioctl = iplioctl, .d_name = "ipl", # if __FreeBSD_version < 600000