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