aboutsummaryrefslogtreecommitdiffstats
path: root/sys/contrib/ipfilter/netinet/fil.c
diff options
context:
space:
mode:
authorGuido van Rooij <guido@FreeBSD.org>2005-12-30 11:22:11 +0000
committerGuido van Rooij <guido@FreeBSD.org>2005-12-30 11:22:11 +0000
commitfc79eaf127b2927f108bf1971bfb850f7dabea63 (patch)
treeb7932fb536591098a7a0c82617edb30ea41453b7 /sys/contrib/ipfilter/netinet/fil.c
parent8158c4468d2bf40eabe8e413f647e1dd581bb6e7 (diff)
downloadsrc-fc79eaf127b2927f108bf1971bfb850f7dabea63.tar.gz
src-fc79eaf127b2927f108bf1971bfb850f7dabea63.zip
Import IP Filter version 4.1.10
Notes
Notes: svn path=/vendor-sys/ipfilter/dist/; revision=153872
Diffstat (limited to 'sys/contrib/ipfilter/netinet/fil.c')
-rw-r--r--sys/contrib/ipfilter/netinet/fil.c798
1 files changed, 478 insertions, 320 deletions
diff --git a/sys/contrib/ipfilter/netinet/fil.c b/sys/contrib/ipfilter/netinet/fil.c
index e62b0edf7bba..c8c1b55074f4 100644
--- a/sys/contrib/ipfilter/netinet/fil.c
+++ b/sys/contrib/ipfilter/netinet/fil.c
@@ -1,5 +1,3 @@
-/* $FreeBSD$ */
-
/*
* Copyright (C) 1993-2003 by Darren Reed.
*
@@ -34,7 +32,9 @@
#else
# include <sys/ioctl.h>
#endif
-#include <sys/fcntl.h>
+#if !defined(_AIX51)
+# include <sys/fcntl.h>
+#endif
#if defined(_KERNEL)
# include <sys/systm.h>
# include <sys/file.h>
@@ -74,6 +74,9 @@ struct file;
# include <net/af.h>
#endif
#if !defined(_KERNEL) && defined(__FreeBSD__)
+# if (__FreeBSD_version >= 504000)
+# undef _RADIX_H_
+# endif
# include "radix_ipf.h"
#endif
#include <net/route.h>
@@ -88,7 +91,7 @@ struct file;
# include <netinet/in_var.h>
#endif
#include <netinet/tcp.h>
-#if !defined(__sgi) || defined(_KERNEL)
+#if (!defined(__sgi) && !defined(AIX)) || defined(_KERNEL)
# include <netinet/udp.h>
# include <netinet/ip_icmp.h>
#endif
@@ -134,7 +137,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.57 2005/03/28 10:47:50 darrenr Exp";
+static const char rcsid[] = "@(#)$Id: fil.c,v 2.243.2.70 2005/12/07 08:15:16 darrenr Exp $";
#endif
#ifndef _KERNEL
@@ -173,6 +176,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};
@@ -218,6 +222,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 *));
@@ -226,15 +231,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 **));
@@ -277,6 +282,7 @@ struct optlist ip6exthdr[] = {
{ IPPROTO_AH, 0x000020 },
{ IPPROTO_NONE, 0x000040 },
{ IPPROTO_DSTOPTS, 0x000080 },
+ { IPPROTO_MOBILITY, 0x000100 },
{ 0, 0 }
};
#endif
@@ -328,15 +334,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));
/* ------------------------------------------------------------------------ */
@@ -349,37 +360,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;
@@ -389,7 +395,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;
@@ -416,48 +421,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) {
@@ -472,12 +464,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 :
@@ -491,9 +479,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)) {
@@ -502,19 +490,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;
@@ -539,8 +540,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;
}
@@ -552,6 +560,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 */
/* Parameters: fin(I) - pointer to packet information */
@@ -563,100 +601,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);
-
- /* 8 is default length of extension hdr */
- if ((fin->fin_dlen - 8) < 0) {
- fin->fin_flx |= FI_SHORT;
- return IPPROTO_NONE;
- }
+ fin->fin_flx |= FI_FRAG;
- /*
- * 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;
+ return;
+ frag = fin->fin_dp;
/*
- * Length must be zero, i.e. it has no length.
+ * Fragment but no fragmentation info set? Bad packet...
*/
- if (hdr->ip6e_len != 0) {
+ if (frag->ip6f_offlg == 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;
fin->fin_off = frag->ip6f_offlg & IP6F_OFF_MASK;
fin->fin_off <<= 3;
if (fin->fin_off != 0)
@@ -664,8 +669,6 @@ fr_info_t *fin;
fin->fin_dp = (char *)fin->fin_dp + sizeof(*frag);
fin->fin_dlen -= sizeof(*frag);
-
- return frag->ip6f_nxt;
}
@@ -681,34 +684,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);
}
@@ -758,7 +734,7 @@ fr_info_t *fin;
}
}
- frpr_short(fin, minicmpsz);
+ frpr_short6(fin, minicmpsz);
}
@@ -769,16 +745,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);
}
@@ -789,16 +765,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));
+
+ if (frpr_tcpcommon(fin) == 0)
+ fr_checkv6sum(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);
+}
- frpr_short(fin, sizeof(struct tcphdr));
- frpr_tcpcommon(fin);
+/* ------------------------------------------------------------------------ */
+/* 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 */
@@ -836,28 +882,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;
}
}
@@ -870,7 +913,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? */
@@ -880,13 +923,17 @@ fr_info_t *fin;
{
int minicmpsz = sizeof(struct icmp);
icmphdr_t *icmp;
+ ip_t *oip;
- if (frpr_pullup(fin, ICMPERR_ICMPHLEN) == -1)
+ if (fin->fin_off != 0) {
+ frpr_short(fin, ICMPERR_ICMPHLEN);
return;
+ }
- fr_checkv4sum(fin);
+ if (frpr_pullup(fin, ICMPERR_ICMPHLEN) == -1)
+ return;
- if (!fin->fin_off && (fin->fin_dlen > 1)) {
+ if (fin->fin_dlen > 1) {
icmp = fin->fin_dp;
fin->fin_data[0] = *(u_short *)icmp;
@@ -920,13 +967,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;
@@ -937,12 +998,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, */
@@ -950,20 +1013,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) {
@@ -971,8 +1032,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
@@ -981,7 +1042,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;
@@ -1035,10 +1096,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;
@@ -1077,31 +1138,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;
@@ -1109,6 +1170,8 @@ fr_info_t *fin;
fin->fin_sport = ntohs(udp->uh_sport);
fin->fin_dport = ntohs(udp->uh_dport);
}
+
+ return 0;
}
@@ -1124,11 +1187,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);
}
@@ -1144,11 +1206,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);
}
@@ -1166,15 +1227,42 @@ fr_info_t *fin;
static INLINE void frpr_esp(fin)
fr_info_t *fin;
{
- if (frpr_pullup(fin, 8) == -1)
- return;
- if (fin->fin_v == 4)
+ if (fin->fin_off == 0) {
frpr_short(fin, 8);
-#ifdef USE_INET6
- else if (fin->fin_v == 6)
- frpr_short6(fin, sizeof(grehdr_t));
-#endif
+ (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 (frpr_pullup(fin, sizeof(*ah)) == -1)
+ return;
+
+ ah = (authhdr_t *)fin->fin_dp;
+
+ len = (ah->ah_plen + 2) << 2;
+ frpr_short(fin, len);
}
@@ -1190,18 +1278,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;
+ }
}
@@ -1257,12 +1346,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;
@@ -1270,7 +1353,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;
}
}
@@ -1291,6 +1384,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;
@@ -1419,8 +1515,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;
@@ -1548,6 +1646,7 @@ frtuc_t *ft;
}
+
/* ------------------------------------------------------------------------ */
/* Function: fr_ipfcheck */
/* Returns: int - 0 == match, 1 == no match */
@@ -1753,7 +1852,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.
@@ -1821,15 +1920,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;
}
@@ -1911,6 +2008,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)
@@ -1933,8 +2031,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;
@@ -2019,18 +2138,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];
@@ -2039,9 +2162,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);
}
@@ -2136,7 +2263,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 */
@@ -2186,6 +2313,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
@@ -2225,6 +2353,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;
@@ -2261,11 +2393,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);
@@ -2278,7 +2412,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
@@ -2291,8 +2425,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
@@ -2386,22 +2522,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
@@ -2423,7 +2568,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);
}
}
@@ -2439,13 +2585,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;
@@ -2456,26 +2596,26 @@ filtered:
* 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)) {
@@ -2489,14 +2629,16 @@ finished:
#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 OpenBSD >= 200311
+# if OpenBSD >= 200311
if (FR_ISPASS(pass) && (v == 4)) {
ip = fin->fin_ip;
ip->ip_len = ntohs(ip->ip_len);
@@ -2887,7 +3029,7 @@ nodata:
#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.
@@ -2917,7 +3059,7 @@ nodata:
* 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,
@@ -2986,7 +3128,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;
@@ -3035,7 +3177,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];
@@ -3328,7 +3470,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;
@@ -3995,10 +4138,15 @@ caddr_t data;
fprev = &fg->fg_start;
}
- for (f = *fprev; (f = *fprev) != NULL; fprev = &f->fr_next)
- if (fp->fr_collect <= f->fr_collect)
- break;
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.
@@ -4097,7 +4245,6 @@ caddr_t data;
break;
#endif
default :
-
break;
}
break;
@@ -4137,14 +4284,17 @@ caddr_t data;
WRITE_ENTER(&ipf_mutex);
bzero((char *)frcache, sizeof(frcache));
- for (; (f = *ftail) != NULL; ftail = &f->fr_next)
- if ((fp->fr_cksum == f->fr_cksum) &&
- (f->fr_dsize == fp->fr_dsize) &&
- !bcmp((char *)&f->fr_func,
- (char *)&fp->fr_func, FR_CMPSIZ) &&
- (!ptr || !f->fr_data ||
+ for (; (f = *ftail) != NULL; ftail = &f->fr_next) {
+ if ((fp->fr_cksum != f->fr_cksum) ||
+ (f->fr_dsize != fp->fr_dsize))
+ continue;
+ if (bcmp((char *)&f->fr_func, (char *)&fp->fr_func, FR_CMPSIZ))
+ continue;
+ if ((!ptr && !f->fr_data) ||
+ (ptr && f->fr_data &&
!bcmp((char *)ptr, (char *)f->fr_data, f->fr_dsize)))
break;
+ }
/*
* If zero'ing statistics, copy current to caller and zero.
@@ -4190,12 +4340,40 @@ caddr_t data;
}
if (!f) {
- if (req == (ioctlcmd_t)SIOCINAFR ||
- req == (ioctlcmd_t)SIOCINIFR) {
+ /*
+ * At the end of this, ftail must point to the place where the
+ * new rule is to be saved/inserted/added.
+ * For SIOCAD*FR, this should be the last rule in the group of
+ * rules that have equal fr_collect fields.
+ * For SIOCIN*FR, ...
+ */
+ if (req == (ioctlcmd_t)SIOCADAFR ||
+ req == (ioctlcmd_t)SIOCADIFR) {
+
+ for (ftail = fprev; (f = *ftail) != NULL; ) {
+ if (f->fr_collect > fp->fr_collect)
+ break;
+ ftail = &f->fr_next;
+ }
+ f = NULL;
+ ptr = NULL;
+ error = 0;
+ } else if (req == (ioctlcmd_t)SIOCINAFR ||
+ req == (ioctlcmd_t)SIOCINIFR) {
+ while ((f = *fprev) != NULL) {
+ if (f->fr_collect >= fp->fr_collect)
+ break;
+ fprev = &f->fr_next;
+ }
ftail = fprev;
if (fp->fr_hits != 0) {
- while (--fp->fr_hits && (f = *ftail))
+ while (fp->fr_hits && (f = *ftail)) {
+ if (f->fr_collect != fp->fr_collect)
+ break;
+ fprev = ftail;
ftail = &f->fr_next;
+ fp->fr_hits--;
+ }
}
f = NULL;
ptr = NULL;
@@ -4240,7 +4418,7 @@ caddr_t data;
}
if (*f->fr_grhead != '\0')
fr_delgroup(f->fr_grhead, unit, set);
- fr_fixskip(fprev, f, -1);
+ fr_fixskip(ftail, f, -1);
*ftail = f->fr_next;
f->fr_next = NULL;
(void)fr_derefrule(&f);
@@ -4261,7 +4439,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,
@@ -4280,7 +4458,7 @@ caddr_t data;
*ftail = f;
if (req == (ioctlcmd_t)SIOCINIFR ||
req == (ioctlcmd_t)SIOCINAFR)
- fr_fixskip(fprev, f, 1);
+ fr_fixskip(ftail, f, 1);
f->fr_grp = NULL;
group = f->fr_grhead;
if (*group != '\0') {
@@ -4928,7 +5106,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;
@@ -4980,7 +5158,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];
@@ -4992,7 +5170,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++)
;
@@ -5605,6 +5783,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 */
@@ -5750,7 +5932,7 @@ void *cookie, **next;
/* to the matching structure. */
/* ------------------------------------------------------------------------ */
static ipftuneable_t *fr_findtunebyname(name)
-char *name;
+const char *name;
{
ipftuneable_t *ta;
@@ -5930,6 +6112,7 @@ void *data;
tu.ipft_vshort = *ta->ipft_pshort;
else if (ta->ipft_sz == sizeof(u_char))
tu.ipft_vchar = *ta->ipft_pchar;
+ tu.ipft_cookie = ta;
tu.ipft_sz = ta->ipft_sz;
tu.ipft_min = ta->ipft_min;
tu.ipft_max = ta->ipft_max;
@@ -6141,31 +6324,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 */
/* pointer to interface structure for NIC */