1/* $FreeBSD: head/sys/contrib/ipfilter/netinet/ip_frag.c 145522 2005-04-25 18:43:14Z darrenr $ */ 2 |
3/*
|
2 * Copyright (C) 1993-2001 by Darren Reed.
|
4 * Copyright (C) 1993-2003 by Darren Reed. |
5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 */
|
6#if defined(KERNEL) && !defined(_KERNEL)
7# define _KERNEL
|
8#if defined(KERNEL) || defined(_KERNEL) 9# undef KERNEL 10# undef _KERNEL 11# define KERNEL 1 12# define _KERNEL 1 |
13#endif
|
9
10#if defined(__sgi) && (IRIX > 602)
11# include <sys/ptimers.h>
12#endif
|
14#include <sys/errno.h> 15#include <sys/types.h> 16#include <sys/param.h> 17#include <sys/time.h> 18#include <sys/file.h>
|
18#if !defined(_KERNEL) && !defined(KERNEL)
|
19#ifdef __hpux 20# include <sys/timeout.h> 21#endif 22#if !defined(_KERNEL) |
23# include <stdio.h> 24# include <string.h> 25# include <stdlib.h>
|
26# define _KERNEL 27# ifdef __OpenBSD__ 28struct file; 29# endif 30# include <sys/uio.h> 31# undef _KERNEL |
32#endif
|
23#if (defined(KERNEL) || defined(_KERNEL)) && (__FreeBSD_version >= 220000)
|
33#if defined(_KERNEL) && (__FreeBSD_version >= 220000) |
34# include <sys/filio.h> 35# include <sys/fcntl.h> 36#else 37# include <sys/ioctl.h> 38#endif
|
29#ifndef linux
|
39#if !defined(linux) |
40# include <sys/protosw.h> 41#endif 42#include <sys/socket.h>
|
33#if defined(_KERNEL) && !defined(linux)
|
43#if defined(_KERNEL) |
44# include <sys/systm.h>
|
45# if !defined(__SVR4) && !defined(__svr4__) 46# include <sys/mbuf.h> 47# endif |
48#endif 49#if !defined(__SVR4) && !defined(__svr4__) 50# if defined(_KERNEL) && !defined(__sgi) 51# include <sys/kernel.h> 52# endif
|
40# ifndef linux
41# include <sys/mbuf.h>
42# endif
|
53#else 54# include <sys/byteorder.h> 55# ifdef _KERNEL 56# include <sys/dditypes.h> 57# endif 58# include <sys/stream.h> 59# include <sys/kmem.h> 60#endif 61#include <net/if.h> 62#ifdef sun 63# include <net/af.h> 64#endif 65#include <net/route.h> 66#include <netinet/in.h> 67#include <netinet/in_systm.h> 68#include <netinet/ip.h>
|
59#ifndef linux
|
69#if !defined(linux) |
70# include <netinet/ip_var.h> 71#endif 72#include <netinet/tcp.h> 73#include <netinet/udp.h> 74#include <netinet/ip_icmp.h> 75#include "netinet/ip_compat.h" 76#include <netinet/tcpip.h> 77#include "netinet/ip_fil.h" 78#include "netinet/ip_nat.h" 79#include "netinet/ip_frag.h" 80#include "netinet/ip_state.h" 81#include "netinet/ip_auth.h"
|
82#include "netinet/ip_proxy.h" |
83#if (__FreeBSD_version >= 300000) 84# include <sys/malloc.h>
|
74# if (defined(KERNEL) || defined(_KERNEL))
|
85# if defined(_KERNEL) |
86# ifndef IPFILTER_LKM 87# include <sys/libkern.h> 88# include <sys/systm.h> 89# endif
|
79extern struct callout_handle ipfr_slowtimer_ch;
|
90extern struct callout_handle fr_slowtimer_ch; |
91# endif 92#endif 93#if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) 94# include <sys/callout.h>
|
84extern struct callout ipfr_slowtimer_ch;
|
95extern struct callout fr_slowtimer_ch; |
96#endif 97#if defined(__OpenBSD__) 98# include <sys/timeout.h>
|
88extern struct timeout ipfr_slowtimer_ch;
|
99extern struct timeout fr_slowtimer_ch; |
100#endif
|
101/* END OF INCLUDES */ |
102 103#if !defined(lint) 104static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed";
|
93static const char rcsid[] = "@(#)$FreeBSD: head/sys/contrib/ipfilter/netinet/ip_frag.c 139255 2004-12-24 09:14:26Z darrenr $";
|
105static const char rcsid[] = "@(#)$FreeBSD: head/sys/contrib/ipfilter/netinet/ip_frag.c 145522 2005-04-25 18:43:14Z darrenr $"; 106static const char rcsid[] = "@(#)Id: ip_frag.c,v 2.77 2004/01/27 00:24:54 darrenr Exp"; |
107#endif 108 109
|
97static ipfr_t *ipfr_heads[IPFT_SIZE];
98static ipfr_t *ipfr_nattab[IPFT_SIZE];
|
110static ipfr_t *ipfr_list = NULL; 111static ipfr_t **ipfr_tail = &ipfr_list; 112static ipfr_t **ipfr_heads; 113 114static ipfr_t *ipfr_natlist = NULL; 115static ipfr_t **ipfr_nattail = &ipfr_natlist; 116static ipfr_t **ipfr_nattab; 117 118static ipfr_t *ipfr_ipidlist = NULL; 119static ipfr_t **ipfr_ipidtail = &ipfr_ipidlist; 120static ipfr_t **ipfr_ipidtab; 121 |
122static ipfrstat_t ipfr_stats; 123static int ipfr_inuse = 0;
|
124int ipfr_size = IPFT_SIZE; |
125 126int fr_ipfrttl = 120; /* 60 seconds */ 127int fr_frag_lock = 0;
|
128int fr_frag_init = 0; 129u_long fr_ticks = 0; |
130
|
105#ifdef _KERNEL
106# if SOLARIS2 >= 7
107extern timeout_id_t ipfr_timer_id;
108# else
109extern int ipfr_timer_id;
110# endif
111#endif
112#ifdef USE_MUTEX
113extern KRWLOCK_T ipf_frag, ipf_natfrag, ipf_nat, ipf_mutex;
114# if SOLARIS
115extern KRWLOCK_T ipf_solaris;
116# else
117KRWLOCK_T ipf_solaris;
118# endif
119extern kmutex_t ipf_rw;
120#endif
|
131
|
132static ipfr_t *ipfr_newfrag __P((fr_info_t *, u_32_t, ipfr_t **)); 133static ipfr_t *fr_fraglookup __P((fr_info_t *, ipfr_t **)); 134static void fr_fragdelete __P((ipfr_t *, ipfr_t ***)); |
135
|
123static ipfr_t *ipfr_new __P((ip_t *, fr_info_t *, ipfr_t **));
124static ipfr_t *ipfr_lookup __P((ip_t *, fr_info_t *, ipfr_t **));
125static void ipfr_delete __P((ipfr_t *));
|
136
|
137/* ------------------------------------------------------------------------ */ 138/* Function: fr_fraginit */ 139/* Returns: int - 0 == success, -1 == error */ 140/* Parameters: Nil */ 141/* */ 142/* Initialise the hash tables for the fragment cache lookups. */ 143/* ------------------------------------------------------------------------ */ 144int fr_fraginit() 145{ 146 KMALLOCS(ipfr_heads, ipfr_t **, ipfr_size * sizeof(ipfr_t *)); 147 if (ipfr_heads == NULL) 148 return -1; 149 bzero((char *)ipfr_heads, ipfr_size * sizeof(ipfr_t *)); |
150
|
128ipfrstat_t *ipfr_fragstats()
|
151 KMALLOCS(ipfr_nattab, ipfr_t **, ipfr_size * sizeof(ipfr_t *)); 152 if (ipfr_nattab == NULL) 153 return -1; 154 bzero((char *)ipfr_nattab, ipfr_size * sizeof(ipfr_t *)); 155 156 KMALLOCS(ipfr_ipidtab, ipfr_t **, ipfr_size * sizeof(ipfr_t *)); 157 if (ipfr_ipidtab == NULL) 158 return -1; 159 bzero((char *)ipfr_ipidtab, ipfr_size * sizeof(ipfr_t *)); 160 161 RWLOCK_INIT(&ipf_frag, "ipf fragment rwlock"); 162 fr_frag_init = 1; 163 164 return 0; 165} 166 167 168/* ------------------------------------------------------------------------ */ 169/* Function: fr_fragunload */ 170/* Returns: Nil */ 171/* Parameters: Nil */ 172/* */ 173/* Free all memory allocated whilst running and from initialisation. */ 174/* ------------------------------------------------------------------------ */ 175void fr_fragunload() |
176{
|
177 if (fr_frag_init == 1) { 178 fr_fragclear(); 179 180 RW_DESTROY(&ipf_frag); 181 fr_frag_init = 0; 182 } 183 184 if (ipfr_heads != NULL) 185 KFREES(ipfr_heads, ipfr_size * sizeof(ipfr_t *)); 186 ipfr_heads = NULL; 187 188 if (ipfr_nattab != NULL) 189 KFREES(ipfr_nattab, ipfr_size * sizeof(ipfr_t *)); 190 ipfr_nattab = NULL; 191 192 if (ipfr_ipidtab != NULL) 193 KFREES(ipfr_ipidtab, ipfr_size * sizeof(ipfr_t *)); 194 ipfr_ipidtab = NULL; 195} 196 197 198/* ------------------------------------------------------------------------ */ 199/* Function: fr_fragstats */ 200/* Returns: ipfrstat_t* - pointer to struct with current frag stats */ 201/* Parameters: Nil */ 202/* */ 203/* Updates ipfr_stats with current information and returns a pointer to it */ 204/* ------------------------------------------------------------------------ */ 205ipfrstat_t *fr_fragstats() 206{ |
207 ipfr_stats.ifs_table = ipfr_heads; 208 ipfr_stats.ifs_nattab = ipfr_nattab; 209 ipfr_stats.ifs_inuse = ipfr_inuse; 210 return &ipfr_stats; 211} 212 213
|
137/*
138 * add a new entry to the fragment cache, registering it as having come
139 * through this box, with the result of the filter operation.
140 */
141static ipfr_t *ipfr_new(ip, fin, table)
142ip_t *ip;
|
214/* ------------------------------------------------------------------------ */ 215/* Function: ipfr_newfrag */ 216/* Returns: ipfr_t * - pointer to fragment cache state info or NULL */ 217/* Parameters: fin(I) - pointer to packet information */ 218/* table(I) - pointer to frag table to add to */ 219/* */ 220/* Add a new entry to the fragment cache, registering it as having come */ 221/* through this box, with the result of the filter operation. */ 222/* ------------------------------------------------------------------------ */ 223static ipfr_t *ipfr_newfrag(fin, pass, table) |
224fr_info_t *fin;
|
225u_32_t pass; |
226ipfr_t *table[]; 227{
|
146 ipfr_t **fp, *fra, frag;
|
228 ipfr_t *fra, frag; |
229 u_int idx, off;
|
230 ip_t *ip; |
231 232 if (ipfr_inuse >= IPFT_SIZE) 233 return NULL; 234
|
152 if (!(fin->fin_fl & FI_FRAG))
|
235 if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) |
236 return NULL; 237
|
238 ip = fin->fin_ip; 239 240 if (pass & FR_FRSTRICT) 241 if ((ip->ip_off & IP_OFFMASK) != 0) 242 return NULL; 243 |
244 frag.ipfr_p = ip->ip_p; 245 idx = ip->ip_p; 246 frag.ipfr_id = ip->ip_id; 247 idx += ip->ip_id; 248 frag.ipfr_tos = ip->ip_tos; 249 frag.ipfr_src.s_addr = ip->ip_src.s_addr; 250 idx += ip->ip_src.s_addr; 251 frag.ipfr_dst.s_addr = ip->ip_dst.s_addr; 252 idx += ip->ip_dst.s_addr; 253 frag.ipfr_ifp = fin->fin_ifp; 254 idx *= 127; 255 idx %= IPFT_SIZE; 256 257 frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY; 258 frag.ipfr_secmsk = fin->fin_fi.fi_secmsk; 259 frag.ipfr_auth = fin->fin_fi.fi_auth; 260 261 /* 262 * first, make sure it isn't already there... 263 */
|
175 for (fp = &table[idx]; (fra = *fp); fp = &fra->ipfr_next)
176 if (!bcmp((char *)&frag.ipfr_src, (char *)&fra->ipfr_src,
|
264 for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext) 265 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, |
266 IPFR_CMPSZ)) {
|
178 ATOMIC_INCL(ipfr_stats.ifs_exists);
|
267 ipfr_stats.ifs_exists++; |
268 return NULL; 269 } 270 271 /* 272 * allocate some memory, if possible, if not, just record that we 273 * failed to do so. 274 */ 275 KMALLOC(fra, ipfr_t *); 276 if (fra == NULL) {
|
188 ATOMIC_INCL(ipfr_stats.ifs_nomem);
|
277 ipfr_stats.ifs_nomem++; |
278 return NULL; 279 } 280
|
192 if ((fra->ipfr_rule = fin->fin_fr) != NULL) {
193 ATOMIC_INC32(fin->fin_fr->fr_ref);
194 }
|
281 if ((fra->ipfr_rule = fin->fin_fr) != NULL) 282 fin->fin_fr->fr_ref++; |
283
|
196
|
284 /* 285 * Insert the fragment into the fragment table, copy the struct used 286 * in the search using bcopy rather than reassign each field. 287 * Set the ttl to the default. 288 */
|
202 if ((fra->ipfr_next = table[idx]))
203 table[idx]->ipfr_prev = fra;
204 fra->ipfr_prev = NULL;
|
289 if ((fra->ipfr_hnext = table[idx]) != NULL) 290 table[idx]->ipfr_hprev = &fra->ipfr_hnext; 291 fra->ipfr_hprev = table + idx; |
292 fra->ipfr_data = NULL; 293 table[idx] = fra;
|
207 bcopy((char *)&frag.ipfr_src, (char *)&fra->ipfr_src, IPFR_CMPSZ);
208 fra->ipfr_ttl = fr_ipfrttl;
|
294 bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ); 295 fra->ipfr_ttl = fr_ticks + fr_ipfrttl; 296 |
297 /* 298 * Compute the offset of the expected start of the next packet. 299 */ 300 off = ip->ip_off & IP_OFFMASK;
|
213 if (!off)
|
301 if (off == 0) |
302 fra->ipfr_seen0 = 1; 303 fra->ipfr_off = off + (fin->fin_dlen >> 3);
|
216 ATOMIC_INCL(ipfr_stats.ifs_new);
217 ATOMIC_INC32(ipfr_inuse);
|
304 fra->ipfr_pass = pass; 305 ipfr_stats.ifs_new++; 306 ipfr_inuse++; |
307 return fra; 308} 309 310
|
222int ipfr_newfrag(ip, fin)
223ip_t *ip;
|
311/* ------------------------------------------------------------------------ */ 312/* Function: fr_newfrag */ 313/* Returns: int - 0 == success, -1 == error */ 314/* Parameters: fin(I) - pointer to packet information */ 315/* */ 316/* Add a new entry to the fragment cache table based on the current packet */ 317/* ------------------------------------------------------------------------ */ 318int fr_newfrag(fin, pass) 319u_32_t pass; |
320fr_info_t *fin; 321{
|
226 ipfr_t *ipf;
|
322 ipfr_t *fra; |
323
|
228 if ((ip->ip_v != 4) || (fr_frag_lock))
|
324 if ((fin->fin_v != 4) || (fr_frag_lock != 0)) |
325 return -1;
|
326 |
327 WRITE_ENTER(&ipf_frag);
|
231 ipf = ipfr_new(ip, fin, ipfr_heads);
232 RWLOCK_EXIT(&ipf_frag);
233 if (ipf == NULL) {
234 ATOMIC_INCL(frstats[fin->fin_out].fr_bnfr);
235 return -1;
|
328 fra = ipfr_newfrag(fin, pass, ipfr_heads); 329 if (fra != NULL) { 330 *ipfr_tail = fra; 331 fra->ipfr_prev = ipfr_tail; 332 ipfr_tail = &fra->ipfr_next; 333 if (ipfr_list == NULL) 334 ipfr_list = fra; 335 fra->ipfr_next = NULL; |
336 }
|
237 ATOMIC_INCL(frstats[fin->fin_out].fr_nfr);
238 return 0;
|
337 RWLOCK_EXIT(&ipf_frag); 338 return fra ? 0 : -1; |
339} 340 341
|
242int ipfr_nat_newfrag(ip, fin, nat)
243ip_t *ip;
|
342/* ------------------------------------------------------------------------ */ 343/* Function: fr_nat_newfrag */ 344/* Returns: int - 0 == success, -1 == error */ 345/* Parameters: fin(I) - pointer to packet information */ 346/* nat(I) - pointer to NAT structure */ 347/* */ 348/* Create a new NAT fragment cache entry based on the current packet and */ 349/* the NAT structure for this "session". */ 350/* ------------------------------------------------------------------------ */ 351int fr_nat_newfrag(fin, pass, nat) |
352fr_info_t *fin;
|
353u_32_t pass; |
354nat_t *nat; 355{
|
247 ipfr_t *ipf;
248 int off;
|
356 ipfr_t *fra; |
357
|
250 if ((ip->ip_v != 4) || (fr_frag_lock))
251 return -1;
|
358 if ((fin->fin_v != 4) || (fr_frag_lock != 0)) 359 return 0; |
360
|
253 off = fin->fin_off;
254 off <<= 3;
255 if ((off + fin->fin_dlen) > 0xffff || (fin->fin_dlen == 0))
256 return -1;
257
|
361 WRITE_ENTER(&ipf_natfrag);
|
259 ipf = ipfr_new(ip, fin, ipfr_nattab);
260 if (ipf != NULL) {
261 ipf->ipfr_data = nat;
262 nat->nat_data = ipf;
|
362 fra = ipfr_newfrag(fin, pass, ipfr_nattab); 363 if (fra != NULL) { 364 fra->ipfr_data = nat; 365 nat->nat_data = fra; 366 *ipfr_nattail = fra; 367 fra->ipfr_prev = ipfr_nattail; 368 ipfr_nattail = &fra->ipfr_next; 369 fra->ipfr_next = NULL; |
370 } 371 RWLOCK_EXIT(&ipf_natfrag);
|
265 return ipf ? 0 : -1;
|
372 return fra ? 0 : -1; |
373} 374 375
|
269/*
270 * check the fragment cache to see if there is already a record of this packet
271 * with its filter result known.
272 */
273static ipfr_t *ipfr_lookup(ip, fin, table)
274ip_t *ip;
|
376/* ------------------------------------------------------------------------ */ 377/* Function: fr_ipid_newfrag */ 378/* Returns: int - 0 == success, -1 == error */ 379/* Parameters: fin(I) - pointer to packet information */ 380/* ipid(I) - new IP ID for this fragmented packet */ 381/* */ 382/* Create a new fragment cache entry for this packet and store, as a data */ 383/* pointer, the new IP ID value. */ 384/* ------------------------------------------------------------------------ */ 385int fr_ipid_newfrag(fin, ipid) |
386fr_info_t *fin;
|
387u_32_t ipid; 388{ 389 ipfr_t *fra; 390 391 if ((fin->fin_v != 4) || (fr_frag_lock)) 392 return 0; 393 394 WRITE_ENTER(&ipf_ipidfrag); 395 fra = ipfr_newfrag(fin, 0, ipfr_ipidtab); 396 if (fra != NULL) { 397 fra->ipfr_data = (void *)ipid; 398 *ipfr_ipidtail = fra; 399 fra->ipfr_prev = ipfr_ipidtail; 400 ipfr_ipidtail = &fra->ipfr_next; 401 fra->ipfr_next = NULL; 402 } 403 RWLOCK_EXIT(&ipf_ipidfrag); 404 return fra ? 0 : -1; 405} 406 407 408/* ------------------------------------------------------------------------ */ 409/* Function: fr_fraglookup */ 410/* Returns: ipfr_t * - pointer to ipfr_t structure if there's a */ 411/* matching entry in the frag table, else NULL */ 412/* Parameters: fin(I) - pointer to packet information */ 413/* table(I) - pointer to fragment cache table to search */ 414/* */ 415/* Check the fragment cache to see if there is already a record of this */ 416/* packet with its filter result known. */ 417/* ------------------------------------------------------------------------ */ 418static ipfr_t *fr_fraglookup(fin, table) 419fr_info_t *fin; |
420ipfr_t *table[]; 421{
|
278 ipfr_t *f, frag;
279 u_int idx;
|
422 ipfr_t *f, frag; 423 u_int idx; 424 ip_t *ip; |
425
|
426 if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) 427 return NULL; 428 |
429 /* 430 * For fragments, we record protocol, packet id, TOS and both IP#'s 431 * (these should all be the same for all fragments of a packet). 432 * 433 * build up a hash value to index the table with. 434 */
|
435 ip = fin->fin_ip; |
436 frag.ipfr_p = ip->ip_p; 437 idx = ip->ip_p; 438 frag.ipfr_id = ip->ip_id; 439 idx += ip->ip_id; 440 frag.ipfr_tos = ip->ip_tos; 441 frag.ipfr_src.s_addr = ip->ip_src.s_addr; 442 idx += ip->ip_src.s_addr; 443 frag.ipfr_dst.s_addr = ip->ip_dst.s_addr; 444 idx += ip->ip_dst.s_addr; 445 frag.ipfr_ifp = fin->fin_ifp; 446 idx *= 127; 447 idx %= IPFT_SIZE; 448 449 frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY; 450 frag.ipfr_secmsk = fin->fin_fi.fi_secmsk; 451 frag.ipfr_auth = fin->fin_fi.fi_auth; 452 453 /* 454 * check the table, careful to only compare the right amount of data 455 */
|
307 for (f = table[idx]; f; f = f->ipfr_next)
308 if (!bcmp((char *)&frag.ipfr_src, (char *)&f->ipfr_src,
|
456 for (f = table[idx]; f; f = f->ipfr_hnext) 457 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&f->ipfr_ifp, |
458 IPFR_CMPSZ)) {
|
310 u_short atoff, off;
|
459 u_short off; |
460
|
312 off = fin->fin_off;
|
461 /* 462 * We don't want to let short packets match because 463 * they could be compromising the security of other 464 * rules that want to match on layer 4 fields (and 465 * can't because they have been fragmented off.) 466 * Why do this check here? The counter acts as an 467 * indicator of this kind of attack, whereas if it was 468 * elsewhere, it wouldn't know if other matching 469 * packets had been seen. 470 */ 471 if (fin->fin_flx & FI_SHORT) { 472 ATOMIC_INCL(ipfr_stats.ifs_short); 473 continue; 474 } |
475 476 /* 477 * XXX - We really need to be guarding against the 478 * retransmission of (src,dst,id,offset-range) here 479 * because a fragmented packet is never resent with
|
318 * the same IP ID#.
|
480 * the same IP ID# (or shouldn't). |
481 */
|
482 off = ip->ip_off & IP_OFFMASK; |
483 if (f->ipfr_seen0) {
|
321 if (!off || (fin->fin_fl & FI_SHORT))
|
484 if (off == 0) { 485 ATOMIC_INCL(ipfr_stats.ifs_retrans0); |
486 continue;
|
323 } else if (!off)
|
487 } 488 } else if (off == 0) |
489 f->ipfr_seen0 = 1; 490 491 if (f != table[idx]) {
|
492 ipfr_t **fp; 493 |
494 /*
|
328 * move fragment info. to the top of the list
329 * to speed up searches.
|
495 * Move fragment info. to the top of the list 496 * to speed up searches. First, delink... |
497 */
|
331 if ((f->ipfr_prev->ipfr_next = f->ipfr_next))
332 f->ipfr_next->ipfr_prev = f->ipfr_prev;
333 f->ipfr_next = table[idx];
334 table[idx]->ipfr_prev = f;
335 f->ipfr_prev = NULL;
|
498 fp = f->ipfr_hprev; 499 (*fp) = f->ipfr_hnext; 500 if (f->ipfr_hnext != NULL) 501 f->ipfr_hnext->ipfr_hprev = fp; 502 /* 503 * Then put back at the top of the chain. 504 */ 505 f->ipfr_hnext = table[idx]; 506 table[idx]->ipfr_hprev = &f->ipfr_hnext; 507 f->ipfr_hprev = table + idx; |
508 table[idx] = f; 509 }
|
338 atoff = off + (fin->fin_dlen >> 3);
|
510 |
511 /* 512 * If we've follwed the fragments, and this is the 513 * last (in order), shrink expiration time. 514 */ 515 if (off == f->ipfr_off) { 516 if (!(ip->ip_off & IP_MF))
|
345 f->ipfr_ttl = 1;
346 else
347 f->ipfr_off = atoff;
348 }
|
517 f->ipfr_ttl = fr_ticks + 1; 518 f->ipfr_off = (fin->fin_dlen >> 3) + off; 519 } else if (f->ipfr_pass & FR_FRSTRICT) 520 continue; |
521 ATOMIC_INCL(ipfr_stats.ifs_hits); 522 return f; 523 } 524 return NULL; 525} 526 527
|
356/*
357 * functional interface for NAT lookups of the NAT fragment cache
358 */
359nat_t *ipfr_nat_knownfrag(ip, fin)
360ip_t *ip;
|
528/* ------------------------------------------------------------------------ */ 529/* Function: fr_nat_knownfrag */ 530/* Returns: nat_t* - pointer to 'parent' NAT structure if frag table */ 531/* match found, else NULL */ 532/* Parameters: fin(I) - pointer to packet information */ 533/* */ 534/* Functional interface for NAT lookups of the NAT fragment cache */ 535/* ------------------------------------------------------------------------ */ 536nat_t *fr_nat_knownfrag(fin) |
537fr_info_t *fin; 538{
|
363 ipfr_t *ipf;
364 nat_t *nat;
365 int off;
|
539 nat_t *nat; 540 ipfr_t *ipf; |
541
|
367 if ((fin->fin_v != 4) || (fr_frag_lock))
|
542 if ((fin->fin_v != 4) || (fr_frag_lock) || !ipfr_natlist) |
543 return NULL;
|
369
370 off = fin->fin_off;
371 off <<= 3;
372 if ((off + fin->fin_dlen) > 0xffff || (fin->fin_dlen == 0))
373 return NULL;
374
|
544 READ_ENTER(&ipf_natfrag);
|
376 ipf = ipfr_lookup(ip, fin, ipfr_nattab);
|
545 ipf = fr_fraglookup(fin, ipfr_nattab); |
546 if (ipf != NULL) { 547 nat = ipf->ipfr_data; 548 /* 549 * This is the last fragment for this packet. 550 */
|
382 if ((ipf->ipfr_ttl == 1) && (nat != NULL)) {
|
551 if ((ipf->ipfr_ttl == fr_ticks + 1) && (nat != NULL)) { |
552 nat->nat_data = NULL; 553 ipf->ipfr_data = NULL; 554 } 555 } else 556 nat = NULL; 557 RWLOCK_EXIT(&ipf_natfrag); 558 return nat; 559} 560 561
|
393/*
394 * functional interface for normal lookups of the fragment cache
395 */
396frentry_t *ipfr_knownfrag(ip, fin)
397ip_t *ip;
|
562/* ------------------------------------------------------------------------ */ 563/* Function: fr_ipid_knownfrag */ 564/* Returns: u_32_t - IPv4 ID for this packet if match found, else */ 565/* return 0xfffffff to indicate no match. */ 566/* Parameters: fin(I) - pointer to packet information */ 567/* */ 568/* Functional interface for IP ID lookups of the IP ID fragment cache */ 569/* ------------------------------------------------------------------------ */ 570u_32_t fr_ipid_knownfrag(fin) |
571fr_info_t *fin; 572{
|
400 frentry_t *fr;
401 ipfr_t *fra;
402 int off;
|
573 ipfr_t *ipf; 574 u_32_t id; |
575
|
404 if ((fin->fin_v != 4) || (fr_frag_lock))
405 return NULL;
|
576 if ((fin->fin_v != 4) || (fr_frag_lock) || !ipfr_ipidlist) 577 return 0xffffffff; |
578
|
407 off = fin->fin_off;
408 off <<= 3;
409 if ((off + fin->fin_dlen) > 0xffff || (fin->fin_dlen == 0))
|
579 READ_ENTER(&ipf_ipidfrag); 580 ipf = fr_fraglookup(fin, ipfr_ipidtab); 581 if (ipf != NULL) 582 id = (u_32_t)ipf->ipfr_data; 583 else 584 id = 0xffffffff; 585 RWLOCK_EXIT(&ipf_ipidfrag); 586 return id; 587} 588 589 590/* ------------------------------------------------------------------------ */ 591/* Function: fr_knownfrag */ 592/* Returns: frentry_t* - pointer to filter rule if a match is found in */ 593/* the frag cache table, else NULL. */ 594/* Parameters: fin(I) - pointer to packet information */ 595/* passp(O) - pointer to where to store rule flags resturned */ 596/* */ 597/* Functional interface for normal lookups of the fragment cache. If a */ 598/* match is found, return the rule pointer and flags from the rule, except */ 599/* that if FR_LOGFIRST is set, reset FR_LOG. */ 600/* ------------------------------------------------------------------------ */ 601frentry_t *fr_knownfrag(fin, passp) 602fr_info_t *fin; 603u_32_t *passp; 604{ 605 frentry_t *fr = NULL; 606 ipfr_t *fra; 607 u_32_t pass; 608 609 if ((fin->fin_v != 4) || (fr_frag_lock) || (ipfr_list == NULL)) |
610 return NULL; 611 612 READ_ENTER(&ipf_frag);
|
413 fra = ipfr_lookup(ip, fin, ipfr_heads);
414 if (fra != NULL)
|
613 fra = fr_fraglookup(fin, ipfr_heads); 614 if (fra != NULL) { |
615 fr = fra->ipfr_rule;
|
416 else
417 fr = NULL;
|
616 fin->fin_fr = fr; 617 if (fr != NULL) { 618 pass = fr->fr_flags; 619 if ((pass & FR_LOGFIRST) != 0) 620 pass &= ~(FR_LOGFIRST|FR_LOG); 621 *passp = pass; 622 } 623 } |
624 RWLOCK_EXIT(&ipf_frag); 625 return fr; 626} 627 628
|
423/*
424 * forget any references to this external object.
425 */
426void ipfr_forget(ptr)
|
629/* ------------------------------------------------------------------------ */ 630/* Function: fr_forget */ 631/* Returns: Nil */ 632/* Parameters: ptr(I) - pointer to data structure */ 633/* */ 634/* Search through all of the fragment cache entries and wherever a pointer */ 635/* is found to match ptr, reset it to NULL. */ 636/* ------------------------------------------------------------------------ */ 637void fr_forget(ptr) |
638void *ptr; 639{ 640 ipfr_t *fr;
|
430 int idx;
|
641 642 WRITE_ENTER(&ipf_frag);
|
433 for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
434 for (fr = ipfr_heads[idx]; fr; fr = fr->ipfr_next)
435 if (fr->ipfr_data == ptr)
436 fr->ipfr_data = NULL;
437
|
643 for (fr = ipfr_list; fr; fr = fr->ipfr_next) 644 if (fr->ipfr_data == ptr) 645 fr->ipfr_data = NULL; |
646 RWLOCK_EXIT(&ipf_frag); 647} 648 649
|
442/*
443 * forget any references to this external object.
444 */
445void ipfr_forgetnat(nat)
446void *nat;
|
650/* ------------------------------------------------------------------------ */ 651/* Function: fr_forgetnat */ 652/* Returns: Nil */ 653/* Parameters: ptr(I) - pointer to data structure */ 654/* */ 655/* Search through all of the fragment cache entries for NAT and wherever a */ 656/* pointer is found to match ptr, reset it to NULL. */ 657/* ------------------------------------------------------------------------ */ 658void fr_forgetnat(ptr) 659void *ptr; |
660{ 661 ipfr_t *fr;
|
449 int idx;
|
662 663 WRITE_ENTER(&ipf_natfrag);
|
452 for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
453 for (fr = ipfr_nattab[idx]; fr; fr = fr->ipfr_next)
454 if (fr->ipfr_data == nat)
455 fr->ipfr_data = NULL;
456
|
664 for (fr = ipfr_natlist; fr; fr = fr->ipfr_next) 665 if (fr->ipfr_data == ptr) 666 fr->ipfr_data = NULL; |
667 RWLOCK_EXIT(&ipf_natfrag); 668} 669 670
|
461static void ipfr_delete(fra)
462ipfr_t *fra;
|
671/* ------------------------------------------------------------------------ */ 672/* Function: fr_fragdelete */ 673/* Returns: Nil */ 674/* Parameters: fra(I) - pointer to fragment structure to delete */ 675/* tail(IO) - pointer to the pointer to the tail of the frag */ 676/* list */ 677/* */ 678/* Remove a fragment cache table entry from the table & list. Also free */ 679/* the filter rule it is associated with it if it is no longer used as a */ 680/* result of decreasing the reference count. */ 681/* ------------------------------------------------------------------------ */ 682static void fr_fragdelete(fra, tail) 683ipfr_t *fra, ***tail; |
684{ 685 frentry_t *fr; 686 687 fr = fra->ipfr_rule;
|
467 if (fr != NULL) {
468 ATOMIC_DEC32(fr->fr_ref);
469 if (fr->fr_ref == 0)
470 KFREE(fr);
471 }
472 if (fra->ipfr_prev)
473 fra->ipfr_prev->ipfr_next = fra->ipfr_next;
|
688 if (fr != NULL) 689 (void)fr_derefrule(&fr); 690 |
691 if (fra->ipfr_next) 692 fra->ipfr_next->ipfr_prev = fra->ipfr_prev;
|
693 *fra->ipfr_prev = fra->ipfr_next; 694 if (*tail == &fra->ipfr_next) 695 *tail = fra->ipfr_prev; 696 697 if (fra->ipfr_hnext) 698 fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev; 699 *fra->ipfr_hprev = fra->ipfr_hnext; |
700 KFREE(fra); 701} 702 703
|
480/*
481 * Free memory in use by fragment state info. kept.
482 */
483void ipfr_unload()
|
704/* ------------------------------------------------------------------------ */ 705/* Function: fr_fragclear */ 706/* Returns: Nil */ 707/* Parameters: Nil */ 708/* */ 709/* Free memory in use by fragment state information kept. Do the normal */ 710/* fragment state stuff first and then the NAT-fragment table. */ 711/* ------------------------------------------------------------------------ */ 712void fr_fragclear() |
713{
|
485 ipfr_t **fp, *fra;
|
714 ipfr_t *fra; |
715 nat_t *nat;
|
487 int idx;
|
716 717 WRITE_ENTER(&ipf_frag);
|
490 for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
491 for (fp = &ipfr_heads[idx]; (fra = *fp); ) {
492 *fp = fra->ipfr_next;
493 ipfr_delete(fra);
494 }
|
718 while ((fra = ipfr_list) != NULL) 719 fr_fragdelete(fra, &ipfr_tail); 720 ipfr_tail = &ipfr_list; |
721 RWLOCK_EXIT(&ipf_frag); 722 723 WRITE_ENTER(&ipf_nat); 724 WRITE_ENTER(&ipf_natfrag);
|
499 for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
500 for (fp = &ipfr_nattab[idx]; (fra = *fp); ) {
501 *fp = fra->ipfr_next;
502 nat = fra->ipfr_data;
503 if (nat != NULL) {
504 if (nat->nat_data == fra)
505 nat->nat_data = NULL;
506 }
507 ipfr_delete(fra);
|
725 while ((fra = ipfr_natlist) != NULL) { 726 nat = fra->ipfr_data; 727 if (nat != NULL) { 728 if (nat->nat_data == fra) 729 nat->nat_data = NULL; |
730 }
|
731 fr_fragdelete(fra, &ipfr_nattail); 732 } 733 ipfr_nattail = &ipfr_natlist; |
734 RWLOCK_EXIT(&ipf_natfrag); 735 RWLOCK_EXIT(&ipf_nat); 736} 737 738
|
514void ipfr_fragexpire()
|
739/* ------------------------------------------------------------------------ */ 740/* Function: fr_fragexpire */ 741/* Returns: Nil */ 742/* Parameters: Nil */ 743/* */ 744/* Expire entries in the fragment cache table that have been there too long */ 745/* ------------------------------------------------------------------------ */ 746void fr_fragexpire() |
747{ 748 ipfr_t **fp, *fra; 749 nat_t *nat;
|
518 int idx;
519#if defined(_KERNEL)
520# if !SOLARIS
|
750#if defined(USE_SPL) && defined(_KERNEL) |
751 int s;
|
522# endif
|
752#endif 753 754 if (fr_frag_lock) 755 return; 756 757 SPL_NET(s); 758 WRITE_ENTER(&ipf_frag);
|
530
|
759 /* 760 * Go through the entire table, looking for entries to expire,
|
533 * decreasing the ttl by one for each entry. If it reaches 0,
534 * remove it from the chain and free it.
|
761 * which is indicated by the ttl being less than or equal to fr_ticks. |
762 */
|
536 for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
537 for (fp = &ipfr_heads[idx]; (fra = *fp); ) {
538 --fra->ipfr_ttl;
539 if (fra->ipfr_ttl == 0) {
540 *fp = fra->ipfr_next;
541 ipfr_delete(fra);
542 ATOMIC_INCL(ipfr_stats.ifs_expire);
543 ATOMIC_DEC32(ipfr_inuse);
544 } else
545 fp = &fra->ipfr_next;
546 }
|
763 for (fp = &ipfr_list; ((fra = *fp) != NULL); ) { 764 if (fra->ipfr_ttl > fr_ticks) 765 break; 766 fr_fragdelete(fra, &ipfr_tail); 767 ipfr_stats.ifs_expire++; 768 ipfr_inuse--; 769 } |
770 RWLOCK_EXIT(&ipf_frag); 771
|
772 WRITE_ENTER(&ipf_ipidfrag); 773 for (fp = &ipfr_ipidlist; ((fra = *fp) != NULL); ) { 774 if (fra->ipfr_ttl > fr_ticks) 775 break; 776 fr_fragdelete(fra, &ipfr_ipidtail); 777 ipfr_stats.ifs_expire++; 778 ipfr_inuse--; 779 } 780 RWLOCK_EXIT(&ipf_ipidfrag); 781 |
782 /* 783 * Same again for the NAT table, except that if the structure also 784 * still points to a NAT structure, and the NAT structure points back 785 * at the one to be free'd, NULL the reference from the NAT struct. 786 * NOTE: We need to grab both mutex's early, and in this order so as 787 * to prevent a deadlock if both try to expire at the same time. 788 */ 789 WRITE_ENTER(&ipf_nat); 790 WRITE_ENTER(&ipf_natfrag);
|
558 for (idx = IPFT_SIZE - 1; idx >= 0; idx--)
559 for (fp = &ipfr_nattab[idx]; (fra = *fp); ) {
560 --fra->ipfr_ttl;
561 if (fra->ipfr_ttl == 0) {
562 ATOMIC_INCL(ipfr_stats.ifs_expire);
563 ATOMIC_DEC32(ipfr_inuse);
564 nat = fra->ipfr_data;
565 if (nat != NULL) {
566 if (nat->nat_data == fra)
567 nat->nat_data = NULL;
568 }
569 *fp = fra->ipfr_next;
570 ipfr_delete(fra);
571 } else
572 fp = &fra->ipfr_next;
|
791 for (fp = &ipfr_natlist; ((fra = *fp) != NULL); ) { 792 if (fra->ipfr_ttl > fr_ticks) 793 break; 794 nat = fra->ipfr_data; 795 if (nat != NULL) { 796 if (nat->nat_data == fra) 797 nat->nat_data = NULL; |
798 }
|
799 fr_fragdelete(fra, &ipfr_nattail); 800 ipfr_stats.ifs_expire++; 801 ipfr_inuse--; 802 } |
803 RWLOCK_EXIT(&ipf_natfrag); 804 RWLOCK_EXIT(&ipf_nat); 805 SPL_X(s); 806} 807 808
|
580/*
581 * Slowly expire held state for fragments. Timeouts are set * in expectation
582 * of this being called twice per second.
583 */
584#ifdef _KERNEL
585# if (BSD >= 199306) || SOLARIS || defined(__sgi)
586# if defined(SOLARIS2) && (SOLARIS2 < 7)
587void ipfr_slowtimer()
588# else
589void ipfr_slowtimer __P((void *ptr))
590# endif
|
809/* ------------------------------------------------------------------------ */ 810/* Function: fr_slowtimer */ 811/* Returns: Nil */ 812/* Parameters: Nil */ 813/* */ 814/* Slowly expire held state for fragments. Timeouts are set * in */ 815/* expectation of this being called twice per second. */ 816/* ------------------------------------------------------------------------ */ 817#if !defined(_KERNEL) || (!SOLARIS && !defined(__hpux) && !defined(__sgi) && \ 818 !defined(__osf__)) 819# if defined(_KERNEL) && ((BSD >= 199103) || defined(__sgi)) 820void fr_slowtimer __P((void *ptr)) |
821# else
|
592int ipfr_slowtimer()
|
822int fr_slowtimer() |
823# endif
|
594#else
595void ipfr_slowtimer()
596#endif
|
824{
|
598#if defined(_KERNEL) && SOLARIS
599 extern int fr_running;
|
825 READ_ENTER(&ipf_global); |
826
|
601 if (fr_running <= 0)
602 return;
603 READ_ENTER(&ipf_solaris);
604#endif
605
606#if defined(__sgi) && defined(_KERNEL)
607 ipfilter_sgi_intfsync();
608#endif
609
610 ipfr_fragexpire();
|
827 fr_fragexpire(); |
828 fr_timeoutstate();
|
612 ip_natexpire();
|
829 fr_natexpire(); |
830 fr_authexpire();
|
614#if defined(_KERNEL)
615# if SOLARIS
616 ipfr_timer_id = timeout(ipfr_slowtimer, NULL, drv_usectohz(500000));
617 RWLOCK_EXIT(&ipf_solaris);
618# else
|
831 fr_ticks++; 832 if (fr_running <= 0) 833 goto done; 834# ifdef _KERNEL |
835# if defined(__NetBSD__) && (__NetBSD_Version__ >= 104240000)
|
620 callout_reset(&ipfr_slowtimer_ch, hz / 2, ipfr_slowtimer, NULL);
|
836 callout_reset(&fr_slowtimer_ch, hz / 2, fr_slowtimer, NULL); |
837# else
|
622# if (__FreeBSD_version >= 300000)
623 ipfr_slowtimer_ch = timeout(ipfr_slowtimer, NULL, hz/2);
|
838# if defined(__OpenBSD__) 839 timeout_add(&fr_slowtimer_ch, hz/2); |
840# else
|
625# if defined(__OpenBSD__)
626 timeout_add(&ipfr_slowtimer_ch, hz/2);
|
841# if (__FreeBSD_version >= 300000) 842 fr_slowtimer_ch = timeout(fr_slowtimer, NULL, hz/2); |
843# else
|
628 timeout(ipfr_slowtimer, NULL, hz/2);
629# endif
630# endif
631# if (BSD < 199306) && !defined(__sgi)
632 return 0;
633# endif /* FreeBSD */
|
844# ifdef linux 845 ; 846# else 847 timeout(fr_slowtimer, NULL, hz/2); 848# endif 849# endif /* FreeBSD */ 850# endif /* OpenBSD */ |
851# endif /* NetBSD */
|
635# endif /* SOLARIS */
636#endif /* defined(_KERNEL) */
|
852# endif 853done: 854 RWLOCK_EXIT(&ipf_global); 855# if (BSD < 199103) || !defined(_KERNEL) 856 return 0; 857# endif |
858}
|
859#endif /* !SOLARIS && !defined(__hpux) && !defined(__sgi) */ |
|