summaryrefslogtreecommitdiffstats
path: root/sys/contrib/ipfilter/netinet/ip_frag.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/contrib/ipfilter/netinet/ip_frag.c')
-rw-r--r--sys/contrib/ipfilter/netinet/ip_frag.c107
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;
OpenPOWER on IntegriCloud