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