diff options
Diffstat (limited to 'sys/contrib/ipfilter/netinet/ip_frag.c')
-rw-r--r-- | sys/contrib/ipfilter/netinet/ip_frag.c | 107 |
1 files changed, 84 insertions, 23 deletions
diff --git a/sys/contrib/ipfilter/netinet/ip_frag.c b/sys/contrib/ipfilter/netinet/ip_frag.c index 556478d..b0e63a9 100644 --- a/sys/contrib/ipfilter/netinet/ip_frag.c +++ b/sys/contrib/ipfilter/netinet/ip_frag.c @@ -1,15 +1,8 @@ /* - * Copyright (C) 1993-2000 by Darren Reed. + * Copyright (C) 1993-2001 by Darren Reed. * - * Redistribution and use in source and binary forms are permitted - * provided that this notice is preserved and due credit is given - * to the original author and the contributors. + * See the IPFILTER.LICENCE file for details on licencing. */ -#if !defined(lint) -static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed"; -static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.10.2.7 2000/11/27 10:26:56 darrenr Exp $"; -#endif - #if defined(KERNEL) && !defined(_KERNEL) # define _KERNEL #endif @@ -81,7 +74,7 @@ static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.10.2.7 2000/11/27 10:26:56 d # ifndef IPFILTER_LKM # include <sys/libkern.h> # include <sys/systm.h> -# endif +# endif extern struct callout_handle ipfr_slowtimer_ch; # endif #endif @@ -89,6 +82,15 @@ extern struct callout_handle ipfr_slowtimer_ch; # include <sys/callout.h> extern struct callout ipfr_slowtimer_ch; #endif +#if defined(__OpenBSD__) +# include <sys/timeout.h> +extern struct timeout ipfr_slowtimer_ch; +#endif + +#if !defined(lint) +static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed"; +static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.10.2.14 2001/07/15 22:06:15 darrenr Exp $"; +#endif static ipfr_t *ipfr_heads[IPFT_SIZE]; @@ -141,12 +143,15 @@ fr_info_t *fin; u_int pass; ipfr_t *table[]; { - ipfr_t **fp, *fra, frag; - u_int idx; + ipfr_t **fp, *fra, frag; + u_int idx, off; if (ipfr_inuse >= IPFT_SIZE) return NULL; + if (!(fin->fin_fl & FI_FRAG)) + return NULL; + frag.ipfr_p = ip->ip_p; idx = ip->ip_p; frag.ipfr_id = ip->ip_id; @@ -160,6 +165,10 @@ ipfr_t *table[]; idx *= 127; idx %= IPFT_SIZE; + frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY; + frag.ipfr_secmsk = fin->fin_fi.fi_secmsk; + frag.ipfr_auth = fin->fin_fi.fi_auth; + /* * first, make sure it isn't already there... */ @@ -200,7 +209,10 @@ ipfr_t *table[]; /* * Compute the offset of the expected start of the next packet. */ - fra->ipfr_off = (ip->ip_off & IP_OFFMASK) + (fin->fin_dlen >> 3); + off = ip->ip_off & IP_OFFMASK; + if (!off) + fra->ipfr_seen0 = 1; + fra->ipfr_off = off + (fin->fin_dlen >> 3); ATOMIC_INCL(ipfr_stats.ifs_new); ATOMIC_INC32(ipfr_inuse); return fra; @@ -219,7 +231,12 @@ u_int pass; WRITE_ENTER(&ipf_frag); ipf = ipfr_new(ip, fin, pass, ipfr_heads); RWLOCK_EXIT(&ipf_frag); - return ipf ? 0 : -1; + if (ipf == NULL) { + ATOMIC_INCL(frstats[fin->fin_out].fr_bnfr); + return -1; + } + ATOMIC_INCL(frstats[fin->fin_out].fr_nfr); + return 0; } @@ -230,9 +247,16 @@ u_int pass; nat_t *nat; { ipfr_t *ipf; + int off; if ((ip->ip_v != 4) || (fr_frag_lock)) return -1; + + off = fin->fin_off; + off <<= 3; + if ((off + fin->fin_dlen) > 0xffff || (fin->fin_dlen == 0)) + return NULL; + WRITE_ENTER(&ipf_natfrag); ipf = ipfr_new(ip, fin, pass, ipfr_nattab); if (ipf != NULL) { @@ -254,8 +278,8 @@ fr_info_t *fin; ipfr_t *table[]; { ipfr_t *f, frag; - u_int idx; - + u_int idx; + /* * For fragments, we record protocol, packet id, TOS and both IP#'s * (these should all be the same for all fragments of a packet). @@ -275,6 +299,10 @@ ipfr_t *table[]; idx *= 127; idx %= IPFT_SIZE; + frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY; + frag.ipfr_secmsk = fin->fin_fi.fi_secmsk; + frag.ipfr_auth = fin->fin_fi.fi_auth; + /* * check the table, careful to only compare the right amount of data */ @@ -283,6 +311,20 @@ ipfr_t *table[]; IPFR_CMPSZ)) { u_short atoff, off; + off = fin->fin_off; + + /* + * XXX - We really need to be guarding against the + * retransmission of (src,dst,id,offset-range) here + * because a fragmented packet is never resent with + * the same IP ID#. + */ + if (f->ipfr_seen0) { + if (!off || (fin->fin_fl & FI_SHORT)) + continue; + } else if (!off) + f->ipfr_seen0 = 1; + if (f != table[idx]) { /* * move fragment info. to the top of the list @@ -295,7 +337,6 @@ ipfr_t *table[]; f->ipfr_prev = NULL; table[idx] = f; } - off = ip->ip_off & IP_OFFMASK; atoff = off + (fin->fin_dlen >> 3); /* * If we've follwed the fragments, and this is the @@ -321,11 +362,18 @@ nat_t *ipfr_nat_knownfrag(ip, fin) ip_t *ip; fr_info_t *fin; { - nat_t *nat; - ipfr_t *ipf; + ipfr_t *ipf; + nat_t *nat; + int off; - if ((ip->ip_v != 4) || (fr_frag_lock)) + if ((fin->fin_v != 4) || (fr_frag_lock)) + return NULL; + + off = fin->fin_off; + off <<= 3; + if ((off + fin->fin_dlen) > 0xffff || (fin->fin_dlen == 0)) return NULL; + READ_ENTER(&ipf_natfrag); ipf = ipfr_lookup(ip, fin, ipfr_nattab); if (ipf != NULL) { @@ -351,15 +399,24 @@ frentry_t *ipfr_knownfrag(ip, fin) ip_t *ip; fr_info_t *fin; { - frentry_t *fr = NULL; - ipfr_t *fra; + frentry_t *fr; + ipfr_t *fra; + int off; - if ((ip->ip_v != 4) || (fr_frag_lock)) + if ((fin->fin_v != 4) || (fr_frag_lock)) + return NULL; + + off = fin->fin_off; + off <<= 3; + if ((off + fin->fin_dlen) > 0xffff || (fin->fin_dlen == 0)) return NULL; + READ_ENTER(&ipf_frag); fra = ipfr_lookup(ip, fin, ipfr_heads); if (fra != NULL) fr = fra->ipfr_rule; + else + fr = NULL; RWLOCK_EXIT(&ipf_frag); return fr; } @@ -544,7 +601,11 @@ int ipfr_slowtimer() # if (__FreeBSD_version >= 300000) ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2); # else +# if defined(__OpenBSD_) + timeout_add(&ipfr_slowtimer_ch, hz/2, ipfr_slowtimer, NULL); +# else timeout(ipfr_slowtimer, NULL, hz/2); +# endif # endif # if (BSD < 199306) && !defined(__sgi) return 0; |