diff options
Diffstat (limited to 'contrib/ipfilter/ip_frag.c')
-rw-r--r-- | contrib/ipfilter/ip_frag.c | 294 |
1 files changed, 179 insertions, 115 deletions
diff --git a/contrib/ipfilter/ip_frag.c b/contrib/ipfilter/ip_frag.c index 923f685..3f0831f 100644 --- a/contrib/ipfilter/ip_frag.c +++ b/contrib/ipfilter/ip_frag.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 1993-1997 by Darren Reed. + * Copyright (C) 1993-1998 by Darren Reed. * * Redistribution and use in source and binary forms are permitted * provided that this notice is preserved and due credit is given @@ -7,53 +7,62 @@ */ #if !defined(lint) static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-1995 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.0.2.19.2.1 1997/11/12 10:50:21 darrenr Exp $"; +static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.4.2.3 1999/09/18 15:03:54 darrenr Exp $"; #endif -#if !defined(_KERNEL) && !defined(KERNEL) -# include <string.h> -# include <stdlib.h> +#if defined(KERNEL) && !defined(_KERNEL) +# define _KERNEL #endif + #include <sys/errno.h> #include <sys/types.h> #include <sys/param.h> #include <sys/time.h> #include <sys/file.h> +#if !defined(_KERNEL) && !defined(KERNEL) +# include <stdio.h> +# include <string.h> +# include <stdlib.h> +#endif #if defined(KERNEL) && (__FreeBSD_version >= 220000) -#include <sys/filio.h> -#include <sys/fcntl.h> +# include <sys/filio.h> +# include <sys/fcntl.h> #else -#include <sys/ioctl.h> +# include <sys/ioctl.h> #endif #include <sys/uio.h> #ifndef linux -#include <sys/protosw.h> +# include <sys/protosw.h> #endif #include <sys/socket.h> #if defined(_KERNEL) && !defined(linux) # include <sys/systm.h> #endif #if !defined(__SVR4) && !defined(__svr4__) +# if defined(_KERNEL) && !defined(__sgi) +# include <sys/kernel.h> +# endif # ifndef linux # include <sys/mbuf.h> # endif #else # include <sys/byteorder.h> -# include <sys/dditypes.h> +# ifdef _KERNEL +# include <sys/dditypes.h> +# endif # include <sys/stream.h> # include <sys/kmem.h> #endif - #include <net/if.h> #ifdef sun -#include <net/af.h> +# include <net/af.h> #endif #include <net/route.h> #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> #ifndef linux -#include <netinet/ip_var.h> +# include <netinet/ip_var.h> #endif #include <netinet/tcp.h> #include <netinet/udp.h> @@ -66,6 +75,17 @@ static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.0.2.19.2.1 1997/11/12 10:50: #include "netinet/ip_frag.h" #include "netinet/ip_state.h" #include "netinet/ip_auth.h" +#if (__FreeBSD_version >= 300000) +# include <sys/malloc.h> +# if (defined(KERNEL) || defined(_KERNEL)) +# ifndef IPFILTER_LKM +# include <sys/libkern.h> +# include <sys/systm.h> +# endif +extern struct callout_handle ipfr_slowtimer_ch; +# endif +#endif + ipfr_t *ipfr_heads[IPFT_SIZE]; ipfr_t *ipfr_nattab[IPFT_SIZE]; @@ -73,17 +93,26 @@ ipfrstat_t ipfr_stats; int ipfr_inuse = 0, fr_ipfrttl = 120; /* 60 seconds */ #ifdef _KERNEL +# if SOLARIS2 >= 7 +extern timeout_id_t ipfr_timer_id; +# else extern int ipfr_timer_id; +# endif #endif #if (SOLARIS || defined(__sgi)) && defined(_KERNEL) -extern kmutex_t ipf_frag; -extern kmutex_t ipf_natfrag; -extern kmutex_t ipf_nat; +extern KRWLOCK_T ipf_frag, ipf_natfrag, ipf_nat, ipf_mutex; +# if SOLARIS +extern KRWLOCK_T ipf_solaris; +# else +KRWLOCK_T ipf_solaris; +# endif +extern kmutex_t ipf_rw; #endif -static ipfr_t *ipfr_new __P((ip_t *, fr_info_t *, int, ipfr_t **)); +static ipfr_t *ipfr_new __P((ip_t *, fr_info_t *, u_int, ipfr_t **)); static ipfr_t *ipfr_lookup __P((ip_t *, fr_info_t *, ipfr_t **)); +static void ipfr_delete __P((ipfr_t *)); ipfrstat_t *ipfr_fragstats() @@ -102,10 +131,10 @@ ipfrstat_t *ipfr_fragstats() static ipfr_t *ipfr_new(ip, fin, pass, table) ip_t *ip; fr_info_t *fin; -int pass; +u_int pass; ipfr_t *table[]; { - ipfr_t **fp, *fr, frag; + ipfr_t **fp, *fra, frag; u_int idx; frag.ipfr_p = ip->ip_p; @@ -123,10 +152,10 @@ ipfr_t *table[]; /* * first, make sure it isn't already there... */ - for (fp = &table[idx]; (fr = *fp); fp = &fr->ipfr_next) - if (!bcmp((char *)&frag.ipfr_src, (char *)&fr->ipfr_src, + for (fp = &table[idx]; (fra = *fp); fp = &fra->ipfr_next) + if (!bcmp((char *)&frag.ipfr_src, (char *)&fra->ipfr_src, IPFR_CMPSZ)) { - ipfr_stats.ifs_exists++; + ATOMIC_INC(ipfr_stats.ifs_exists); return NULL; } @@ -134,45 +163,49 @@ ipfr_t *table[]; * allocate some memory, if possible, if not, just record that we * failed to do so. */ - KMALLOC(fr, ipfr_t *, sizeof(*fr)); - if (fr == NULL) { - ipfr_stats.ifs_nomem++; + KMALLOC(fra, ipfr_t *); + if (fra == NULL) { + ATOMIC_INC(ipfr_stats.ifs_nomem); return NULL; } + if ((fra->ipfr_rule = fin->fin_fr) != NULL) { + ATOMIC_INC(fin->fin_fr->fr_ref); + } + + /* * Instert the fragment into the fragment table, copy the struct used * in the search using bcopy rather than reassign each field. * Set the ttl to the default and mask out logging from "pass" */ - if ((fr->ipfr_next = table[idx])) - table[idx]->ipfr_prev = fr; - fr->ipfr_prev = NULL; - fr->ipfr_data = NULL; - table[idx] = fr; - bcopy((char *)&frag.ipfr_src, (char *)&fr->ipfr_src, IPFR_CMPSZ); - fr->ipfr_ttl = fr_ipfrttl; - fr->ipfr_pass = pass & ~(FR_LOGFIRST|FR_LOG); + if ((fra->ipfr_next = table[idx])) + table[idx]->ipfr_prev = fra; + fra->ipfr_prev = NULL; + fra->ipfr_data = NULL; + table[idx] = fra; + bcopy((char *)&frag.ipfr_src, (char *)&fra->ipfr_src, IPFR_CMPSZ); + fra->ipfr_ttl = fr_ipfrttl; /* * Compute the offset of the expected start of the next packet. */ - fr->ipfr_off = (ip->ip_off & 0x1fff) + (fin->fin_dlen >> 3); - ipfr_stats.ifs_new++; - ipfr_inuse++; - return fr; + fra->ipfr_off = (ip->ip_off & IP_OFFMASK) + (fin->fin_dlen >> 3); + ATOMIC_INC(ipfr_stats.ifs_new); + ATOMIC_INC(ipfr_inuse); + return fra; } int ipfr_newfrag(ip, fin, pass) ip_t *ip; fr_info_t *fin; -int pass; +u_int pass; { ipfr_t *ipf; - MUTEX_ENTER(&ipf_frag); + WRITE_ENTER(&ipf_frag); ipf = ipfr_new(ip, fin, pass, ipfr_heads); - MUTEX_EXIT(&ipf_frag); + RWLOCK_EXIT(&ipf_frag); return ipf ? 0 : -1; } @@ -180,17 +213,18 @@ int pass; int ipfr_nat_newfrag(ip, fin, pass, nat) ip_t *ip; fr_info_t *fin; -int pass; +u_int pass; nat_t *nat; { ipfr_t *ipf; - MUTEX_ENTER(&ipf_natfrag); - if ((ipf = ipfr_new(ip, fin, pass, ipfr_nattab))) { + WRITE_ENTER(&ipf_natfrag); + ipf = ipfr_new(ip, fin, pass, ipfr_nattab); + if (ipf != NULL) { ipf->ipfr_data = nat; nat->nat_data = ipf; } - MUTEX_EXIT(&ipf_natfrag); + RWLOCK_EXIT(&ipf_natfrag); return ipf ? 0 : -1; } @@ -251,13 +285,13 @@ ipfr_t *table[]; * If we've follwed the fragments, and this is the * last (in order), shrink expiration time. */ - if ((off & 0x1fff) == f->ipfr_off) { + if ((off & IP_OFFMASK) == f->ipfr_off) { if (!(off & IP_MF)) f->ipfr_ttl = 1; else f->ipfr_off = atoff; } - ipfr_stats.ifs_hits++; + ATOMIC_INC(ipfr_stats.ifs_hits); return f; } return NULL; @@ -274,20 +308,20 @@ fr_info_t *fin; nat_t *nat; ipfr_t *ipf; - MUTEX_ENTER(&ipf_natfrag); + READ_ENTER(&ipf_natfrag); ipf = ipfr_lookup(ip, fin, ipfr_nattab); - if (ipf) { + if (ipf != NULL) { nat = ipf->ipfr_data; /* * This is the last fragment for this packet. */ - if (ipf->ipfr_ttl == 1) { + if ((ipf->ipfr_ttl == 1) && (nat != NULL)) { nat->nat_data = NULL; ipf->ipfr_data = NULL; } } else nat = NULL; - MUTEX_EXIT(&ipf_natfrag); + RWLOCK_EXIT(&ipf_natfrag); return nat; } @@ -295,18 +329,19 @@ fr_info_t *fin; /* * functional interface for normal lookups of the fragment cache */ -int ipfr_knownfrag(ip, fin) +frentry_t *ipfr_knownfrag(ip, fin) ip_t *ip; fr_info_t *fin; { - int ret; - ipfr_t *ipf; - - MUTEX_ENTER(&ipf_frag); - ipf = ipfr_lookup(ip, fin, ipfr_heads); - ret = ipf ? ipf->ipfr_pass : 0; - MUTEX_EXIT(&ipf_frag); - return ret; + frentry_t *fr = NULL; + ipfr_t *fra; + + READ_ENTER(&ipf_frag); + fra = ipfr_lookup(ip, fin, ipfr_heads); + if (fra != NULL) + fr = fra->ipfr_rule; + RWLOCK_EXIT(&ipf_frag); + return fr; } @@ -319,13 +354,32 @@ void *nat; ipfr_t *fr; int idx; - MUTEX_ENTER(&ipf_natfrag); + WRITE_ENTER(&ipf_natfrag); for (idx = IPFT_SIZE - 1; idx >= 0; idx--) for (fr = ipfr_heads[idx]; fr; fr = fr->ipfr_next) if (fr->ipfr_data == nat) fr->ipfr_data = NULL; - MUTEX_EXIT(&ipf_natfrag); + RWLOCK_EXIT(&ipf_natfrag); +} + + +static void ipfr_delete(fra) +ipfr_t *fra; +{ + frentry_t *fr; + + fr = fra->ipfr_rule; + if (fr != NULL) { + ATOMIC_DEC(fr->fr_ref); + if (fr->fr_ref == 0) + KFREE(fr); + } + if (fra->ipfr_prev) + fra->ipfr_prev->ipfr_next = fra->ipfr_next; + if (fra->ipfr_next) + fra->ipfr_next->ipfr_prev = fra->ipfr_prev; + KFREE(fra); } @@ -334,31 +388,32 @@ void *nat; */ void ipfr_unload() { - ipfr_t **fp, *fr; + ipfr_t **fp, *fra; nat_t *nat; int idx; - MUTEX_ENTER(&ipf_frag); + WRITE_ENTER(&ipf_frag); for (idx = IPFT_SIZE - 1; idx >= 0; idx--) - for (fp = &ipfr_heads[idx]; (fr = *fp); ) { - *fp = fr->ipfr_next; - KFREE(fr); + for (fp = &ipfr_heads[idx]; (fra = *fp); ) { + *fp = fra->ipfr_next; + ipfr_delete(fra); } - MUTEX_EXIT(&ipf_frag); + RWLOCK_EXIT(&ipf_frag); - MUTEX_ENTER(&ipf_nat); - MUTEX_ENTER(&ipf_natfrag); + WRITE_ENTER(&ipf_nat); + WRITE_ENTER(&ipf_natfrag); for (idx = IPFT_SIZE - 1; idx >= 0; idx--) - for (fp = &ipfr_nattab[idx]; (fr = *fp); ) { - *fp = fr->ipfr_next; - if ((nat = (nat_t *)fr->ipfr_data)) { - if (nat->nat_data == fr) + for (fp = &ipfr_nattab[idx]; (fra = *fp); ) { + *fp = fra->ipfr_next; + nat = fra->ipfr_data; + if (nat != NULL) { + if (nat->nat_data == fra) nat->nat_data = NULL; } - KFREE(fr); + ipfr_delete(fra); } - MUTEX_EXIT(&ipf_natfrag); - MUTEX_EXIT(&ipf_nat); + RWLOCK_EXIT(&ipf_natfrag); + RWLOCK_EXIT(&ipf_nat); } @@ -368,21 +423,36 @@ void ipfr_unload() * of this being called twice per second. */ # if (BSD >= 199306) || SOLARIS || defined(__sgi) +# if defined(SOLARIS2) && (SOLARIS2 < 7) void ipfr_slowtimer() +# else +void ipfr_slowtimer __P((void *ptr)) +# endif # else int ipfr_slowtimer() # endif { - ipfr_t **fp, *fr; + ipfr_t **fp, *fra; nat_t *nat; - int s, idx; + int idx; +#if defined(_KERNEL) +# if !SOLARIS + int s; +# else + extern int fr_running; + + if (fr_running <= 0) + return; +# endif +#endif + READ_ENTER(&ipf_solaris); #ifdef __sgi ipfilter_sgi_intfsync(); #endif SPL_NET(s); - MUTEX_ENTER(&ipf_frag); + WRITE_ENTER(&ipf_frag); /* * Go through the entire table, looking for entries to expire, @@ -390,23 +460,17 @@ int ipfr_slowtimer() * remove it from the chain and free it. */ for (idx = IPFT_SIZE - 1; idx >= 0; idx--) - for (fp = &ipfr_heads[idx]; (fr = *fp); ) { - --fr->ipfr_ttl; - if (fr->ipfr_ttl == 0) { - if (fr->ipfr_prev) - fr->ipfr_prev->ipfr_next = - fr->ipfr_next; - if (fr->ipfr_next) - fr->ipfr_next->ipfr_prev = - fr->ipfr_prev; - *fp = fr->ipfr_next; - ipfr_stats.ifs_expire++; - ipfr_inuse--; - KFREE(fr); + for (fp = &ipfr_heads[idx]; (fra = *fp); ) { + --fra->ipfr_ttl; + if (fra->ipfr_ttl == 0) { + *fp = fra->ipfr_next; + ipfr_delete(fra); + ATOMIC_INC(ipfr_stats.ifs_expire); + ATOMIC_DEC(ipfr_inuse); } else - fp = &fr->ipfr_next; + fp = &fra->ipfr_next; } - MUTEX_EXIT(&ipf_frag); + RWLOCK_EXIT(&ipf_frag); /* * Same again for the NAT table, except that if the structure also @@ -415,31 +479,26 @@ int ipfr_slowtimer() * NOTE: We need to grab both mutex's early, and in this order so as * to prevent a deadlock if both try to expire at the same time. */ - MUTEX_ENTER(&ipf_nat); - MUTEX_ENTER(&ipf_natfrag); + WRITE_ENTER(&ipf_nat); + WRITE_ENTER(&ipf_natfrag); for (idx = IPFT_SIZE - 1; idx >= 0; idx--) - for (fp = &ipfr_nattab[idx]; (fr = *fp); ) { - --fr->ipfr_ttl; - if (fr->ipfr_ttl == 0) { - if (fr->ipfr_prev) - fr->ipfr_prev->ipfr_next = - fr->ipfr_next; - if (fr->ipfr_next) - fr->ipfr_next->ipfr_prev = - fr->ipfr_prev; - *fp = fr->ipfr_next; - ipfr_stats.ifs_expire++; - ipfr_inuse--; - if ((nat = (nat_t *)fr->ipfr_data)) { - if (nat->nat_data == fr) + for (fp = &ipfr_nattab[idx]; (fra = *fp); ) { + --fra->ipfr_ttl; + if (fra->ipfr_ttl == 0) { + ATOMIC_INC(ipfr_stats.ifs_expire); + ATOMIC_DEC(ipfr_inuse); + nat = fra->ipfr_data; + if (nat != NULL) { + if (nat->nat_data == fra) nat->nat_data = NULL; } - KFREE(fr); + *fp = fra->ipfr_next; + ipfr_delete(fra); } else - fp = &fr->ipfr_next; + fp = &fra->ipfr_next; } - MUTEX_EXIT(&ipf_natfrag); - MUTEX_EXIT(&ipf_nat); + RWLOCK_EXIT(&ipf_natfrag); + RWLOCK_EXIT(&ipf_nat); SPL_X(s); fr_timeoutstate(); ip_natexpire(); @@ -448,11 +507,16 @@ int ipfr_slowtimer() ipfr_timer_id = timeout(ipfr_slowtimer, NULL, drv_usectohz(500000)); # else # ifndef linux - ip_slowtimo(); +# if (__FreeBSD_version >= 300000) + ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); +# else + timeout(ipfr_slowtimer, NULL, hz/2); +# endif # endif # if (BSD < 199306) && !defined(__sgi) return 0; # endif # endif + RWLOCK_EXIT(&ipf_solaris); } #endif /* defined(_KERNEL) */ |