1
2 /*
3 * Copyright (C) 2012 by Darren Reed.
4 *
5 * See the IPFILTER.LICENCE file for details on licencing.
6 */
7 #if defined(KERNEL) || defined(_KERNEL)
8 # undef KERNEL
9 # undef _KERNEL
10 # define KERNEL 1
11 # define _KERNEL 1
12 #endif
13 #include <sys/errno.h>
14 #include <sys/types.h>
15 #include <sys/param.h>
16 #include <sys/time.h>
17 #include <sys/file.h>
18 #if !defined(_KERNEL)
19 # include <stdio.h>
20 # include <string.h>
21 # include <stdlib.h>
22 # define _KERNEL
23 # include <sys/uio.h>
24 # undef _KERNEL
25 #endif
26 #if defined(_KERNEL) && defined(__FreeBSD__)
27 # include <sys/filio.h>
28 # include <sys/fcntl.h>
29 #else
30 # include <sys/ioctl.h>
31 #endif
32 # include <sys/protosw.h>
33 #include <sys/socket.h>
34 #if defined(_KERNEL)
35 # include <sys/systm.h>
36 # if !defined(__SVR4)
37 # include <sys/mbuf.h>
38 # endif
39 #endif
40 #if !defined(__SVR4)
41 # if defined(_KERNEL)
42 # include <sys/kernel.h>
43 # endif
44 #else
45 # include <sys/byteorder.h>
46 # ifdef _KERNEL
47 # include <sys/dditypes.h>
48 # endif
49 # include <sys/stream.h>
50 # include <sys/kmem.h>
51 #endif
52 #include <net/if.h>
53 #ifdef sun
54 # include <net/af.h>
55 #endif
56 #include <netinet/in.h>
57 #include <netinet/in_systm.h>
58 #include <netinet/ip.h>
59 # include <netinet/ip_var.h>
60 #include <netinet/tcp.h>
61 #include <netinet/udp.h>
62 #include <netinet/ip_icmp.h>
63 #include "netinet/ip_compat.h"
64 #include <netinet/tcpip.h>
65 #include "netinet/ip_fil.h"
66 #include "netinet/ip_nat.h"
67 #include "netinet/ip_frag.h"
68 #include "netinet/ip_state.h"
69 #include "netinet/ip_auth.h"
70 #include "netinet/ip_lookup.h"
71 #include "netinet/ip_proxy.h"
72 #include "netinet/ip_sync.h"
73 /* END OF INCLUDES */
74
75 #if !defined(lint)
76 static const char sccsid[] = "@(#)ip_frag.c 1.11 3/24/96 (C) 1993-2000 Darren Reed";
77 /* static const char rcsid[] = "@(#)$Id: ip_frag.c,v 2.77.2.12 2007/09/20 12:51:51 darrenr Exp $"; */
78 #endif
79
80
81 #ifdef USE_MUTEXES
82 static ipfr_t *ipfr_frag_new(ipf_main_softc_t *, ipf_frag_softc_t *,
83 fr_info_t *, u_32_t, ipfr_t **,
84 ipfrwlock_t *);
85 static ipfr_t *ipf_frag_lookup(ipf_main_softc_t *, ipf_frag_softc_t *, fr_info_t *, ipfr_t **, ipfrwlock_t *);
86 static void ipf_frag_deref(void *, ipfr_t **, ipfrwlock_t *);
87 static int ipf_frag_next(ipf_main_softc_t *, ipftoken_t *, ipfgeniter_t *,
88 ipfr_t **, ipfrwlock_t *);
89 #else
90 static ipfr_t *ipfr_frag_new(ipf_main_softc_t *, ipf_frag_softc_t *,
91 fr_info_t *, u_32_t, ipfr_t **);
92 static ipfr_t *ipf_frag_lookup(ipf_main_softc_t *, ipf_frag_softc_t *, fr_info_t *, ipfr_t **);
93 static void ipf_frag_deref(void *, ipfr_t **);
94 static int ipf_frag_next(ipf_main_softc_t *, ipftoken_t *, ipfgeniter_t *,
95 ipfr_t **);
96 #endif
97 static void ipf_frag_delete(ipf_main_softc_t *, ipfr_t *, ipfr_t ***);
98 static void ipf_frag_free(ipf_frag_softc_t *, ipfr_t *);
99
100 static frentry_t ipfr_block;
101
102 static ipftuneable_t ipf_frag_tuneables[] = {
103 { { (void *)offsetof(ipf_frag_softc_t, ipfr_size) },
104 "frag_size", 1, 0x7fffffff,
105 stsizeof(ipf_frag_softc_t, ipfr_size),
106 IPFT_WRDISABLED, NULL, NULL },
107 { { (void *)offsetof(ipf_frag_softc_t, ipfr_ttl) },
108 "frag_ttl", 1, 0x7fffffff,
109 stsizeof(ipf_frag_softc_t, ipfr_ttl),
110 0, NULL, NULL },
111 { { NULL },
112 NULL, 0, 0,
113 0,
114 0, NULL, NULL }
115 };
116
117 #define FBUMP(x) softf->ipfr_stats.x++
118 #define FBUMPD(x) do { softf->ipfr_stats.x++; DT(x); } while (0)
119
120
121 /* ------------------------------------------------------------------------ */
122 /* Function: ipf_frag_main_load */
123 /* Returns: int - 0 == success, -1 == error */
124 /* Parameters: Nil */
125 /* */
126 /* Initialise the filter rule associted with blocked packets - everyone can */
127 /* use it. */
128 /* ------------------------------------------------------------------------ */
129 int
ipf_frag_main_load(void)130 ipf_frag_main_load(void)
131 {
132 bzero((char *)&ipfr_block, sizeof(ipfr_block));
133 ipfr_block.fr_flags = FR_BLOCK|FR_QUICK;
134 ipfr_block.fr_ref = 1;
135
136 return (0);
137 }
138
139
140 /* ------------------------------------------------------------------------ */
141 /* Function: ipf_frag_main_unload */
142 /* Returns: int - 0 == success, -1 == error */
143 /* Parameters: Nil */
144 /* */
145 /* A null-op function that exists as a placeholder so that the flow in */
146 /* other functions is obvious. */
147 /* ------------------------------------------------------------------------ */
148 int
ipf_frag_main_unload(void)149 ipf_frag_main_unload(void)
150 {
151 return (0);
152 }
153
154
155 /* ------------------------------------------------------------------------ */
156 /* Function: ipf_frag_soft_create */
157 /* Returns: void * - NULL = failure, else pointer to local context */
158 /* Parameters: softc(I) - pointer to soft context main structure */
159 /* */
160 /* Allocate a new soft context structure to track fragment related info. */
161 /* ------------------------------------------------------------------------ */
162 /*ARGSUSED*/
163 void *
ipf_frag_soft_create(ipf_main_softc_t * softc)164 ipf_frag_soft_create(ipf_main_softc_t *softc)
165 {
166 ipf_frag_softc_t *softf;
167
168 KMALLOC(softf, ipf_frag_softc_t *);
169 if (softf == NULL)
170 return (NULL);
171
172 bzero((char *)softf, sizeof(*softf));
173
174 RWLOCK_INIT(&softf->ipfr_ipidfrag, "frag ipid lock");
175 RWLOCK_INIT(&softf->ipfr_frag, "ipf fragment rwlock");
176 RWLOCK_INIT(&softf->ipfr_natfrag, "ipf NAT fragment rwlock");
177
178 softf->ipf_frag_tune = ipf_tune_array_copy(softf,
179 sizeof(ipf_frag_tuneables),
180 ipf_frag_tuneables);
181 if (softf->ipf_frag_tune == NULL) {
182 ipf_frag_soft_destroy(softc, softf);
183 return (NULL);
184 }
185 if (ipf_tune_array_link(softc, softf->ipf_frag_tune) == -1) {
186 ipf_frag_soft_destroy(softc, softf);
187 return (NULL);
188 }
189
190 softf->ipfr_size = IPFT_SIZE;
191 softf->ipfr_ttl = IPF_TTLVAL(60);
192 softf->ipfr_lock = 1;
193 softf->ipfr_tail = &softf->ipfr_list;
194 softf->ipfr_nattail = &softf->ipfr_natlist;
195 softf->ipfr_ipidtail = &softf->ipfr_ipidlist;
196
197 return (softf);
198 }
199
200
201 /* ------------------------------------------------------------------------ */
202 /* Function: ipf_frag_soft_destroy */
203 /* Returns: Nil */
204 /* Parameters: softc(I) - pointer to soft context main structure */
205 /* arg(I) - pointer to local context to use */
206 /* */
207 /* Initialise the hash tables for the fragment cache lookups. */
208 /* ------------------------------------------------------------------------ */
209 void
ipf_frag_soft_destroy(ipf_main_softc_t * softc,void * arg)210 ipf_frag_soft_destroy(ipf_main_softc_t *softc, void *arg)
211 {
212 ipf_frag_softc_t *softf = arg;
213
214 RW_DESTROY(&softf->ipfr_ipidfrag);
215 RW_DESTROY(&softf->ipfr_frag);
216 RW_DESTROY(&softf->ipfr_natfrag);
217
218 if (softf->ipf_frag_tune != NULL) {
219 ipf_tune_array_unlink(softc, softf->ipf_frag_tune);
220 KFREES(softf->ipf_frag_tune, sizeof(ipf_frag_tuneables));
221 softf->ipf_frag_tune = NULL;
222 }
223
224 KFREE(softf);
225 }
226
227
228 /* ------------------------------------------------------------------------ */
229 /* Function: ipf_frag_soft_init */
230 /* Returns: int - 0 == success, -1 == error */
231 /* Parameters: softc(I) - pointer to soft context main structure */
232 /* arg(I) - pointer to local context to use */
233 /* */
234 /* Initialise the hash tables for the fragment cache lookups. */
235 /* ------------------------------------------------------------------------ */
236 /*ARGSUSED*/
237 int
ipf_frag_soft_init(ipf_main_softc_t * softc,void * arg)238 ipf_frag_soft_init(ipf_main_softc_t *softc, void *arg)
239 {
240 ipf_frag_softc_t *softf = arg;
241
242 KMALLOCS(softf->ipfr_heads, ipfr_t **,
243 softf->ipfr_size * sizeof(ipfr_t *));
244 if (softf->ipfr_heads == NULL)
245 return (-1);
246
247 bzero((char *)softf->ipfr_heads, softf->ipfr_size * sizeof(ipfr_t *));
248
249 KMALLOCS(softf->ipfr_nattab, ipfr_t **,
250 softf->ipfr_size * sizeof(ipfr_t *));
251 if (softf->ipfr_nattab == NULL)
252 return (-2);
253
254 bzero((char *)softf->ipfr_nattab, softf->ipfr_size * sizeof(ipfr_t *));
255
256 KMALLOCS(softf->ipfr_ipidtab, ipfr_t **,
257 softf->ipfr_size * sizeof(ipfr_t *));
258 if (softf->ipfr_ipidtab == NULL)
259 return (-3);
260
261 bzero((char *)softf->ipfr_ipidtab,
262 softf->ipfr_size * sizeof(ipfr_t *));
263
264 softf->ipfr_lock = 0;
265 softf->ipfr_inited = 1;
266
267 return (0);
268 }
269
270
271 /* ------------------------------------------------------------------------ */
272 /* Function: ipf_frag_soft_fini */
273 /* Returns: int - 0 == success, -1 == error */
274 /* Parameters: softc(I) - pointer to soft context main structure */
275 /* arg(I) - pointer to local context to use */
276 /* */
277 /* Free all memory allocated whilst running and from initialisation. */
278 /* ------------------------------------------------------------------------ */
279 int
ipf_frag_soft_fini(ipf_main_softc_t * softc,void * arg)280 ipf_frag_soft_fini(ipf_main_softc_t *softc, void *arg)
281 {
282 ipf_frag_softc_t *softf = arg;
283
284 softf->ipfr_lock = 1;
285
286 if (softf->ipfr_inited == 1) {
287 ipf_frag_clear(softc);
288
289 softf->ipfr_inited = 0;
290 }
291
292 if (softf->ipfr_heads != NULL)
293 KFREES(softf->ipfr_heads,
294 softf->ipfr_size * sizeof(ipfr_t *));
295 softf->ipfr_heads = NULL;
296
297 if (softf->ipfr_nattab != NULL)
298 KFREES(softf->ipfr_nattab,
299 softf->ipfr_size * sizeof(ipfr_t *));
300 softf->ipfr_nattab = NULL;
301
302 if (softf->ipfr_ipidtab != NULL)
303 KFREES(softf->ipfr_ipidtab,
304 softf->ipfr_size * sizeof(ipfr_t *));
305 softf->ipfr_ipidtab = NULL;
306
307 return (0);
308 }
309
310
311 /* ------------------------------------------------------------------------ */
312 /* Function: ipf_frag_set_lock */
313 /* Returns: Nil */
314 /* Parameters: arg(I) - pointer to local context to use */
315 /* tmp(I) - new value for lock */
316 /* */
317 /* Stub function that allows for external manipulation of ipfr_lock */
318 /* ------------------------------------------------------------------------ */
319 void
ipf_frag_setlock(void * arg,int tmp)320 ipf_frag_setlock(void *arg, int tmp)
321 {
322 ipf_frag_softc_t *softf = arg;
323
324 softf->ipfr_lock = tmp;
325 }
326
327
328 /* ------------------------------------------------------------------------ */
329 /* Function: ipf_frag_stats */
330 /* Returns: ipfrstat_t* - pointer to struct with current frag stats */
331 /* Parameters: arg(I) - pointer to local context to use */
332 /* */
333 /* Updates ipfr_stats with current information and returns a pointer to it */
334 /* ------------------------------------------------------------------------ */
335 ipfrstat_t *
ipf_frag_stats(void * arg)336 ipf_frag_stats(void *arg)
337 {
338 ipf_frag_softc_t *softf = arg;
339
340 softf->ipfr_stats.ifs_table = softf->ipfr_heads;
341 softf->ipfr_stats.ifs_nattab = softf->ipfr_nattab;
342 return (&softf->ipfr_stats);
343 }
344
345
346 /* ------------------------------------------------------------------------ */
347 /* Function: ipfr_frag_new */
348 /* Returns: ipfr_t * - pointer to fragment cache state info or NULL */
349 /* Parameters: fin(I) - pointer to packet information */
350 /* table(I) - pointer to frag table to add to */
351 /* lock(I) - pointer to lock to get a write hold of */
352 /* */
353 /* Add a new entry to the fragment cache, registering it as having come */
354 /* through this box, with the result of the filter operation. */
355 /* */
356 /* If this function succeeds, it returns with a write lock held on "lock". */
357 /* If it fails, no lock is held on return. */
358 /* ------------------------------------------------------------------------ */
359 static ipfr_t *
ipfr_frag_new(ipf_main_softc_t * softc,ipf_frag_softc_t * softf,fr_info_t * fin,u_32_t pass,ipfr_t * table[],ipfrwlock_t * lock)360 ipfr_frag_new(ipf_main_softc_t *softc, ipf_frag_softc_t *softf,
361 fr_info_t *fin, u_32_t pass, ipfr_t *table[]
362 #ifdef USE_MUTEXES
363 , ipfrwlock_t *lock
364 #endif
365 )
366 {
367 ipfr_t *fra, frag, *fran;
368 u_int idx, off;
369 frentry_t *fr;
370
371 if (softf->ipfr_stats.ifs_inuse >= softf->ipfr_size) {
372 FBUMPD(ifs_maximum);
373 return (NULL);
374 }
375
376 if ((fin->fin_flx & (FI_FRAG|FI_BAD)) != FI_FRAG) {
377 FBUMPD(ifs_newbad);
378 return (NULL);
379 }
380
381 if (pass & FR_FRSTRICT) {
382 if (fin->fin_off != 0) {
383 FBUMPD(ifs_newrestrictnot0);
384 return (NULL);
385 }
386 }
387
388 memset(&frag, 0, sizeof(frag));
389 frag.ipfr_v = fin->fin_v;
390 idx = fin->fin_v;
391 frag.ipfr_p = fin->fin_p;
392 idx += fin->fin_p;
393 frag.ipfr_id = fin->fin_id;
394 idx += fin->fin_id;
395 frag.ipfr_source = fin->fin_fi.fi_src;
396 idx += frag.ipfr_src.s_addr;
397 frag.ipfr_dest = fin->fin_fi.fi_dst;
398 idx += frag.ipfr_dst.s_addr;
399 frag.ipfr_ifp = fin->fin_ifp;
400 idx *= 127;
401 idx %= softf->ipfr_size;
402
403 frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
404 frag.ipfr_secmsk = fin->fin_fi.fi_secmsk;
405 frag.ipfr_auth = fin->fin_fi.fi_auth;
406
407 off = fin->fin_off >> 3;
408 if (off == 0) {
409 char *ptr;
410 int end;
411
412 #ifdef USE_INET6
413 if (fin->fin_v == 6) {
414
415 ptr = (char *)fin->fin_fraghdr +
416 sizeof(struct ip6_frag);
417 } else
418 #endif
419 {
420 ptr = fin->fin_dp;
421 }
422 end = fin->fin_plen - (ptr - (char *)fin->fin_ip);
423 frag.ipfr_firstend = end >> 3;
424 } else {
425 frag.ipfr_firstend = 0;
426 }
427
428 /*
429 * allocate some memory, if possible, if not, just record that we
430 * failed to do so.
431 */
432 KMALLOC(fran, ipfr_t *);
433 if (fran == NULL) {
434 FBUMPD(ifs_nomem);
435 return (NULL);
436 }
437 memset(fran, 0, sizeof(*fran));
438
439 WRITE_ENTER(lock);
440
441 /*
442 * first, make sure it isn't already there...
443 */
444 for (fra = table[idx]; (fra != NULL); fra = fra->ipfr_hnext)
445 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp,
446 IPFR_CMPSZ)) {
447 RWLOCK_EXIT(lock);
448 FBUMPD(ifs_exists);
449 KFREE(fran);
450 return (NULL);
451 }
452
453 fra = fran;
454 fran = NULL;
455 fr = fin->fin_fr;
456 fra->ipfr_rule = fr;
457 if (fr != NULL) {
458 MUTEX_ENTER(&fr->fr_lock);
459 fr->fr_ref++;
460 MUTEX_EXIT(&fr->fr_lock);
461 }
462
463 /*
464 * Insert the fragment into the fragment table, copy the struct used
465 * in the search using bcopy rather than reassign each field.
466 * Set the ttl to the default.
467 */
468 if ((fra->ipfr_hnext = table[idx]) != NULL)
469 table[idx]->ipfr_hprev = &fra->ipfr_hnext;
470 fra->ipfr_hprev = table + idx;
471 fra->ipfr_data = NULL;
472 table[idx] = fra;
473 bcopy((char *)&frag.ipfr_ifp, (char *)&fra->ipfr_ifp, IPFR_CMPSZ);
474 fra->ipfr_v = fin->fin_v;
475 fra->ipfr_p = fin->fin_p;
476 fra->ipfr_ttl = softc->ipf_ticks + softf->ipfr_ttl;
477 fra->ipfr_firstend = frag.ipfr_firstend;
478
479 /*
480 * Compute the offset of the expected start of the next packet.
481 */
482 if (off == 0)
483 fra->ipfr_seen0 = 1;
484 fra->ipfr_off = off + (fin->fin_dlen >> 3);
485 fra->ipfr_pass = pass;
486 fra->ipfr_ref = 1;
487 fra->ipfr_pkts = 1;
488 fra->ipfr_bytes = fin->fin_plen;
489 FBUMP(ifs_inuse);
490 FBUMP(ifs_new);
491 return (fra);
492 }
493
494
495 /* ------------------------------------------------------------------------ */
496 /* Function: ipf_frag_new */
497 /* Returns: int - 0 == success, -1 == error */
498 /* Parameters: fin(I) - pointer to packet information */
499 /* */
500 /* Add a new entry to the fragment cache table based on the current packet */
501 /* ------------------------------------------------------------------------ */
502 int
ipf_frag_new(ipf_main_softc_t * softc,fr_info_t * fin,u_32_t pass)503 ipf_frag_new(ipf_main_softc_t *softc, fr_info_t *fin, u_32_t pass)
504 {
505 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
506 ipfr_t *fra;
507
508 if (softf->ipfr_lock != 0)
509 return (-1);
510
511 #ifdef USE_MUTEXES
512 fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_heads, &softc->ipf_frag);
513 #else
514 fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_heads);
515 #endif
516 if (fra != NULL) {
517 *softf->ipfr_tail = fra;
518 fra->ipfr_prev = softf->ipfr_tail;
519 softf->ipfr_tail = &fra->ipfr_next;
520 fra->ipfr_next = NULL;
521 RWLOCK_EXIT(&softc->ipf_frag);
522 }
523 return (fra ? 0 : -1);
524 }
525
526
527 /* ------------------------------------------------------------------------ */
528 /* Function: ipf_frag_natnew */
529 /* Returns: int - 0 == success, -1 == error */
530 /* Parameters: fin(I) - pointer to packet information */
531 /* nat(I) - pointer to NAT structure */
532 /* */
533 /* Create a new NAT fragment cache entry based on the current packet and */
534 /* the NAT structure for this "session". */
535 /* ------------------------------------------------------------------------ */
536 int
ipf_frag_natnew(ipf_main_softc_t * softc,fr_info_t * fin,u_32_t pass,nat_t * nat)537 ipf_frag_natnew(ipf_main_softc_t *softc, fr_info_t *fin, u_32_t pass,
538 nat_t *nat)
539 {
540 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
541 ipfr_t *fra;
542
543 if (softf->ipfr_lock != 0)
544 return (0);
545
546 #ifdef USE_MUTEXES
547 fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_nattab,
548 &softf->ipfr_natfrag);
549 #else
550 fra = ipfr_frag_new(softc, softf, fin, pass, softf->ipfr_nattab);
551 #endif
552 if (fra != NULL) {
553 fra->ipfr_data = nat;
554 nat->nat_data = fra;
555 *softf->ipfr_nattail = fra;
556 fra->ipfr_prev = softf->ipfr_nattail;
557 softf->ipfr_nattail = &fra->ipfr_next;
558 fra->ipfr_next = NULL;
559 RWLOCK_EXIT(&softf->ipfr_natfrag);
560 return (0);
561 }
562 return (-1);
563 }
564
565
566 /* ------------------------------------------------------------------------ */
567 /* Function: ipf_frag_ipidnew */
568 /* Returns: int - 0 == success, -1 == error */
569 /* Parameters: fin(I) - pointer to packet information */
570 /* ipid(I) - new IP ID for this fragmented packet */
571 /* */
572 /* Create a new fragment cache entry for this packet and store, as a data */
573 /* pointer, the new IP ID value. */
574 /* ------------------------------------------------------------------------ */
575 int
ipf_frag_ipidnew(fr_info_t * fin,u_32_t ipid)576 ipf_frag_ipidnew(fr_info_t *fin, u_32_t ipid)
577 {
578 ipf_main_softc_t *softc = fin->fin_main_soft;
579 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
580 ipfr_t *fra;
581
582 if (softf->ipfr_lock)
583 return (0);
584
585 #ifdef USE_MUTEXES
586 fra = ipfr_frag_new(softc, softf, fin, 0, softf->ipfr_ipidtab, &softf->ipfr_ipidfrag);
587 #else
588 fra = ipfr_frag_new(softc, softf, fin, 0, softf->ipfr_ipidtab);
589 #endif
590 if (fra != NULL) {
591 fra->ipfr_data = (void *)(intptr_t)ipid;
592 *softf->ipfr_ipidtail = fra;
593 fra->ipfr_prev = softf->ipfr_ipidtail;
594 softf->ipfr_ipidtail = &fra->ipfr_next;
595 fra->ipfr_next = NULL;
596 RWLOCK_EXIT(&softf->ipfr_ipidfrag);
597 }
598 return (fra ? 0 : -1);
599 }
600
601
602 /* ------------------------------------------------------------------------ */
603 /* Function: ipf_frag_lookup */
604 /* Returns: ipfr_t * - pointer to ipfr_t structure if there's a */
605 /* matching entry in the frag table, else NULL */
606 /* Parameters: fin(I) - pointer to packet information */
607 /* table(I) - pointer to fragment cache table to search */
608 /* */
609 /* Check the fragment cache to see if there is already a record of this */
610 /* packet with its filter result known. */
611 /* */
612 /* If this function succeeds, it returns with a write lock held on "lock". */
613 /* If it fails, no lock is held on return. */
614 /* ------------------------------------------------------------------------ */
615 static ipfr_t *
ipf_frag_lookup(ipf_main_softc_t * softc,ipf_frag_softc_t * softf,fr_info_t * fin,ipfr_t * table[],ipfrwlock_t * lock)616 ipf_frag_lookup(ipf_main_softc_t *softc, ipf_frag_softc_t *softf,
617 fr_info_t *fin, ipfr_t *table[]
618 #ifdef USE_MUTEXES
619 , ipfrwlock_t *lock
620 #endif
621 )
622 {
623 ipfr_t *f, frag;
624 u_int idx;
625
626 /*
627 * We don't want to let short packets match because they could be
628 * compromising the security of other rules that want to match on
629 * layer 4 fields (and can't because they have been fragmented off.)
630 * Why do this check here? The counter acts as an indicator of this
631 * kind of attack, whereas if it was elsewhere, it wouldn't know if
632 * other matching packets had been seen.
633 */
634 if (fin->fin_flx & FI_SHORT) {
635 FBUMPD(ifs_short);
636 return (NULL);
637 }
638
639 if ((fin->fin_flx & FI_BAD) != 0) {
640 FBUMPD(ifs_bad);
641 return (NULL);
642 }
643
644 /*
645 * For fragments, we record protocol, packet id, TOS and both IP#'s
646 * (these should all be the same for all fragments of a packet).
647 *
648 * build up a hash value to index the table with.
649 */
650 memset(&frag, 0, sizeof(frag));
651 frag.ipfr_v = fin->fin_v;
652 idx = fin->fin_v;
653 frag.ipfr_p = fin->fin_p;
654 idx += fin->fin_p;
655 frag.ipfr_id = fin->fin_id;
656 idx += fin->fin_id;
657 frag.ipfr_source = fin->fin_fi.fi_src;
658 idx += frag.ipfr_src.s_addr;
659 frag.ipfr_dest = fin->fin_fi.fi_dst;
660 idx += frag.ipfr_dst.s_addr;
661 frag.ipfr_ifp = fin->fin_ifp;
662 idx *= 127;
663 idx %= softf->ipfr_size;
664
665 frag.ipfr_optmsk = fin->fin_fi.fi_optmsk & IPF_OPTCOPY;
666 frag.ipfr_secmsk = fin->fin_fi.fi_secmsk;
667 frag.ipfr_auth = fin->fin_fi.fi_auth;
668
669 READ_ENTER(lock);
670
671 /*
672 * check the table, careful to only compare the right amount of data
673 */
674 for (f = table[idx]; f; f = f->ipfr_hnext) {
675 if (!bcmp((char *)&frag.ipfr_ifp, (char *)&f->ipfr_ifp,
676 IPFR_CMPSZ)) {
677 u_short off;
678
679 /*
680 * XXX - We really need to be guarding against the
681 * retransmission of (src,dst,id,offset-range) here
682 * because a fragmented packet is never resent with
683 * the same IP ID# (or shouldn't).
684 */
685 off = fin->fin_off >> 3;
686 if (f->ipfr_seen0) {
687 if (off == 0) {
688 FBUMPD(ifs_retrans0);
689 continue;
690 }
691
692 /*
693 * Case 3. See comment for frpr_fragment6.
694 */
695 if ((f->ipfr_firstend != 0) &&
696 (off < f->ipfr_firstend)) {
697 FBUMP(ifs_overlap);
698 DT2(ifs_overlap, u_short, off,
699 ipfr_t *, f);
700 DT3(ipf_fi_bad_ifs_overlap, fr_info_t *, fin, u_short, off,
701 ipfr_t *, f);
702 fin->fin_flx |= FI_BAD;
703 break;
704 }
705 } else if (off == 0)
706 f->ipfr_seen0 = 1;
707
708 if (f != table[idx] && MUTEX_TRY_UPGRADE(lock)) {
709 ipfr_t **fp;
710
711 /*
712 * Move fragment info. to the top of the list
713 * to speed up searches. First, delink...
714 */
715 fp = f->ipfr_hprev;
716 (*fp) = f->ipfr_hnext;
717 if (f->ipfr_hnext != NULL)
718 f->ipfr_hnext->ipfr_hprev = fp;
719 /*
720 * Then put back at the top of the chain.
721 */
722 f->ipfr_hnext = table[idx];
723 table[idx]->ipfr_hprev = &f->ipfr_hnext;
724 f->ipfr_hprev = table + idx;
725 table[idx] = f;
726 MUTEX_DOWNGRADE(lock);
727 }
728
729 /*
730 * If we've follwed the fragments, and this is the
731 * last (in order), shrink expiration time.
732 */
733 if (off == f->ipfr_off) {
734 f->ipfr_off = (fin->fin_dlen >> 3) + off;
735
736 /*
737 * Well, we could shrink the expiration time
738 * but only if every fragment has been seen
739 * in order upto this, the last. ipfr_badorder
740 * is used here to count those out of order
741 * and if it equals 0 when we get to the last
742 * fragment then we can assume all of the
743 * fragments have been seen and in order.
744 */
745 #if 0
746 /*
747 * Doing this properly requires moving it to
748 * the head of the list which is infesible.
749 */
750 if ((more == 0) && (f->ipfr_badorder == 0))
751 f->ipfr_ttl = softc->ipf_ticks + 1;
752 #endif
753 } else {
754 f->ipfr_badorder++;
755 FBUMPD(ifs_unordered);
756 if (f->ipfr_pass & FR_FRSTRICT) {
757 FBUMPD(ifs_strict);
758 continue;
759 }
760 }
761 f->ipfr_pkts++;
762 f->ipfr_bytes += fin->fin_plen;
763 FBUMP(ifs_hits);
764 return (f);
765 }
766 }
767
768 RWLOCK_EXIT(lock);
769 FBUMP(ifs_miss);
770 return (NULL);
771 }
772
773
774 /* ------------------------------------------------------------------------ */
775 /* Function: ipf_frag_natknown */
776 /* Returns: nat_t* - pointer to 'parent' NAT structure if frag table */
777 /* match found, else NULL */
778 /* Parameters: fin(I) - pointer to packet information */
779 /* */
780 /* Functional interface for NAT lookups of the NAT fragment cache */
781 /* ------------------------------------------------------------------------ */
782 nat_t *
ipf_frag_natknown(fr_info_t * fin)783 ipf_frag_natknown(fr_info_t *fin)
784 {
785 ipf_main_softc_t *softc = fin->fin_main_soft;
786 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
787 nat_t *nat;
788 ipfr_t *ipf;
789
790 if ((softf->ipfr_lock) || !softf->ipfr_natlist)
791 return (NULL);
792 #ifdef USE_MUTEXES
793 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_nattab,
794 &softf->ipfr_natfrag);
795 #else
796 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_nattab);
797 #endif
798 if (ipf != NULL) {
799 nat = ipf->ipfr_data;
800 /*
801 * This is the last fragment for this packet.
802 */
803 if ((ipf->ipfr_ttl == softc->ipf_ticks + 1) && (nat != NULL)) {
804 nat->nat_data = NULL;
805 ipf->ipfr_data = NULL;
806 }
807 RWLOCK_EXIT(&softf->ipfr_natfrag);
808 } else
809 nat = NULL;
810 return (nat);
811 }
812
813
814 /* ------------------------------------------------------------------------ */
815 /* Function: ipf_frag_ipidknown */
816 /* Returns: u_32_t - IPv4 ID for this packet if match found, else */
817 /* return 0xfffffff to indicate no match. */
818 /* Parameters: fin(I) - pointer to packet information */
819 /* */
820 /* Functional interface for IP ID lookups of the IP ID fragment cache */
821 /* ------------------------------------------------------------------------ */
822 u_32_t
ipf_frag_ipidknown(fr_info_t * fin)823 ipf_frag_ipidknown(fr_info_t *fin)
824 {
825 ipf_main_softc_t *softc = fin->fin_main_soft;
826 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
827 ipfr_t *ipf;
828 u_32_t id;
829
830 if (softf->ipfr_lock || !softf->ipfr_ipidlist)
831 return (0xffffffff);
832
833 #ifdef USE_MUTEXES
834 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_ipidtab,
835 &softf->ipfr_ipidfrag);
836 #else
837 ipf = ipf_frag_lookup(softc, softf, fin, softf->ipfr_ipidtab);
838 #endif
839 if (ipf != NULL) {
840 id = (u_32_t)(intptr_t)ipf->ipfr_data;
841 RWLOCK_EXIT(&softf->ipfr_ipidfrag);
842 } else
843 id = 0xffffffff;
844 return (id);
845 }
846
847
848 /* ------------------------------------------------------------------------ */
849 /* Function: ipf_frag_known */
850 /* Returns: frentry_t* - pointer to filter rule if a match is found in */
851 /* the frag cache table, else NULL. */
852 /* Parameters: fin(I) - pointer to packet information */
853 /* passp(O) - pointer to where to store rule flags resturned */
854 /* */
855 /* Functional interface for normal lookups of the fragment cache. If a */
856 /* match is found, return the rule pointer and flags from the rule, except */
857 /* that if FR_LOGFIRST is set, reset FR_LOG. */
858 /* ------------------------------------------------------------------------ */
859 frentry_t *
ipf_frag_known(fr_info_t * fin,u_32_t * passp)860 ipf_frag_known(fr_info_t *fin, u_32_t *passp)
861 {
862 ipf_main_softc_t *softc = fin->fin_main_soft;
863 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
864 frentry_t *fr = NULL;
865 ipfr_t *fra;
866 u_32_t pass;
867
868 if ((softf->ipfr_lock) || (softf->ipfr_list == NULL))
869 return (NULL);
870
871 #ifdef USE_MUTEXES
872 fra = ipf_frag_lookup(softc, softf, fin, softf->ipfr_heads,
873 &softc->ipf_frag);
874 #else
875 fra = ipf_frag_lookup(softc, softf, fin, softf->ipfr_heads);
876 #endif
877 if (fra != NULL) {
878 if (fin->fin_flx & FI_BAD) {
879 fr = &ipfr_block;
880 fin->fin_reason = FRB_BADFRAG;
881 DT2(ipf_frb_badfrag, fr_info_t *, fin, uint, fra);
882 } else {
883 fr = fra->ipfr_rule;
884 }
885 fin->fin_fr = fr;
886 if (fr != NULL) {
887 pass = fr->fr_flags;
888 if ((pass & FR_KEEPSTATE) != 0) {
889 fin->fin_flx |= FI_STATE;
890 /*
891 * Reset the keep state flag here so that we
892 * don't try and add a new state entry because
893 * of a match here. That leads to blocking of
894 * the packet later because the add fails.
895 */
896 pass &= ~FR_KEEPSTATE;
897 }
898 if ((pass & FR_LOGFIRST) != 0)
899 pass &= ~(FR_LOGFIRST|FR_LOG);
900 *passp = pass;
901 }
902 RWLOCK_EXIT(&softc->ipf_frag);
903 }
904 return (fr);
905 }
906
907
908 /* ------------------------------------------------------------------------ */
909 /* Function: ipf_frag_natforget */
910 /* Returns: Nil */
911 /* Parameters: softc(I) - pointer to soft context main structure */
912 /* ptr(I) - pointer to data structure */
913 /* */
914 /* Search through all of the fragment cache entries for NAT and wherever a */
915 /* pointer is found to match ptr, reset it to NULL. */
916 /* ------------------------------------------------------------------------ */
917 void
ipf_frag_natforget(ipf_main_softc_t * softc,void * ptr)918 ipf_frag_natforget(ipf_main_softc_t *softc, void *ptr)
919 {
920 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
921 ipfr_t *fr;
922
923 WRITE_ENTER(&softf->ipfr_natfrag);
924 for (fr = softf->ipfr_natlist; fr; fr = fr->ipfr_next)
925 if (fr->ipfr_data == ptr)
926 fr->ipfr_data = NULL;
927 RWLOCK_EXIT(&softf->ipfr_natfrag);
928 }
929
930
931 /* ------------------------------------------------------------------------ */
932 /* Function: ipf_frag_delete */
933 /* Returns: Nil */
934 /* Parameters: softc(I) - pointer to soft context main structure */
935 /* fra(I) - pointer to fragment structure to delete */
936 /* tail(IO) - pointer to the pointer to the tail of the frag */
937 /* list */
938 /* */
939 /* Remove a fragment cache table entry from the table & list. Also free */
940 /* the filter rule it is associated with it if it is no longer used as a */
941 /* result of decreasing the reference count. */
942 /* ------------------------------------------------------------------------ */
943 static void
ipf_frag_delete(ipf_main_softc_t * softc,ipfr_t * fra,ipfr_t *** tail)944 ipf_frag_delete(ipf_main_softc_t *softc, ipfr_t *fra, ipfr_t ***tail)
945 {
946 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
947
948 if (fra->ipfr_next)
949 fra->ipfr_next->ipfr_prev = fra->ipfr_prev;
950 *fra->ipfr_prev = fra->ipfr_next;
951 if (*tail == &fra->ipfr_next)
952 *tail = fra->ipfr_prev;
953
954 if (fra->ipfr_hnext)
955 fra->ipfr_hnext->ipfr_hprev = fra->ipfr_hprev;
956 *fra->ipfr_hprev = fra->ipfr_hnext;
957
958 if (fra->ipfr_rule != NULL) {
959 (void) ipf_derefrule(softc, &fra->ipfr_rule);
960 }
961
962 if (fra->ipfr_ref <= 0)
963 ipf_frag_free(softf, fra);
964 }
965
966
967 /* ------------------------------------------------------------------------ */
968 /* Function: ipf_frag_free */
969 /* Returns: Nil */
970 /* Parameters: softf(I) - pointer to fragment context information */
971 /* fra(I) - pointer to fragment structure to free */
972 /* */
973 /* Free up a fragment cache entry and bump relevent statistics. */
974 /* ------------------------------------------------------------------------ */
975 static void
ipf_frag_free(ipf_frag_softc_t * softf,ipfr_t * fra)976 ipf_frag_free(ipf_frag_softc_t *softf, ipfr_t *fra)
977 {
978 KFREE(fra);
979 FBUMP(ifs_expire);
980 softf->ipfr_stats.ifs_inuse--;
981 }
982
983
984 /* ------------------------------------------------------------------------ */
985 /* Function: ipf_frag_clear */
986 /* Returns: Nil */
987 /* Parameters: softc(I) - pointer to soft context main structure */
988 /* */
989 /* Free memory in use by fragment state information kept. Do the normal */
990 /* fragment state stuff first and then the NAT-fragment table. */
991 /* ------------------------------------------------------------------------ */
992 void
ipf_frag_clear(ipf_main_softc_t * softc)993 ipf_frag_clear(ipf_main_softc_t *softc)
994 {
995 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
996 ipfr_t *fra;
997 nat_t *nat;
998
999 WRITE_ENTER(&softc->ipf_frag);
1000 while ((fra = softf->ipfr_list) != NULL) {
1001 fra->ipfr_ref--;
1002 ipf_frag_delete(softc, fra, &softf->ipfr_tail);
1003 }
1004 softf->ipfr_tail = &softf->ipfr_list;
1005 RWLOCK_EXIT(&softc->ipf_frag);
1006
1007 WRITE_ENTER(&softc->ipf_nat);
1008 WRITE_ENTER(&softf->ipfr_natfrag);
1009 while ((fra = softf->ipfr_natlist) != NULL) {
1010 nat = fra->ipfr_data;
1011 if (nat != NULL) {
1012 if (nat->nat_data == fra)
1013 nat->nat_data = NULL;
1014 }
1015 fra->ipfr_ref--;
1016 ipf_frag_delete(softc, fra, &softf->ipfr_nattail);
1017 }
1018 softf->ipfr_nattail = &softf->ipfr_natlist;
1019 RWLOCK_EXIT(&softf->ipfr_natfrag);
1020 RWLOCK_EXIT(&softc->ipf_nat);
1021 }
1022
1023
1024 /* ------------------------------------------------------------------------ */
1025 /* Function: ipf_frag_expire */
1026 /* Returns: Nil */
1027 /* Parameters: softc(I) - pointer to soft context main structure */
1028 /* */
1029 /* Expire entries in the fragment cache table that have been there too long */
1030 /* ------------------------------------------------------------------------ */
1031 void
ipf_frag_expire(ipf_main_softc_t * softc)1032 ipf_frag_expire(ipf_main_softc_t *softc)
1033 {
1034 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
1035 ipfr_t **fp, *fra;
1036 nat_t *nat;
1037 SPL_INT(s);
1038
1039 if (softf->ipfr_lock)
1040 return;
1041
1042 SPL_NET(s);
1043 WRITE_ENTER(&softc->ipf_frag);
1044 /*
1045 * Go through the entire table, looking for entries to expire,
1046 * which is indicated by the ttl being less than or equal to ipf_ticks.
1047 */
1048 for (fp = &softf->ipfr_list; ((fra = *fp) != NULL); ) {
1049 if (fra->ipfr_ttl > softc->ipf_ticks)
1050 break;
1051 fra->ipfr_ref--;
1052 ipf_frag_delete(softc, fra, &softf->ipfr_tail);
1053 }
1054 RWLOCK_EXIT(&softc->ipf_frag);
1055
1056 WRITE_ENTER(&softf->ipfr_ipidfrag);
1057 for (fp = &softf->ipfr_ipidlist; ((fra = *fp) != NULL); ) {
1058 if (fra->ipfr_ttl > softc->ipf_ticks)
1059 break;
1060 fra->ipfr_ref--;
1061 ipf_frag_delete(softc, fra, &softf->ipfr_ipidtail);
1062 }
1063 RWLOCK_EXIT(&softf->ipfr_ipidfrag);
1064
1065 /*
1066 * Same again for the NAT table, except that if the structure also
1067 * still points to a NAT structure, and the NAT structure points back
1068 * at the one to be free'd, NULL the reference from the NAT struct.
1069 * NOTE: We need to grab both mutex's early, and in this order so as
1070 * to prevent a deadlock if both try to expire at the same time.
1071 * The extra if() statement here is because it locks out all NAT
1072 * operations - no need to do that if there are no entries in this
1073 * list, right?
1074 */
1075 if (softf->ipfr_natlist != NULL) {
1076 WRITE_ENTER(&softc->ipf_nat);
1077 WRITE_ENTER(&softf->ipfr_natfrag);
1078 for (fp = &softf->ipfr_natlist; ((fra = *fp) != NULL); ) {
1079 if (fra->ipfr_ttl > softc->ipf_ticks)
1080 break;
1081 nat = fra->ipfr_data;
1082 if (nat != NULL) {
1083 if (nat->nat_data == fra)
1084 nat->nat_data = NULL;
1085 }
1086 fra->ipfr_ref--;
1087 ipf_frag_delete(softc, fra, &softf->ipfr_nattail);
1088 }
1089 RWLOCK_EXIT(&softf->ipfr_natfrag);
1090 RWLOCK_EXIT(&softc->ipf_nat);
1091 }
1092 SPL_X(s);
1093 }
1094
1095
1096 /* ------------------------------------------------------------------------ */
1097 /* Function: ipf_frag_pkt_next */
1098 /* Returns: int - 0 == success, else error */
1099 /* Parameters: softc(I) - pointer to soft context main structure */
1100 /* token(I) - pointer to token information for this caller */
1101 /* itp(I) - pointer to generic iterator from caller */
1102 /* */
1103 /* This function is used to step through the fragment cache list used for */
1104 /* filter rules. The hard work is done by the more generic ipf_frag_next. */
1105 /* ------------------------------------------------------------------------ */
1106 int
ipf_frag_pkt_next(ipf_main_softc_t * softc,ipftoken_t * token,ipfgeniter_t * itp)1107 ipf_frag_pkt_next(ipf_main_softc_t *softc, ipftoken_t *token,
1108 ipfgeniter_t *itp)
1109 {
1110 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
1111
1112 #ifdef USE_MUTEXES
1113 return (ipf_frag_next(softc, token, itp, &softf->ipfr_list,
1114 &softf->ipfr_frag));
1115 #else
1116 return (ipf_frag_next(softc, token, itp, &softf->ipfr_list));
1117 #endif
1118 }
1119
1120
1121 /* ------------------------------------------------------------------------ */
1122 /* Function: ipf_frag_nat_next */
1123 /* Returns: int - 0 == success, else error */
1124 /* Parameters: softc(I) - pointer to soft context main structure */
1125 /* token(I) - pointer to token information for this caller */
1126 /* itp(I) - pointer to generic iterator from caller */
1127 /* */
1128 /* This function is used to step through the fragment cache list used for */
1129 /* NAT. The hard work is done by the more generic ipf_frag_next. */
1130 /* ------------------------------------------------------------------------ */
1131 int
ipf_frag_nat_next(ipf_main_softc_t * softc,ipftoken_t * token,ipfgeniter_t * itp)1132 ipf_frag_nat_next(ipf_main_softc_t *softc, ipftoken_t *token,
1133 ipfgeniter_t *itp)
1134 {
1135 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
1136
1137 #ifdef USE_MUTEXES
1138 return (ipf_frag_next(softc, token, itp, &softf->ipfr_natlist,
1139 &softf->ipfr_natfrag));
1140 #else
1141 return (ipf_frag_next(softc, token, itp, &softf->ipfr_natlist));
1142 #endif
1143 }
1144
1145 /* ------------------------------------------------------------------------ */
1146 /* Function: ipf_frag_next */
1147 /* Returns: int - 0 == success, else error */
1148 /* Parameters: softc(I) - pointer to soft context main structure */
1149 /* token(I) - pointer to token information for this caller */
1150 /* itp(I) - pointer to generic iterator from caller */
1151 /* top(I) - top of the fragment list */
1152 /* lock(I) - fragment cache lock */
1153 /* */
1154 /* This function is used to interate through the list of entries in the */
1155 /* fragment cache. It increases the reference count on the one currently */
1156 /* being returned so that the caller can come back and resume from it later.*/
1157 /* */
1158 /* This function is used for both the NAT fragment cache as well as the ipf */
1159 /* fragment cache - hence the reason for passing in top and lock. */
1160 /* ------------------------------------------------------------------------ */
1161 static int
ipf_frag_next(ipf_main_softc_t * softc,ipftoken_t * token,ipfgeniter_t * itp,ipfr_t ** top,ipfrwlock_t * lock)1162 ipf_frag_next(ipf_main_softc_t *softc, ipftoken_t *token, ipfgeniter_t *itp,
1163 ipfr_t **top
1164 #ifdef USE_MUTEXES
1165 , ipfrwlock_t *lock
1166 #endif
1167 )
1168 {
1169 ipfr_t *frag, *next, zero;
1170 int error = 0;
1171
1172 if (itp->igi_data == NULL) {
1173 IPFERROR(20001);
1174 return (EFAULT);
1175 }
1176
1177 if (itp->igi_nitems != 1) {
1178 IPFERROR(20003);
1179 return (EFAULT);
1180 }
1181
1182 frag = token->ipt_data;
1183
1184 READ_ENTER(lock);
1185
1186 if (frag == NULL)
1187 next = *top;
1188 else
1189 next = frag->ipfr_next;
1190
1191 if (next != NULL) {
1192 ATOMIC_INC(next->ipfr_ref);
1193 token->ipt_data = next;
1194 } else {
1195 bzero(&zero, sizeof(zero));
1196 next = &zero;
1197 token->ipt_data = NULL;
1198 }
1199 if (next->ipfr_next == NULL)
1200 ipf_token_mark_complete(token);
1201
1202 RWLOCK_EXIT(lock);
1203
1204 error = COPYOUT(next, itp->igi_data, sizeof(*next));
1205 if (error != 0)
1206 IPFERROR(20002);
1207
1208 if (frag != NULL) {
1209 #ifdef USE_MUTEXES
1210 ipf_frag_deref(softc, &frag, lock);
1211 #else
1212 ipf_frag_deref(softc, &frag);
1213 #endif
1214 }
1215 return (error);
1216 }
1217
1218
1219 /* ------------------------------------------------------------------------ */
1220 /* Function: ipf_frag_pkt_deref */
1221 /* Returns: Nil */
1222 /* Parameters: softc(I) - pointer to soft context main structure */
1223 /* data(I) - pointer to frag cache pointer */
1224 /* */
1225 /* This function is the external interface for dropping a reference to a */
1226 /* fragment cache entry used by filter rules. */
1227 /* ------------------------------------------------------------------------ */
1228 void
ipf_frag_pkt_deref(ipf_main_softc_t * softc,void * data)1229 ipf_frag_pkt_deref(ipf_main_softc_t *softc, void *data)
1230 {
1231 ipfr_t **frp = data;
1232
1233 #ifdef USE_MUTEXES
1234 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
1235
1236 ipf_frag_deref(softc->ipf_frag_soft, frp, &softf->ipfr_frag);
1237 #else
1238 ipf_frag_deref(softc->ipf_frag_soft, frp);
1239 #endif
1240 }
1241
1242
1243 /* ------------------------------------------------------------------------ */
1244 /* Function: ipf_frag_nat_deref */
1245 /* Returns: Nil */
1246 /* Parameters: softc(I) - pointer to soft context main structure */
1247 /* data(I) - pointer to frag cache pointer */
1248 /* */
1249 /* This function is the external interface for dropping a reference to a */
1250 /* fragment cache entry used by NAT table entries. */
1251 /* ------------------------------------------------------------------------ */
1252 void
ipf_frag_nat_deref(ipf_main_softc_t * softc,void * data)1253 ipf_frag_nat_deref(ipf_main_softc_t *softc, void *data)
1254 {
1255 ipfr_t **frp = data;
1256
1257 #ifdef USE_MUTEXES
1258 ipf_frag_softc_t *softf = softc->ipf_frag_soft;
1259
1260 ipf_frag_deref(softc->ipf_frag_soft, frp, &softf->ipfr_natfrag);
1261 #else
1262 ipf_frag_deref(softc->ipf_frag_soft, frp);
1263 #endif
1264 }
1265
1266
1267 /* ------------------------------------------------------------------------ */
1268 /* Function: ipf_frag_deref */
1269 /* Returns: Nil */
1270 /* Parameters: frp(IO) - pointer to fragment structure to deference */
1271 /* lock(I) - lock associated with the fragment */
1272 /* */
1273 /* This function dereferences a fragment structure (ipfr_t). The pointer */
1274 /* passed in will always be reset back to NULL, even if the structure is */
1275 /* not freed, to enforce the notion that the caller is no longer entitled */
1276 /* to use the pointer it is dropping the reference to. */
1277 /* ------------------------------------------------------------------------ */
1278 static void
ipf_frag_deref(void * arg,ipfr_t ** frp,ipfrwlock_t * lock)1279 ipf_frag_deref(void *arg, ipfr_t **frp
1280 #ifdef USE_MUTEXES
1281 , ipfrwlock_t *lock
1282 #endif
1283 )
1284 {
1285 ipf_frag_softc_t *softf = arg;
1286 ipfr_t *fra;
1287
1288 fra = *frp;
1289 *frp = NULL;
1290
1291 WRITE_ENTER(lock);
1292 fra->ipfr_ref--;
1293 if (fra->ipfr_ref <= 0)
1294 ipf_frag_free(softf, fra);
1295 RWLOCK_EXIT(lock);
1296 }
1297