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 #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 #if defined(__NetBSD__) 21 # if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL) 22 # include "opt_ipfilter_log.h" 23 # endif 24 #endif 25 #if defined(_KERNEL) && defined(__FreeBSD_version) && \ 26 (__FreeBSD_version >= 220000) 27 # if (__FreeBSD_version >= 400000) 28 # if !defined(IPFILTER_LKM) 29 # include "opt_inet6.h" 30 # endif 31 # if (__FreeBSD_version == 400019) 32 # define CSUM_DELAY_DATA 33 # endif 34 # endif 35 # include <sys/filio.h> 36 #else 37 # include <sys/ioctl.h> 38 #endif 39 #if !defined(_AIX51) 40 # include <sys/fcntl.h> 41 #endif 42 #if defined(_KERNEL) 43 # include <sys/systm.h> 44 # include <sys/file.h> 45 #else 46 # include <stdio.h> 47 # include <string.h> 48 # include <stdlib.h> 49 # include <stddef.h> 50 # include <sys/file.h> 51 # define _KERNEL 52 # ifdef __OpenBSD__ 53 struct file; 54 # endif 55 # include <sys/uio.h> 56 # undef _KERNEL 57 #endif 58 #if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux) && \ 59 !defined(linux) 60 # include <sys/mbuf.h> 61 #else 62 # if !defined(linux) 63 # include <sys/byteorder.h> 64 # endif 65 # if (SOLARIS2 < 5) && defined(sun) 66 # include <sys/dditypes.h> 67 # endif 68 #endif 69 #ifdef __hpux 70 # define _NET_ROUTE_INCLUDED 71 #endif 72 #if !defined(linux) 73 # include <sys/protosw.h> 74 #endif 75 #include <sys/socket.h> 76 #include <net/if.h> 77 #ifdef sun 78 # include <net/af.h> 79 #endif 80 #if !defined(_KERNEL) && defined(__FreeBSD__) 81 # include "radix_ipf.h" 82 #endif 83 #include <net/route.h> 84 #include <netinet/in.h> 85 #include <netinet/in_systm.h> 86 #include <netinet/ip.h> 87 #if !defined(linux) 88 # include <netinet/ip_var.h> 89 #endif 90 #if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */ 91 # include <sys/hashing.h> 92 # include <netinet/in_var.h> 93 #endif 94 #include <netinet/tcp.h> 95 #if (!defined(__sgi) && !defined(AIX)) || defined(_KERNEL) 96 # include <netinet/udp.h> 97 # include <netinet/ip_icmp.h> 98 #endif 99 #ifdef __hpux 100 # undef _NET_ROUTE_INCLUDED 101 #endif 102 #include "netinet/ip_compat.h" 103 #ifdef USE_INET6 104 # include <netinet/icmp6.h> 105 # if !SOLARIS && defined(_KERNEL) && !defined(__osf__) && !defined(__hpux) 106 # include <netinet6/in6_var.h> 107 # endif 108 #endif 109 #include <netinet/tcpip.h> 110 #include "netinet/ip_fil.h" 111 #include "netinet/ip_nat.h" 112 #include "netinet/ip_frag.h" 113 #include "netinet/ip_state.h" 114 #include "netinet/ip_proxy.h" 115 #include "netinet/ip_auth.h" 116 #include "netinet/ipf_stack.h" 117 #ifdef IPFILTER_SCAN 118 # include "netinet/ip_scan.h" 119 #endif 120 #ifdef IPFILTER_SYNC 121 # include "netinet/ip_sync.h" 122 #endif 123 #include "netinet/ip_pool.h" 124 #include "netinet/ip_htable.h" 125 #ifdef IPFILTER_COMPILED 126 # include "netinet/ip_rules.h" 127 #endif 128 #if defined(IPFILTER_BPF) && defined(_KERNEL) 129 # include <net/bpf.h> 130 #endif 131 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 132 # include <sys/malloc.h> 133 # if defined(_KERNEL) && !defined(IPFILTER_LKM) 134 # include "opt_ipfilter.h" 135 # endif 136 #endif 137 #include "netinet/ipl.h" 138 /* END OF INCLUDES */ 139 140 #if !defined(lint) 141 static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed"; 142 static const char rcsid[] = "@(#)$Id: fil.c,v 2.243.2.64 2005/08/13 05:19:59 darrenr Exp $"; 143 #endif 144 145 #ifndef _KERNEL 146 # include "ipf.h" 147 # include "ipt.h" 148 # include "bpf-ipf.h" 149 extern int opts; 150 151 # define FR_VERBOSE(verb_pr) verbose verb_pr 152 # define FR_DEBUG(verb_pr) debug verb_pr 153 #else /* #ifndef _KERNEL */ 154 # define FR_VERBOSE(verb_pr) 155 # define FR_DEBUG(verb_pr) 156 #endif /* _KERNEL */ 157 158 159 char ipfilter_version[] = IPL_VERSION; 160 int fr_features = 0 161 #ifdef IPFILTER_LKM 162 | IPF_FEAT_LKM 163 #endif 164 #ifdef IPFILTER_LOG 165 | IPF_FEAT_LOG 166 #endif 167 #ifdef IPFILTER_LOOKUP 168 | IPF_FEAT_LOOKUP 169 #endif 170 #ifdef IPFILTER_BPF 171 | IPF_FEAT_BPF 172 #endif 173 #ifdef IPFILTER_COMPILED 174 | IPF_FEAT_COMPILED 175 #endif 176 #ifdef IPFILTER_CKSUM 177 | IPF_FEAT_CKSUM 178 #endif 179 #ifdef IPFILTER_SYNC 180 | IPF_FEAT_SYNC 181 #endif 182 #ifdef IPFILTER_SCAN 183 | IPF_FEAT_SCAN 184 #endif 185 #ifdef USE_INET6 186 | IPF_FEAT_IPV6 187 #endif 188 ; 189 190 #define IPF_BUMP(x) (x)++ 191 192 static INLINE int fr_ipfcheck __P((fr_info_t *, frentry_t *, int)); 193 static INLINE int fr_ipfcheck __P((fr_info_t *, frentry_t *, int)); 194 static int fr_portcheck __P((frpcmp_t *, u_short *)); 195 static int frflushlist __P((int, minor_t, int *, frentry_t **, 196 ipf_stack_t *)); 197 static ipfunc_t fr_findfunc __P((ipfunc_t)); 198 static frentry_t *fr_firewall __P((fr_info_t *, u_32_t *)); 199 static int fr_funcinit __P((frentry_t *fr, ipf_stack_t *)); 200 static INLINE void frpr_ah __P((fr_info_t *)); 201 static INLINE void frpr_esp __P((fr_info_t *)); 202 static INLINE void frpr_gre __P((fr_info_t *)); 203 static INLINE void frpr_udp __P((fr_info_t *)); 204 static INLINE void frpr_tcp __P((fr_info_t *)); 205 static INLINE void frpr_icmp __P((fr_info_t *)); 206 static INLINE void frpr_ipv4hdr __P((fr_info_t *)); 207 static INLINE int frpr_pullup __P((fr_info_t *, int)); 208 static INLINE void frpr_short __P((fr_info_t *, int)); 209 static INLINE void frpr_tcpcommon __P((fr_info_t *)); 210 static INLINE void frpr_udpcommon __P((fr_info_t *)); 211 static INLINE int fr_updateipid __P((fr_info_t *)); 212 #ifdef IPFILTER_LOOKUP 213 static int fr_grpmapinit __P((frentry_t *fr, ipf_stack_t *)); 214 static INLINE void *fr_resolvelookup __P((u_int, u_int, lookupfunc_t *, 215 ipf_stack_t *)); 216 #endif 217 static void frsynclist __P((int, int, void *, char *, frentry_t *, 218 ipf_stack_t *)); 219 static void *fr_ifsync __P((int, int, char *, char *, 220 void *, void *, ipf_stack_t *)); 221 static ipftuneable_t *fr_findtunebyname __P((const char *, ipf_stack_t *)); 222 static ipftuneable_t *fr_findtunebycookie __P((void *, void **, ipf_stack_t *)); 223 224 /* 225 * bit values for identifying presence of individual IP options 226 * All of these tables should be ordered by increasing key value on the left 227 * hand side to allow for binary searching of the array and include a trailer 228 * with a 0 for the bitmask for linear searches to easily find the end with. 229 */ 230 const struct optlist ipopts[20] = { 231 { IPOPT_NOP, 0x000001 }, 232 { IPOPT_RR, 0x000002 }, 233 { IPOPT_ZSU, 0x000004 }, 234 { IPOPT_MTUP, 0x000008 }, 235 { IPOPT_MTUR, 0x000010 }, 236 { IPOPT_ENCODE, 0x000020 }, 237 { IPOPT_TS, 0x000040 }, 238 { IPOPT_TR, 0x000080 }, 239 { IPOPT_SECURITY, 0x000100 }, 240 { IPOPT_LSRR, 0x000200 }, 241 { IPOPT_E_SEC, 0x000400 }, 242 { IPOPT_CIPSO, 0x000800 }, 243 { IPOPT_SATID, 0x001000 }, 244 { IPOPT_SSRR, 0x002000 }, 245 { IPOPT_ADDEXT, 0x004000 }, 246 { IPOPT_VISA, 0x008000 }, 247 { IPOPT_IMITD, 0x010000 }, 248 { IPOPT_EIP, 0x020000 }, 249 { IPOPT_FINN, 0x040000 }, 250 { 0, 0x000000 } 251 }; 252 253 #ifdef USE_INET6 254 struct optlist ip6exthdr[] = { 255 { IPPROTO_HOPOPTS, 0x000001 }, 256 { IPPROTO_IPV6, 0x000002 }, 257 { IPPROTO_ROUTING, 0x000004 }, 258 { IPPROTO_FRAGMENT, 0x000008 }, 259 { IPPROTO_ESP, 0x000010 }, 260 { IPPROTO_AH, 0x000020 }, 261 { IPPROTO_NONE, 0x000040 }, 262 { IPPROTO_DSTOPTS, 0x000080 }, 263 { 0, 0 } 264 }; 265 #endif 266 267 struct optlist tcpopts[] = { 268 { TCPOPT_NOP, 0x000001 }, 269 { TCPOPT_MAXSEG, 0x000002 }, 270 { TCPOPT_WINDOW, 0x000004 }, 271 { TCPOPT_SACK_PERMITTED, 0x000008 }, 272 { TCPOPT_SACK, 0x000010 }, 273 { TCPOPT_TIMESTAMP, 0x000020 }, 274 { 0, 0x000000 } 275 }; 276 277 /* 278 * bit values for identifying presence of individual IP security options 279 */ 280 const struct optlist secopt[8] = { 281 { IPSO_CLASS_RES4, 0x01 }, 282 { IPSO_CLASS_TOPS, 0x02 }, 283 { IPSO_CLASS_SECR, 0x04 }, 284 { IPSO_CLASS_RES3, 0x08 }, 285 { IPSO_CLASS_CONF, 0x10 }, 286 { IPSO_CLASS_UNCL, 0x20 }, 287 { IPSO_CLASS_RES2, 0x40 }, 288 { IPSO_CLASS_RES1, 0x80 } 289 }; 290 291 292 /* 293 * Table of functions available for use with call rules. 294 */ 295 static ipfunc_resolve_t fr_availfuncs[] = { 296 #ifdef IPFILTER_LOOKUP 297 { "fr_srcgrpmap", fr_srcgrpmap, fr_grpmapinit }, 298 { "fr_dstgrpmap", fr_dstgrpmap, fr_grpmapinit }, 299 #endif 300 { "", NULL } 301 }; 302 303 304 /* 305 * Below we declare a list of constants used only by the ipf_extraflush() 306 * routine. We are placing it here, instead of in ipf_extraflush() itself, 307 * because we want to make it visible to tools such as mdb, nm etc., so the 308 * values can easily be altered during debugging. 309 */ 310 static const int idletime_tab[] = { 311 IPF_TTLVAL(30), /* 30 seconds */ 312 IPF_TTLVAL(1800), /* 30 minutes */ 313 IPF_TTLVAL(43200), /* 12 hours */ 314 IPF_TTLVAL(345600), /* 4 days */ 315 }; 316 317 318 /* 319 * The next section of code is a a collection of small routines that set 320 * fields in the fr_info_t structure passed based on properties of the 321 * current packet. There are different routines for the same protocol 322 * for each of IPv4 and IPv6. Adding a new protocol, for which there 323 * will "special" inspection for setup, is now more easily done by adding 324 * a new routine and expanding the frpr_ipinit*() function rather than by 325 * adding more code to a growing switch statement. 326 */ 327 #ifdef USE_INET6 328 static INLINE int frpr_ah6 __P((fr_info_t *)); 329 static INLINE void frpr_esp6 __P((fr_info_t *)); 330 static INLINE void frpr_gre6 __P((fr_info_t *)); 331 static INLINE void frpr_udp6 __P((fr_info_t *)); 332 static INLINE void frpr_tcp6 __P((fr_info_t *)); 333 static INLINE void frpr_icmp6 __P((fr_info_t *)); 334 static INLINE int frpr_ipv6hdr __P((fr_info_t *)); 335 static INLINE void frpr_short6 __P((fr_info_t *, int)); 336 static INLINE int frpr_hopopts6 __P((fr_info_t *)); 337 static INLINE int frpr_routing6 __P((fr_info_t *)); 338 static INLINE int frpr_dstopts6 __P((fr_info_t *)); 339 static INLINE int frpr_fragment6 __P((fr_info_t *)); 340 static INLINE int frpr_ipv6exthdr __P((fr_info_t *, int, int)); 341 342 343 /* ------------------------------------------------------------------------ */ 344 /* Function: frpr_short6 */ 345 /* Returns: void */ 346 /* Parameters: fin(I) - pointer to packet information */ 347 /* */ 348 /* IPv6 Only */ 349 /* This is function enforces the 'is a packet too short to be legit' rule */ 350 /* for IPv6 and marks the packet with FI_SHORT if so. See function comment */ 351 /* for frpr_short() for more details. */ 352 /* ------------------------------------------------------------------------ */ 353 static INLINE void frpr_short6(fin, xmin) 354 fr_info_t *fin; 355 int xmin; 356 { 357 358 if (fin->fin_dlen < xmin) 359 fin->fin_flx |= FI_SHORT; 360 } 361 362 363 /* ------------------------------------------------------------------------ */ 364 /* Function: frpr_ipv6hdr */ 365 /* Returns: int */ 366 /* Parameters: fin(I) - pointer to packet information */ 367 /* */ 368 /* IPv6 Only */ 369 /* Copy values from the IPv6 header into the fr_info_t struct and call the */ 370 /* per-protocol analyzer if it exists. */ 371 /* ------------------------------------------------------------------------ */ 372 static INLINE int frpr_ipv6hdr(fin) 373 fr_info_t *fin; 374 { 375 ip6_t *ip6 = (ip6_t *)fin->fin_ip; 376 int p, go = 1, i, hdrcount; 377 fr_ip_t *fi = &fin->fin_fi; 378 379 fin->fin_off = 0; 380 381 fi->fi_tos = 0; 382 fi->fi_optmsk = 0; 383 fi->fi_secmsk = 0; 384 fi->fi_auth = 0; 385 386 p = ip6->ip6_nxt; 387 fi->fi_ttl = ip6->ip6_hlim; 388 fi->fi_src.in6 = ip6->ip6_src; 389 fi->fi_dst.in6 = ip6->ip6_dst; 390 fin->fin_id = 0; 391 392 hdrcount = 0; 393 while (go && !(fin->fin_flx & (FI_BAD|FI_SHORT))) { 394 switch (p) 395 { 396 case IPPROTO_UDP : 397 frpr_udp6(fin); 398 go = 0; 399 break; 400 401 case IPPROTO_TCP : 402 frpr_tcp6(fin); 403 go = 0; 404 break; 405 406 case IPPROTO_ICMPV6 : 407 frpr_icmp6(fin); 408 go = 0; 409 break; 410 411 case IPPROTO_GRE : 412 frpr_gre6(fin); 413 go = 0; 414 break; 415 416 case IPPROTO_HOPOPTS : 417 /* 418 * hop by hop ext header is only allowed 419 * right after IPv6 header. 420 */ 421 if (hdrcount != 0) { 422 fin->fin_flx |= FI_BAD; 423 p = IPPROTO_NONE; 424 } else { 425 p = frpr_hopopts6(fin); 426 } 427 break; 428 429 case IPPROTO_DSTOPTS : 430 p = frpr_dstopts6(fin); 431 break; 432 433 case IPPROTO_ROUTING : 434 p = frpr_routing6(fin); 435 break; 436 437 case IPPROTO_AH : 438 p = frpr_ah6(fin); 439 break; 440 441 case IPPROTO_ESP : 442 frpr_esp6(fin); 443 go = 0; 444 break; 445 446 case IPPROTO_IPV6 : 447 for (i = 0; ip6exthdr[i].ol_bit != 0; i++) 448 if (ip6exthdr[i].ol_val == p) { 449 fin->fin_flx |= ip6exthdr[i].ol_bit; 450 break; 451 } 452 go = 0; 453 break; 454 455 case IPPROTO_NONE : 456 go = 0; 457 break; 458 459 case IPPROTO_FRAGMENT : 460 p = frpr_fragment6(fin); 461 if (fin->fin_off != 0) /* Not the first frag */ 462 go = 0; 463 break; 464 465 default : 466 go = 0; 467 break; 468 } 469 hdrcount++; 470 471 /* 472 * It is important to note that at this point, for the 473 * extension headers (go != 0), the entire header may not have 474 * been pulled up when the code gets to this point. This is 475 * only done for "go != 0" because the other header handlers 476 * will all pullup their complete header. The other indicator 477 * of an incomplete packet is that this was just an extension 478 * header. 479 */ 480 if ((go != 0) && (p != IPPROTO_NONE) && 481 (frpr_pullup(fin, 0) == -1)) { 482 p = IPPROTO_NONE; 483 go = 0; 484 } 485 } 486 fi->fi_p = p; 487 488 if (fin->fin_flx & FI_BAD) 489 return -1; 490 491 return 0; 492 } 493 494 495 /* ------------------------------------------------------------------------ */ 496 /* Function: frpr_ipv6exthdr */ 497 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 498 /* Parameters: fin(I) - pointer to packet information */ 499 /* multiple(I) - flag indicating yes/no if multiple occurances */ 500 /* of this extension header are allowed. */ 501 /* proto(I) - protocol number for this extension header */ 502 /* */ 503 /* IPv6 Only */ 504 /* ------------------------------------------------------------------------ */ 505 static INLINE int frpr_ipv6exthdr(fin, multiple, proto) 506 fr_info_t *fin; 507 int multiple, proto; 508 { 509 struct ip6_ext *hdr; 510 u_short shift; 511 int i; 512 513 fin->fin_flx |= FI_V6EXTHDR; 514 515 /* 8 is default length of extension hdr */ 516 if ((fin->fin_dlen - 8) < 0) { 517 fin->fin_flx |= FI_SHORT; 518 return IPPROTO_NONE; 519 } 520 521 if (frpr_pullup(fin, 8) == -1) 522 return IPPROTO_NONE; 523 524 hdr = fin->fin_dp; 525 shift = 8 + (hdr->ip6e_len << 3); 526 if (shift > fin->fin_dlen) { /* Nasty extension header length? */ 527 fin->fin_flx |= FI_BAD; 528 return IPPROTO_NONE; 529 } 530 531 for (i = 0; ip6exthdr[i].ol_bit != 0; i++) 532 if (ip6exthdr[i].ol_val == proto) { 533 /* 534 * Most IPv6 extension headers are only allowed once. 535 */ 536 if ((multiple == 0) && 537 ((fin->fin_optmsk & ip6exthdr[i].ol_bit) != 0)) 538 fin->fin_flx |= FI_BAD; 539 else 540 fin->fin_optmsk |= ip6exthdr[i].ol_bit; 541 break; 542 } 543 544 fin->fin_dp = (char *)fin->fin_dp + shift; 545 fin->fin_dlen -= shift; 546 547 return hdr->ip6e_nxt; 548 } 549 550 551 /* ------------------------------------------------------------------------ */ 552 /* Function: frpr_hopopts6 */ 553 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 554 /* Parameters: fin(I) - pointer to packet information */ 555 /* */ 556 /* IPv6 Only */ 557 /* This is function checks pending hop by hop options extension header */ 558 /* ------------------------------------------------------------------------ */ 559 static INLINE int frpr_hopopts6(fin) 560 fr_info_t *fin; 561 { 562 return frpr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS); 563 } 564 565 566 /* ------------------------------------------------------------------------ */ 567 /* Function: frpr_routing6 */ 568 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 569 /* Parameters: fin(I) - pointer to packet information */ 570 /* */ 571 /* IPv6 Only */ 572 /* This is function checks pending routing extension header */ 573 /* ------------------------------------------------------------------------ */ 574 static INLINE int frpr_routing6(fin) 575 fr_info_t *fin; 576 { 577 struct ip6_ext *hdr; 578 int shift; 579 580 hdr = fin->fin_dp; 581 if (frpr_ipv6exthdr(fin, 0, IPPROTO_ROUTING) == IPPROTO_NONE) 582 return IPPROTO_NONE; 583 584 shift = 8 + (hdr->ip6e_len << 3); 585 /* 586 * Nasty extension header length? 587 */ 588 if ((hdr->ip6e_len << 3) & 15) { 589 fin->fin_flx |= FI_BAD; 590 /* 591 * Compensate for the changes made in frpr_ipv6exthdr() 592 */ 593 fin->fin_dlen += shift; 594 fin->fin_dp = (char *)fin->fin_dp - shift; 595 return IPPROTO_NONE; 596 } 597 598 return hdr->ip6e_nxt; 599 } 600 601 602 /* ------------------------------------------------------------------------ */ 603 /* Function: frpr_fragment6 */ 604 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 605 /* Parameters: fin(I) - pointer to packet information */ 606 /* */ 607 /* IPv6 Only */ 608 /* Examine the IPv6 fragment header and extract fragment offset information.*/ 609 /* */ 610 /* We don't know where the transport layer header (or whatever is next is), */ 611 /* as it could be behind destination options (amongst others). Because */ 612 /* there is no fragment cache, there is no knowledge about whether or not an*/ 613 /* upper layer header has been seen (or where it ends) and thus we are not */ 614 /* able to continue processing beyond this header with any confidence. */ 615 /* ------------------------------------------------------------------------ */ 616 static INLINE int frpr_fragment6(fin) 617 fr_info_t *fin; 618 { 619 struct ip6_frag *frag; 620 int dlen; 621 622 fin->fin_flx |= FI_FRAG; 623 624 dlen = fin->fin_dlen; 625 if (frpr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT) == IPPROTO_NONE) 626 return IPPROTO_NONE; 627 628 if (frpr_pullup(fin, sizeof(*frag)) == -1) 629 return IPPROTO_NONE; 630 631 frpr_short6(fin, sizeof(*frag)); 632 633 if ((fin->fin_flx & FI_SHORT) != 0) 634 return IPPROTO_NONE; 635 636 frag = (struct ip6_frag *)((char *)fin->fin_dp - sizeof(*frag)); 637 /* 638 * Fragment but no fragmentation info set? Bad packet... 639 */ 640 if (frag->ip6f_offlg == 0) { 641 fin->fin_flx |= FI_BAD; 642 return IPPROTO_NONE; 643 } 644 645 fin->fin_id = frag->ip6f_ident; 646 fin->fin_off = frag->ip6f_offlg & IP6F_OFF_MASK; 647 fin->fin_off = ntohs(fin->fin_off); 648 if (fin->fin_off != 0) 649 fin->fin_flx |= FI_FRAGBODY; 650 651 fin->fin_dp = (char *)frag + sizeof(*frag); 652 fin->fin_dlen = dlen - sizeof(*frag); 653 654 /* length of hdrs(after frag hdr) + data */ 655 fin->fin_flen = fin->fin_dlen; 656 657 /* 658 * If the frag is not the last one and the payload length 659 * is not multiple of 8, it must be dropped. 660 */ 661 if ((frag->ip6f_offlg & IP6F_MORE_FRAG) && (dlen % 8)) { 662 fin->fin_flx |= FI_BAD; 663 return IPPROTO_NONE; 664 } 665 666 return frag->ip6f_nxt; 667 } 668 669 670 /* ------------------------------------------------------------------------ */ 671 /* Function: frpr_dstopts6 */ 672 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 673 /* Parameters: fin(I) - pointer to packet information */ 674 /* nextheader(I) - stores next header value */ 675 /* */ 676 /* IPv6 Only */ 677 /* This is function checks pending destination options extension header */ 678 /* ------------------------------------------------------------------------ */ 679 static INLINE int frpr_dstopts6(fin) 680 fr_info_t *fin; 681 { 682 return frpr_ipv6exthdr(fin, 1, IPPROTO_DSTOPTS); 683 } 684 685 686 /* ------------------------------------------------------------------------ */ 687 /* Function: frpr_icmp6 */ 688 /* Returns: void */ 689 /* Parameters: fin(I) - pointer to packet information */ 690 /* */ 691 /* IPv6 Only */ 692 /* This routine is mainly concerned with determining the minimum valid size */ 693 /* for an ICMPv6 packet. */ 694 /* ------------------------------------------------------------------------ */ 695 static INLINE void frpr_icmp6(fin) 696 fr_info_t *fin; 697 { 698 int minicmpsz = sizeof(struct icmp6_hdr); 699 struct icmp6_hdr *icmp6; 700 701 if (frpr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1) 702 return; 703 704 if (fin->fin_dlen > 1) { 705 icmp6 = fin->fin_dp; 706 707 fin->fin_data[0] = *(u_short *)icmp6; 708 709 if ((icmp6->icmp6_type & ICMP6_INFOMSG_MASK) != 0) 710 fin->fin_flx |= FI_ICMPQUERY; 711 712 switch (icmp6->icmp6_type) 713 { 714 case ICMP6_ECHO_REPLY : 715 case ICMP6_ECHO_REQUEST : 716 if (fin->fin_dlen >= 6) 717 fin->fin_data[1] = icmp6->icmp6_id; 718 minicmpsz = ICMP6ERR_MINPKTLEN - sizeof(ip6_t); 719 break; 720 case ICMP6_DST_UNREACH : 721 case ICMP6_PACKET_TOO_BIG : 722 case ICMP6_TIME_EXCEEDED : 723 case ICMP6_PARAM_PROB : 724 if ((fin->fin_m != NULL) && 725 (M_LEN(fin->fin_m) < fin->fin_plen)) { 726 if (fr_coalesce(fin) != 1) 727 return; 728 } 729 fin->fin_flx |= FI_ICMPERR; 730 minicmpsz = ICMP6ERR_IPICMPHLEN - sizeof(ip6_t); 731 break; 732 default : 733 break; 734 } 735 } 736 737 frpr_short6(fin, minicmpsz); 738 fin->fin_flen -= fin->fin_dlen - minicmpsz; 739 } 740 741 742 /* ------------------------------------------------------------------------ */ 743 /* Function: frpr_udp6 */ 744 /* Returns: void */ 745 /* Parameters: fin(I) - pointer to packet information */ 746 /* */ 747 /* IPv6 Only */ 748 /* Analyse the packet for IPv6/UDP properties. */ 749 /* Is not expected to be called for fragmented packets. */ 750 /* ------------------------------------------------------------------------ */ 751 static INLINE void frpr_udp6(fin) 752 fr_info_t *fin; 753 { 754 755 fr_checkv6sum(fin); 756 757 frpr_short6(fin, sizeof(struct udphdr)); 758 if (frpr_pullup(fin, sizeof(struct udphdr)) == -1) 759 return; 760 761 fin->fin_flen -= fin->fin_dlen - sizeof(struct udphdr); 762 763 frpr_udpcommon(fin); 764 } 765 766 767 /* ------------------------------------------------------------------------ */ 768 /* Function: frpr_tcp6 */ 769 /* Returns: void */ 770 /* Parameters: fin(I) - pointer to packet information */ 771 /* */ 772 /* IPv6 Only */ 773 /* Analyse the packet for IPv6/TCP properties. */ 774 /* Is not expected to be called for fragmented packets. */ 775 /* ------------------------------------------------------------------------ */ 776 static INLINE void frpr_tcp6(fin) 777 fr_info_t *fin; 778 { 779 780 fr_checkv6sum(fin); 781 782 frpr_short6(fin, sizeof(struct tcphdr)); 783 if (frpr_pullup(fin, sizeof(struct tcphdr)) == -1) 784 return; 785 786 fin->fin_flen -= fin->fin_dlen - sizeof(struct tcphdr); 787 788 frpr_tcpcommon(fin); 789 } 790 791 792 /* ------------------------------------------------------------------------ */ 793 /* Function: frpr_esp6 */ 794 /* Returns: void */ 795 /* Parameters: fin(I) - pointer to packet information */ 796 /* */ 797 /* IPv6 Only */ 798 /* Analyse the packet for ESP properties. */ 799 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ 800 /* even though the newer ESP packets must also have a sequence number that */ 801 /* is 32bits as well, it is not possible(?) to determine the version from a */ 802 /* simple packet header. */ 803 /* ------------------------------------------------------------------------ */ 804 static INLINE void frpr_esp6(fin) 805 fr_info_t *fin; 806 { 807 int i; 808 frpr_short6(fin, sizeof(grehdr_t)); 809 810 (void) frpr_pullup(fin, 8); 811 812 for (i = 0; ip6exthdr[i].ol_bit != 0; i++) 813 if (ip6exthdr[i].ol_val == IPPROTO_ESP) { 814 fin->fin_optmsk |= ip6exthdr[i].ol_bit; 815 break; 816 } 817 } 818 819 820 /* ------------------------------------------------------------------------ */ 821 /* Function: frpr_ah6 */ 822 /* Returns: void */ 823 /* Parameters: fin(I) - pointer to packet information */ 824 /* */ 825 /* IPv6 Only */ 826 /* Analyse the packet for AH properties. */ 827 /* The minimum length is taken to be the combination of all fields in the */ 828 /* header being present and no authentication data (null algorithm used.) */ 829 /* ------------------------------------------------------------------------ */ 830 static INLINE int frpr_ah6(fin) 831 fr_info_t *fin; 832 { 833 authhdr_t *ah; 834 int i, shift; 835 836 frpr_short6(fin, 12); 837 838 if (frpr_pullup(fin, sizeof(*ah)) == -1) 839 return IPPROTO_NONE; 840 841 for (i = 0; ip6exthdr[i].ol_bit != 0; i++) 842 if (ip6exthdr[i].ol_val == IPPROTO_AH) { 843 fin->fin_optmsk |= ip6exthdr[i].ol_bit; 844 break; 845 } 846 847 ah = (authhdr_t *)fin->fin_dp; 848 849 shift = (ah->ah_plen + 2) * 4; 850 fin->fin_dlen -= shift; 851 fin->fin_dp = (char*)fin->fin_dp + shift; 852 853 return ah->ah_next; 854 } 855 856 857 /* ------------------------------------------------------------------------ */ 858 /* Function: frpr_gre6 */ 859 /* Returns: void */ 860 /* Parameters: fin(I) - pointer to packet information */ 861 /* */ 862 /* Analyse the packet for GRE properties. */ 863 /* ------------------------------------------------------------------------ */ 864 static INLINE void frpr_gre6(fin) 865 fr_info_t *fin; 866 { 867 grehdr_t *gre; 868 869 frpr_short6(fin, sizeof(grehdr_t)); 870 871 if (frpr_pullup(fin, sizeof(grehdr_t)) == -1) 872 return; 873 874 gre = fin->fin_dp; 875 if (GRE_REV(gre->gr_flags) == 1) 876 fin->fin_data[0] = gre->gr_call; 877 } 878 #endif /* USE_INET6 */ 879 880 881 /* ------------------------------------------------------------------------ */ 882 /* Function: frpr_pullup */ 883 /* Returns: int - 0 == pullup succeeded, -1 == failure */ 884 /* Parameters: fin(I) - pointer to packet information */ 885 /* plen(I) - length (excluding L3 header) to pullup */ 886 /* */ 887 /* Short inline function to cut down on code duplication to perform a call */ 888 /* to fr_pullup to ensure there is the required amount of data, */ 889 /* consecutively in the packet buffer. */ 890 /* ------------------------------------------------------------------------ */ 891 static INLINE int frpr_pullup(fin, plen) 892 fr_info_t *fin; 893 int plen; 894 { 895 #if defined(_KERNEL) 896 if (fin->fin_m != NULL) { 897 int ipoff; 898 899 ipoff = (char *)fin->fin_ip - MTOD(fin->fin_m, char *); 900 901 if (fin->fin_dp != NULL) 902 plen += (char *)fin->fin_dp - 903 ((char *)fin->fin_ip + fin->fin_hlen); 904 plen += fin->fin_hlen; 905 /* 906 * We don't do 'plen += ipoff;' here. The fr_pullup() will 907 * do it for us. 908 */ 909 if (M_LEN(fin->fin_m) < plen + ipoff) { 910 if (fr_pullup(fin->fin_m, fin, plen) == NULL) 911 return -1; 912 } 913 } 914 #endif 915 return 0; 916 } 917 918 919 /* ------------------------------------------------------------------------ */ 920 /* Function: frpr_short */ 921 /* Returns: void */ 922 /* Parameters: fin(I) - pointer to packet information */ 923 /* xmin(I) - minimum header size */ 924 /* */ 925 /* Check if a packet is "short" as defined by xmin. The rule we are */ 926 /* applying here is that the packet must not be fragmented within the layer */ 927 /* 4 header. That is, it must not be a fragment that has its offset set to */ 928 /* start within the layer 4 header (hdrmin) or if it is at offset 0, the */ 929 /* entire layer 4 header must be present (min). */ 930 /* ------------------------------------------------------------------------ */ 931 static INLINE void frpr_short(fin, xmin) 932 fr_info_t *fin; 933 int xmin; 934 { 935 936 if (fin->fin_off == 0) { 937 if (fin->fin_dlen < xmin) 938 fin->fin_flx |= FI_SHORT; 939 } else if (fin->fin_off < xmin) { 940 fin->fin_flx |= FI_SHORT; 941 } 942 } 943 944 945 /* ------------------------------------------------------------------------ */ 946 /* Function: frpr_icmp */ 947 /* Returns: void */ 948 /* Parameters: fin(I) - pointer to packet information */ 949 /* */ 950 /* IPv4 Only */ 951 /* Do a sanity check on the packet for ICMP (v4). In nearly all cases, */ 952 /* except extrememly bad packets, both type and code will be present. */ 953 /* The expected minimum size of an ICMP packet is very much dependent on */ 954 /* the type of it. */ 955 /* */ 956 /* XXX - other ICMP sanity checks? */ 957 /* ------------------------------------------------------------------------ */ 958 static INLINE void frpr_icmp(fin) 959 fr_info_t *fin; 960 { 961 int minicmpsz = sizeof(struct icmp); 962 icmphdr_t *icmp; 963 ip_t *oip; 964 ipf_stack_t *ifs = fin->fin_ifs; 965 966 if (fin->fin_off != 0) { 967 frpr_short(fin, ICMPERR_ICMPHLEN); 968 return; 969 } 970 971 if (frpr_pullup(fin, ICMPERR_ICMPHLEN) == -1) 972 return; 973 974 fr_checkv4sum(fin); 975 976 if (fin->fin_dlen > 1) { 977 icmp = fin->fin_dp; 978 979 fin->fin_data[0] = *(u_short *)icmp; 980 981 switch (icmp->icmp_type) 982 { 983 case ICMP_ECHOREPLY : 984 case ICMP_ECHO : 985 /* Router discovery messaes - RFC 1256 */ 986 case ICMP_ROUTERADVERT : 987 case ICMP_ROUTERSOLICIT : 988 minicmpsz = ICMP_MINLEN; 989 break; 990 /* 991 * type(1) + code(1) + cksum(2) + id(2) seq(2) + 992 * 3 * timestamp(3 * 4) 993 */ 994 case ICMP_TSTAMP : 995 case ICMP_TSTAMPREPLY : 996 minicmpsz = 20; 997 break; 998 /* 999 * type(1) + code(1) + cksum(2) + id(2) seq(2) + 1000 * mask(4) 1001 */ 1002 case ICMP_MASKREQ : 1003 case ICMP_MASKREPLY : 1004 minicmpsz = 12; 1005 break; 1006 /* 1007 * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+) 1008 */ 1009 case ICMP_UNREACH : 1010 if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG) { 1011 if (icmp->icmp_nextmtu < ifs->ifs_fr_icmpminfragmtu) 1012 fin->fin_flx |= FI_BAD; 1013 } 1014 /* FALLTHRU */ 1015 case ICMP_SOURCEQUENCH : 1016 case ICMP_REDIRECT : 1017 case ICMP_TIMXCEED : 1018 case ICMP_PARAMPROB : 1019 fin->fin_flx |= FI_ICMPERR; 1020 if (fr_coalesce(fin) != 1) 1021 return; 1022 /* 1023 * ICMP error packets should not be generated for IP 1024 * packets that are a fragment that isn't the first 1025 * fragment. 1026 */ 1027 oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN); 1028 if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0) 1029 fin->fin_flx |= FI_BAD; 1030 break; 1031 default : 1032 break; 1033 } 1034 1035 if (fin->fin_dlen >= 6) /* ID field */ 1036 fin->fin_data[1] = icmp->icmp_id; 1037 } 1038 1039 frpr_short(fin, minicmpsz); 1040 } 1041 1042 1043 /* ------------------------------------------------------------------------ */ 1044 /* Function: frpr_tcpcommon */ 1045 /* Returns: void */ 1046 /* Parameters: fin(I) - pointer to packet information */ 1047 /* */ 1048 /* TCP header sanity checking. Look for bad combinations of TCP flags, */ 1049 /* and make some checks with how they interact with other fields. */ 1050 /* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is */ 1051 /* valid and mark the packet as bad if not. */ 1052 /* ------------------------------------------------------------------------ */ 1053 static INLINE void frpr_tcpcommon(fin) 1054 fr_info_t *fin; 1055 { 1056 int flags, tlen; 1057 tcphdr_t *tcp; 1058 1059 fin->fin_flx |= FI_TCPUDP; 1060 if (fin->fin_off != 0) 1061 return; 1062 1063 if (frpr_pullup(fin, sizeof(*tcp)) == -1) 1064 return; 1065 tcp = fin->fin_dp; 1066 1067 if (fin->fin_dlen > 3) { 1068 fin->fin_sport = ntohs(tcp->th_sport); 1069 fin->fin_dport = ntohs(tcp->th_dport); 1070 } 1071 1072 if ((fin->fin_flx & FI_SHORT) != 0) 1073 return; 1074 1075 /* 1076 * Use of the TCP data offset *must* result in a value that is at 1077 * least the same size as the TCP header. 1078 */ 1079 tlen = TCP_OFF(tcp) << 2; 1080 if (tlen < sizeof(tcphdr_t)) { 1081 fin->fin_flx |= FI_BAD; 1082 return; 1083 } 1084 1085 flags = tcp->th_flags; 1086 fin->fin_tcpf = tcp->th_flags; 1087 1088 /* 1089 * If the urgent flag is set, then the urgent pointer must 1090 * also be set and vice versa. Good TCP packets do not have 1091 * just one of these set. 1092 */ 1093 if ((flags & TH_URG) != 0 && (tcp->th_urp == 0)) { 1094 fin->fin_flx |= FI_BAD; 1095 } else if ((flags & TH_URG) == 0 && (tcp->th_urp != 0)) { 1096 /* Ignore this case, it shows up in "real" traffic with */ 1097 /* bogus values in the urgent pointer field. */ 1098 flags = flags; /* LINT */ 1099 } else if (((flags & (TH_SYN|TH_FIN)) != 0) && 1100 ((flags & (TH_RST|TH_ACK)) == TH_RST)) { 1101 /* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */ 1102 fin->fin_flx |= FI_BAD; 1103 } else if (!(flags & TH_ACK)) { 1104 /* 1105 * If the ack bit isn't set, then either the SYN or 1106 * RST bit must be set. If the SYN bit is set, then 1107 * we expect the ACK field to be 0. If the ACK is 1108 * not set and if URG, PSH or FIN are set, consdier 1109 * that to indicate a bad TCP packet. 1110 */ 1111 if ((flags == TH_SYN) && (tcp->th_ack != 0)) { 1112 /* 1113 * Cisco PIX sets the ACK field to a random value. 1114 * In light of this, do not set FI_BAD until a patch 1115 * is available from Cisco to ensure that 1116 * interoperability between existing systems is 1117 * achieved. 1118 */ 1119 /*fin->fin_flx |= FI_BAD*/; 1120 flags = flags; /* LINT */ 1121 } else if (!(flags & (TH_RST|TH_SYN))) { 1122 fin->fin_flx |= FI_BAD; 1123 } else if ((flags & (TH_URG|TH_PUSH|TH_FIN)) != 0) { 1124 fin->fin_flx |= FI_BAD; 1125 } 1126 } 1127 1128 /* 1129 * At this point, it's not exactly clear what is to be gained by 1130 * marking up which TCP options are and are not present. The one we 1131 * are most interested in is the TCP window scale. This is only in 1132 * a SYN packet [RFC1323] so we don't need this here...? 1133 * Now if we were to analyse the header for passive fingerprinting, 1134 * then that might add some weight to adding this... 1135 */ 1136 if (tlen == sizeof(tcphdr_t)) 1137 return; 1138 1139 if (frpr_pullup(fin, tlen) == -1) 1140 return; 1141 1142 #if 0 1143 ip = fin->fin_ip; 1144 s = (u_char *)(tcp + 1); 1145 off = IP_HL(ip) << 2; 1146 # ifdef _KERNEL 1147 if (fin->fin_mp != NULL) { 1148 mb_t *m = *fin->fin_mp; 1149 1150 if (off + tlen > M_LEN(m)) 1151 return; 1152 } 1153 # endif 1154 for (tlen -= (int)sizeof(*tcp); tlen > 0; ) { 1155 opt = *s; 1156 if (opt == '\0') 1157 break; 1158 else if (opt == TCPOPT_NOP) 1159 ol = 1; 1160 else { 1161 if (tlen < 2) 1162 break; 1163 ol = (int)*(s + 1); 1164 if (ol < 2 || ol > tlen) 1165 break; 1166 } 1167 1168 for (i = 9, mv = 4; mv >= 0; ) { 1169 op = ipopts + i; 1170 if (opt == (u_char)op->ol_val) { 1171 optmsk |= op->ol_bit; 1172 break; 1173 } 1174 } 1175 tlen -= ol; 1176 s += ol; 1177 } 1178 #endif /* 0 */ 1179 } 1180 1181 1182 1183 /* ------------------------------------------------------------------------ */ 1184 /* Function: frpr_udpcommon */ 1185 /* Returns: void */ 1186 /* Parameters: fin(I) - pointer to packet information */ 1187 /* */ 1188 /* Extract the UDP source and destination ports, if present. If compiled */ 1189 /* with IPFILTER_CKSUM, check to see if the UDP checksum is valid. */ 1190 /* ------------------------------------------------------------------------ */ 1191 static INLINE void frpr_udpcommon(fin) 1192 fr_info_t *fin; 1193 { 1194 udphdr_t *udp; 1195 1196 fin->fin_flx |= FI_TCPUDP; 1197 1198 if (!fin->fin_off && (fin->fin_dlen > 3)) { 1199 if (frpr_pullup(fin, sizeof(*udp)) == -1) { 1200 fin->fin_flx |= FI_SHORT; 1201 return; 1202 } 1203 1204 udp = fin->fin_dp; 1205 1206 fin->fin_sport = ntohs(udp->uh_sport); 1207 fin->fin_dport = ntohs(udp->uh_dport); 1208 } 1209 } 1210 1211 1212 /* ------------------------------------------------------------------------ */ 1213 /* Function: frpr_tcp */ 1214 /* Returns: void */ 1215 /* Parameters: fin(I) - pointer to packet information */ 1216 /* */ 1217 /* IPv4 Only */ 1218 /* Analyse the packet for IPv4/TCP properties. */ 1219 /* ------------------------------------------------------------------------ */ 1220 static INLINE void frpr_tcp(fin) 1221 fr_info_t *fin; 1222 { 1223 1224 fr_checkv4sum(fin); 1225 1226 frpr_short(fin, sizeof(tcphdr_t)); 1227 1228 frpr_tcpcommon(fin); 1229 } 1230 1231 1232 /* ------------------------------------------------------------------------ */ 1233 /* Function: frpr_udp */ 1234 /* Returns: void */ 1235 /* Parameters: fin(I) - pointer to packet information */ 1236 /* */ 1237 /* IPv4 Only */ 1238 /* Analyse the packet for IPv4/UDP properties. */ 1239 /* ------------------------------------------------------------------------ */ 1240 static INLINE void frpr_udp(fin) 1241 fr_info_t *fin; 1242 { 1243 1244 fr_checkv4sum(fin); 1245 1246 frpr_short(fin, sizeof(udphdr_t)); 1247 1248 frpr_udpcommon(fin); 1249 } 1250 1251 1252 /* ------------------------------------------------------------------------ */ 1253 /* Function: frpr_esp */ 1254 /* Returns: void */ 1255 /* Parameters: fin(I) - pointer to packet information */ 1256 /* */ 1257 /* Analyse the packet for ESP properties. */ 1258 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ 1259 /* even though the newer ESP packets must also have a sequence number that */ 1260 /* is 32bits as well, it is not possible(?) to determine the version from a */ 1261 /* simple packet header. */ 1262 /* ------------------------------------------------------------------------ */ 1263 static INLINE void frpr_esp(fin) 1264 fr_info_t *fin; 1265 { 1266 if ((fin->fin_off == 0) && (frpr_pullup(fin, 8) == -1)) 1267 return; 1268 1269 frpr_short(fin, 8); 1270 } 1271 1272 1273 /* ------------------------------------------------------------------------ */ 1274 /* Function: frpr_ah */ 1275 /* Returns: void */ 1276 /* Parameters: fin(I) - pointer to packet information */ 1277 /* */ 1278 /* Analyse the packet for AH properties. */ 1279 /* The minimum length is taken to be the combination of all fields in the */ 1280 /* header being present and no authentication data (null algorithm used.) */ 1281 /* ------------------------------------------------------------------------ */ 1282 static INLINE void frpr_ah(fin) 1283 fr_info_t *fin; 1284 { 1285 authhdr_t *ah; 1286 int len; 1287 1288 if ((fin->fin_off == 0) && (frpr_pullup(fin, sizeof(*ah)) == -1)) 1289 return; 1290 1291 ah = (authhdr_t *)fin->fin_dp; 1292 1293 len = (ah->ah_plen + 2) << 2; 1294 frpr_short(fin, len); 1295 } 1296 1297 1298 /* ------------------------------------------------------------------------ */ 1299 /* Function: frpr_gre */ 1300 /* Returns: void */ 1301 /* Parameters: fin(I) - pointer to packet information */ 1302 /* */ 1303 /* Analyse the packet for GRE properties. */ 1304 /* ------------------------------------------------------------------------ */ 1305 static INLINE void frpr_gre(fin) 1306 fr_info_t *fin; 1307 { 1308 grehdr_t *gre; 1309 1310 if ((fin->fin_off == 0) && (frpr_pullup(fin, sizeof(grehdr_t)) == -1)) 1311 return; 1312 1313 frpr_short(fin, sizeof(grehdr_t)); 1314 1315 if (fin->fin_off == 0) { 1316 gre = fin->fin_dp; 1317 if (GRE_REV(gre->gr_flags) == 1) 1318 fin->fin_data[0] = gre->gr_call; 1319 } 1320 } 1321 1322 1323 /* ------------------------------------------------------------------------ */ 1324 /* Function: frpr_ipv4hdr */ 1325 /* Returns: void */ 1326 /* Parameters: fin(I) - pointer to packet information */ 1327 /* */ 1328 /* IPv4 Only */ 1329 /* Analyze the IPv4 header and set fields in the fr_info_t structure. */ 1330 /* Check all options present and flag their presence if any exist. */ 1331 /* ------------------------------------------------------------------------ */ 1332 static INLINE void frpr_ipv4hdr(fin) 1333 fr_info_t *fin; 1334 { 1335 u_short optmsk = 0, secmsk = 0, auth = 0; 1336 int hlen, ol, mv, p, i; 1337 const struct optlist *op; 1338 u_char *s, opt; 1339 u_short off; 1340 fr_ip_t *fi; 1341 ip_t *ip; 1342 1343 fi = &fin->fin_fi; 1344 hlen = fin->fin_hlen; 1345 1346 ip = fin->fin_ip; 1347 p = ip->ip_p; 1348 fi->fi_p = p; 1349 fi->fi_tos = ip->ip_tos; 1350 fin->fin_id = ip->ip_id; 1351 off = ip->ip_off; 1352 1353 /* Get both TTL and protocol */ 1354 fi->fi_p = ip->ip_p; 1355 fi->fi_ttl = ip->ip_ttl; 1356 #if 0 1357 (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4)); 1358 #endif 1359 1360 /* Zero out bits not used in IPv6 address */ 1361 fi->fi_src.i6[1] = 0; 1362 fi->fi_src.i6[2] = 0; 1363 fi->fi_src.i6[3] = 0; 1364 fi->fi_dst.i6[1] = 0; 1365 fi->fi_dst.i6[2] = 0; 1366 fi->fi_dst.i6[3] = 0; 1367 1368 fi->fi_saddr = ip->ip_src.s_addr; 1369 fi->fi_daddr = ip->ip_dst.s_addr; 1370 1371 /* 1372 * set packet attribute flags based on the offset and 1373 * calculate the byte offset that it represents. 1374 */ 1375 off &= IP_MF|IP_OFFMASK; 1376 if (off != 0) { 1377 fi->fi_flx |= FI_FRAG; 1378 off &= IP_OFFMASK; 1379 if (off != 0) { 1380 fin->fin_flx |= FI_FRAGBODY; 1381 off <<= 3; 1382 if ((off + fin->fin_dlen > 65535) || 1383 (fin->fin_dlen == 0) || 1384 ((ip->ip_off & IP_MF) && (fin->fin_dlen & 7))) { 1385 /* 1386 * The length of the packet, starting at its 1387 * offset cannot exceed 65535 (0xffff) as the 1388 * length of an IP packet is only 16 bits. 1389 * 1390 * Any fragment that isn't the last fragment 1391 * must have a length greater than 0 and it 1392 * must be an even multiple of 8. 1393 */ 1394 fi->fi_flx |= FI_BAD; 1395 } 1396 } 1397 } 1398 fin->fin_off = off; 1399 1400 /* 1401 * Call per-protocol setup and checking 1402 */ 1403 switch (p) 1404 { 1405 case IPPROTO_UDP : 1406 frpr_udp(fin); 1407 break; 1408 case IPPROTO_TCP : 1409 frpr_tcp(fin); 1410 break; 1411 case IPPROTO_ICMP : 1412 frpr_icmp(fin); 1413 break; 1414 case IPPROTO_AH : 1415 frpr_ah(fin); 1416 break; 1417 case IPPROTO_ESP : 1418 frpr_esp(fin); 1419 break; 1420 case IPPROTO_GRE : 1421 frpr_gre(fin); 1422 break; 1423 } 1424 1425 ip = fin->fin_ip; 1426 if (ip == NULL) 1427 return; 1428 1429 /* 1430 * If it is a standard IP header (no options), set the flag fields 1431 * which relate to options to 0. 1432 */ 1433 if (hlen == sizeof(*ip)) { 1434 fi->fi_optmsk = 0; 1435 fi->fi_secmsk = 0; 1436 fi->fi_auth = 0; 1437 return; 1438 } 1439 1440 /* 1441 * So the IP header has some IP options attached. Walk the entire 1442 * list of options present with this packet and set flags to indicate 1443 * which ones are here and which ones are not. For the somewhat out 1444 * of date and obscure security classification options, set a flag to 1445 * represent which classification is present. 1446 */ 1447 fi->fi_flx |= FI_OPTIONS; 1448 1449 for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) { 1450 opt = *s; 1451 if (opt == '\0') 1452 break; 1453 else if (opt == IPOPT_NOP) 1454 ol = 1; 1455 else { 1456 if (hlen < 2) 1457 break; 1458 ol = (int)*(s + 1); 1459 if (ol < 2 || ol > hlen) 1460 break; 1461 } 1462 for (i = 9, mv = 4; mv >= 0; ) { 1463 op = ipopts + i; 1464 if ((opt == (u_char)op->ol_val) && (ol > 4)) { 1465 optmsk |= op->ol_bit; 1466 if (opt == IPOPT_SECURITY) { 1467 const struct optlist *sp; 1468 u_char sec; 1469 int j, m; 1470 1471 sec = *(s + 2); /* classification */ 1472 for (j = 3, m = 2; m >= 0; ) { 1473 sp = secopt + j; 1474 if (sec == sp->ol_val) { 1475 secmsk |= sp->ol_bit; 1476 auth = *(s + 3); 1477 auth *= 256; 1478 auth += *(s + 4); 1479 break; 1480 } 1481 if (sec < sp->ol_val) 1482 j -= m; 1483 else 1484 j += m; 1485 m--; 1486 } 1487 } 1488 break; 1489 } 1490 if (opt < op->ol_val) 1491 i -= mv; 1492 else 1493 i += mv; 1494 mv--; 1495 } 1496 hlen -= ol; 1497 s += ol; 1498 } 1499 1500 /* 1501 * 1502 */ 1503 if (auth && !(auth & 0x0100)) 1504 auth &= 0xff00; 1505 fi->fi_optmsk = optmsk; 1506 fi->fi_secmsk = secmsk; 1507 fi->fi_auth = auth; 1508 } 1509 1510 1511 /* ------------------------------------------------------------------------ */ 1512 /* Function: fr_makefrip */ 1513 /* Returns: int - 1 == hdr checking error, 0 == OK */ 1514 /* Parameters: hlen(I) - length of IP packet header */ 1515 /* ip(I) - pointer to the IP header */ 1516 /* fin(IO) - pointer to packet information */ 1517 /* */ 1518 /* Compact the IP header into a structure which contains just the info. */ 1519 /* which is useful for comparing IP headers with and store this information */ 1520 /* in the fr_info_t structure pointer to by fin. At present, it is assumed */ 1521 /* this function will be called with either an IPv4 or IPv6 packet. */ 1522 /* ------------------------------------------------------------------------ */ 1523 int fr_makefrip(hlen, ip, fin) 1524 int hlen; 1525 ip_t *ip; 1526 fr_info_t *fin; 1527 { 1528 int v; 1529 1530 fin->fin_nat = NULL; 1531 fin->fin_state = NULL; 1532 fin->fin_depth = 0; 1533 fin->fin_hlen = (u_short)hlen; 1534 fin->fin_ip = ip; 1535 fin->fin_rule = 0xffffffff; 1536 fin->fin_group[0] = -1; 1537 fin->fin_group[1] = '\0'; 1538 fin->fin_dlen = fin->fin_plen - hlen; 1539 fin->fin_dp = (char *)ip + hlen; 1540 1541 v = fin->fin_v; 1542 if (v == 4) 1543 frpr_ipv4hdr(fin); 1544 #ifdef USE_INET6 1545 else if (v == 6) { 1546 if (frpr_ipv6hdr(fin) == -1) 1547 return -1; 1548 } 1549 #endif 1550 if (fin->fin_ip == NULL) 1551 return -1; 1552 return 0; 1553 } 1554 1555 1556 /* ------------------------------------------------------------------------ */ 1557 /* Function: fr_portcheck */ 1558 /* Returns: int - 1 == port matched, 0 == port match failed */ 1559 /* Parameters: frp(I) - pointer to port check `expression' */ 1560 /* pop(I) - pointer to port number to evaluate */ 1561 /* */ 1562 /* Perform a comparison of a port number against some other(s), using a */ 1563 /* structure with compare information stored in it. */ 1564 /* ------------------------------------------------------------------------ */ 1565 static INLINE int fr_portcheck(frp, pop) 1566 frpcmp_t *frp; 1567 u_short *pop; 1568 { 1569 u_short tup, po; 1570 int err = 1; 1571 1572 tup = *pop; 1573 po = frp->frp_port; 1574 1575 /* 1576 * Do opposite test to that required and continue if that succeeds. 1577 */ 1578 switch (frp->frp_cmp) 1579 { 1580 case FR_EQUAL : 1581 if (tup != po) /* EQUAL */ 1582 err = 0; 1583 break; 1584 case FR_NEQUAL : 1585 if (tup == po) /* NOTEQUAL */ 1586 err = 0; 1587 break; 1588 case FR_LESST : 1589 if (tup >= po) /* LESSTHAN */ 1590 err = 0; 1591 break; 1592 case FR_GREATERT : 1593 if (tup <= po) /* GREATERTHAN */ 1594 err = 0; 1595 break; 1596 case FR_LESSTE : 1597 if (tup > po) /* LT or EQ */ 1598 err = 0; 1599 break; 1600 case FR_GREATERTE : 1601 if (tup < po) /* GT or EQ */ 1602 err = 0; 1603 break; 1604 case FR_OUTRANGE : 1605 if (tup >= po && tup <= frp->frp_top) /* Out of range */ 1606 err = 0; 1607 break; 1608 case FR_INRANGE : 1609 if (tup <= po || tup >= frp->frp_top) /* In range */ 1610 err = 0; 1611 break; 1612 case FR_INCRANGE : 1613 if (tup < po || tup > frp->frp_top) /* Inclusive range */ 1614 err = 0; 1615 break; 1616 default : 1617 break; 1618 } 1619 return err; 1620 } 1621 1622 1623 /* ------------------------------------------------------------------------ */ 1624 /* Function: fr_tcpudpchk */ 1625 /* Returns: int - 1 == protocol matched, 0 == check failed */ 1626 /* Parameters: fin(I) - pointer to packet information */ 1627 /* ft(I) - pointer to structure with comparison data */ 1628 /* */ 1629 /* Compares the current pcket (assuming it is TCP/UDP) information with a */ 1630 /* structure containing information that we want to match against. */ 1631 /* ------------------------------------------------------------------------ */ 1632 int fr_tcpudpchk(fin, ft) 1633 fr_info_t *fin; 1634 frtuc_t *ft; 1635 { 1636 int err = 1; 1637 1638 /* 1639 * Both ports should *always* be in the first fragment. 1640 * So far, I cannot find any cases where they can not be. 1641 * 1642 * compare destination ports 1643 */ 1644 if (ft->ftu_dcmp) 1645 err = fr_portcheck(&ft->ftu_dst, &fin->fin_dport); 1646 1647 /* 1648 * compare source ports 1649 */ 1650 if (err && ft->ftu_scmp) 1651 err = fr_portcheck(&ft->ftu_src, &fin->fin_sport); 1652 1653 /* 1654 * If we don't have all the TCP/UDP header, then how can we 1655 * expect to do any sort of match on it ? If we were looking for 1656 * TCP flags, then NO match. If not, then match (which should 1657 * satisfy the "short" class too). 1658 */ 1659 if (err && (fin->fin_p == IPPROTO_TCP)) { 1660 if (fin->fin_flx & FI_SHORT) 1661 return !(ft->ftu_tcpf | ft->ftu_tcpfm); 1662 /* 1663 * Match the flags ? If not, abort this match. 1664 */ 1665 if (ft->ftu_tcpfm && 1666 ft->ftu_tcpf != (fin->fin_tcpf & ft->ftu_tcpfm)) { 1667 FR_DEBUG(("f. %#x & %#x != %#x\n", fin->fin_tcpf, 1668 ft->ftu_tcpfm, ft->ftu_tcpf)); 1669 err = 0; 1670 } 1671 } 1672 return err; 1673 } 1674 1675 1676 /* ------------------------------------------------------------------------ */ 1677 /* Function: fr_ipfcheck */ 1678 /* Returns: int - 0 == match, 1 == no match */ 1679 /* Parameters: fin(I) - pointer to packet information */ 1680 /* fr(I) - pointer to filter rule */ 1681 /* portcmp(I) - flag indicating whether to attempt matching on */ 1682 /* TCP/UDP port data. */ 1683 /* */ 1684 /* Check to see if a packet matches an IPFilter rule. Checks of addresses, */ 1685 /* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */ 1686 /* this function. */ 1687 /* ------------------------------------------------------------------------ */ 1688 static INLINE int fr_ipfcheck(fin, fr, portcmp) 1689 fr_info_t *fin; 1690 frentry_t *fr; 1691 int portcmp; 1692 { 1693 u_32_t *ld, *lm, *lip; 1694 fripf_t *fri; 1695 fr_ip_t *fi; 1696 int i; 1697 ipf_stack_t *ifs = fin->fin_ifs; 1698 1699 fi = &fin->fin_fi; 1700 fri = fr->fr_ipf; 1701 lip = (u_32_t *)fi; 1702 lm = (u_32_t *)&fri->fri_mip; 1703 ld = (u_32_t *)&fri->fri_ip; 1704 1705 /* 1706 * first 32 bits to check coversion: 1707 * IP version, TOS, TTL, protocol 1708 */ 1709 i = ((*lip & *lm) != *ld); 1710 FR_DEBUG(("0. %#08x & %#08x != %#08x\n", 1711 *lip, *lm, *ld)); 1712 if (i) 1713 return 1; 1714 1715 /* 1716 * Next 32 bits is a constructed bitmask indicating which IP options 1717 * are present (if any) in this packet. 1718 */ 1719 lip++, lm++, ld++; 1720 i |= ((*lip & *lm) != *ld); 1721 FR_DEBUG(("1. %#08x & %#08x != %#08x\n", 1722 *lip, *lm, *ld)); 1723 if (i) 1724 return 1; 1725 1726 lip++, lm++, ld++; 1727 /* 1728 * Unrolled loops (4 each, for 32 bits) for address checks. 1729 */ 1730 /* 1731 * Check the source address. 1732 */ 1733 #ifdef IPFILTER_LOOKUP 1734 if (fr->fr_satype == FRI_LOOKUP) { 1735 i = (*fr->fr_srcfunc)(fr->fr_srcptr, fi->fi_v, lip, ifs); 1736 if (i == -1) 1737 return 1; 1738 lip += 3; 1739 lm += 3; 1740 ld += 3; 1741 } else { 1742 #endif 1743 i = ((*lip & *lm) != *ld); 1744 FR_DEBUG(("2a. %#08x & %#08x != %#08x\n", 1745 *lip, *lm, *ld)); 1746 if (fi->fi_v == 6) { 1747 lip++, lm++, ld++; 1748 i |= ((*lip & *lm) != *ld); 1749 FR_DEBUG(("2b. %#08x & %#08x != %#08x\n", 1750 *lip, *lm, *ld)); 1751 lip++, lm++, ld++; 1752 i |= ((*lip & *lm) != *ld); 1753 FR_DEBUG(("2c. %#08x & %#08x != %#08x\n", 1754 *lip, *lm, *ld)); 1755 lip++, lm++, ld++; 1756 i |= ((*lip & *lm) != *ld); 1757 FR_DEBUG(("2d. %#08x & %#08x != %#08x\n", 1758 *lip, *lm, *ld)); 1759 } else { 1760 lip += 3; 1761 lm += 3; 1762 ld += 3; 1763 } 1764 #ifdef IPFILTER_LOOKUP 1765 } 1766 #endif 1767 i ^= (fr->fr_flags & FR_NOTSRCIP) >> 6; 1768 if (i) 1769 return 1; 1770 1771 /* 1772 * Check the destination address. 1773 */ 1774 lip++, lm++, ld++; 1775 #ifdef IPFILTER_LOOKUP 1776 if (fr->fr_datype == FRI_LOOKUP) { 1777 i = (*fr->fr_dstfunc)(fr->fr_dstptr, fi->fi_v, lip, ifs); 1778 if (i == -1) 1779 return 1; 1780 lip += 3; 1781 lm += 3; 1782 ld += 3; 1783 } else { 1784 #endif 1785 i = ((*lip & *lm) != *ld); 1786 FR_DEBUG(("3a. %#08x & %#08x != %#08x\n", 1787 *lip, *lm, *ld)); 1788 if (fi->fi_v == 6) { 1789 lip++, lm++, ld++; 1790 i |= ((*lip & *lm) != *ld); 1791 FR_DEBUG(("3b. %#08x & %#08x != %#08x\n", 1792 *lip, *lm, *ld)); 1793 lip++, lm++, ld++; 1794 i |= ((*lip & *lm) != *ld); 1795 FR_DEBUG(("3c. %#08x & %#08x != %#08x\n", 1796 *lip, *lm, *ld)); 1797 lip++, lm++, ld++; 1798 i |= ((*lip & *lm) != *ld); 1799 FR_DEBUG(("3d. %#08x & %#08x != %#08x\n", 1800 *lip, *lm, *ld)); 1801 } else { 1802 lip += 3; 1803 lm += 3; 1804 ld += 3; 1805 } 1806 #ifdef IPFILTER_LOOKUP 1807 } 1808 #endif 1809 i ^= (fr->fr_flags & FR_NOTDSTIP) >> 7; 1810 if (i) 1811 return 1; 1812 /* 1813 * IP addresses matched. The next 32bits contains: 1814 * mast of old IP header security & authentication bits. 1815 */ 1816 lip++, lm++, ld++; 1817 i |= ((*lip & *lm) != *ld); 1818 FR_DEBUG(("4. %#08x & %#08x != %#08x\n", 1819 *lip, *lm, *ld)); 1820 1821 /* 1822 * Next we have 32 bits of packet flags. 1823 */ 1824 lip++, lm++, ld++; 1825 i |= ((*lip & *lm) != *ld); 1826 FR_DEBUG(("5. %#08x & %#08x != %#08x\n", 1827 *lip, *lm, *ld)); 1828 1829 if (i == 0) { 1830 /* 1831 * If a fragment, then only the first has what we're 1832 * looking for here... 1833 */ 1834 if (portcmp) { 1835 if (!fr_tcpudpchk(fin, &fr->fr_tuc)) 1836 i = 1; 1837 } else { 1838 if (fr->fr_dcmp || fr->fr_scmp || 1839 fr->fr_tcpf || fr->fr_tcpfm) 1840 i = 1; 1841 if (fr->fr_icmpm || fr->fr_icmp) { 1842 if (((fi->fi_p != IPPROTO_ICMP) && 1843 (fi->fi_p != IPPROTO_ICMPV6)) || 1844 fin->fin_off || (fin->fin_dlen < 2)) 1845 i = 1; 1846 else if ((fin->fin_data[0] & fr->fr_icmpm) != 1847 fr->fr_icmp) { 1848 FR_DEBUG(("i. %#x & %#x != %#x\n", 1849 fin->fin_data[0], 1850 fr->fr_icmpm, fr->fr_icmp)); 1851 i = 1; 1852 } 1853 } 1854 } 1855 } 1856 return i; 1857 } 1858 1859 1860 /* ------------------------------------------------------------------------ */ 1861 /* Function: fr_scanlist */ 1862 /* Returns: int - result flags of scanning filter list */ 1863 /* Parameters: fin(I) - pointer to packet information */ 1864 /* pass(I) - default result to return for filtering */ 1865 /* */ 1866 /* Check the input/output list of rules for a match to the current packet. */ 1867 /* If a match is found, the value of fr_flags from the rule becomes the */ 1868 /* return value and fin->fin_fr points to the matched rule. */ 1869 /* */ 1870 /* This function may be called recusively upto 16 times (limit inbuilt.) */ 1871 /* When unwinding, it should finish up with fin_depth as 0. */ 1872 /* */ 1873 /* Could be per interface, but this gets real nasty when you don't have, */ 1874 /* or can't easily change, the kernel source code to . */ 1875 /* ------------------------------------------------------------------------ */ 1876 int fr_scanlist(fin, pass) 1877 fr_info_t *fin; 1878 u_32_t pass; 1879 { 1880 int rulen, portcmp, off, logged, skip; 1881 struct frentry *fr, *fnext; 1882 u_32_t passt, passo; 1883 ipf_stack_t *ifs = fin->fin_ifs; 1884 1885 /* 1886 * Do not allow nesting deeper than 16 levels. 1887 */ 1888 if (fin->fin_depth >= 16) 1889 return pass; 1890 1891 fr = fin->fin_fr; 1892 1893 /* 1894 * If there are no rules in this list, return now. 1895 */ 1896 if (fr == NULL) 1897 return pass; 1898 1899 skip = 0; 1900 logged = 0; 1901 portcmp = 0; 1902 fin->fin_depth++; 1903 fin->fin_fr = NULL; 1904 off = fin->fin_off; 1905 1906 if ((fin->fin_flx & FI_TCPUDP) && (fin->fin_dlen > 3) && !off) 1907 portcmp = 1; 1908 1909 for (rulen = 0; fr; fr = fnext, rulen++) { 1910 fnext = fr->fr_next; 1911 if (skip != 0) { 1912 FR_VERBOSE(("%d (%#x)\n", skip, fr->fr_flags)); 1913 skip--; 1914 continue; 1915 } 1916 1917 /* 1918 * In all checks below, a null (zero) value in the 1919 * filter struture is taken to mean a wildcard. 1920 * 1921 * check that we are working for the right interface 1922 */ 1923 #ifdef _KERNEL 1924 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) 1925 continue; 1926 #else 1927 if (opts & (OPT_VERBOSE|OPT_DEBUG)) 1928 printf("\n"); 1929 FR_VERBOSE(("%c", FR_ISSKIP(pass) ? 's' : 1930 FR_ISPASS(pass) ? 'p' : 1931 FR_ISACCOUNT(pass) ? 'A' : 1932 FR_ISAUTH(pass) ? 'a' : 1933 (pass & FR_NOMATCH) ? 'n' :'b')); 1934 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) 1935 continue; 1936 FR_VERBOSE((":i")); 1937 #endif 1938 1939 switch (fr->fr_type) 1940 { 1941 case FR_T_IPF : 1942 case FR_T_IPF|FR_T_BUILTIN : 1943 if (fr_ipfcheck(fin, fr, portcmp)) 1944 continue; 1945 break; 1946 #if defined(IPFILTER_BPF) 1947 case FR_T_BPFOPC : 1948 case FR_T_BPFOPC|FR_T_BUILTIN : 1949 { 1950 u_char *mc; 1951 1952 if (*fin->fin_mp == NULL) 1953 continue; 1954 if (fin->fin_v != fr->fr_v) 1955 continue; 1956 mc = (u_char *)fin->fin_m; 1957 if (!bpf_filter(fr->fr_data, mc, fin->fin_plen, 0)) 1958 continue; 1959 break; 1960 } 1961 #endif 1962 case FR_T_CALLFUNC|FR_T_BUILTIN : 1963 { 1964 frentry_t *f; 1965 1966 f = (*fr->fr_func)(fin, &pass); 1967 if (f != NULL) 1968 fr = f; 1969 else 1970 continue; 1971 break; 1972 } 1973 default : 1974 break; 1975 } 1976 1977 if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) { 1978 if (fin->fin_nattag == NULL) 1979 continue; 1980 if (fr_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0) 1981 continue; 1982 } 1983 FR_VERBOSE(("=%s.%d *", fr->fr_group, rulen)); 1984 1985 passt = fr->fr_flags; 1986 1987 /* 1988 * Allowing a rule with the "keep state" flag set to match 1989 * packets that have been tagged "out of window" by the TCP 1990 * state tracking is foolish as the attempt to add a new 1991 * state entry to the table will fail. 1992 */ 1993 if ((passt & FR_KEEPSTATE) && (fin->fin_flx & FI_OOW)) 1994 continue; 1995 1996 /* 1997 * If the rule is a "call now" rule, then call the function 1998 * in the rule, if it exists and use the results from that. 1999 * If the function pointer is bad, just make like we ignore 2000 * it, except for increasing the hit counter. 2001 */ 2002 if ((passt & FR_CALLNOW) != 0) { 2003 IPF_BUMP(fr->fr_hits); 2004 if ((fr->fr_func != NULL) && 2005 (fr->fr_func != (ipfunc_t)-1)) { 2006 frentry_t *frs; 2007 2008 frs = fin->fin_fr; 2009 fin->fin_fr = fr; 2010 fr = (*fr->fr_func)(fin, &passt); 2011 if (fr == NULL) { 2012 fin->fin_fr = frs; 2013 continue; 2014 } 2015 passt = fr->fr_flags; 2016 fin->fin_fr = fr; 2017 } 2018 } else { 2019 fin->fin_fr = fr; 2020 } 2021 2022 #ifdef IPFILTER_LOG 2023 /* 2024 * Just log this packet... 2025 */ 2026 if ((passt & FR_LOGMASK) == FR_LOG) { 2027 if (ipflog(fin, passt) == -1) { 2028 if (passt & FR_LOGORBLOCK) { 2029 passt &= ~FR_CMDMASK; 2030 passt |= FR_BLOCK|FR_QUICK; 2031 } 2032 IPF_BUMP(ifs->ifs_frstats[fin->fin_out].fr_skip); 2033 } 2034 IPF_BUMP(ifs->ifs_frstats[fin->fin_out].fr_pkl); 2035 logged = 1; 2036 } 2037 #endif /* IPFILTER_LOG */ 2038 fr->fr_bytes += (U_QUAD_T)fin->fin_plen; 2039 passo = pass; 2040 if (FR_ISSKIP(passt)) 2041 skip = fr->fr_arg; 2042 else if ((passt & FR_LOGMASK) != FR_LOG) 2043 pass = passt; 2044 if (passt & (FR_RETICMP|FR_FAKEICMP)) 2045 fin->fin_icode = fr->fr_icode; 2046 FR_DEBUG(("pass %#x\n", pass)); 2047 IPF_BUMP(fr->fr_hits); 2048 fin->fin_rule = rulen; 2049 (void) strncpy(fin->fin_group, fr->fr_group, FR_GROUPLEN); 2050 if (fr->fr_grp != NULL) { 2051 fin->fin_fr = *fr->fr_grp; 2052 pass = fr_scanlist(fin, pass); 2053 if (fin->fin_fr == NULL) { 2054 fin->fin_rule = rulen; 2055 (void) strncpy(fin->fin_group, fr->fr_group, 2056 FR_GROUPLEN); 2057 fin->fin_fr = fr; 2058 } 2059 if (fin->fin_flx & FI_DONTCACHE) 2060 logged = 1; 2061 } 2062 2063 if (pass & FR_QUICK) { 2064 /* 2065 * Finally, if we've asked to track state for this 2066 * packet, set it up. Add state for "quick" rules 2067 * here so that if the action fails we can consider 2068 * the rule to "not match" and keep on processing 2069 * filter rules. 2070 */ 2071 if ((pass & FR_KEEPSTATE) && 2072 !(fin->fin_flx & FI_STATE)) { 2073 int out = fin->fin_out; 2074 2075 if (fr_addstate(fin, NULL, 0) != NULL) { 2076 IPF_BUMP(ifs->ifs_frstats[out].fr_ads); 2077 } else { 2078 IPF_BUMP(ifs->ifs_frstats[out].fr_bads); 2079 pass = passo; 2080 continue; 2081 } 2082 } 2083 break; 2084 } 2085 } 2086 if (logged) 2087 fin->fin_flx |= FI_DONTCACHE; 2088 fin->fin_depth--; 2089 return pass; 2090 } 2091 2092 2093 /* ------------------------------------------------------------------------ */ 2094 /* Function: fr_acctpkt */ 2095 /* Returns: frentry_t* - always returns NULL */ 2096 /* Parameters: fin(I) - pointer to packet information */ 2097 /* passp(IO) - pointer to current/new filter decision (unused) */ 2098 /* */ 2099 /* Checks a packet against accounting rules, if there are any for the given */ 2100 /* IP protocol version. */ 2101 /* */ 2102 /* N.B.: this function returns NULL to match the prototype used by other */ 2103 /* functions called from the IPFilter "mainline" in fr_check(). */ 2104 /* ------------------------------------------------------------------------ */ 2105 frentry_t *fr_acctpkt(fin, passp) 2106 fr_info_t *fin; 2107 u_32_t *passp; 2108 { 2109 char group[FR_GROUPLEN]; 2110 frentry_t *fr, *frsave; 2111 u_32_t pass, rulen; 2112 ipf_stack_t *ifs = fin->fin_ifs; 2113 2114 passp = passp; 2115 #ifdef USE_INET6 2116 if (fin->fin_v == 6) 2117 fr = ifs->ifs_ipacct6[fin->fin_out][ifs->ifs_fr_active]; 2118 else 2119 #endif 2120 fr = ifs->ifs_ipacct[fin->fin_out][ifs->ifs_fr_active]; 2121 2122 if (fr != NULL) { 2123 frsave = fin->fin_fr; 2124 bcopy(fin->fin_group, group, FR_GROUPLEN); 2125 rulen = fin->fin_rule; 2126 fin->fin_fr = fr; 2127 pass = fr_scanlist(fin, FR_NOMATCH); 2128 if (FR_ISACCOUNT(pass)) { 2129 IPF_BUMP(ifs->ifs_frstats[0].fr_acct); 2130 } 2131 fin->fin_fr = frsave; 2132 bcopy(group, fin->fin_group, FR_GROUPLEN); 2133 fin->fin_rule = rulen; 2134 } 2135 return NULL; 2136 } 2137 2138 2139 /* ------------------------------------------------------------------------ */ 2140 /* Function: fr_firewall */ 2141 /* Returns: frentry_t* - returns pointer to matched rule, if no matches */ 2142 /* were found, returns NULL. */ 2143 /* Parameters: fin(I) - pointer to packet information */ 2144 /* passp(IO) - pointer to current/new filter decision (unused) */ 2145 /* */ 2146 /* Applies an appropriate set of firewall rules to the packet, to see if */ 2147 /* there are any matches. The first check is to see if a match can be seen */ 2148 /* in the cache. If not, then search an appropriate list of rules. Once a */ 2149 /* matching rule is found, take any appropriate actions as defined by the */ 2150 /* rule - except logging. */ 2151 /* ------------------------------------------------------------------------ */ 2152 static frentry_t *fr_firewall(fin, passp) 2153 fr_info_t *fin; 2154 u_32_t *passp; 2155 { 2156 frentry_t *fr; 2157 u_32_t pass; 2158 int out; 2159 ipf_stack_t *ifs = fin->fin_ifs; 2160 2161 out = fin->fin_out; 2162 pass = *passp; 2163 2164 #ifdef USE_INET6 2165 if (fin->fin_v == 6) 2166 fin->fin_fr = ifs->ifs_ipfilter6[out][ifs->ifs_fr_active]; 2167 else 2168 #endif 2169 fin->fin_fr = ifs->ifs_ipfilter[out][ifs->ifs_fr_active]; 2170 if (fin->fin_fr != NULL) 2171 pass = fr_scanlist(fin, ifs->ifs_fr_pass); 2172 2173 if ((pass & FR_NOMATCH)) { 2174 IPF_BUMP(ifs->ifs_frstats[out].fr_nom); 2175 } 2176 fr = fin->fin_fr; 2177 2178 /* 2179 * Apply packets per second rate-limiting to a rule as required. 2180 */ 2181 if ((fr != NULL) && (fr->fr_pps != 0) && 2182 !ppsratecheck(&fr->fr_lastpkt, &fr->fr_curpps, fr->fr_pps)) { 2183 pass &= ~(FR_CMDMASK|FR_DUP|FR_RETICMP|FR_RETRST); 2184 pass |= FR_BLOCK; 2185 IPF_BUMP(ifs->ifs_frstats[out].fr_ppshit); 2186 } 2187 2188 /* 2189 * If we fail to add a packet to the authorization queue, then we 2190 * drop the packet later. However, if it was added then pretend 2191 * we've dropped it already. 2192 */ 2193 if (FR_ISAUTH(pass)) { 2194 if (fr_newauth(fin->fin_m, fin) != 0) { 2195 #ifdef _KERNEL 2196 fin->fin_m = *fin->fin_mp = NULL; 2197 #else 2198 ; 2199 #endif 2200 fin->fin_error = 0; 2201 } else 2202 fin->fin_error = ENOSPC; 2203 } 2204 2205 if ((fr != NULL) && (fr->fr_func != NULL) && 2206 (fr->fr_func != (ipfunc_t)-1) && !(pass & FR_CALLNOW)) 2207 (void) (*fr->fr_func)(fin, &pass); 2208 2209 /* 2210 * If a rule is a pre-auth rule, check again in the list of rules 2211 * loaded for authenticated use. It does not particulary matter 2212 * if this search fails because a "preauth" result, from a rule, 2213 * is treated as "not a pass", hence the packet is blocked. 2214 */ 2215 if (FR_ISPREAUTH(pass)) { 2216 if ((fin->fin_fr = ifs->ifs_ipauth) != NULL) 2217 pass = fr_scanlist(fin, ifs->ifs_fr_pass); 2218 } 2219 2220 /* 2221 * If the rule has "keep frag" and the packet is actually a fragment, 2222 * then create a fragment state entry. 2223 */ 2224 if ((pass & (FR_KEEPFRAG|FR_KEEPSTATE)) == FR_KEEPFRAG) { 2225 if (fin->fin_flx & FI_FRAG) { 2226 if (fr_newfrag(fin, pass) == -1) { 2227 IPF_BUMP(ifs->ifs_frstats[out].fr_bnfr); 2228 } else { 2229 IPF_BUMP(ifs->ifs_frstats[out].fr_nfr); 2230 } 2231 } else { 2232 IPF_BUMP(ifs->ifs_frstats[out].fr_cfr); 2233 } 2234 } 2235 2236 /* 2237 * Finally, if we've asked to track state for this packet, set it up. 2238 */ 2239 if ((pass & FR_KEEPSTATE) && !(fin->fin_flx & FI_STATE)) { 2240 if (fr_addstate(fin, NULL, 0) != NULL) { 2241 IPF_BUMP(ifs->ifs_frstats[out].fr_ads); 2242 } else { 2243 IPF_BUMP(ifs->ifs_frstats[out].fr_bads); 2244 if (FR_ISPASS(pass)) { 2245 pass &= ~FR_CMDMASK; 2246 pass |= FR_BLOCK; 2247 } 2248 } 2249 } 2250 2251 fr = fin->fin_fr; 2252 2253 if (passp != NULL) 2254 *passp = pass; 2255 2256 return fr; 2257 } 2258 2259 2260 /* ------------------------------------------------------------------------ */ 2261 /* Function: fr_check */ 2262 /* Returns: int - 0 == packet allowed through, */ 2263 /* User space: */ 2264 /* -1 == packet blocked */ 2265 /* 1 == packet not matched */ 2266 /* -2 == requires authentication */ 2267 /* Kernel: */ 2268 /* > 0 == filter error # for packet */ 2269 /* Parameters: ip(I) - pointer to start of IPv4/6 packet */ 2270 /* hlen(I) - length of header */ 2271 /* ifp(I) - pointer to interface this packet is on */ 2272 /* out(I) - 0 == packet going in, 1 == packet going out */ 2273 /* mp(IO) - pointer to caller's buffer pointer that holds this */ 2274 /* IP packet. */ 2275 /* Solaris & HP-UX ONLY : */ 2276 /* qpi(I) - pointer to STREAMS queue information for this */ 2277 /* interface & direction. */ 2278 /* */ 2279 /* fr_check() is the master function for all IPFilter packet processing. */ 2280 /* It orchestrates: Network Address Translation (NAT), checking for packet */ 2281 /* authorisation (or pre-authorisation), presence of related state info., */ 2282 /* generating log entries, IP packet accounting, routing of packets as */ 2283 /* directed by firewall rules and of course whether or not to allow the */ 2284 /* packet to be further processed by the kernel. */ 2285 /* */ 2286 /* For packets blocked, the contents of "mp" will be NULL'd and the buffer */ 2287 /* freed. Packets passed may be returned with the pointer pointed to by */ 2288 /* by "mp" changed to a new buffer. */ 2289 /* ------------------------------------------------------------------------ */ 2290 int fr_check(ip, hlen, ifp, out 2291 #if defined(_KERNEL) && defined(MENTAT) 2292 , qif, mp, ifs) 2293 void *qif; 2294 #else 2295 , mp, ifs) 2296 #endif 2297 mb_t **mp; 2298 ip_t *ip; 2299 int hlen; 2300 void *ifp; 2301 int out; 2302 ipf_stack_t *ifs; 2303 { 2304 /* 2305 * The above really sucks, but short of writing a diff 2306 */ 2307 fr_info_t frinfo; 2308 fr_info_t *fin = &frinfo; 2309 u_32_t pass; 2310 frentry_t *fr = NULL; 2311 int v = IP_V(ip); 2312 mb_t *mc = NULL; 2313 mb_t *m; 2314 #ifdef USE_INET6 2315 ip6_t *ip6; 2316 #endif 2317 #ifdef _KERNEL 2318 # ifdef MENTAT 2319 qpktinfo_t *qpi = qif; 2320 #endif 2321 #endif 2322 2323 SPL_INT(s); 2324 pass = ifs->ifs_fr_pass; 2325 2326 /* 2327 * The first part of fr_check() deals with making sure that what goes 2328 * into the filtering engine makes some sense. Information about the 2329 * the packet is distilled, collected into a fr_info_t structure and 2330 * the an attempt to ensure the buffer the packet is in is big enough 2331 * to hold all the required packet headers. 2332 */ 2333 #ifdef _KERNEL 2334 # ifdef MENTAT 2335 if (!OK_32PTR(ip)) 2336 return 2; 2337 # endif 2338 2339 2340 if (ifs->ifs_fr_running <= 0) { 2341 return 0; 2342 } 2343 2344 bzero((char *)fin, sizeof(*fin)); 2345 2346 # ifdef MENTAT 2347 fin->fin_flx = qpi->qpi_flags & (FI_NOCKSUM|FI_MBCAST|FI_MULTICAST| 2348 FI_BROADCAST); 2349 m = qpi->qpi_m; 2350 fin->fin_qfm = m; 2351 fin->fin_qpi = qpi; 2352 # else /* MENTAT */ 2353 2354 m = *mp; 2355 2356 # if defined(M_MCAST) 2357 if ((m->m_flags & M_MCAST) != 0) 2358 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2359 # endif 2360 # if defined(M_MLOOP) 2361 if ((m->m_flags & M_MLOOP) != 0) 2362 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2363 # endif 2364 # if defined(M_BCAST) 2365 if ((m->m_flags & M_BCAST) != 0) 2366 fin->fin_flx |= FI_MBCAST|FI_BROADCAST; 2367 # endif 2368 # ifdef M_CANFASTFWD 2369 /* 2370 * XXX For now, IP Filter and fast-forwarding of cached flows 2371 * XXX are mutually exclusive. Eventually, IP Filter should 2372 * XXX get a "can-fast-forward" filter rule. 2373 */ 2374 m->m_flags &= ~M_CANFASTFWD; 2375 # endif /* M_CANFASTFWD */ 2376 # ifdef CSUM_DELAY_DATA 2377 /* 2378 * disable delayed checksums. 2379 */ 2380 if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 2381 in_delayed_cksum(m); 2382 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 2383 } 2384 # endif /* CSUM_DELAY_DATA */ 2385 # endif /* MENTAT */ 2386 #else 2387 2388 bzero((char *)fin, sizeof(*fin)); 2389 m = *mp; 2390 #endif /* _KERNEL */ 2391 2392 fin->fin_v = v; 2393 fin->fin_m = m; 2394 fin->fin_ip = ip; 2395 fin->fin_mp = mp; 2396 fin->fin_out = out; 2397 fin->fin_ifp = ifp; 2398 fin->fin_error = ENETUNREACH; 2399 fin->fin_hlen = (u_short)hlen; 2400 fin->fin_dp = (char *)ip + hlen; 2401 fin->fin_ipoff = (char *)ip - MTOD(m, char *); 2402 fin->fin_ifs = ifs; 2403 2404 SPL_NET(s); 2405 2406 #ifdef USE_INET6 2407 if (v == 6) { 2408 IPF_BUMP(ifs->ifs_frstats[out].fr_ipv6); 2409 /* 2410 * Jumbo grams are quite likely too big for internal buffer 2411 * structures to handle comfortably, for now, so just drop 2412 * them. 2413 */ 2414 ip6 = (ip6_t *)ip; 2415 fin->fin_plen = ntohs(ip6->ip6_plen); 2416 if (fin->fin_plen == 0) { 2417 READ_ENTER(&ifs->ifs_ipf_mutex); 2418 pass = FR_BLOCK|FR_NOMATCH; 2419 goto filtered; 2420 } 2421 fin->fin_plen += sizeof(ip6_t); 2422 } else 2423 #endif 2424 { 2425 #if (OpenBSD >= 200311) && defined(_KERNEL) 2426 ip->ip_len = ntohs(ip->ip_len); 2427 ip->ip_off = ntohs(ip->ip_off); 2428 #endif 2429 fin->fin_plen = ip->ip_len; 2430 } 2431 2432 if (fr_makefrip(hlen, ip, fin) == -1) { 2433 READ_ENTER(&ifs->ifs_ipf_mutex); 2434 pass = FR_BLOCK; 2435 goto filtered; 2436 } 2437 2438 /* 2439 * For at least IPv6 packets, if a m_pullup() fails then this pointer 2440 * becomes NULL and so we have no packet to free. 2441 */ 2442 if (*fin->fin_mp == NULL) 2443 goto finished; 2444 2445 if (!out) { 2446 if (v == 4) { 2447 #ifdef _KERNEL 2448 if (ifs->ifs_fr_chksrc && !fr_verifysrc(fin)) { 2449 IPF_BUMP(ifs->ifs_frstats[0].fr_badsrc); 2450 fin->fin_flx |= FI_BADSRC; 2451 } 2452 #endif 2453 if (fin->fin_ip->ip_ttl < ifs->ifs_fr_minttl) { 2454 IPF_BUMP(ifs->ifs_frstats[0].fr_badttl); 2455 fin->fin_flx |= FI_LOWTTL; 2456 } 2457 } 2458 #ifdef USE_INET6 2459 else if (v == 6) { 2460 ip6 = (ip6_t *)ip; 2461 #ifdef _KERNEL 2462 if (ifs->ifs_fr_chksrc && !fr_verifysrc(fin)) { 2463 IPF_BUMP(ifs->ifs_frstats[0].fr_badsrc); 2464 fin->fin_flx |= FI_BADSRC; 2465 } 2466 #endif 2467 if (ip6->ip6_hlim < ifs->ifs_fr_minttl) { 2468 IPF_BUMP(ifs->ifs_frstats[0].fr_badttl); 2469 fin->fin_flx |= FI_LOWTTL; 2470 } 2471 } 2472 #endif 2473 } 2474 2475 if (fin->fin_flx & FI_SHORT) { 2476 IPF_BUMP(ifs->ifs_frstats[out].fr_short); 2477 } 2478 2479 READ_ENTER(&ifs->ifs_ipf_mutex); 2480 2481 /* 2482 * Check auth now. This, combined with the check below to see if apass 2483 * is 0 is to ensure that we don't count the packet twice, which can 2484 * otherwise occur when we reprocess it. As it is, we only count it 2485 * after it has no auth. table matchup. This also stops NAT from 2486 * occuring until after the packet has been auth'd. 2487 */ 2488 fr = fr_checkauth(fin, &pass); 2489 if (!out) { 2490 switch (fin->fin_v) 2491 { 2492 case 4 : 2493 if (fr_checknatin(fin, &pass) == -1) { 2494 RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2495 goto finished; 2496 } 2497 break; 2498 #ifdef USE_INET6 2499 case 6 : 2500 if (fr_checknat6in(fin, &pass) == -1) { 2501 RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2502 goto finished; 2503 } 2504 break; 2505 #endif 2506 default : 2507 break; 2508 } 2509 } 2510 if (!out) 2511 (void) fr_acctpkt(fin, NULL); 2512 2513 if (fr == NULL) 2514 if ((fin->fin_flx & (FI_FRAG|FI_BAD)) == FI_FRAG) 2515 fr = fr_knownfrag(fin, &pass); 2516 if (fr == NULL) 2517 fr = fr_checkstate(fin, &pass); 2518 2519 if ((pass & FR_NOMATCH) || (fr == NULL)) 2520 fr = fr_firewall(fin, &pass); 2521 2522 fin->fin_fr = fr; 2523 2524 /* 2525 * Only count/translate packets which will be passed on, out the 2526 * interface. 2527 */ 2528 if (out && FR_ISPASS(pass)) { 2529 (void) fr_acctpkt(fin, NULL); 2530 2531 switch (fin->fin_v) 2532 { 2533 case 4 : 2534 if (fr_checknatout(fin, &pass) == -1) { 2535 RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2536 goto finished; 2537 } 2538 break; 2539 #ifdef USE_INET6 2540 case 6 : 2541 if (fr_checknat6out(fin, &pass) == -1) { 2542 RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2543 goto finished; 2544 } 2545 break; 2546 #endif 2547 default : 2548 break; 2549 } 2550 2551 if ((ifs->ifs_fr_update_ipid != 0) && (v == 4)) { 2552 if (fr_updateipid(fin) == -1) { 2553 IPF_BUMP(ifs->ifs_frstats[1].fr_ipud); 2554 pass &= ~FR_CMDMASK; 2555 pass |= FR_BLOCK; 2556 } else { 2557 IPF_BUMP(ifs->ifs_frstats[0].fr_ipud); 2558 } 2559 } 2560 } 2561 2562 #ifdef IPFILTER_LOG 2563 if ((ifs->ifs_fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) { 2564 (void) fr_dolog(fin, &pass); 2565 } 2566 #endif 2567 2568 if (fin->fin_state != NULL) 2569 fr_statederef((ipstate_t **)&fin->fin_state, ifs); 2570 2571 /* 2572 * Only allow FR_DUP to work if a rule matched - it makes no sense to 2573 * set FR_DUP as a "default" as there are no instructions about where 2574 * to send the packet. Use fin_m here because it may have changed 2575 * (without an update of 'm') in prior processing. 2576 */ 2577 if ((fr != NULL) && (pass & FR_DUP)) { 2578 mc = M_DUPLICATE(fin->fin_m); 2579 } 2580 2581 if (pass & (FR_RETRST|FR_RETICMP)) { 2582 /* 2583 * Should we return an ICMP packet to indicate error 2584 * status passing through the packet filter ? 2585 * WARNING: ICMP error packets AND TCP RST packets should 2586 * ONLY be sent in repsonse to incoming packets. Sending them 2587 * in response to outbound packets can result in a panic on 2588 * some operating systems. 2589 */ 2590 if (!out) { 2591 nat_t *savenat; 2592 2593 /* 2594 * In case this packet is associated with a NAT entry, 2595 * we need to save a pointer to it, set it to NULL, 2596 * and restore the pointer after any return packets 2597 * have been sent. 2598 * 2599 * We must do this to keep calls to fr_send_icmp_err() 2600 * and fr_send_reset() from trying to dereference the 2601 * entry; as the dereference happens (for all packets) 2602 * later on. 2603 */ 2604 savenat = fin->fin_nat; 2605 fin->fin_nat = NULL; 2606 2607 if (pass & FR_RETICMP) { 2608 int dst; 2609 2610 if ((pass & FR_RETMASK) == FR_FAKEICMP) 2611 dst = 1; 2612 else 2613 dst = 0; 2614 (void) fr_send_icmp_err(ICMP_UNREACH, fin, dst); 2615 IPF_BUMP(ifs->ifs_frstats[0].fr_ret); 2616 } else if (((pass & FR_RETMASK) == FR_RETRST) && 2617 !(fin->fin_flx & FI_SHORT)) { 2618 if (fr_send_reset(fin) == 0) { 2619 IPF_BUMP(ifs->ifs_frstats[1].fr_ret); 2620 } 2621 } 2622 2623 fin->fin_nat = savenat; 2624 } else { 2625 if (pass & FR_RETRST) 2626 fin->fin_error = ECONNRESET; 2627 } 2628 } 2629 2630 /* 2631 * fr_send_icmp_err() and fr_send_reset() are the last functions that 2632 * could require use of a NAT entry. If this packet is associated with 2633 * one, it's time to clean up our reference to it. 2634 * 2635 * Note: 2636 * If a new NAT entry was created as result of this packet, and the 2637 * packet was blocked, then the entry should be forcibly removed 2638 * from the table. Otherwise, it's sufficient to simply give up the 2639 * reference to it. 2640 */ 2641 if (fin->fin_nat != NULL) { 2642 if (FR_ISBLOCK(pass) && (fin->fin_flx & FI_NEWNAT)) { 2643 WRITE_ENTER(&ifs->ifs_ipf_nat); 2644 (void) nat_delete((nat_t *)fin->fin_nat, NL_DESTROY, ifs); 2645 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 2646 fin->fin_nat = NULL; 2647 } else { 2648 fr_natderef((nat_t **)&fin->fin_nat, ifs); 2649 } 2650 } 2651 2652 /* 2653 * If we didn't drop off the bottom of the list of rules (and thus 2654 * the 'current' rule fr is not NULL), then we may have some extra 2655 * instructions about what to do with a packet. 2656 * Once we're finished return to our caller, freeing the packet if 2657 * we are dropping it (* BSD ONLY *). 2658 * Reassign m from fin_m as we may have a new buffer, now. 2659 */ 2660 filtered: 2661 m = fin->fin_m; 2662 2663 if (fr != NULL) { 2664 frdest_t *fdp; 2665 2666 fdp = &fr->fr_tifs[fin->fin_rev]; 2667 2668 if (!out && (pass & FR_FASTROUTE)) { 2669 /* 2670 * For fastroute rule, no destioation interface defined 2671 * so pass NULL as the frdest_t parameter 2672 */ 2673 (void) fr_fastroute(m, mp, fin, NULL); 2674 m = *mp = NULL; 2675 } else if ((fdp->fd_ifp != NULL) && 2676 (fdp->fd_ifp != (struct ifnet *)-1)) { 2677 /* this is for to rules: */ 2678 (void) fr_fastroute(m, mp, fin, fdp); 2679 m = *mp = NULL; 2680 } 2681 2682 /* 2683 * Generate a duplicated packet. 2684 */ 2685 if (mc != NULL) 2686 (void) fr_fastroute(mc, &mc, fin, &fr->fr_dif); 2687 } 2688 2689 /* 2690 * This late because the likes of fr_fastroute() use fin_fr. 2691 */ 2692 RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2693 2694 finished: 2695 if (!FR_ISPASS(pass)) { 2696 IPF_BUMP(ifs->ifs_frstats[out].fr_block); 2697 if (*mp != NULL) { 2698 FREE_MB_T(*mp); 2699 m = *mp = NULL; 2700 } 2701 } else { 2702 IPF_BUMP(ifs->ifs_frstats[out].fr_pass); 2703 #if defined(_KERNEL) && defined(__sgi) 2704 if ((fin->fin_hbuf != NULL) && 2705 (mtod(fin->fin_m, struct ip *) != fin->fin_ip)) { 2706 COPYBACK(m, 0, fin->fin_plen, fin->fin_hbuf); 2707 } 2708 #endif 2709 } 2710 2711 SPL_X(s); 2712 2713 #ifdef _KERNEL 2714 # if OpenBSD >= 200311 2715 if (FR_ISPASS(pass) && (v == 4)) { 2716 ip = fin->fin_ip; 2717 ip->ip_len = ntohs(ip->ip_len); 2718 ip->ip_off = ntohs(ip->ip_off); 2719 } 2720 # endif 2721 return (FR_ISPASS(pass)) ? 0 : fin->fin_error; 2722 #else /* _KERNEL */ 2723 FR_VERBOSE(("fin_flx %#x pass %#x ", fin->fin_flx, pass)); 2724 if ((pass & FR_NOMATCH) != 0) 2725 return 1; 2726 2727 if ((pass & FR_RETMASK) != 0) 2728 switch (pass & FR_RETMASK) 2729 { 2730 case FR_RETRST : 2731 return 3; 2732 case FR_RETICMP : 2733 return 4; 2734 case FR_FAKEICMP : 2735 return 5; 2736 } 2737 2738 switch (pass & FR_CMDMASK) 2739 { 2740 case FR_PASS : 2741 return 0; 2742 case FR_BLOCK : 2743 return -1; 2744 case FR_AUTH : 2745 return -2; 2746 case FR_ACCOUNT : 2747 return -3; 2748 case FR_PREAUTH : 2749 return -4; 2750 } 2751 return 2; 2752 #endif /* _KERNEL */ 2753 } 2754 2755 2756 #ifdef IPFILTER_LOG 2757 /* ------------------------------------------------------------------------ */ 2758 /* Function: fr_dolog */ 2759 /* Returns: frentry_t* - returns contents of fin_fr (no change made) */ 2760 /* Parameters: fin(I) - pointer to packet information */ 2761 /* passp(IO) - pointer to current/new filter decision (unused) */ 2762 /* */ 2763 /* Checks flags set to see how a packet should be logged, if it is to be */ 2764 /* logged. Adjust statistics based on its success or not. */ 2765 /* ------------------------------------------------------------------------ */ 2766 frentry_t *fr_dolog(fin, passp) 2767 fr_info_t *fin; 2768 u_32_t *passp; 2769 { 2770 u_32_t pass; 2771 int out; 2772 ipf_stack_t *ifs = fin->fin_ifs; 2773 2774 out = fin->fin_out; 2775 pass = *passp; 2776 2777 if ((ifs->ifs_fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) { 2778 pass |= FF_LOGNOMATCH; 2779 IPF_BUMP(ifs->ifs_frstats[out].fr_npkl); 2780 goto logit; 2781 } else if (((pass & FR_LOGMASK) == FR_LOGP) || 2782 (FR_ISPASS(pass) && (ifs->ifs_fr_flags & FF_LOGPASS))) { 2783 if ((pass & FR_LOGMASK) != FR_LOGP) 2784 pass |= FF_LOGPASS; 2785 IPF_BUMP(ifs->ifs_frstats[out].fr_ppkl); 2786 goto logit; 2787 } else if (((pass & FR_LOGMASK) == FR_LOGB) || 2788 (FR_ISBLOCK(pass) && (ifs->ifs_fr_flags & FF_LOGBLOCK))) { 2789 if ((pass & FR_LOGMASK) != FR_LOGB) 2790 pass |= FF_LOGBLOCK; 2791 IPF_BUMP(ifs->ifs_frstats[out].fr_bpkl); 2792 logit: 2793 if (ipflog(fin, pass) == -1) { 2794 IPF_BUMP(ifs->ifs_frstats[out].fr_skip); 2795 2796 /* 2797 * If the "or-block" option has been used then 2798 * block the packet if we failed to log it. 2799 */ 2800 if ((pass & FR_LOGORBLOCK) && 2801 FR_ISPASS(pass)) { 2802 pass &= ~FR_CMDMASK; 2803 pass |= FR_BLOCK; 2804 } 2805 } 2806 *passp = pass; 2807 } 2808 2809 return fin->fin_fr; 2810 } 2811 #endif /* IPFILTER_LOG */ 2812 2813 2814 /* ------------------------------------------------------------------------ */ 2815 /* Function: ipf_cksum */ 2816 /* Returns: u_short - IP header checksum */ 2817 /* Parameters: addr(I) - pointer to start of buffer to checksum */ 2818 /* len(I) - length of buffer in bytes */ 2819 /* */ 2820 /* Calculate the two's complement 16 bit checksum of the buffer passed. */ 2821 /* */ 2822 /* N.B.: addr should be 16bit aligned. */ 2823 /* ------------------------------------------------------------------------ */ 2824 u_short ipf_cksum(addr, len) 2825 u_short *addr; 2826 int len; 2827 { 2828 u_32_t sum = 0; 2829 2830 for (sum = 0; len > 1; len -= 2) 2831 sum += *addr++; 2832 2833 /* mop up an odd byte, if necessary */ 2834 if (len == 1) 2835 sum += *(u_char *)addr; 2836 2837 /* 2838 * add back carry outs from top 16 bits to low 16 bits 2839 */ 2840 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 2841 sum += (sum >> 16); /* add carry */ 2842 return (u_short)(~sum); 2843 } 2844 2845 2846 /* ------------------------------------------------------------------------ */ 2847 /* Function: fr_cksum */ 2848 /* Returns: u_short - layer 4 checksum */ 2849 /* Parameters: m(I ) - pointer to buffer holding packet */ 2850 /* ip(I) - pointer to IP header */ 2851 /* l4proto(I) - protocol to caclulate checksum for */ 2852 /* l4hdr(I) - pointer to layer 4 header */ 2853 /* */ 2854 /* Calculates the TCP checksum for the packet held in "m", using the data */ 2855 /* in the IP header "ip" to seed it. */ 2856 /* */ 2857 /* NB: This function assumes we've pullup'd enough for all of the IP header */ 2858 /* and the TCP header. We also assume that data blocks aren't allocated in */ 2859 /* odd sizes. */ 2860 /* */ 2861 /* Expects ip_len to be in host byte order when called. */ 2862 /* ------------------------------------------------------------------------ */ 2863 u_short fr_cksum(m, ip, l4proto, l4hdr) 2864 mb_t *m; 2865 ip_t *ip; 2866 int l4proto; 2867 void *l4hdr; 2868 { 2869 u_short *sp, slen, sumsave, l4hlen, *csump; 2870 u_int sum, sum2; 2871 int hlen; 2872 #ifdef USE_INET6 2873 ip6_t *ip6; 2874 #endif 2875 2876 csump = NULL; 2877 sumsave = 0; 2878 l4hlen = 0; 2879 sp = NULL; 2880 slen = 0; 2881 hlen = 0; 2882 sum = 0; 2883 2884 /* 2885 * Add up IP Header portion 2886 */ 2887 #ifdef USE_INET6 2888 if (IP_V(ip) == 4) { 2889 #endif 2890 hlen = IP_HL(ip) << 2; 2891 slen = ip->ip_len - hlen; 2892 sum = htons((u_short)l4proto); 2893 sum += htons(slen); 2894 sp = (u_short *)&ip->ip_src; 2895 sum += *sp++; /* ip_src */ 2896 sum += *sp++; 2897 sum += *sp++; /* ip_dst */ 2898 sum += *sp++; 2899 #ifdef USE_INET6 2900 } else if (IP_V(ip) == 6) { 2901 ip6 = (ip6_t *)ip; 2902 hlen = sizeof(*ip6); 2903 slen = ntohs(ip6->ip6_plen); 2904 sum = htons((u_short)l4proto); 2905 sum += htons(slen); 2906 sp = (u_short *)&ip6->ip6_src; 2907 sum += *sp++; /* ip6_src */ 2908 sum += *sp++; 2909 sum += *sp++; 2910 sum += *sp++; 2911 sum += *sp++; 2912 sum += *sp++; 2913 sum += *sp++; 2914 sum += *sp++; 2915 sum += *sp++; /* ip6_dst */ 2916 sum += *sp++; 2917 sum += *sp++; 2918 sum += *sp++; 2919 sum += *sp++; 2920 sum += *sp++; 2921 sum += *sp++; 2922 sum += *sp++; 2923 } 2924 #endif 2925 2926 switch (l4proto) 2927 { 2928 case IPPROTO_UDP : 2929 csump = &((udphdr_t *)l4hdr)->uh_sum; 2930 l4hlen = sizeof(udphdr_t); 2931 break; 2932 2933 case IPPROTO_TCP : 2934 csump = &((tcphdr_t *)l4hdr)->th_sum; 2935 l4hlen = sizeof(tcphdr_t); 2936 break; 2937 case IPPROTO_ICMP : 2938 csump = &((icmphdr_t *)l4hdr)->icmp_cksum; 2939 l4hlen = 4; 2940 sum = 0; 2941 break; 2942 default : 2943 break; 2944 } 2945 2946 if (csump != NULL) { 2947 sumsave = *csump; 2948 *csump = 0; 2949 } 2950 2951 l4hlen = l4hlen; /* LINT */ 2952 2953 #ifdef _KERNEL 2954 # ifdef MENTAT 2955 { 2956 void *rp = m->b_rptr; 2957 2958 if ((unsigned char *)ip > m->b_rptr && (unsigned char *)ip < m->b_wptr) 2959 m->b_rptr = (u_char *)ip; 2960 sum2 = ip_cksum(m, hlen, sum); /* hlen == offset */ 2961 m->b_rptr = rp; 2962 sum2 = (sum2 & 0xffff) + (sum2 >> 16); 2963 sum2 = ~sum2 & 0xffff; 2964 } 2965 # else /* MENTAT */ 2966 # if defined(BSD) || defined(sun) 2967 # if BSD >= 199103 2968 m->m_data += hlen; 2969 # else 2970 m->m_off += hlen; 2971 # endif 2972 m->m_len -= hlen; 2973 sum2 = in_cksum(m, slen); 2974 m->m_len += hlen; 2975 # if BSD >= 199103 2976 m->m_data -= hlen; 2977 # else 2978 m->m_off -= hlen; 2979 # endif 2980 /* 2981 * Both sum and sum2 are partial sums, so combine them together. 2982 */ 2983 sum += ~sum2 & 0xffff; 2984 while (sum > 0xffff) 2985 sum = (sum & 0xffff) + (sum >> 16); 2986 sum2 = ~sum & 0xffff; 2987 # else /* defined(BSD) || defined(sun) */ 2988 { 2989 union { 2990 u_char c[2]; 2991 u_short s; 2992 } bytes; 2993 u_short len = ip->ip_len; 2994 # if defined(__sgi) 2995 int add; 2996 # endif 2997 2998 /* 2999 * Add up IP Header portion 3000 */ 3001 if (sp != (u_short *)l4hdr) 3002 sp = (u_short *)l4hdr; 3003 3004 switch (l4proto) 3005 { 3006 case IPPROTO_UDP : 3007 sum += *sp++; /* sport */ 3008 sum += *sp++; /* dport */ 3009 sum += *sp++; /* udp length */ 3010 sum += *sp++; /* checksum */ 3011 break; 3012 3013 case IPPROTO_TCP : 3014 sum += *sp++; /* sport */ 3015 sum += *sp++; /* dport */ 3016 sum += *sp++; /* seq */ 3017 sum += *sp++; 3018 sum += *sp++; /* ack */ 3019 sum += *sp++; 3020 sum += *sp++; /* off */ 3021 sum += *sp++; /* win */ 3022 sum += *sp++; /* checksum */ 3023 sum += *sp++; /* urp */ 3024 break; 3025 case IPPROTO_ICMP : 3026 sum = *sp++; /* type/code */ 3027 sum += *sp++; /* checksum */ 3028 break; 3029 } 3030 3031 # ifdef __sgi 3032 /* 3033 * In case we had to copy the IP & TCP header out of mbufs, 3034 * skip over the mbuf bits which are the header 3035 */ 3036 if ((caddr_t)ip != mtod(m, caddr_t)) { 3037 hlen = (caddr_t)sp - (caddr_t)ip; 3038 while (hlen) { 3039 add = MIN(hlen, m->m_len); 3040 sp = (u_short *)(mtod(m, caddr_t) + add); 3041 hlen -= add; 3042 if (add == m->m_len) { 3043 m = m->m_next; 3044 if (!hlen) { 3045 if (!m) 3046 break; 3047 sp = mtod(m, u_short *); 3048 } 3049 PANIC((!m),("fr_cksum(1): not enough data")); 3050 } 3051 } 3052 } 3053 # endif 3054 3055 len -= (l4hlen + hlen); 3056 if (len <= 0) 3057 goto nodata; 3058 3059 while (len > 1) { 3060 if (((caddr_t)sp - mtod(m, caddr_t)) >= m->m_len) { 3061 m = m->m_next; 3062 PANIC((!m),("fr_cksum(2): not enough data")); 3063 sp = mtod(m, u_short *); 3064 } 3065 if (((caddr_t)(sp + 1) - mtod(m, caddr_t)) > m->m_len) { 3066 bytes.c[0] = *(u_char *)sp; 3067 m = m->m_next; 3068 PANIC((!m),("fr_cksum(3): not enough data")); 3069 sp = mtod(m, u_short *); 3070 bytes.c[1] = *(u_char *)sp; 3071 sum += bytes.s; 3072 sp = (u_short *)((u_char *)sp + 1); 3073 } 3074 if ((u_long)sp & 1) { 3075 bcopy((char *)sp++, (char *)&bytes.s, sizeof(bytes.s)); 3076 sum += bytes.s; 3077 } else 3078 sum += *sp++; 3079 len -= 2; 3080 } 3081 3082 if (len != 0) 3083 sum += ntohs(*(u_char *)sp << 8); 3084 nodata: 3085 while (sum > 0xffff) 3086 sum = (sum & 0xffff) + (sum >> 16); 3087 sum2 = (u_short)(~sum & 0xffff); 3088 } 3089 # endif /* defined(BSD) || defined(sun) */ 3090 # endif /* MENTAT */ 3091 #else /* _KERNEL */ 3092 for (; slen > 1; slen -= 2) 3093 sum += *sp++; 3094 if (slen) 3095 sum += ntohs(*(u_char *)sp << 8); 3096 while (sum > 0xffff) 3097 sum = (sum & 0xffff) + (sum >> 16); 3098 sum2 = (u_short)(~sum & 0xffff); 3099 #endif /* _KERNEL */ 3100 if (csump != NULL) 3101 *csump = sumsave; 3102 return sum2; 3103 } 3104 3105 3106 #if defined(_KERNEL) && ( ((BSD < 199103) && !defined(MENTAT)) || \ 3107 defined(__sgi) ) && !defined(linux) && !defined(_AIX51) 3108 /* 3109 * Copyright (c) 1982, 1986, 1988, 1991, 1993 3110 * The Regents of the University of California. All rights reserved. 3111 * 3112 * Redistribution and use in source and binary forms, with or without 3113 * modification, are permitted provided that the following conditions 3114 * are met: 3115 * 1. Redistributions of source code must retain the above copyright 3116 * notice, this list of conditions and the following disclaimer. 3117 * 2. Redistributions in binary form must reproduce the above copyright 3118 * notice, this list of conditions and the following disclaimer in the 3119 * documentation and/or other materials provided with the distribution. 3120 * 3. Neither the name of the University nor the names of its contributors 3121 * may be used to endorse or promote products derived from this software 3122 * without specific prior written permission. 3123 * 3124 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 3125 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 3126 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3127 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3128 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3129 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3130 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3131 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3132 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3133 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3134 * SUCH DAMAGE. 3135 * 3136 * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 3137 * $Id: fil.c,v 2.243.2.64 2005/08/13 05:19:59 darrenr Exp $ 3138 */ 3139 /* 3140 * Copy data from an mbuf chain starting "off" bytes from the beginning, 3141 * continuing for "len" bytes, into the indicated buffer. 3142 */ 3143 void 3144 m_copydata(m, off, len, cp) 3145 mb_t *m; 3146 int off; 3147 int len; 3148 caddr_t cp; 3149 { 3150 unsigned count; 3151 3152 if (off < 0 || len < 0) 3153 panic("m_copydata"); 3154 while (off > 0) { 3155 if (m == 0) 3156 panic("m_copydata"); 3157 if (off < m->m_len) 3158 break; 3159 off -= m->m_len; 3160 m = m->m_next; 3161 } 3162 while (len > 0) { 3163 if (m == 0) 3164 panic("m_copydata"); 3165 count = MIN(m->m_len - off, len); 3166 bcopy(mtod(m, caddr_t) + off, cp, count); 3167 len -= count; 3168 cp += count; 3169 off = 0; 3170 m = m->m_next; 3171 } 3172 } 3173 3174 3175 /* 3176 * Copy data from a buffer back into the indicated mbuf chain, 3177 * starting "off" bytes from the beginning, extending the mbuf 3178 * chain if necessary. 3179 */ 3180 void 3181 m_copyback(m0, off, len, cp) 3182 struct mbuf *m0; 3183 int off; 3184 int len; 3185 caddr_t cp; 3186 { 3187 int mlen; 3188 struct mbuf *m = m0, *n; 3189 int totlen = 0; 3190 3191 if (m0 == 0) 3192 return; 3193 while (off > (mlen = m->m_len)) { 3194 off -= mlen; 3195 totlen += mlen; 3196 if (m->m_next == 0) { 3197 n = m_getclr(M_DONTWAIT, m->m_type); 3198 if (n == 0) 3199 goto out; 3200 n->m_len = min(MLEN, len + off); 3201 m->m_next = n; 3202 } 3203 m = m->m_next; 3204 } 3205 while (len > 0) { 3206 mlen = min(m->m_len - off, len); 3207 bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); 3208 cp += mlen; 3209 len -= mlen; 3210 mlen += off; 3211 off = 0; 3212 totlen += mlen; 3213 if (len == 0) 3214 break; 3215 if (m->m_next == 0) { 3216 n = m_get(M_DONTWAIT, m->m_type); 3217 if (n == 0) 3218 break; 3219 n->m_len = min(MLEN, len); 3220 m->m_next = n; 3221 } 3222 m = m->m_next; 3223 } 3224 out: 3225 #if 0 3226 if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) 3227 m->m_pkthdr.len = totlen; 3228 #endif 3229 return; 3230 } 3231 #endif /* (_KERNEL) && ( ((BSD < 199103) && !MENTAT) || __sgi) */ 3232 3233 3234 /* ------------------------------------------------------------------------ */ 3235 /* Function: fr_findgroup */ 3236 /* Returns: frgroup_t * - NULL = group not found, else pointer to group */ 3237 /* Parameters: group(I) - group name to search for */ 3238 /* unit(I) - device to which this group belongs */ 3239 /* set(I) - which set of rules (inactive/inactive) this is */ 3240 /* fgpp(O) - pointer to place to store pointer to the pointer */ 3241 /* to where to add the next (last) group or where */ 3242 /* to delete group from. */ 3243 /* */ 3244 /* Search amongst the defined groups for a particular group number. */ 3245 /* ------------------------------------------------------------------------ */ 3246 frgroup_t *fr_findgroup(group, unit, set, fgpp, ifs) 3247 char *group; 3248 minor_t unit; 3249 int set; 3250 frgroup_t ***fgpp; 3251 ipf_stack_t *ifs; 3252 { 3253 frgroup_t *fg, **fgp; 3254 3255 /* 3256 * Which list of groups to search in is dependent on which list of 3257 * rules are being operated on. 3258 */ 3259 fgp = &ifs->ifs_ipfgroups[unit][set]; 3260 3261 while ((fg = *fgp) != NULL) { 3262 if (strncmp(group, fg->fg_name, FR_GROUPLEN) == 0) 3263 break; 3264 else 3265 fgp = &fg->fg_next; 3266 } 3267 if (fgpp != NULL) 3268 *fgpp = fgp; 3269 return fg; 3270 } 3271 3272 3273 /* ------------------------------------------------------------------------ */ 3274 /* Function: fr_addgroup */ 3275 /* Returns: frgroup_t * - NULL == did not create group, */ 3276 /* != NULL == pointer to the group */ 3277 /* Parameters: num(I) - group number to add */ 3278 /* head(I) - rule pointer that is using this as the head */ 3279 /* flags(I) - rule flags which describe the type of rule it is */ 3280 /* unit(I) - device to which this group will belong to */ 3281 /* set(I) - which set of rules (inactive/inactive) this is */ 3282 /* Write Locks: ipf_mutex */ 3283 /* */ 3284 /* Add a new group head, or if it already exists, increase the reference */ 3285 /* count to it. */ 3286 /* ------------------------------------------------------------------------ */ 3287 frgroup_t *fr_addgroup(group, head, flags, unit, set, ifs) 3288 char *group; 3289 void *head; 3290 u_32_t flags; 3291 minor_t unit; 3292 int set; 3293 ipf_stack_t *ifs; 3294 { 3295 frgroup_t *fg, **fgp; 3296 u_32_t gflags; 3297 3298 if (group == NULL) 3299 return NULL; 3300 3301 if (unit == IPL_LOGIPF && *group == '\0') 3302 return NULL; 3303 3304 fgp = NULL; 3305 gflags = flags & FR_INOUT; 3306 3307 fg = fr_findgroup(group, unit, set, &fgp, ifs); 3308 if (fg != NULL) { 3309 if (fg->fg_flags == 0) 3310 fg->fg_flags = gflags; 3311 else if (gflags != fg->fg_flags) 3312 return NULL; 3313 fg->fg_ref++; 3314 return fg; 3315 } 3316 KMALLOC(fg, frgroup_t *); 3317 if (fg != NULL) { 3318 fg->fg_head = head; 3319 fg->fg_start = NULL; 3320 fg->fg_next = *fgp; 3321 bcopy(group, fg->fg_name, FR_GROUPLEN); 3322 fg->fg_flags = gflags; 3323 fg->fg_ref = 1; 3324 *fgp = fg; 3325 } 3326 return fg; 3327 } 3328 3329 3330 /* ------------------------------------------------------------------------ */ 3331 /* Function: fr_delgroup */ 3332 /* Returns: Nil */ 3333 /* Parameters: group(I) - group name to delete */ 3334 /* unit(I) - device to which this group belongs */ 3335 /* set(I) - which set of rules (inactive/inactive) this is */ 3336 /* Write Locks: ipf_mutex */ 3337 /* */ 3338 /* Attempt to delete a group head. */ 3339 /* Only do this when its reference count reaches 0. */ 3340 /* ------------------------------------------------------------------------ */ 3341 void fr_delgroup(group, unit, set, ifs) 3342 char *group; 3343 minor_t unit; 3344 int set; 3345 ipf_stack_t *ifs; 3346 { 3347 frgroup_t *fg, **fgp; 3348 3349 fg = fr_findgroup(group, unit, set, &fgp, ifs); 3350 if (fg == NULL) 3351 return; 3352 3353 fg->fg_ref--; 3354 if (fg->fg_ref == 0) { 3355 *fgp = fg->fg_next; 3356 KFREE(fg); 3357 } 3358 } 3359 3360 3361 /* ------------------------------------------------------------------------ */ 3362 /* Function: fr_getrulen */ 3363 /* Returns: frentry_t * - NULL == not found, else pointer to rule n */ 3364 /* Parameters: unit(I) - device for which to count the rule's number */ 3365 /* flags(I) - which set of rules to find the rule in */ 3366 /* group(I) - group name */ 3367 /* n(I) - rule number to find */ 3368 /* */ 3369 /* Find rule # n in group # g and return a pointer to it. Return NULl if */ 3370 /* group # g doesn't exist or there are less than n rules in the group. */ 3371 /* ------------------------------------------------------------------------ */ 3372 frentry_t *fr_getrulen(unit, group, n, ifs) 3373 int unit; 3374 char *group; 3375 u_32_t n; 3376 ipf_stack_t *ifs; 3377 { 3378 frentry_t *fr; 3379 frgroup_t *fg; 3380 3381 fg = fr_findgroup(group, unit, ifs->ifs_fr_active, NULL, ifs); 3382 if (fg == NULL) 3383 return NULL; 3384 for (fr = fg->fg_head; fr && n; fr = fr->fr_next, n--) 3385 ; 3386 if (n != 0) 3387 return NULL; 3388 return fr; 3389 } 3390 3391 3392 /* ------------------------------------------------------------------------ */ 3393 /* Function: fr_rulen */ 3394 /* Returns: int - >= 0 - rule number, -1 == search failed */ 3395 /* Parameters: unit(I) - device for which to count the rule's number */ 3396 /* fr(I) - pointer to rule to match */ 3397 /* */ 3398 /* Return the number for a rule on a specific filtering device. */ 3399 /* ------------------------------------------------------------------------ */ 3400 int fr_rulen(unit, fr, ifs) 3401 int unit; 3402 frentry_t *fr; 3403 ipf_stack_t *ifs; 3404 { 3405 frentry_t *fh; 3406 frgroup_t *fg; 3407 u_32_t n = 0; 3408 3409 if (fr == NULL) 3410 return -1; 3411 fg = fr_findgroup(fr->fr_group, unit, ifs->ifs_fr_active, NULL, ifs); 3412 if (fg == NULL) 3413 return -1; 3414 for (fh = fg->fg_head; fh; n++, fh = fh->fr_next) 3415 if (fh == fr) 3416 break; 3417 if (fh == NULL) 3418 return -1; 3419 return n; 3420 } 3421 3422 3423 /* ------------------------------------------------------------------------ */ 3424 /* Function: frflushlist */ 3425 /* Returns: int - >= 0 - number of flushed rules */ 3426 /* Parameters: set(I) - which set of rules (inactive/inactive) this is */ 3427 /* unit(I) - device for which to flush rules */ 3428 /* flags(I) - which set of rules to flush */ 3429 /* nfreedp(O) - pointer to int where flush count is stored */ 3430 /* listp(I) - pointer to list to flush pointer */ 3431 /* Write Locks: ipf_mutex */ 3432 /* */ 3433 /* Recursively flush rules from the list, descending groups as they are */ 3434 /* encountered. if a rule is the head of a group and it has lost all its */ 3435 /* group members, then also delete the group reference. nfreedp is needed */ 3436 /* to store the accumulating count of rules removed, whereas the returned */ 3437 /* value is just the number removed from the current list. The latter is */ 3438 /* needed to correctly adjust reference counts on rules that define groups. */ 3439 /* */ 3440 /* NOTE: Rules not loaded from user space cannot be flushed. */ 3441 /* ------------------------------------------------------------------------ */ 3442 static int frflushlist(set, unit, nfreedp, listp, ifs) 3443 int set; 3444 minor_t unit; 3445 int *nfreedp; 3446 frentry_t **listp; 3447 ipf_stack_t *ifs; 3448 { 3449 int freed = 0; 3450 frentry_t *fp; 3451 3452 while ((fp = *listp) != NULL) { 3453 if ((fp->fr_type & FR_T_BUILTIN) || 3454 !(fp->fr_flags & FR_COPIED)) { 3455 listp = &fp->fr_next; 3456 continue; 3457 } 3458 *listp = fp->fr_next; 3459 if (fp->fr_grp != NULL) { 3460 (void) frflushlist(set, unit, nfreedp, fp->fr_grp, ifs); 3461 } 3462 3463 if (fp->fr_grhead != NULL) { 3464 fr_delgroup(fp->fr_grhead, unit, set, ifs); 3465 *fp->fr_grhead = '\0'; 3466 } 3467 3468 ASSERT(fp->fr_ref > 0); 3469 fp->fr_next = NULL; 3470 if (fr_derefrule(&fp, ifs) == 0) 3471 freed++; 3472 } 3473 *nfreedp += freed; 3474 return freed; 3475 } 3476 3477 3478 /* ------------------------------------------------------------------------ */ 3479 /* Function: frflush */ 3480 /* Returns: int - >= 0 - number of flushed rules */ 3481 /* Parameters: unit(I) - device for which to flush rules */ 3482 /* flags(I) - which set of rules to flush */ 3483 /* */ 3484 /* Calls flushlist() for all filter rules (accounting, firewall - both IPv4 */ 3485 /* and IPv6) as defined by the value of flags. */ 3486 /* ------------------------------------------------------------------------ */ 3487 int frflush(unit, proto, flags, ifs) 3488 minor_t unit; 3489 int proto, flags; 3490 ipf_stack_t *ifs; 3491 { 3492 int flushed = 0, set; 3493 3494 WRITE_ENTER(&ifs->ifs_ipf_mutex); 3495 3496 set = ifs->ifs_fr_active; 3497 if ((flags & FR_INACTIVE) == FR_INACTIVE) 3498 set = 1 - set; 3499 3500 if (flags & FR_OUTQUE) { 3501 if (proto == 0 || proto == 6) { 3502 (void) frflushlist(set, unit, 3503 &flushed, &ifs->ifs_ipfilter6[1][set], ifs); 3504 (void) frflushlist(set, unit, 3505 &flushed, &ifs->ifs_ipacct6[1][set], ifs); 3506 } 3507 if (proto == 0 || proto == 4) { 3508 (void) frflushlist(set, unit, 3509 &flushed, &ifs->ifs_ipfilter[1][set], ifs); 3510 (void) frflushlist(set, unit, 3511 &flushed, &ifs->ifs_ipacct[1][set], ifs); 3512 } 3513 } 3514 if (flags & FR_INQUE) { 3515 if (proto == 0 || proto == 6) { 3516 (void) frflushlist(set, unit, 3517 &flushed, &ifs->ifs_ipfilter6[0][set], ifs); 3518 (void) frflushlist(set, unit, 3519 &flushed, &ifs->ifs_ipacct6[0][set], ifs); 3520 } 3521 if (proto == 0 || proto == 4) { 3522 (void) frflushlist(set, unit, 3523 &flushed, &ifs->ifs_ipfilter[0][set], ifs); 3524 (void) frflushlist(set, unit, 3525 &flushed, &ifs->ifs_ipacct[0][set], ifs); 3526 } 3527 } 3528 RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 3529 3530 if (unit == IPL_LOGIPF) { 3531 int tmp; 3532 3533 tmp = frflush(IPL_LOGCOUNT, proto, flags, ifs); 3534 if (tmp >= 0) 3535 flushed += tmp; 3536 } 3537 return flushed; 3538 } 3539 3540 3541 /* ------------------------------------------------------------------------ */ 3542 /* Function: memstr */ 3543 /* Returns: char * - NULL if failed, != NULL pointer to matching bytes */ 3544 /* Parameters: src(I) - pointer to byte sequence to match */ 3545 /* dst(I) - pointer to byte sequence to search */ 3546 /* slen(I) - match length */ 3547 /* dlen(I) - length available to search in */ 3548 /* */ 3549 /* Search dst for a sequence of bytes matching those at src and extend for */ 3550 /* slen bytes. */ 3551 /* ------------------------------------------------------------------------ */ 3552 char *memstr(src, dst, slen, dlen) 3553 char *src, *dst; 3554 int slen, dlen; 3555 { 3556 char *s = NULL; 3557 3558 while (dlen >= slen) { 3559 if (bcmp(src, dst, slen) == 0) { 3560 s = dst; 3561 break; 3562 } 3563 dst++; 3564 dlen--; 3565 } 3566 return s; 3567 } 3568 /* ------------------------------------------------------------------------ */ 3569 /* Function: fr_fixskip */ 3570 /* Returns: Nil */ 3571 /* Parameters: listp(IO) - pointer to start of list with skip rule */ 3572 /* rp(I) - rule added/removed with skip in it. */ 3573 /* addremove(I) - adjustment (-1/+1) to make to skip count, */ 3574 /* depending on whether a rule was just added */ 3575 /* or removed. */ 3576 /* */ 3577 /* Adjust all the rules in a list which would have skip'd past the position */ 3578 /* where we are inserting to skip to the right place given the change. */ 3579 /* ------------------------------------------------------------------------ */ 3580 void fr_fixskip(listp, rp, addremove) 3581 frentry_t **listp, *rp; 3582 int addremove; 3583 { 3584 int rules, rn; 3585 frentry_t *fp; 3586 3587 rules = 0; 3588 for (fp = *listp; (fp != NULL) && (fp != rp); fp = fp->fr_next) 3589 rules++; 3590 3591 if (!fp) 3592 return; 3593 3594 for (rn = 0, fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++) 3595 if (FR_ISSKIP(fp->fr_flags) && (rn + fp->fr_arg >= rules)) 3596 fp->fr_arg += addremove; 3597 } 3598 3599 3600 #ifdef _KERNEL 3601 /* ------------------------------------------------------------------------ */ 3602 /* Function: count4bits */ 3603 /* Returns: int - >= 0 - number of consecutive bits in input */ 3604 /* Parameters: ip(I) - 32bit IP address */ 3605 /* */ 3606 /* IPv4 ONLY */ 3607 /* count consecutive 1's in bit mask. If the mask generated by counting */ 3608 /* consecutive 1's is different to that passed, return -1, else return # */ 3609 /* of bits. */ 3610 /* ------------------------------------------------------------------------ */ 3611 int count4bits(ip) 3612 u_32_t ip; 3613 { 3614 u_32_t ipn; 3615 int cnt = 0, i, j; 3616 3617 ip = ipn = ntohl(ip); 3618 for (i = 32; i; i--, ipn *= 2) 3619 if (ipn & 0x80000000) 3620 cnt++; 3621 else 3622 break; 3623 ipn = 0; 3624 for (i = 32, j = cnt; i; i--, j--) { 3625 ipn *= 2; 3626 if (j > 0) 3627 ipn++; 3628 } 3629 if (ipn == ip) 3630 return cnt; 3631 return -1; 3632 } 3633 3634 3635 #ifdef USE_INET6 3636 /* ------------------------------------------------------------------------ */ 3637 /* Function: count6bits */ 3638 /* Returns: int - >= 0 - number of consecutive bits in input */ 3639 /* Parameters: msk(I) - pointer to start of IPv6 bitmask */ 3640 /* */ 3641 /* IPv6 ONLY */ 3642 /* count consecutive 1's in bit mask. */ 3643 /* ------------------------------------------------------------------------ */ 3644 int count6bits(msk) 3645 u_32_t *msk; 3646 { 3647 int i = 0, k; 3648 u_32_t j; 3649 3650 for (k = 3; k >= 0; k--) 3651 if (msk[k] == 0xffffffff) 3652 i += 32; 3653 else { 3654 for (j = msk[k]; j; j <<= 1) 3655 if (j & 0x80000000) 3656 i++; 3657 } 3658 return i; 3659 } 3660 # endif 3661 #endif /* _KERNEL */ 3662 3663 3664 /* ------------------------------------------------------------------------ */ 3665 /* Function: fr_ifsync */ 3666 /* Returns: void * - new interface identifier */ 3667 /* Parameters: action(I) - type of synchronisation to do */ 3668 /* v(I) - IP version being sync'd (v4 or v6) */ 3669 /* newifp(I) - interface identifier being introduced/removed */ 3670 /* oldifp(I) - interface identifier in a filter rule */ 3671 /* newname(I) - name associated with newifp interface */ 3672 /* oldname(I) - name associated with oldifp interface */ 3673 /* ifs - pointer to IPF stack instance */ 3674 /* */ 3675 /* This function returns what the new value for "oldifp" should be for its */ 3676 /* caller. In some cases it will not change, in some it will. */ 3677 /* action == IPFSYNC_RESYNC */ 3678 /* a new value for oldifp will always be looked up, according to oldname, */ 3679 /* the values of newname and newifp are ignored. */ 3680 /* action == IPFSYNC_NEWIFP */ 3681 /* if oldname matches newname then we are doing a sync for the matching */ 3682 /* interface, so we return newifp to be used in place of oldifp. If the */ 3683 /* the names don't match, just return oldifp. */ 3684 /* action == IPFSYNC_OLDIFP */ 3685 /* if oldifp matches newifp then we are are doing a sync to remove any */ 3686 /* references to oldifp, so we return "-1". */ 3687 /* ----- */ 3688 /* NOTE: */ 3689 /* This function processes NIC event from PF_HOOKS. The action parameter */ 3690 /* is set in ipf_nic_event_v4()/ipf_nic_event_v6() function. There is */ 3691 /* one single switch statement() in ipf_nic_event_vx() function, which */ 3692 /* translates the HOOK event type to action parameter passed to fr_ifsync. */ 3693 /* The translation table looks as follows: */ 3694 /* event | action */ 3695 /* ----------------+------------- */ 3696 /* NE_PLUMB | IPFSYNC_NEWIFP */ 3697 /* NE_UNPLUMB | IPFSYNC_OLDIFP */ 3698 /* NE_ADDRESS_CHANGE | IPFSYNC_RESYNC */ 3699 /* */ 3700 /* The oldname and oldifp parameters are taken from IPF entry (rule, state */ 3701 /* table entry, NAT table entry, fragment ...). The newname and newifp */ 3702 /* parameters come from hook event data, parameters are taken from event */ 3703 /* in ipf_nic_event_vx() functions. Any time NIC changes, the IPF is */ 3704 /* notified by hook function. */ 3705 /* */ 3706 /* We get NE_UNPLUMB event from PF_HOOKS even if someone coincidently tries */ 3707 /* to plumb the interface, which is already plumbed. In such case we always */ 3708 /* get the event from PF_HOOKS as follows: */ 3709 /* event: NE_PLUMB */ 3710 /* NIC: 0x0 */ 3711 /* ------------------------------------------------------------------------ */ 3712 static void *fr_ifsync(action, v, newname, oldname, newifp, oldifp, ifs) 3713 int action, v; 3714 char *newname, *oldname; 3715 void *newifp, *oldifp; 3716 ipf_stack_t *ifs; 3717 { 3718 void *rval = oldifp; 3719 3720 switch (action) 3721 { 3722 case IPFSYNC_RESYNC : 3723 if (oldname[0] != '\0') { 3724 rval = fr_resolvenic(oldname, v, ifs); 3725 } 3726 break; 3727 case IPFSYNC_NEWIFP : 3728 if (!strncmp(newname, oldname, LIFNAMSIZ)) 3729 rval = newifp; 3730 break; 3731 case IPFSYNC_OLDIFP : 3732 /* 3733 * If interface gets unplumbed it must be invalidated, which 3734 * means set all existing references to the interface to -1. 3735 * We don't want to invalidate references for wildcard 3736 * (unbound) rules (entries). 3737 */ 3738 if (newifp == oldifp) 3739 rval = (oldifp) ? (void *)-1 : NULL; 3740 break; 3741 } 3742 3743 return rval; 3744 } 3745 3746 3747 /* ------------------------------------------------------------------------ */ 3748 /* Function: frsynclist */ 3749 /* Returns: void */ 3750 /* Parameters: action(I) - type of synchronisation to do */ 3751 /* v(I) - IP version being sync'd (v4 or v6) */ 3752 /* ifp(I) - interface identifier associated with action */ 3753 /* ifname(I) - name associated with ifp parameter */ 3754 /* fr(I) - pointer to filter rule */ 3755 /* ifs - pointer to IPF stack instance */ 3756 /* Write Locks: ipf_mutex */ 3757 /* */ 3758 /* Walk through a list of filter rules and resolve any interface names into */ 3759 /* pointers. Where dynamic addresses are used, also update the IP address */ 3760 /* used in the rule. The interface pointer is used to limit the lookups to */ 3761 /* a specific set of matching names if it is non-NULL. */ 3762 /* ------------------------------------------------------------------------ */ 3763 static void frsynclist(action, v, ifp, ifname, fr, ifs) 3764 int action, v; 3765 void *ifp; 3766 char *ifname; 3767 frentry_t *fr; 3768 ipf_stack_t *ifs; 3769 { 3770 frdest_t *fdp; 3771 int rv, i; 3772 3773 for (; fr; fr = fr->fr_next) { 3774 rv = fr->fr_v; 3775 if (v != 0 && v != rv) 3776 continue; 3777 3778 /* 3779 * Lookup all the interface names that are part of the rule. 3780 */ 3781 for (i = 0; i < 4; i++) { 3782 fr->fr_ifas[i] = fr_ifsync(action, rv, ifname, 3783 fr->fr_ifnames[i], 3784 ifp, fr->fr_ifas[i], 3785 ifs); 3786 } 3787 3788 fdp = &fr->fr_tifs[0]; 3789 fdp->fd_ifp = fr_ifsync(action, rv, ifname, fdp->fd_ifname, 3790 ifp, fdp->fd_ifp, ifs); 3791 3792 fdp = &fr->fr_tifs[1]; 3793 fdp->fd_ifp = fr_ifsync(action, rv, ifname, fdp->fd_ifname, 3794 ifp, fdp->fd_ifp, ifs); 3795 3796 fdp = &fr->fr_dif; 3797 fdp->fd_ifp = fr_ifsync(action, rv, ifname, fdp->fd_ifname, 3798 ifp, fdp->fd_ifp, ifs); 3799 3800 if (action != IPFSYNC_RESYNC) 3801 continue; 3802 3803 if (fr->fr_type == FR_T_IPF) { 3804 if (fr->fr_satype != FRI_NORMAL && 3805 fr->fr_satype != FRI_LOOKUP) { 3806 (void)fr_ifpaddr(rv, fr->fr_satype, 3807 fr->fr_ifas[fr->fr_sifpidx], 3808 &fr->fr_src, &fr->fr_smsk, 3809 ifs); 3810 } 3811 if (fr->fr_datype != FRI_NORMAL && 3812 fr->fr_datype != FRI_LOOKUP) { 3813 (void)fr_ifpaddr(rv, fr->fr_datype, 3814 fr->fr_ifas[fr->fr_difpidx], 3815 &fr->fr_dst, &fr->fr_dmsk, 3816 ifs); 3817 } 3818 } 3819 3820 #ifdef IPFILTER_LOOKUP 3821 if (fr->fr_type == FR_T_IPF && fr->fr_satype == FRI_LOOKUP && 3822 fr->fr_srcptr == NULL) { 3823 fr->fr_srcptr = fr_resolvelookup(fr->fr_srctype, 3824 fr->fr_srcnum, 3825 &fr->fr_srcfunc, ifs); 3826 } 3827 if (fr->fr_type == FR_T_IPF && fr->fr_datype == FRI_LOOKUP && 3828 fr->fr_dstptr == NULL) { 3829 fr->fr_dstptr = fr_resolvelookup(fr->fr_dsttype, 3830 fr->fr_dstnum, 3831 &fr->fr_dstfunc, ifs); 3832 } 3833 #endif 3834 } 3835 } 3836 3837 3838 #ifdef _KERNEL 3839 /* ------------------------------------------------------------------------ */ 3840 /* Function: frsync */ 3841 /* Returns: void */ 3842 /* Parameters: action(I) - type of synchronisation to do */ 3843 /* v(I) - IP version being sync'd (v4 or v6) */ 3844 /* ifp(I) - interface identifier associated with action */ 3845 /* name(I) - name associated with ifp parameter */ 3846 /* */ 3847 /* frsync() is called when we suspect that the interface list or */ 3848 /* information about interfaces (like IP#) has changed. Go through all */ 3849 /* filter rules, NAT entries and the state table and check if anything */ 3850 /* needs to be changed/updated. */ 3851 /* With the filtering hooks added to Solaris, we needed to change the manner*/ 3852 /* in which this was done to support three different types of sync: */ 3853 /* - complete resync of all interface name/identifiers */ 3854 /* - new interface being announced with its name and identifier */ 3855 /* - interface removal being announced by only its identifier */ 3856 /* ------------------------------------------------------------------------ */ 3857 void frsync(action, v, ifp, name, ifs) 3858 int action, v; 3859 void *ifp; 3860 char *name; 3861 ipf_stack_t *ifs; 3862 { 3863 int i; 3864 3865 WRITE_ENTER(&ifs->ifs_ipf_mutex); 3866 frsynclist(action, v, ifp, name, ifs->ifs_ipacct[0][ifs->ifs_fr_active], ifs); 3867 frsynclist(action, v, ifp, name, ifs->ifs_ipacct[1][ifs->ifs_fr_active], ifs); 3868 frsynclist(action, v, ifp, name, ifs->ifs_ipfilter[0][ifs->ifs_fr_active], ifs); 3869 frsynclist(action, v, ifp, name, ifs->ifs_ipfilter[1][ifs->ifs_fr_active], ifs); 3870 frsynclist(action, v, ifp, name, ifs->ifs_ipacct6[0][ifs->ifs_fr_active], ifs); 3871 frsynclist(action, v, ifp, name, ifs->ifs_ipacct6[1][ifs->ifs_fr_active], ifs); 3872 frsynclist(action, v, ifp, name, ifs->ifs_ipfilter6[0][ifs->ifs_fr_active], ifs); 3873 frsynclist(action, v, ifp, name, ifs->ifs_ipfilter6[1][ifs->ifs_fr_active], ifs); 3874 3875 for (i = 0; i < IPL_LOGSIZE; i++) { 3876 frgroup_t *g; 3877 3878 for (g = ifs->ifs_ipfgroups[i][0]; g != NULL; g = g->fg_next) 3879 frsynclist(action, v, ifp, name, g->fg_start, ifs); 3880 for (g = ifs->ifs_ipfgroups[i][1]; g != NULL; g = g->fg_next) 3881 frsynclist(action, v, ifp, name, g->fg_start, ifs); 3882 } 3883 RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 3884 } 3885 3886 3887 /* 3888 * In the functions below, bcopy() is called because the pointer being 3889 * copied _from_ in this instance is a pointer to a char buf (which could 3890 * end up being unaligned) and on the kernel's local stack. 3891 */ 3892 /* ------------------------------------------------------------------------ */ 3893 /* Function: copyinptr */ 3894 /* Returns: int - 0 = success, else failure */ 3895 /* Parameters: src(I) - pointer to the source address */ 3896 /* dst(I) - destination address */ 3897 /* size(I) - number of bytes to copy */ 3898 /* */ 3899 /* Copy a block of data in from user space, given a pointer to the pointer */ 3900 /* to start copying from (src) and a pointer to where to store it (dst). */ 3901 /* NB: src - pointer to user space pointer, dst - kernel space pointer */ 3902 /* ------------------------------------------------------------------------ */ 3903 int copyinptr(src, dst, size) 3904 void *src, *dst; 3905 size_t size; 3906 { 3907 caddr_t ca; 3908 int err; 3909 3910 # if SOLARIS 3911 err = COPYIN(src, (caddr_t)&ca, sizeof(ca)); 3912 if (err != 0) 3913 return err; 3914 # else 3915 bcopy(src, (caddr_t)&ca, sizeof(ca)); 3916 # endif 3917 err = COPYIN(ca, dst, size); 3918 return err; 3919 } 3920 3921 3922 /* ------------------------------------------------------------------------ */ 3923 /* Function: copyoutptr */ 3924 /* Returns: int - 0 = success, else failure */ 3925 /* Parameters: src(I) - pointer to the source address */ 3926 /* dst(I) - destination address */ 3927 /* size(I) - number of bytes to copy */ 3928 /* */ 3929 /* Copy a block of data out to user space, given a pointer to the pointer */ 3930 /* to start copying from (src) and a pointer to where to store it (dst). */ 3931 /* NB: src - kernel space pointer, dst - pointer to user space pointer. */ 3932 /* ------------------------------------------------------------------------ */ 3933 int copyoutptr(src, dst, size) 3934 void *src, *dst; 3935 size_t size; 3936 { 3937 caddr_t ca; 3938 int err; 3939 3940 # if SOLARIS 3941 err = COPYIN(dst, (caddr_t)&ca, sizeof(ca)); 3942 if (err != 0) 3943 return err; 3944 # else 3945 bcopy(dst, (caddr_t)&ca, sizeof(ca)); 3946 # endif 3947 err = COPYOUT(src, ca, size); 3948 return err; 3949 } 3950 #endif 3951 3952 3953 /* ------------------------------------------------------------------------ */ 3954 /* Function: fr_lock */ 3955 /* Returns: int - 0 = success, else error */ 3956 /* Parameters: data(I) - pointer to lock value to set */ 3957 /* lockp(O) - pointer to location to store old lock value */ 3958 /* */ 3959 /* Get the new value for the lock integer, set it and return the old value */ 3960 /* in *lockp. */ 3961 /* ------------------------------------------------------------------------ */ 3962 int fr_lock(data, lockp) 3963 caddr_t data; 3964 int *lockp; 3965 { 3966 int arg, err; 3967 3968 err = BCOPYIN(data, (caddr_t)&arg, sizeof(arg)); 3969 if (err != 0) 3970 return (EFAULT); 3971 err = BCOPYOUT((caddr_t)lockp, data, sizeof(*lockp)); 3972 if (err != 0) 3973 return (EFAULT); 3974 *lockp = arg; 3975 return (0); 3976 } 3977 3978 3979 /* ------------------------------------------------------------------------ */ 3980 /* Function: fr_getstat */ 3981 /* Returns: Nil */ 3982 /* Parameters: fiop(I) - pointer to ipfilter stats structure */ 3983 /* */ 3984 /* Stores a copy of current pointers, counters, etc, in the friostat */ 3985 /* structure. */ 3986 /* ------------------------------------------------------------------------ */ 3987 void fr_getstat(fiop, ifs) 3988 friostat_t *fiop; 3989 ipf_stack_t *ifs; 3990 { 3991 int i, j; 3992 3993 bcopy((char *)&ifs->ifs_frstats, (char *)fiop->f_st, 3994 sizeof(filterstats_t) * 2); 3995 fiop->f_locks[IPL_LOGSTATE] = ifs->ifs_fr_state_lock; 3996 fiop->f_locks[IPL_LOGNAT] = ifs->ifs_fr_nat_lock; 3997 fiop->f_locks[IPL_LOGIPF] = ifs->ifs_fr_frag_lock; 3998 fiop->f_locks[IPL_LOGAUTH] = ifs->ifs_fr_auth_lock; 3999 4000 for (i = 0; i < 2; i++) 4001 for (j = 0; j < 2; j++) { 4002 fiop->f_ipf[i][j] = ifs->ifs_ipfilter[i][j]; 4003 fiop->f_acct[i][j] = ifs->ifs_ipacct[i][j]; 4004 fiop->f_ipf6[i][j] = ifs->ifs_ipfilter6[i][j]; 4005 fiop->f_acct6[i][j] = ifs->ifs_ipacct6[i][j]; 4006 } 4007 4008 fiop->f_ticks = ifs->ifs_fr_ticks; 4009 fiop->f_active = ifs->ifs_fr_active; 4010 fiop->f_froute[0] = ifs->ifs_fr_frouteok[0]; 4011 fiop->f_froute[1] = ifs->ifs_fr_frouteok[1]; 4012 4013 fiop->f_running = ifs->ifs_fr_running; 4014 for (i = 0; i < IPL_LOGSIZE; i++) { 4015 fiop->f_groups[i][0] = ifs->ifs_ipfgroups[i][0]; 4016 fiop->f_groups[i][1] = ifs->ifs_ipfgroups[i][1]; 4017 } 4018 #ifdef IPFILTER_LOG 4019 fiop->f_logging = 1; 4020 #else 4021 fiop->f_logging = 0; 4022 #endif 4023 fiop->f_defpass = ifs->ifs_fr_pass; 4024 fiop->f_features = fr_features; 4025 (void) strncpy(fiop->f_version, ipfilter_version, 4026 sizeof(fiop->f_version)); 4027 } 4028 4029 4030 #ifdef USE_INET6 4031 int icmptoicmp6types[ICMP_MAXTYPE+1] = { 4032 ICMP6_ECHO_REPLY, /* 0: ICMP_ECHOREPLY */ 4033 -1, /* 1: UNUSED */ 4034 -1, /* 2: UNUSED */ 4035 ICMP6_DST_UNREACH, /* 3: ICMP_UNREACH */ 4036 -1, /* 4: ICMP_SOURCEQUENCH */ 4037 ND_REDIRECT, /* 5: ICMP_REDIRECT */ 4038 -1, /* 6: UNUSED */ 4039 -1, /* 7: UNUSED */ 4040 ICMP6_ECHO_REQUEST, /* 8: ICMP_ECHO */ 4041 -1, /* 9: UNUSED */ 4042 -1, /* 10: UNUSED */ 4043 ICMP6_TIME_EXCEEDED, /* 11: ICMP_TIMXCEED */ 4044 ICMP6_PARAM_PROB, /* 12: ICMP_PARAMPROB */ 4045 -1, /* 13: ICMP_TSTAMP */ 4046 -1, /* 14: ICMP_TSTAMPREPLY */ 4047 -1, /* 15: ICMP_IREQ */ 4048 -1, /* 16: ICMP_IREQREPLY */ 4049 -1, /* 17: ICMP_MASKREQ */ 4050 -1, /* 18: ICMP_MASKREPLY */ 4051 }; 4052 4053 4054 int icmptoicmp6unreach[ICMP_MAX_UNREACH] = { 4055 ICMP6_DST_UNREACH_ADDR, /* 0: ICMP_UNREACH_NET */ 4056 ICMP6_DST_UNREACH_ADDR, /* 1: ICMP_UNREACH_HOST */ 4057 -1, /* 2: ICMP_UNREACH_PROTOCOL */ 4058 ICMP6_DST_UNREACH_NOPORT, /* 3: ICMP_UNREACH_PORT */ 4059 -1, /* 4: ICMP_UNREACH_NEEDFRAG */ 4060 ICMP6_DST_UNREACH_NOTNEIGHBOR, /* 5: ICMP_UNREACH_SRCFAIL */ 4061 ICMP6_DST_UNREACH_ADDR, /* 6: ICMP_UNREACH_NET_UNKNOWN */ 4062 ICMP6_DST_UNREACH_ADDR, /* 7: ICMP_UNREACH_HOST_UNKNOWN */ 4063 -1, /* 8: ICMP_UNREACH_ISOLATED */ 4064 ICMP6_DST_UNREACH_ADMIN, /* 9: ICMP_UNREACH_NET_PROHIB */ 4065 ICMP6_DST_UNREACH_ADMIN, /* 10: ICMP_UNREACH_HOST_PROHIB */ 4066 -1, /* 11: ICMP_UNREACH_TOSNET */ 4067 -1, /* 12: ICMP_UNREACH_TOSHOST */ 4068 ICMP6_DST_UNREACH_ADMIN, /* 13: ICMP_UNREACH_ADMIN_PROHIBIT */ 4069 }; 4070 int icmpreplytype6[ICMP6_MAXTYPE + 1]; 4071 #endif 4072 4073 int icmpreplytype4[ICMP_MAXTYPE + 1]; 4074 4075 4076 /* ------------------------------------------------------------------------ */ 4077 /* Function: fr_matchicmpqueryreply */ 4078 /* Returns: int - 1 if "icmp" is a valid reply to "ic" else 0. */ 4079 /* Parameters: v(I) - IP protocol version (4 or 6) */ 4080 /* ic(I) - ICMP information */ 4081 /* icmp(I) - ICMP packet header */ 4082 /* rev(I) - direction (0 = forward/1 = reverse) of packet */ 4083 /* */ 4084 /* Check if the ICMP packet defined by the header pointed to by icmp is a */ 4085 /* reply to one as described by what's in ic. If it is a match, return 1, */ 4086 /* else return 0 for no match. */ 4087 /* ------------------------------------------------------------------------ */ 4088 int fr_matchicmpqueryreply(v, ic, icmp, rev) 4089 int v; 4090 icmpinfo_t *ic; 4091 icmphdr_t *icmp; 4092 int rev; 4093 { 4094 int ictype; 4095 4096 ictype = ic->ici_type; 4097 4098 if (v == 4) { 4099 /* 4100 * If we matched its type on the way in, then when going out 4101 * it will still be the same type. 4102 */ 4103 if ((!rev && (icmp->icmp_type == ictype)) || 4104 (rev && (icmpreplytype4[ictype] == icmp->icmp_type))) { 4105 if (icmp->icmp_type != ICMP_ECHOREPLY) 4106 return 1; 4107 if (icmp->icmp_id == ic->ici_id) 4108 return 1; 4109 } 4110 } 4111 #ifdef USE_INET6 4112 else if (v == 6) { 4113 if ((!rev && (icmp->icmp_type == ictype)) || 4114 (rev && (icmpreplytype6[ictype] == icmp->icmp_type))) { 4115 if (icmp->icmp_type != ICMP6_ECHO_REPLY) 4116 return 1; 4117 if (icmp->icmp_id == ic->ici_id) 4118 return 1; 4119 } 4120 } 4121 #endif 4122 return 0; 4123 } 4124 4125 4126 #ifdef IPFILTER_LOOKUP 4127 /* ------------------------------------------------------------------------ */ 4128 /* Function: fr_resolvelookup */ 4129 /* Returns: void * - NULL = failure, else success. */ 4130 /* Parameters: type(I) - type of lookup these parameters are for. */ 4131 /* number(I) - table number to use when searching */ 4132 /* funcptr(IO) - pointer to pointer for storing IP address */ 4133 /* searching function. */ 4134 /* */ 4135 /* Search for the "table" number passed in amongst those configured for */ 4136 /* that particular type. If the type is recognised then the function to */ 4137 /* call to do the IP address search will be change, regardless of whether */ 4138 /* or not the "table" number exists. */ 4139 /* ------------------------------------------------------------------------ */ 4140 static void *fr_resolvelookup(type, number, funcptr, ifs) 4141 u_int type, number; 4142 lookupfunc_t *funcptr; 4143 ipf_stack_t *ifs; 4144 { 4145 char name[FR_GROUPLEN]; 4146 iphtable_t *iph; 4147 ip_pool_t *ipo; 4148 void *ptr; 4149 4150 #if defined(SNPRINTF) && defined(_KERNEL) 4151 (void) SNPRINTF(name, sizeof(name), "%u", number); 4152 #else 4153 (void) sprintf(name, "%u", number); 4154 #endif 4155 4156 READ_ENTER(&ifs->ifs_ip_poolrw); 4157 4158 switch (type) 4159 { 4160 case IPLT_POOL : 4161 # if (defined(__osf__) && defined(_KERNEL)) 4162 ptr = NULL; 4163 *funcptr = NULL; 4164 # else 4165 ipo = ip_pool_find(IPL_LOGIPF, name, ifs); 4166 ptr = ipo; 4167 if (ipo != NULL) { 4168 ATOMIC_INC32(ipo->ipo_ref); 4169 } 4170 *funcptr = ip_pool_search; 4171 # endif 4172 break; 4173 case IPLT_HASH : 4174 iph = fr_findhtable(IPL_LOGIPF, name, ifs); 4175 ptr = iph; 4176 if (iph != NULL) { 4177 ATOMIC_INC32(iph->iph_ref); 4178 } 4179 *funcptr = fr_iphmfindip; 4180 break; 4181 default: 4182 ptr = NULL; 4183 *funcptr = NULL; 4184 break; 4185 } 4186 RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 4187 4188 return ptr; 4189 } 4190 #endif 4191 4192 4193 /* ------------------------------------------------------------------------ */ 4194 /* Function: frrequest */ 4195 /* Returns: int - 0 == success, > 0 == errno value */ 4196 /* Parameters: unit(I) - device for which this is for */ 4197 /* req(I) - ioctl command (SIOC*) */ 4198 /* data(I) - pointr to ioctl data */ 4199 /* set(I) - 1 or 0 (filter set) */ 4200 /* makecopy(I) - flag indicating whether data points to a rule */ 4201 /* in kernel space & hence doesn't need copying. */ 4202 /* */ 4203 /* This function handles all the requests which operate on the list of */ 4204 /* filter rules. This includes adding, deleting, insertion. It is also */ 4205 /* responsible for creating groups when a "head" rule is loaded. Interface */ 4206 /* names are resolved here and other sanity checks are made on the content */ 4207 /* of the rule structure being loaded. If a rule has user defined timeouts */ 4208 /* then make sure they are created and initialised before exiting. */ 4209 /* ------------------------------------------------------------------------ */ 4210 int frrequest(unit, req, data, set, makecopy, ifs) 4211 int unit; 4212 ioctlcmd_t req; 4213 int set, makecopy; 4214 caddr_t data; 4215 ipf_stack_t *ifs; 4216 { 4217 frentry_t frd, *fp, *f, **fprev, **ftail; 4218 int error = 0, in, v; 4219 void *ptr, *uptr; 4220 u_int *p, *pp; 4221 frgroup_t *fg; 4222 char *group; 4223 4224 fg = NULL; 4225 fp = &frd; 4226 if (makecopy != 0) { 4227 error = fr_inobj(data, fp, IPFOBJ_FRENTRY); 4228 if (error) 4229 return EFAULT; 4230 if ((fp->fr_flags & FR_T_BUILTIN) != 0) 4231 return EINVAL; 4232 fp->fr_ref = 0; 4233 fp->fr_flags |= FR_COPIED; 4234 } else { 4235 fp = (frentry_t *)data; 4236 if ((fp->fr_type & FR_T_BUILTIN) == 0) 4237 return EINVAL; 4238 fp->fr_flags &= ~FR_COPIED; 4239 } 4240 4241 if (((fp->fr_dsize == 0) && (fp->fr_data != NULL)) || 4242 ((fp->fr_dsize != 0) && (fp->fr_data == NULL))) 4243 return EINVAL; 4244 4245 v = fp->fr_v; 4246 uptr = fp->fr_data; 4247 4248 /* 4249 * Only filter rules for IPv4 or IPv6 are accepted. 4250 */ 4251 if (v == 4) 4252 /*EMPTY*/; 4253 #ifdef USE_INET6 4254 else if (v == 6) 4255 /*EMPTY*/; 4256 #endif 4257 else { 4258 return EINVAL; 4259 } 4260 4261 /* 4262 * If the rule is being loaded from user space, i.e. we had to copy it 4263 * into kernel space, then do not trust the function pointer in the 4264 * rule. 4265 */ 4266 if ((makecopy == 1) && (fp->fr_func != NULL)) { 4267 if (fr_findfunc(fp->fr_func) == NULL) 4268 return ESRCH; 4269 error = fr_funcinit(fp, ifs); 4270 if (error != 0) 4271 return error; 4272 } 4273 4274 ptr = NULL; 4275 /* 4276 * Check that the group number does exist and that its use (in/out) 4277 * matches what the rule is. 4278 */ 4279 if (!strncmp(fp->fr_grhead, "0", FR_GROUPLEN)) 4280 *fp->fr_grhead = '\0'; 4281 group = fp->fr_group; 4282 if (!strncmp(group, "0", FR_GROUPLEN)) 4283 *group = '\0'; 4284 4285 if (FR_ISACCOUNT(fp->fr_flags)) 4286 unit = IPL_LOGCOUNT; 4287 4288 if ((req != (int)SIOCZRLST) && (*group != '\0')) { 4289 fg = fr_findgroup(group, unit, set, NULL, ifs); 4290 if (fg == NULL) 4291 return ESRCH; 4292 if (fg->fg_flags == 0) 4293 fg->fg_flags = fp->fr_flags & FR_INOUT; 4294 else if (fg->fg_flags != (fp->fr_flags & FR_INOUT)) 4295 return ESRCH; 4296 } 4297 4298 in = (fp->fr_flags & FR_INQUE) ? 0 : 1; 4299 4300 /* 4301 * Work out which rule list this change is being applied to. 4302 */ 4303 ftail = NULL; 4304 fprev = NULL; 4305 if (unit == IPL_LOGAUTH) 4306 fprev = &ifs->ifs_ipauth; 4307 else if (v == 4) { 4308 if (FR_ISACCOUNT(fp->fr_flags)) 4309 fprev = &ifs->ifs_ipacct[in][set]; 4310 else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0) 4311 fprev = &ifs->ifs_ipfilter[in][set]; 4312 } else if (v == 6) { 4313 if (FR_ISACCOUNT(fp->fr_flags)) 4314 fprev = &ifs->ifs_ipacct6[in][set]; 4315 else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0) 4316 fprev = &ifs->ifs_ipfilter6[in][set]; 4317 } 4318 if (fprev == NULL) 4319 return ESRCH; 4320 4321 if (*group != '\0') { 4322 if (!fg && !(fg = fr_findgroup(group, unit, set, NULL, ifs))) 4323 return ESRCH; 4324 fprev = &fg->fg_start; 4325 } 4326 4327 ftail = fprev; 4328 for (f = *ftail; (f = *ftail) != NULL; ftail = &f->fr_next) { 4329 if (fp->fr_collect <= f->fr_collect) { 4330 ftail = fprev; 4331 f = NULL; 4332 break; 4333 } 4334 fprev = ftail; 4335 } 4336 4337 /* 4338 * Copy in extra data for the rule. 4339 */ 4340 if (fp->fr_dsize != 0) { 4341 if (makecopy != 0) { 4342 KMALLOCS(ptr, void *, fp->fr_dsize); 4343 if (!ptr) 4344 return ENOMEM; 4345 error = COPYIN(uptr, ptr, fp->fr_dsize); 4346 } else { 4347 ptr = uptr; 4348 error = 0; 4349 } 4350 if (error != 0) { 4351 KFREES(ptr, fp->fr_dsize); 4352 return ENOMEM; 4353 } 4354 fp->fr_data = ptr; 4355 } else 4356 fp->fr_data = NULL; 4357 4358 /* 4359 * Perform per-rule type sanity checks of their members. 4360 */ 4361 switch (fp->fr_type & ~FR_T_BUILTIN) 4362 { 4363 #if defined(IPFILTER_BPF) 4364 case FR_T_BPFOPC : 4365 if (fp->fr_dsize == 0) 4366 return EINVAL; 4367 if (!bpf_validate(ptr, fp->fr_dsize/sizeof(struct bpf_insn))) { 4368 if (makecopy && fp->fr_data != NULL) { 4369 KFREES(fp->fr_data, fp->fr_dsize); 4370 } 4371 return EINVAL; 4372 } 4373 break; 4374 #endif 4375 case FR_T_IPF : 4376 if (fp->fr_dsize != sizeof(fripf_t)) 4377 return EINVAL; 4378 4379 /* 4380 * Allowing a rule with both "keep state" and "with oow" is 4381 * pointless because adding a state entry to the table will 4382 * fail with the out of window (oow) flag set. 4383 */ 4384 if ((fp->fr_flags & FR_KEEPSTATE) && (fp->fr_flx & FI_OOW)) 4385 return EINVAL; 4386 4387 switch (fp->fr_satype) 4388 { 4389 case FRI_BROADCAST : 4390 case FRI_DYNAMIC : 4391 case FRI_NETWORK : 4392 case FRI_NETMASKED : 4393 case FRI_PEERADDR : 4394 if (fp->fr_sifpidx < 0 || fp->fr_sifpidx > 3) { 4395 if (makecopy && fp->fr_data != NULL) { 4396 KFREES(fp->fr_data, fp->fr_dsize); 4397 } 4398 return EINVAL; 4399 } 4400 break; 4401 #ifdef IPFILTER_LOOKUP 4402 case FRI_LOOKUP : 4403 fp->fr_srcptr = fr_resolvelookup(fp->fr_srctype, 4404 fp->fr_srcnum, 4405 &fp->fr_srcfunc, ifs); 4406 break; 4407 #endif 4408 default : 4409 break; 4410 } 4411 4412 switch (fp->fr_datype) 4413 { 4414 case FRI_BROADCAST : 4415 case FRI_DYNAMIC : 4416 case FRI_NETWORK : 4417 case FRI_NETMASKED : 4418 case FRI_PEERADDR : 4419 if (fp->fr_difpidx < 0 || fp->fr_difpidx > 3) { 4420 if (makecopy && fp->fr_data != NULL) { 4421 KFREES(fp->fr_data, fp->fr_dsize); 4422 } 4423 return EINVAL; 4424 } 4425 break; 4426 #ifdef IPFILTER_LOOKUP 4427 case FRI_LOOKUP : 4428 fp->fr_dstptr = fr_resolvelookup(fp->fr_dsttype, 4429 fp->fr_dstnum, 4430 &fp->fr_dstfunc, ifs); 4431 break; 4432 #endif 4433 default : 4434 break; 4435 } 4436 break; 4437 case FR_T_NONE : 4438 break; 4439 case FR_T_CALLFUNC : 4440 break; 4441 case FR_T_COMPIPF : 4442 break; 4443 default : 4444 if (makecopy && fp->fr_data != NULL) { 4445 KFREES(fp->fr_data, fp->fr_dsize); 4446 } 4447 return EINVAL; 4448 } 4449 4450 /* 4451 * Lookup all the interface names that are part of the rule. 4452 */ 4453 frsynclist(0, 0, NULL, NULL, fp, ifs); 4454 fp->fr_statecnt = 0; 4455 4456 /* 4457 * Look for an existing matching filter rule, but don't include the 4458 * next or interface pointer in the comparison (fr_next, fr_ifa). 4459 * This elminates rules which are indentical being loaded. Checksum 4460 * the constant part of the filter rule to make comparisons quicker 4461 * (this meaning no pointers are included). 4462 */ 4463 for (fp->fr_cksum = 0, p = (u_int *)&fp->fr_func, pp = &fp->fr_cksum; 4464 p < pp; p++) 4465 fp->fr_cksum += *p; 4466 pp = (u_int *)(fp->fr_caddr + fp->fr_dsize); 4467 for (p = (u_int *)fp->fr_data; p < pp; p++) 4468 fp->fr_cksum += *p; 4469 4470 WRITE_ENTER(&ifs->ifs_ipf_mutex); 4471 4472 for (; (f = *ftail) != NULL; ftail = &f->fr_next) { 4473 if ((fp->fr_cksum != f->fr_cksum) || 4474 (f->fr_dsize != fp->fr_dsize)) 4475 continue; 4476 if (bcmp((char *)&f->fr_func, (char *)&fp->fr_func, FR_CMPSIZ)) 4477 continue; 4478 if ((!ptr && !f->fr_data) || 4479 (ptr && f->fr_data && 4480 !bcmp((char *)ptr, (char *)f->fr_data, f->fr_dsize))) 4481 break; 4482 } 4483 4484 /* 4485 * If zero'ing statistics, copy current to caller and zero. 4486 */ 4487 if (req == (ioctlcmd_t)SIOCZRLST) { 4488 if (f == NULL) 4489 error = ESRCH; 4490 else { 4491 /* 4492 * Copy and reduce lock because of impending copyout. 4493 * Well we should, but if we do then the atomicity of 4494 * this call and the correctness of fr_hits and 4495 * fr_bytes cannot be guaranteed. As it is, this code 4496 * only resets them to 0 if they are successfully 4497 * copied out into user space. 4498 */ 4499 bcopy((char *)f, (char *)fp, sizeof(*f)); 4500 4501 /* 4502 * When we copy this rule back out, set the data 4503 * pointer to be what it was in user space. 4504 */ 4505 fp->fr_data = uptr; 4506 error = fr_outobj(data, fp, IPFOBJ_FRENTRY); 4507 4508 if (error == 0) { 4509 if ((f->fr_dsize != 0) && (uptr != NULL)) 4510 error = COPYOUT(f->fr_data, uptr, 4511 f->fr_dsize); 4512 if (error == 0) { 4513 f->fr_hits = 0; 4514 f->fr_bytes = 0; 4515 } 4516 } 4517 } 4518 4519 if ((ptr != NULL) && (makecopy != 0)) { 4520 KFREES(ptr, fp->fr_dsize); 4521 } 4522 RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 4523 return error; 4524 } 4525 4526 if (!f) { 4527 /* 4528 * At the end of this, ftail must point to the place where the 4529 * new rule is to be saved/inserted/added. 4530 * For SIOCAD*FR, this should be the last rule in the group of 4531 * rules that have equal fr_collect fields. 4532 * For SIOCIN*FR, ... 4533 */ 4534 if (req == (ioctlcmd_t)SIOCADAFR || 4535 req == (ioctlcmd_t)SIOCADIFR) { 4536 4537 for (ftail = fprev; (f = *ftail) != NULL; ) { 4538 if (f->fr_collect > fp->fr_collect) 4539 break; 4540 ftail = &f->fr_next; 4541 } 4542 f = NULL; 4543 ptr = NULL; 4544 error = 0; 4545 } else if (req == (ioctlcmd_t)SIOCINAFR || 4546 req == (ioctlcmd_t)SIOCINIFR) { 4547 while ((f = *fprev) != NULL) { 4548 if (f->fr_collect >= fp->fr_collect) 4549 break; 4550 fprev = &f->fr_next; 4551 } 4552 ftail = fprev; 4553 if (fp->fr_hits != 0) { 4554 while (fp->fr_hits && (f = *ftail)) { 4555 if (f->fr_collect != fp->fr_collect) 4556 break; 4557 fprev = ftail; 4558 ftail = &f->fr_next; 4559 fp->fr_hits--; 4560 } 4561 } 4562 f = NULL; 4563 ptr = NULL; 4564 error = 0; 4565 } 4566 } 4567 4568 /* 4569 * Request to remove a rule. 4570 */ 4571 if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR) { 4572 if (!f) 4573 error = ESRCH; 4574 else { 4575 /* 4576 * Do not allow activity from user space to interfere 4577 * with rules not loaded that way. 4578 */ 4579 if ((makecopy == 1) && !(f->fr_flags & FR_COPIED)) { 4580 error = EPERM; 4581 goto done; 4582 } 4583 4584 /* 4585 * Return EBUSY if the rule is being reference by 4586 * something else (eg state information. 4587 */ 4588 if (f->fr_ref > 1) { 4589 error = EBUSY; 4590 goto done; 4591 } 4592 #ifdef IPFILTER_SCAN 4593 if (f->fr_isctag[0] != '\0' && 4594 (f->fr_isc != (struct ipscan *)-1)) 4595 ipsc_detachfr(f); 4596 #endif 4597 if (unit == IPL_LOGAUTH) { 4598 error = fr_preauthcmd(req, f, ftail, ifs); 4599 goto done; 4600 } 4601 if (*f->fr_grhead != '\0') 4602 fr_delgroup(f->fr_grhead, unit, set, ifs); 4603 fr_fixskip(ftail, f, -1); 4604 *ftail = f->fr_next; 4605 f->fr_next = NULL; 4606 (void)fr_derefrule(&f, ifs); 4607 } 4608 } else { 4609 /* 4610 * Not removing, so we must be adding/inserting a rule. 4611 */ 4612 if (f) 4613 error = EEXIST; 4614 else { 4615 if (unit == IPL_LOGAUTH) { 4616 error = fr_preauthcmd(req, fp, ftail, ifs); 4617 goto done; 4618 } 4619 if (makecopy) { 4620 KMALLOC(f, frentry_t *); 4621 } else 4622 f = fp; 4623 if (f != NULL) { 4624 if (fp != f) 4625 bcopy((char *)fp, (char *)f, 4626 sizeof(*f)); 4627 MUTEX_NUKE(&f->fr_lock); 4628 MUTEX_INIT(&f->fr_lock, "filter rule lock"); 4629 #ifdef IPFILTER_SCAN 4630 if (f->fr_isctag[0] != '\0' && 4631 ipsc_attachfr(f)) 4632 f->fr_isc = (struct ipscan *)-1; 4633 #endif 4634 f->fr_hits = 0; 4635 if (makecopy != 0) 4636 f->fr_ref = 1; 4637 f->fr_next = *ftail; 4638 *ftail = f; 4639 if (req == (ioctlcmd_t)SIOCINIFR || 4640 req == (ioctlcmd_t)SIOCINAFR) 4641 fr_fixskip(ftail, f, 1); 4642 f->fr_grp = NULL; 4643 group = f->fr_grhead; 4644 if (*group != '\0') { 4645 fg = fr_addgroup(group, f, f->fr_flags, 4646 unit, set, ifs); 4647 if (fg != NULL) 4648 f->fr_grp = &fg->fg_start; 4649 } 4650 } else 4651 error = ENOMEM; 4652 } 4653 } 4654 done: 4655 RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 4656 if ((ptr != NULL) && (error != 0) && (makecopy != 0)) { 4657 KFREES(ptr, fp->fr_dsize); 4658 } 4659 return (error); 4660 } 4661 4662 4663 /* ------------------------------------------------------------------------ */ 4664 /* Function: fr_funcinit */ 4665 /* Returns: int - 0 == success, else ESRCH: cannot resolve rule details */ 4666 /* Parameters: fr(I) - pointer to filter rule */ 4667 /* */ 4668 /* If a rule is a call rule, then check if the function it points to needs */ 4669 /* an init function to be called now the rule has been loaded. */ 4670 /* ------------------------------------------------------------------------ */ 4671 static int fr_funcinit(fr, ifs) 4672 frentry_t *fr; 4673 ipf_stack_t *ifs; 4674 { 4675 ipfunc_resolve_t *ft; 4676 int err; 4677 4678 err = ESRCH; 4679 4680 for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++) 4681 if (ft->ipfu_addr == fr->fr_func) { 4682 err = 0; 4683 if (ft->ipfu_init != NULL) 4684 err = (*ft->ipfu_init)(fr, ifs); 4685 break; 4686 } 4687 return err; 4688 } 4689 4690 4691 /* ------------------------------------------------------------------------ */ 4692 /* Function: fr_findfunc */ 4693 /* Returns: ipfunc_t - pointer to function if found, else NULL */ 4694 /* Parameters: funcptr(I) - function pointer to lookup */ 4695 /* */ 4696 /* Look for a function in the table of known functions. */ 4697 /* ------------------------------------------------------------------------ */ 4698 static ipfunc_t fr_findfunc(funcptr) 4699 ipfunc_t funcptr; 4700 { 4701 ipfunc_resolve_t *ft; 4702 4703 for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++) 4704 if (ft->ipfu_addr == funcptr) 4705 return funcptr; 4706 return NULL; 4707 } 4708 4709 4710 /* ------------------------------------------------------------------------ */ 4711 /* Function: fr_resolvefunc */ 4712 /* Returns: int - 0 == success, else error */ 4713 /* Parameters: data(IO) - ioctl data pointer to ipfunc_resolve_t struct */ 4714 /* */ 4715 /* Copy in a ipfunc_resolve_t structure and then fill in the missing field. */ 4716 /* This will either be the function name (if the pointer is set) or the */ 4717 /* function pointer if the name is set. When found, fill in the other one */ 4718 /* so that the entire, complete, structure can be copied back to user space.*/ 4719 /* ------------------------------------------------------------------------ */ 4720 int fr_resolvefunc(data) 4721 void *data; 4722 { 4723 ipfunc_resolve_t res, *ft; 4724 int err; 4725 4726 err = BCOPYIN(data, &res, sizeof(res)); 4727 if (err != 0) 4728 return EFAULT; 4729 4730 if (res.ipfu_addr == NULL && res.ipfu_name[0] != '\0') { 4731 for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++) 4732 if (strncmp(res.ipfu_name, ft->ipfu_name, 4733 sizeof(res.ipfu_name)) == 0) { 4734 res.ipfu_addr = ft->ipfu_addr; 4735 res.ipfu_init = ft->ipfu_init; 4736 if (COPYOUT(&res, data, sizeof(res)) != 0) 4737 return EFAULT; 4738 return 0; 4739 } 4740 } 4741 if (res.ipfu_addr != NULL && res.ipfu_name[0] == '\0') { 4742 for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++) 4743 if (ft->ipfu_addr == res.ipfu_addr) { 4744 (void) strncpy(res.ipfu_name, ft->ipfu_name, 4745 sizeof(res.ipfu_name)); 4746 res.ipfu_init = ft->ipfu_init; 4747 if (COPYOUT(&res, data, sizeof(res)) != 0) 4748 return EFAULT; 4749 return 0; 4750 } 4751 } 4752 return ESRCH; 4753 } 4754 4755 4756 #if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__FreeBSD__)) || \ 4757 (defined(__FreeBSD__) && (__FreeBSD_version < 490000)) || \ 4758 (defined(__NetBSD__) && (__NetBSD_Version__ < 105000000)) || \ 4759 (defined(__OpenBSD__) && (OpenBSD < 200006)) 4760 /* 4761 * From: NetBSD 4762 * ppsratecheck(): packets (or events) per second limitation. 4763 */ 4764 int 4765 ppsratecheck(lasttime, curpps, maxpps) 4766 struct timeval *lasttime; 4767 int *curpps; 4768 int maxpps; /* maximum pps allowed */ 4769 { 4770 struct timeval tv, delta; 4771 int rv; 4772 4773 GETKTIME(&tv); 4774 4775 delta.tv_sec = tv.tv_sec - lasttime->tv_sec; 4776 delta.tv_usec = tv.tv_usec - lasttime->tv_usec; 4777 if (delta.tv_usec < 0) { 4778 delta.tv_sec--; 4779 delta.tv_usec += 1000000; 4780 } 4781 4782 /* 4783 * check for 0,0 is so that the message will be seen at least once. 4784 * if more than one second have passed since the last update of 4785 * lasttime, reset the counter. 4786 * 4787 * we do increment *curpps even in *curpps < maxpps case, as some may 4788 * try to use *curpps for stat purposes as well. 4789 */ 4790 if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) || 4791 delta.tv_sec >= 1) { 4792 *lasttime = tv; 4793 *curpps = 0; 4794 rv = 1; 4795 } else if (maxpps < 0) 4796 rv = 1; 4797 else if (*curpps < maxpps) 4798 rv = 1; 4799 else 4800 rv = 0; 4801 *curpps = *curpps + 1; 4802 4803 return (rv); 4804 } 4805 #endif 4806 4807 4808 /* ------------------------------------------------------------------------ */ 4809 /* Function: fr_derefrule */ 4810 /* Returns: int - 0 == rule freed up, else rule not freed */ 4811 /* Parameters: fr(I) - pointer to filter rule */ 4812 /* */ 4813 /* Decrement the reference counter to a rule by one. If it reaches zero, */ 4814 /* free it and any associated storage space being used by it. */ 4815 /* ------------------------------------------------------------------------ */ 4816 int fr_derefrule(frp, ifs) 4817 frentry_t **frp; 4818 ipf_stack_t *ifs; 4819 { 4820 frentry_t *fr; 4821 4822 fr = *frp; 4823 4824 MUTEX_ENTER(&fr->fr_lock); 4825 fr->fr_ref--; 4826 if (fr->fr_ref == 0) { 4827 MUTEX_EXIT(&fr->fr_lock); 4828 MUTEX_DESTROY(&fr->fr_lock); 4829 4830 #ifdef IPFILTER_LOOKUP 4831 if (fr->fr_type == FR_T_IPF && fr->fr_satype == FRI_LOOKUP) 4832 ip_lookup_deref(fr->fr_srctype, fr->fr_srcptr, ifs); 4833 if (fr->fr_type == FR_T_IPF && fr->fr_datype == FRI_LOOKUP) 4834 ip_lookup_deref(fr->fr_dsttype, fr->fr_dstptr, ifs); 4835 #endif 4836 4837 if (fr->fr_dsize) { 4838 KFREES(fr->fr_data, fr->fr_dsize); 4839 } 4840 if ((fr->fr_flags & FR_COPIED) != 0) { 4841 KFREE(fr); 4842 return 0; 4843 } 4844 return 1; 4845 } else { 4846 MUTEX_EXIT(&fr->fr_lock); 4847 } 4848 *frp = NULL; 4849 return -1; 4850 } 4851 4852 4853 #ifdef IPFILTER_LOOKUP 4854 /* ------------------------------------------------------------------------ */ 4855 /* Function: fr_grpmapinit */ 4856 /* Returns: int - 0 == success, else ESRCH because table entry not found*/ 4857 /* Parameters: fr(I) - pointer to rule to find hash table for */ 4858 /* */ 4859 /* Looks for group hash table fr_arg and stores a pointer to it in fr_ptr. */ 4860 /* fr_ptr is later used by fr_srcgrpmap and fr_dstgrpmap. */ 4861 /* ------------------------------------------------------------------------ */ 4862 static int fr_grpmapinit(fr, ifs) 4863 frentry_t *fr; 4864 ipf_stack_t *ifs; 4865 { 4866 char name[FR_GROUPLEN]; 4867 iphtable_t *iph; 4868 4869 #if defined(SNPRINTF) && defined(_KERNEL) 4870 (void) SNPRINTF(name, sizeof(name), "%d", fr->fr_arg); 4871 #else 4872 (void) sprintf(name, "%d", fr->fr_arg); 4873 #endif 4874 iph = fr_findhtable(IPL_LOGIPF, name, ifs); 4875 if (iph == NULL) 4876 return ESRCH; 4877 if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT)) 4878 return ESRCH; 4879 fr->fr_ptr = iph; 4880 return 0; 4881 } 4882 4883 4884 /* ------------------------------------------------------------------------ */ 4885 /* Function: fr_srcgrpmap */ 4886 /* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ 4887 /* Parameters: fin(I) - pointer to packet information */ 4888 /* passp(IO) - pointer to current/new filter decision (unused) */ 4889 /* */ 4890 /* Look for a rule group head in a hash table, using the source address as */ 4891 /* the key, and descend into that group and continue matching rules against */ 4892 /* the packet. */ 4893 /* ------------------------------------------------------------------------ */ 4894 frentry_t *fr_srcgrpmap(fin, passp) 4895 fr_info_t *fin; 4896 u_32_t *passp; 4897 { 4898 frgroup_t *fg; 4899 void *rval; 4900 ipf_stack_t *ifs = fin->fin_ifs; 4901 4902 rval = fr_iphmfindgroup(fin->fin_fr->fr_ptr, fin->fin_v, &fin->fin_src, ifs); 4903 if (rval == NULL) 4904 return NULL; 4905 4906 fg = rval; 4907 fin->fin_fr = fg->fg_start; 4908 (void) fr_scanlist(fin, *passp); 4909 return fin->fin_fr; 4910 } 4911 4912 4913 /* ------------------------------------------------------------------------ */ 4914 /* Function: fr_dstgrpmap */ 4915 /* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ 4916 /* Parameters: fin(I) - pointer to packet information */ 4917 /* passp(IO) - pointer to current/new filter decision (unused) */ 4918 /* */ 4919 /* Look for a rule group head in a hash table, using the destination */ 4920 /* address as the key, and descend into that group and continue matching */ 4921 /* rules against the packet. */ 4922 /* ------------------------------------------------------------------------ */ 4923 frentry_t *fr_dstgrpmap(fin, passp) 4924 fr_info_t *fin; 4925 u_32_t *passp; 4926 { 4927 frgroup_t *fg; 4928 void *rval; 4929 ipf_stack_t *ifs = fin->fin_ifs; 4930 4931 rval = fr_iphmfindgroup(fin->fin_fr->fr_ptr, fin->fin_v, &fin->fin_dst, ifs); 4932 if (rval == NULL) 4933 return NULL; 4934 4935 fg = rval; 4936 fin->fin_fr = fg->fg_start; 4937 (void) fr_scanlist(fin, *passp); 4938 return fin->fin_fr; 4939 } 4940 #endif /* IPFILTER_LOOKUP */ 4941 4942 /* 4943 * Queue functions 4944 * =============== 4945 * These functions manage objects on queues for efficient timeouts. There are 4946 * a number of system defined queues as well as user defined timeouts. It is 4947 * expected that a lock is held in the domain in which the queue belongs 4948 * (i.e. either state or NAT) when calling any of these functions that prevents 4949 * fr_freetimeoutqueue() from being called at the same time as any other. 4950 */ 4951 4952 4953 /* ------------------------------------------------------------------------ */ 4954 /* Function: fr_addtimeoutqueue */ 4955 /* Returns: struct ifqtq * - NULL if malloc fails, else pointer to */ 4956 /* timeout queue with given interval. */ 4957 /* Parameters: parent(I) - pointer to pointer to parent node of this list */ 4958 /* of interface queues. */ 4959 /* seconds(I) - timeout value in seconds for this queue. */ 4960 /* */ 4961 /* This routine first looks for a timeout queue that matches the interval */ 4962 /* being requested. If it finds one, increments the reference counter and */ 4963 /* returns a pointer to it. If none are found, it allocates a new one and */ 4964 /* inserts it at the top of the list. */ 4965 /* */ 4966 /* Locking. */ 4967 /* It is assumed that the caller of this function has an appropriate lock */ 4968 /* held (exclusively) in the domain that encompases 'parent'. */ 4969 /* ------------------------------------------------------------------------ */ 4970 ipftq_t *fr_addtimeoutqueue(parent, seconds, ifs) 4971 ipftq_t **parent; 4972 u_int seconds; 4973 ipf_stack_t *ifs; 4974 { 4975 ipftq_t *ifq; 4976 u_int period; 4977 4978 period = seconds * IPF_HZ_DIVIDE; 4979 4980 MUTEX_ENTER(&ifs->ifs_ipf_timeoutlock); 4981 for (ifq = *parent; ifq != NULL; ifq = ifq->ifq_next) { 4982 if (ifq->ifq_ttl == period) { 4983 /* 4984 * Reset the delete flag, if set, so the structure 4985 * gets reused rather than freed and reallocated. 4986 */ 4987 MUTEX_ENTER(&ifq->ifq_lock); 4988 ifq->ifq_flags &= ~IFQF_DELETE; 4989 ifq->ifq_ref++; 4990 MUTEX_EXIT(&ifq->ifq_lock); 4991 MUTEX_EXIT(&ifs->ifs_ipf_timeoutlock); 4992 4993 return ifq; 4994 } 4995 } 4996 4997 KMALLOC(ifq, ipftq_t *); 4998 if (ifq != NULL) { 4999 ifq->ifq_ttl = period; 5000 ifq->ifq_head = NULL; 5001 ifq->ifq_tail = &ifq->ifq_head; 5002 ifq->ifq_next = *parent; 5003 ifq->ifq_pnext = parent; 5004 ifq->ifq_ref = 1; 5005 ifq->ifq_flags = IFQF_USER; 5006 *parent = ifq; 5007 ifs->ifs_fr_userifqs++; 5008 MUTEX_NUKE(&ifq->ifq_lock); 5009 MUTEX_INIT(&ifq->ifq_lock, "ipftq mutex"); 5010 } 5011 MUTEX_EXIT(&ifs->ifs_ipf_timeoutlock); 5012 return ifq; 5013 } 5014 5015 5016 /* ------------------------------------------------------------------------ */ 5017 /* Function: fr_deletetimeoutqueue */ 5018 /* Returns: int - new reference count value of the timeout queue */ 5019 /* Parameters: ifq(I) - timeout queue which is losing a reference. */ 5020 /* Locks: ifq->ifq_lock */ 5021 /* */ 5022 /* This routine must be called when we're discarding a pointer to a timeout */ 5023 /* queue object, taking care of the reference counter. */ 5024 /* */ 5025 /* Now that this just sets a DELETE flag, it requires the expire code to */ 5026 /* check the list of user defined timeout queues and call the free function */ 5027 /* below (currently commented out) to stop memory leaking. It is done this */ 5028 /* way because the locking may not be sufficient to safely do a free when */ 5029 /* this function is called. */ 5030 /* ------------------------------------------------------------------------ */ 5031 int fr_deletetimeoutqueue(ifq) 5032 ipftq_t *ifq; 5033 { 5034 5035 ifq->ifq_ref--; 5036 if ((ifq->ifq_ref == 0) && ((ifq->ifq_flags & IFQF_USER) != 0)) { 5037 ifq->ifq_flags |= IFQF_DELETE; 5038 } 5039 5040 return ifq->ifq_ref; 5041 } 5042 5043 5044 /* ------------------------------------------------------------------------ */ 5045 /* Function: fr_freetimeoutqueue */ 5046 /* Parameters: ifq(I) - timeout queue which is losing a reference. */ 5047 /* Returns: Nil */ 5048 /* */ 5049 /* Locking: */ 5050 /* It is assumed that the caller of this function has an appropriate lock */ 5051 /* held (exclusively) in the domain that encompases the callers "domain". */ 5052 /* The ifq_lock for this structure should not be held. */ 5053 /* */ 5054 /* Remove a user definde timeout queue from the list of queues it is in and */ 5055 /* tidy up after this is done. */ 5056 /* ------------------------------------------------------------------------ */ 5057 void fr_freetimeoutqueue(ifq, ifs) 5058 ipftq_t *ifq; 5059 ipf_stack_t *ifs; 5060 { 5061 5062 5063 if (((ifq->ifq_flags & IFQF_DELETE) == 0) || (ifq->ifq_ref != 0) || 5064 ((ifq->ifq_flags & IFQF_USER) == 0)) { 5065 printf("fr_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n", 5066 (u_long)ifq, ifq->ifq_flags, ifq->ifq_ttl, 5067 ifq->ifq_ref); 5068 return; 5069 } 5070 5071 /* 5072 * Remove from its position in the list. 5073 */ 5074 *ifq->ifq_pnext = ifq->ifq_next; 5075 if (ifq->ifq_next != NULL) 5076 ifq->ifq_next->ifq_pnext = ifq->ifq_pnext; 5077 5078 MUTEX_DESTROY(&ifq->ifq_lock); 5079 ifs->ifs_fr_userifqs--; 5080 KFREE(ifq); 5081 } 5082 5083 5084 /* ------------------------------------------------------------------------ */ 5085 /* Function: fr_deletequeueentry */ 5086 /* Returns: Nil */ 5087 /* Parameters: tqe(I) - timeout queue entry to delete */ 5088 /* ifq(I) - timeout queue to remove entry from */ 5089 /* */ 5090 /* Remove a tail queue entry from its queue and make it an orphan. */ 5091 /* fr_deletetimeoutqueue is called to make sure the reference count on the */ 5092 /* queue is correct. We can't, however, call fr_freetimeoutqueue because */ 5093 /* the correct lock(s) may not be held that would make it safe to do so. */ 5094 /* ------------------------------------------------------------------------ */ 5095 void fr_deletequeueentry(tqe) 5096 ipftqent_t *tqe; 5097 { 5098 ipftq_t *ifq; 5099 5100 ifq = tqe->tqe_ifq; 5101 if (ifq == NULL) 5102 return; 5103 5104 MUTEX_ENTER(&ifq->ifq_lock); 5105 5106 if (tqe->tqe_pnext != NULL) { 5107 *tqe->tqe_pnext = tqe->tqe_next; 5108 if (tqe->tqe_next != NULL) 5109 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5110 else /* we must be the tail anyway */ 5111 ifq->ifq_tail = tqe->tqe_pnext; 5112 5113 tqe->tqe_pnext = NULL; 5114 tqe->tqe_ifq = NULL; 5115 } 5116 5117 (void) fr_deletetimeoutqueue(ifq); 5118 5119 MUTEX_EXIT(&ifq->ifq_lock); 5120 } 5121 5122 5123 /* ------------------------------------------------------------------------ */ 5124 /* Function: fr_queuefront */ 5125 /* Returns: Nil */ 5126 /* Parameters: tqe(I) - pointer to timeout queue entry */ 5127 /* */ 5128 /* Move a queue entry to the front of the queue, if it isn't already there. */ 5129 /* ------------------------------------------------------------------------ */ 5130 void fr_queuefront(tqe) 5131 ipftqent_t *tqe; 5132 { 5133 ipftq_t *ifq; 5134 5135 ifq = tqe->tqe_ifq; 5136 if (ifq == NULL) 5137 return; 5138 5139 MUTEX_ENTER(&ifq->ifq_lock); 5140 if (ifq->ifq_head != tqe) { 5141 *tqe->tqe_pnext = tqe->tqe_next; 5142 if (tqe->tqe_next) 5143 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5144 else 5145 ifq->ifq_tail = tqe->tqe_pnext; 5146 5147 tqe->tqe_next = ifq->ifq_head; 5148 ifq->ifq_head->tqe_pnext = &tqe->tqe_next; 5149 ifq->ifq_head = tqe; 5150 tqe->tqe_pnext = &ifq->ifq_head; 5151 } 5152 MUTEX_EXIT(&ifq->ifq_lock); 5153 } 5154 5155 5156 /* ------------------------------------------------------------------------ */ 5157 /* Function: fr_queueback */ 5158 /* Returns: Nil */ 5159 /* Parameters: tqe(I) - pointer to timeout queue entry */ 5160 /* */ 5161 /* Move a queue entry to the back of the queue, if it isn't already there. */ 5162 /* ------------------------------------------------------------------------ */ 5163 void fr_queueback(tqe, ifs) 5164 ipftqent_t *tqe; 5165 ipf_stack_t *ifs; 5166 { 5167 ipftq_t *ifq; 5168 5169 ifq = tqe->tqe_ifq; 5170 if (ifq == NULL) 5171 return; 5172 tqe->tqe_die = ifs->ifs_fr_ticks + ifq->ifq_ttl; 5173 5174 MUTEX_ENTER(&ifq->ifq_lock); 5175 if (tqe->tqe_next == NULL) { /* at the end already ? */ 5176 MUTEX_EXIT(&ifq->ifq_lock); 5177 return; 5178 } 5179 5180 /* 5181 * Remove from list 5182 */ 5183 *tqe->tqe_pnext = tqe->tqe_next; 5184 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5185 5186 /* 5187 * Make it the last entry. 5188 */ 5189 tqe->tqe_next = NULL; 5190 tqe->tqe_pnext = ifq->ifq_tail; 5191 *ifq->ifq_tail = tqe; 5192 ifq->ifq_tail = &tqe->tqe_next; 5193 MUTEX_EXIT(&ifq->ifq_lock); 5194 } 5195 5196 5197 /* ------------------------------------------------------------------------ */ 5198 /* Function: fr_queueappend */ 5199 /* Returns: Nil */ 5200 /* Parameters: tqe(I) - pointer to timeout queue entry */ 5201 /* ifq(I) - pointer to timeout queue */ 5202 /* parent(I) - owing object pointer */ 5203 /* */ 5204 /* Add a new item to this queue and put it on the very end. */ 5205 /* ------------------------------------------------------------------------ */ 5206 void fr_queueappend(tqe, ifq, parent, ifs) 5207 ipftqent_t *tqe; 5208 ipftq_t *ifq; 5209 void *parent; 5210 ipf_stack_t *ifs; 5211 { 5212 5213 MUTEX_ENTER(&ifq->ifq_lock); 5214 tqe->tqe_parent = parent; 5215 tqe->tqe_pnext = ifq->ifq_tail; 5216 *ifq->ifq_tail = tqe; 5217 ifq->ifq_tail = &tqe->tqe_next; 5218 tqe->tqe_next = NULL; 5219 tqe->tqe_ifq = ifq; 5220 tqe->tqe_die = ifs->ifs_fr_ticks + ifq->ifq_ttl; 5221 ifq->ifq_ref++; 5222 MUTEX_EXIT(&ifq->ifq_lock); 5223 } 5224 5225 5226 /* ------------------------------------------------------------------------ */ 5227 /* Function: fr_movequeue */ 5228 /* Returns: Nil */ 5229 /* Parameters: tq(I) - pointer to timeout queue information */ 5230 /* oifp(I) - old timeout queue entry was on */ 5231 /* nifp(I) - new timeout queue to put entry on */ 5232 /* ifs - ipf stack instance */ 5233 /* */ 5234 /* Move a queue entry from one timeout queue to another timeout queue. */ 5235 /* If it notices that the current entry is already last and does not need */ 5236 /* to move queue, the return. */ 5237 /* ------------------------------------------------------------------------ */ 5238 void fr_movequeue(tqe, oifq, nifq, ifs) 5239 ipftqent_t *tqe; 5240 ipftq_t *oifq, *nifq; 5241 ipf_stack_t *ifs; 5242 { 5243 /* 5244 * If the queue isn't changing, and the clock hasn't ticked 5245 * since the last update, the operation will be a no-op. 5246 */ 5247 if (oifq == nifq && tqe->tqe_touched == ifs->ifs_fr_ticks) 5248 return; 5249 5250 /* 5251 * Grab the lock and update the timers. 5252 */ 5253 MUTEX_ENTER(&oifq->ifq_lock); 5254 tqe->tqe_touched = ifs->ifs_fr_ticks; 5255 tqe->tqe_die = ifs->ifs_fr_ticks + nifq->ifq_ttl; 5256 5257 /* 5258 * The remainder of the operation can still be a no-op. 5259 * 5260 * If the queue isn't changing, check to see if 5261 * an update would be meaningless. 5262 */ 5263 if (oifq == nifq) { 5264 if ((tqe->tqe_next == NULL) || 5265 (tqe->tqe_next->tqe_die == tqe->tqe_die)) { 5266 MUTEX_EXIT(&oifq->ifq_lock); 5267 return; 5268 } 5269 } 5270 5271 /* 5272 * Remove from the old queue 5273 */ 5274 *tqe->tqe_pnext = tqe->tqe_next; 5275 if (tqe->tqe_next) 5276 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5277 else 5278 oifq->ifq_tail = tqe->tqe_pnext; 5279 tqe->tqe_next = NULL; 5280 5281 /* 5282 * If we're moving from one queue to another, release the lock on the 5283 * old queue and get a lock on the new queue. For user defined queues, 5284 * if we're moving off it, call delete in case it can now be freed. 5285 */ 5286 if (oifq != nifq) { 5287 tqe->tqe_ifq = NULL; 5288 5289 (void) fr_deletetimeoutqueue(oifq); 5290 5291 MUTEX_EXIT(&oifq->ifq_lock); 5292 5293 MUTEX_ENTER(&nifq->ifq_lock); 5294 5295 tqe->tqe_ifq = nifq; 5296 nifq->ifq_ref++; 5297 } 5298 5299 /* 5300 * Add to the bottom of the new queue 5301 */ 5302 tqe->tqe_pnext = nifq->ifq_tail; 5303 *nifq->ifq_tail = tqe; 5304 nifq->ifq_tail = &tqe->tqe_next; 5305 MUTEX_EXIT(&nifq->ifq_lock); 5306 } 5307 5308 5309 /* ------------------------------------------------------------------------ */ 5310 /* Function: fr_updateipid */ 5311 /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 5312 /* Parameters: fin(I) - pointer to packet information */ 5313 /* */ 5314 /* When we are doing NAT, change the IP of every packet to represent a */ 5315 /* single sequence of packets coming from the host, hiding any host */ 5316 /* specific sequencing that might otherwise be revealed. If the packet is */ 5317 /* a fragment, then store the 'new' IPid in the fragment cache and look up */ 5318 /* the fragment cache for non-leading fragments. If a non-leading fragment */ 5319 /* has no match in the cache, return an error. */ 5320 /* ------------------------------------------------------------------------ */ 5321 static INLINE int fr_updateipid(fin) 5322 fr_info_t *fin; 5323 { 5324 u_short id, ido, sums; 5325 u_32_t sumd, sum; 5326 ip_t *ip; 5327 5328 if (fin->fin_off != 0) { 5329 sum = fr_ipid_knownfrag(fin); 5330 if (sum == 0xffffffff) 5331 return -1; 5332 sum &= 0xffff; 5333 id = (u_short)sum; 5334 } else { 5335 id = fr_nextipid(fin); 5336 if (fin->fin_off == 0 && (fin->fin_flx & FI_FRAG) != 0) 5337 (void) fr_ipid_newfrag(fin, (u_32_t)id); 5338 } 5339 5340 ip = fin->fin_ip; 5341 ido = ntohs(ip->ip_id); 5342 if (id == ido) 5343 return 0; 5344 ip->ip_id = htons(id); 5345 CALC_SUMD(ido, id, sumd); /* DESTRUCTIVE MACRO! id,ido change */ 5346 sum = (~ntohs(ip->ip_sum)) & 0xffff; 5347 sum += sumd; 5348 sum = (sum >> 16) + (sum & 0xffff); 5349 sum = (sum >> 16) + (sum & 0xffff); 5350 sums = ~(u_short)sum; 5351 ip->ip_sum = htons(sums); 5352 return 0; 5353 } 5354 5355 5356 #ifdef NEED_FRGETIFNAME 5357 /* ------------------------------------------------------------------------ */ 5358 /* Function: fr_getifname */ 5359 /* Returns: char * - pointer to interface name */ 5360 /* Parameters: ifp(I) - pointer to network interface */ 5361 /* buffer(O) - pointer to where to store interface name */ 5362 /* */ 5363 /* Constructs an interface name in the buffer passed. The buffer passed is */ 5364 /* expected to be at least LIFNAMSIZ in bytes big. If buffer is passed in */ 5365 /* as a NULL pointer then return a pointer to a static array. */ 5366 /* ------------------------------------------------------------------------ */ 5367 char *fr_getifname(ifp, buffer) 5368 struct ifnet *ifp; 5369 char *buffer; 5370 { 5371 static char namebuf[LIFNAMSIZ]; 5372 # if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \ 5373 defined(__sgi) || defined(linux) || defined(_AIX51) || \ 5374 (defined(sun) && !defined(__SVR4) && !defined(__svr4__)) 5375 int unit, space; 5376 char temp[20]; 5377 char *s; 5378 # endif 5379 5380 ASSERT(buffer != NULL); 5381 #ifdef notdef 5382 if (buffer == NULL) 5383 buffer = namebuf; 5384 #endif 5385 (void) strncpy(buffer, ifp->if_name, LIFNAMSIZ); 5386 buffer[LIFNAMSIZ - 1] = '\0'; 5387 # if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \ 5388 defined(__sgi) || defined(_AIX51) || \ 5389 (defined(sun) && !defined(__SVR4) && !defined(__svr4__)) 5390 for (s = buffer; *s; s++) 5391 ; 5392 unit = ifp->if_unit; 5393 space = LIFNAMSIZ - (s - buffer); 5394 if (space > 0) { 5395 # if defined(SNPRINTF) && defined(_KERNEL) 5396 (void) SNPRINTF(temp, sizeof(temp), "%d", unit); 5397 # else 5398 (void) sprintf(temp, "%d", unit); 5399 # endif 5400 (void) strncpy(s, temp, space); 5401 } 5402 # endif 5403 return buffer; 5404 } 5405 #endif 5406 5407 5408 /* ------------------------------------------------------------------------ */ 5409 /* Function: fr_ioctlswitch */ 5410 /* Returns: int - -1 continue processing, else ioctl return value */ 5411 /* Parameters: unit(I) - device unit opened */ 5412 /* data(I) - pointer to ioctl data */ 5413 /* cmd(I) - ioctl command */ 5414 /* mode(I) - mode value */ 5415 /* */ 5416 /* Based on the value of unit, call the appropriate ioctl handler or return */ 5417 /* EIO if ipfilter is not running. Also checks if write perms are req'd */ 5418 /* for the device in order to execute the ioctl. */ 5419 /* ------------------------------------------------------------------------ */ 5420 INLINE int fr_ioctlswitch(unit, data, cmd, mode, uid, ctx, ifs) 5421 int unit, mode, uid; 5422 ioctlcmd_t cmd; 5423 void *data, *ctx; 5424 ipf_stack_t *ifs; 5425 { 5426 int error = 0; 5427 5428 switch (unit) 5429 { 5430 case IPL_LOGIPF : 5431 error = -1; 5432 break; 5433 case IPL_LOGNAT : 5434 if (ifs->ifs_fr_running > 0) 5435 error = fr_nat_ioctl(data, cmd, mode, uid, ctx, ifs); 5436 else 5437 error = EIO; 5438 break; 5439 case IPL_LOGSTATE : 5440 if (ifs->ifs_fr_running > 0) 5441 error = fr_state_ioctl(data, cmd, mode, uid, ctx, ifs); 5442 else 5443 error = EIO; 5444 break; 5445 case IPL_LOGAUTH : 5446 if (ifs->ifs_fr_running > 0) { 5447 if ((cmd == (ioctlcmd_t)SIOCADAFR) || 5448 (cmd == (ioctlcmd_t)SIOCRMAFR)) { 5449 if (!(mode & FWRITE)) { 5450 error = EPERM; 5451 } else { 5452 error = frrequest(unit, cmd, data, 5453 ifs->ifs_fr_active, 1, ifs); 5454 } 5455 } else { 5456 error = fr_auth_ioctl(data, cmd, mode, uid, ctx, ifs); 5457 } 5458 } else 5459 error = EIO; 5460 break; 5461 case IPL_LOGSYNC : 5462 #ifdef IPFILTER_SYNC 5463 if (ifs->ifs_fr_running > 0) 5464 error = fr_sync_ioctl(data, cmd, mode, ifs); 5465 else 5466 #endif 5467 error = EIO; 5468 break; 5469 case IPL_LOGSCAN : 5470 #ifdef IPFILTER_SCAN 5471 if (ifs->ifs_fr_running > 0) 5472 error = fr_scan_ioctl(data, cmd, mode, ifs); 5473 else 5474 #endif 5475 error = EIO; 5476 break; 5477 case IPL_LOGLOOKUP : 5478 #ifdef IPFILTER_LOOKUP 5479 if (ifs->ifs_fr_running > 0) 5480 error = ip_lookup_ioctl(data, cmd, mode, uid, ctx, ifs); 5481 else 5482 #endif 5483 error = EIO; 5484 break; 5485 default : 5486 error = EIO; 5487 break; 5488 } 5489 5490 return error; 5491 } 5492 5493 5494 /* 5495 * This array defines the expected size of objects coming into the kernel 5496 * for the various recognised object types. 5497 */ 5498 #define NUM_OBJ_TYPES 19 5499 5500 static int fr_objbytes[NUM_OBJ_TYPES][2] = { 5501 { 1, sizeof(struct frentry) }, /* frentry */ 5502 { 0, sizeof(struct friostat) }, 5503 { 0, sizeof(struct fr_info) }, 5504 { 0, sizeof(struct fr_authstat) }, 5505 { 0, sizeof(struct ipfrstat) }, 5506 { 0, sizeof(struct ipnat) }, 5507 { 0, sizeof(struct natstat) }, 5508 { 0, sizeof(struct ipstate_save) }, 5509 { 1, sizeof(struct nat_save) }, /* nat_save */ 5510 { 0, sizeof(struct natlookup) }, 5511 { 1, sizeof(struct ipstate) }, /* ipstate */ 5512 { 0, sizeof(struct ips_stat) }, 5513 { 0, sizeof(struct frauth) }, 5514 { 0, sizeof(struct ipftune) }, 5515 { 0, sizeof(struct nat) }, /* nat_t */ 5516 { 0, sizeof(struct ipfruleiter) }, 5517 { 0, sizeof(struct ipfgeniter) }, 5518 { 0, sizeof(struct ipftable) }, 5519 { 0, sizeof(struct ipflookupiter) } 5520 }; 5521 5522 5523 /* ------------------------------------------------------------------------ */ 5524 /* Function: fr_inobj */ 5525 /* Returns: int - 0 = success, else failure */ 5526 /* Parameters: data(I) - pointer to ioctl data */ 5527 /* ptr(I) - pointer to store real data in */ 5528 /* type(I) - type of structure being moved */ 5529 /* */ 5530 /* Copy in the contents of what the ipfobj_t points to. In future, we */ 5531 /* add things to check for version numbers, sizes, etc, to make it backward */ 5532 /* compatible at the ABI for user land. */ 5533 /* ------------------------------------------------------------------------ */ 5534 int fr_inobj(data, ptr, type) 5535 void *data; 5536 void *ptr; 5537 int type; 5538 { 5539 ipfobj_t obj; 5540 int error = 0; 5541 5542 if ((type < 0) || (type > NUM_OBJ_TYPES-1)) 5543 return EINVAL; 5544 5545 error = BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj)); 5546 if (error != 0) 5547 return EFAULT; 5548 5549 if (obj.ipfo_type != type) 5550 return EINVAL; 5551 5552 #ifndef IPFILTER_COMPAT 5553 if ((fr_objbytes[type][0] & 1) != 0) { 5554 if (obj.ipfo_size < fr_objbytes[type][1]) 5555 return EINVAL; 5556 } else if (obj.ipfo_size != fr_objbytes[type][1]) 5557 return EINVAL; 5558 #else 5559 if (obj.ipfo_rev != IPFILTER_VERSION) { 5560 error = fr_incomptrans(&obj, ptr); 5561 return error; 5562 } 5563 5564 if ((fr_objbytes[type][0] & 1) != 0 && 5565 obj.ipfo_size < fr_objbytes[type][1] || 5566 obj.ipfo_size != fr_objbytes[type][1]) 5567 return EINVAL; 5568 #endif 5569 5570 if ((fr_objbytes[type][0] & 1) != 0) { 5571 error = COPYIN((caddr_t)obj.ipfo_ptr, (caddr_t)ptr, 5572 fr_objbytes[type][1]); 5573 } else { 5574 error = COPYIN((caddr_t)obj.ipfo_ptr, (caddr_t)ptr, 5575 obj.ipfo_size); 5576 } 5577 return error; 5578 } 5579 5580 5581 /* ------------------------------------------------------------------------ */ 5582 /* Function: fr_inobjsz */ 5583 /* Returns: int - 0 = success, else failure */ 5584 /* Parameters: data(I) - pointer to ioctl data */ 5585 /* ptr(I) - pointer to store real data in */ 5586 /* type(I) - type of structure being moved */ 5587 /* sz(I) - size of data to copy */ 5588 /* */ 5589 /* As per fr_inobj, except the size of the object to copy in is passed in */ 5590 /* but it must not be smaller than the size defined for the type and the */ 5591 /* type must allow for varied sized objects. The extra requirement here is */ 5592 /* that sz must match the size of the object being passed in - this is not */ 5593 /* not possible nor required in fr_inobj(). */ 5594 /* ------------------------------------------------------------------------ */ 5595 int fr_inobjsz(data, ptr, type, sz) 5596 void *data; 5597 void *ptr; 5598 int type, sz; 5599 { 5600 ipfobj_t obj; 5601 int error; 5602 5603 if ((type < 0) || (type > NUM_OBJ_TYPES-1)) 5604 return EINVAL; 5605 if (((fr_objbytes[type][0] & 1) == 0) || (sz < fr_objbytes[type][1])) 5606 return EINVAL; 5607 5608 error = BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj)); 5609 if (error != 0) 5610 return EFAULT; 5611 5612 if (obj.ipfo_type != type) 5613 return EINVAL; 5614 5615 #ifndef IPFILTER_COMPAT 5616 if (obj.ipfo_size != sz) 5617 return EINVAL; 5618 #else 5619 if (obj.ipfo_rev != IPFILTER_VERSION) 5620 /*XXX compatibility hook here */ 5621 /*EMPTY*/; 5622 if (obj.ipfo_size != sz) 5623 /* XXX compatibility hook here */ 5624 return EINVAL; 5625 #endif 5626 5627 error = COPYIN((caddr_t)obj.ipfo_ptr, (caddr_t)ptr, sz); 5628 return error; 5629 } 5630 5631 5632 /* ------------------------------------------------------------------------ */ 5633 /* Function: fr_outobjsz */ 5634 /* Returns: int - 0 = success, else failure */ 5635 /* Parameters: data(I) - pointer to ioctl data */ 5636 /* ptr(I) - pointer to store real data in */ 5637 /* type(I) - type of structure being moved */ 5638 /* sz(I) - size of data to copy */ 5639 /* */ 5640 /* As per fr_outobj, except the size of the object to copy out is passed in */ 5641 /* but it must not be smaller than the size defined for the type and the */ 5642 /* type must allow for varied sized objects. The extra requirement here is */ 5643 /* that sz must match the size of the object being passed in - this is not */ 5644 /* not possible nor required in fr_outobj(). */ 5645 /* ------------------------------------------------------------------------ */ 5646 int fr_outobjsz(data, ptr, type, sz) 5647 void *data; 5648 void *ptr; 5649 int type, sz; 5650 { 5651 ipfobj_t obj; 5652 int error; 5653 5654 if ((type < 0) || (type > NUM_OBJ_TYPES-1) || 5655 ((fr_objbytes[type][0] & 1) == 0) || 5656 (sz < fr_objbytes[type][1])) 5657 return EINVAL; 5658 5659 error = BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj)); 5660 if (error != 0) 5661 return EFAULT; 5662 5663 if (obj.ipfo_type != type) 5664 return EINVAL; 5665 5666 #ifndef IPFILTER_COMPAT 5667 if (obj.ipfo_size != sz) 5668 return EINVAL; 5669 #else 5670 if (obj.ipfo_rev != IPFILTER_VERSION) 5671 /* XXX compatibility hook here */ 5672 /*EMPTY*/; 5673 if (obj.ipfo_size != sz) 5674 /* XXX compatibility hook here */ 5675 return EINVAL; 5676 #endif 5677 5678 error = COPYOUT((caddr_t)ptr, (caddr_t)obj.ipfo_ptr, sz); 5679 return error; 5680 } 5681 5682 5683 /* ------------------------------------------------------------------------ */ 5684 /* Function: fr_outobj */ 5685 /* Returns: int - 0 = success, else failure */ 5686 /* Parameters: data(I) - pointer to ioctl data */ 5687 /* ptr(I) - pointer to store real data in */ 5688 /* type(I) - type of structure being moved */ 5689 /* */ 5690 /* Copy out the contents of what ptr is to where ipfobj points to. In */ 5691 /* future, we add things to check for version numbers, sizes, etc, to make */ 5692 /* it backward compatible at the ABI for user land. */ 5693 /* ------------------------------------------------------------------------ */ 5694 int fr_outobj(data, ptr, type) 5695 void *data; 5696 void *ptr; 5697 int type; 5698 { 5699 ipfobj_t obj; 5700 int error; 5701 5702 if ((type < 0) || (type > NUM_OBJ_TYPES-1)) 5703 return EINVAL; 5704 5705 error = BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj)); 5706 if (error != 0) 5707 return EFAULT; 5708 5709 if (obj.ipfo_type != type) 5710 return EINVAL; 5711 5712 #ifndef IPFILTER_COMPAT 5713 if ((fr_objbytes[type][0] & 1) != 0) { 5714 if (obj.ipfo_size < fr_objbytes[type][1]) 5715 return EINVAL; 5716 } else if (obj.ipfo_size != fr_objbytes[type][1]) 5717 return EINVAL; 5718 #else 5719 if (obj.ipfo_rev != IPFILTER_VERSION) { 5720 error = fr_outcomptrans(&obj, ptr); 5721 return error; 5722 } 5723 5724 if ((fr_objbytes[type][0] & 1) != 0 && 5725 obj.ipfo_size < fr_objbytes[type][1] || 5726 obj.ipfo_size != fr_objbytes[type][1]) 5727 return EINVAL; 5728 #endif 5729 5730 error = COPYOUT((caddr_t)ptr, (caddr_t)obj.ipfo_ptr, obj.ipfo_size); 5731 return error; 5732 } 5733 5734 5735 /* ------------------------------------------------------------------------ */ 5736 /* Function: fr_checkl4sum */ 5737 /* Returns: int - 0 = good, -1 = bad, 1 = cannot check */ 5738 /* Parameters: fin(I) - pointer to packet information */ 5739 /* */ 5740 /* If possible, calculate the layer 4 checksum for the packet. If this is */ 5741 /* not possible, return without indicating a failure or success but in a */ 5742 /* way that is ditinguishable. */ 5743 /* ------------------------------------------------------------------------ */ 5744 int fr_checkl4sum(fin) 5745 fr_info_t *fin; 5746 { 5747 u_short sum, hdrsum, *csump; 5748 udphdr_t *udp; 5749 int dosum; 5750 ipf_stack_t *ifs = fin->fin_ifs; 5751 5752 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) 5753 net_handle_t net_data_p; 5754 if (fin->fin_v == 4) 5755 net_data_p = ifs->ifs_ipf_ipv4; 5756 else 5757 net_data_p = ifs->ifs_ipf_ipv6; 5758 #endif 5759 5760 if ((fin->fin_flx & FI_NOCKSUM) != 0) 5761 return 0; 5762 5763 /* 5764 * If the TCP packet isn't a fragment, isn't too short and otherwise 5765 * isn't already considered "bad", then validate the checksum. If 5766 * this check fails then considered the packet to be "bad". 5767 */ 5768 if ((fin->fin_flx & (FI_FRAG|FI_SHORT|FI_BAD)) != 0) 5769 return 1; 5770 5771 csump = NULL; 5772 hdrsum = 0; 5773 dosum = 0; 5774 sum = 0; 5775 5776 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) 5777 ASSERT(fin->fin_m != NULL); 5778 if (NET_IS_HCK_L4_FULL(net_data_p, fin->fin_m) || 5779 NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) { 5780 hdrsum = 0; 5781 sum = 0; 5782 } else { 5783 #endif 5784 switch (fin->fin_p) 5785 { 5786 case IPPROTO_TCP : 5787 csump = &((tcphdr_t *)fin->fin_dp)->th_sum; 5788 dosum = 1; 5789 break; 5790 5791 case IPPROTO_UDP : 5792 udp = fin->fin_dp; 5793 if (udp->uh_sum != 0) { 5794 csump = &udp->uh_sum; 5795 dosum = 1; 5796 } 5797 break; 5798 5799 case IPPROTO_ICMP : 5800 csump = &((struct icmp *)fin->fin_dp)->icmp_cksum; 5801 dosum = 1; 5802 break; 5803 5804 default : 5805 return 1; 5806 /*NOTREACHED*/ 5807 } 5808 5809 if (csump != NULL) 5810 hdrsum = *csump; 5811 5812 if (dosum) 5813 sum = fr_cksum(fin->fin_m, fin->fin_ip, 5814 fin->fin_p, fin->fin_dp); 5815 #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) 5816 } 5817 #endif 5818 #if !defined(_KERNEL) 5819 if (sum == hdrsum) { 5820 FR_DEBUG(("checkl4sum: %hx == %hx\n", sum, hdrsum)); 5821 } else { 5822 FR_DEBUG(("checkl4sum: %hx != %hx\n", sum, hdrsum)); 5823 } 5824 #endif 5825 if (hdrsum == sum) 5826 return 0; 5827 return -1; 5828 } 5829 5830 5831 /* ------------------------------------------------------------------------ */ 5832 /* Function: fr_ifpfillv4addr */ 5833 /* Returns: int - 0 = address update, -1 = address not updated */ 5834 /* Parameters: atype(I) - type of network address update to perform */ 5835 /* sin(I) - pointer to source of address information */ 5836 /* mask(I) - pointer to source of netmask information */ 5837 /* inp(I) - pointer to destination address store */ 5838 /* inpmask(I) - pointer to destination netmask store */ 5839 /* */ 5840 /* Given a type of network address update (atype) to perform, copy */ 5841 /* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ 5842 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ 5843 /* which case the operation fails. For all values of atype other than */ 5844 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ 5845 /* value. */ 5846 /* ------------------------------------------------------------------------ */ 5847 int fr_ifpfillv4addr(atype, sin, mask, inp, inpmask) 5848 int atype; 5849 struct sockaddr_in *sin, *mask; 5850 struct in_addr *inp, *inpmask; 5851 { 5852 if (inpmask != NULL && atype != FRI_NETMASKED) 5853 inpmask->s_addr = 0xffffffff; 5854 5855 if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { 5856 if (atype == FRI_NETMASKED) { 5857 if (inpmask == NULL) 5858 return -1; 5859 inpmask->s_addr = mask->sin_addr.s_addr; 5860 } 5861 inp->s_addr = sin->sin_addr.s_addr & mask->sin_addr.s_addr; 5862 } else { 5863 inp->s_addr = sin->sin_addr.s_addr; 5864 } 5865 return 0; 5866 } 5867 5868 5869 #ifdef USE_INET6 5870 /* ------------------------------------------------------------------------ */ 5871 /* Function: fr_ifpfillv6addr */ 5872 /* Returns: int - 0 = address update, -1 = address not updated */ 5873 /* Parameters: atype(I) - type of network address update to perform */ 5874 /* sin(I) - pointer to source of address information */ 5875 /* mask(I) - pointer to source of netmask information */ 5876 /* inp(I) - pointer to destination address store */ 5877 /* inpmask(I) - pointer to destination netmask store */ 5878 /* */ 5879 /* Given a type of network address update (atype) to perform, copy */ 5880 /* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ 5881 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ 5882 /* which case the operation fails. For all values of atype other than */ 5883 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ 5884 /* value. */ 5885 /* ------------------------------------------------------------------------ */ 5886 int fr_ifpfillv6addr(atype, sin, mask, inp, inpmask) 5887 int atype; 5888 struct sockaddr_in6 *sin, *mask; 5889 struct in_addr *inp, *inpmask; 5890 { 5891 i6addr_t *src, *dst, *and, *dmask; 5892 5893 src = (i6addr_t *)&sin->sin6_addr; 5894 and = (i6addr_t *)&mask->sin6_addr; 5895 dst = (i6addr_t *)inp; 5896 dmask = (i6addr_t *)inpmask; 5897 5898 if (inpmask != NULL && atype != FRI_NETMASKED) { 5899 dmask->i6[0] = 0xffffffff; 5900 dmask->i6[1] = 0xffffffff; 5901 dmask->i6[2] = 0xffffffff; 5902 dmask->i6[3] = 0xffffffff; 5903 } 5904 5905 if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { 5906 if (atype == FRI_NETMASKED) { 5907 if (inpmask == NULL) 5908 return -1; 5909 dmask->i6[0] = and->i6[0]; 5910 dmask->i6[1] = and->i6[1]; 5911 dmask->i6[2] = and->i6[2]; 5912 dmask->i6[3] = and->i6[3]; 5913 } 5914 5915 dst->i6[0] = src->i6[0] & and->i6[0]; 5916 dst->i6[1] = src->i6[1] & and->i6[1]; 5917 dst->i6[2] = src->i6[2] & and->i6[2]; 5918 dst->i6[3] = src->i6[3] & and->i6[3]; 5919 } else { 5920 dst->i6[0] = src->i6[0]; 5921 dst->i6[1] = src->i6[1]; 5922 dst->i6[2] = src->i6[2]; 5923 dst->i6[3] = src->i6[3]; 5924 } 5925 return 0; 5926 } 5927 #endif 5928 5929 5930 /* ------------------------------------------------------------------------ */ 5931 /* Function: fr_matchtag */ 5932 /* Returns: 0 == mismatch, 1 == match. */ 5933 /* Parameters: tag1(I) - pointer to first tag to compare */ 5934 /* tag2(I) - pointer to second tag to compare */ 5935 /* */ 5936 /* Returns true (non-zero) or false(0) if the two tag structures can be */ 5937 /* considered to be a match or not match, respectively. The tag is 16 */ 5938 /* bytes long (16 characters) but that is overlayed with 4 32bit ints so */ 5939 /* compare the ints instead, for speed. tag1 is the master of the */ 5940 /* comparison. This function should only be called with both tag1 and tag2 */ 5941 /* as non-NULL pointers. */ 5942 /* ------------------------------------------------------------------------ */ 5943 int fr_matchtag(tag1, tag2) 5944 ipftag_t *tag1, *tag2; 5945 { 5946 if (tag1 == tag2) 5947 return 1; 5948 5949 if ((tag1->ipt_num[0] == 0) && (tag2->ipt_num[0] == 0)) 5950 return 1; 5951 5952 if ((tag1->ipt_num[0] == tag2->ipt_num[0]) && 5953 (tag1->ipt_num[1] == tag2->ipt_num[1]) && 5954 (tag1->ipt_num[2] == tag2->ipt_num[2]) && 5955 (tag1->ipt_num[3] == tag2->ipt_num[3])) 5956 return 1; 5957 return 0; 5958 } 5959 5960 5961 /* ------------------------------------------------------------------------ */ 5962 /* Function: fr_coalesce */ 5963 /* Returns: 1 == success, -1 == failure, 0 == no change */ 5964 /* Parameters: fin(I) - pointer to packet information */ 5965 /* */ 5966 /* Attempt to get all of the packet data into a single, contiguous buffer. */ 5967 /* If this call returns a failure then the buffers have also been freed. */ 5968 /* ------------------------------------------------------------------------ */ 5969 int fr_coalesce(fin) 5970 fr_info_t *fin; 5971 { 5972 ipf_stack_t *ifs = fin->fin_ifs; 5973 if ((fin->fin_flx & FI_COALESCE) != 0) 5974 return 1; 5975 5976 /* 5977 * If the mbuf pointers indicate that there is no mbuf to work with, 5978 * return but do not indicate success or failure. 5979 */ 5980 if (fin->fin_m == NULL || fin->fin_mp == NULL) 5981 return 0; 5982 5983 #if defined(_KERNEL) 5984 if (fr_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) { 5985 IPF_BUMP(ifs->ifs_fr_badcoalesces[fin->fin_out]); 5986 # ifdef MENTAT 5987 FREE_MB_T(*fin->fin_mp); 5988 # endif 5989 *fin->fin_mp = NULL; 5990 fin->fin_m = NULL; 5991 return -1; 5992 } 5993 #else 5994 fin = fin; /* LINT */ 5995 #endif 5996 return 1; 5997 } 5998 5999 6000 /* 6001 * The following table lists all of the tunable variables that can be 6002 * accessed via SIOCIPFGET/SIOCIPFSET/SIOCIPFGETNEXT. The format of each row 6003 * in the table below is as follows: 6004 * 6005 * pointer to value, name of value, minimum, maximum, size of the value's 6006 * container, value attribute flags 6007 * 6008 * For convienience, IPFT_RDONLY means the value is read-only, IPFT_WRDISABLED 6009 * means the value can only be written to when IPFilter is loaded but disabled. 6010 * The obvious implication is if neither of these are set then the value can be 6011 * changed at any time without harm. 6012 */ 6013 ipftuneable_t lcl_ipf_tuneables[] = { 6014 /* filtering */ 6015 { { NULL }, "fr_flags", 0, 0xffffffff, 6016 0, 0 }, 6017 { { NULL }, "fr_active", 0, 0, 6018 0, IPFT_RDONLY }, 6019 { { NULL }, "fr_control_forwarding", 0, 1, 6020 0, 0 }, 6021 { { NULL }, "fr_update_ipid", 0, 1, 6022 0, 0 }, 6023 { { NULL }, "fr_chksrc", 0, 1, 6024 0, 0 }, 6025 { { NULL }, "fr_minttl", 0, 1, 6026 0, 0 }, 6027 { { NULL }, "fr_icmpminfragmtu", 0, 1, 6028 0, 0 }, 6029 { { NULL }, "fr_pass", 0, 0xffffffff, 6030 0, 0 }, 6031 #if SOLARIS2 >= 10 6032 { { NULL }, "ipf_loopback", 0, 1, 6033 0, IPFT_WRDISABLED }, 6034 #endif 6035 /* state */ 6036 { { NULL }, "fr_tcpidletimeout", 1, 0x7fffffff, 6037 0, IPFT_WRDISABLED }, 6038 { { NULL }, "fr_tcpclosewait", 1, 0x7fffffff, 6039 0, IPFT_WRDISABLED }, 6040 { { NULL }, "fr_tcplastack", 1, 0x7fffffff, 6041 0, IPFT_WRDISABLED }, 6042 { { NULL }, "fr_tcptimeout", 1, 0x7fffffff, 6043 0, IPFT_WRDISABLED }, 6044 { { NULL }, "fr_tcpclosed", 1, 0x7fffffff, 6045 0, IPFT_WRDISABLED }, 6046 { { NULL }, "fr_tcphalfclosed", 1, 0x7fffffff, 6047 0, IPFT_WRDISABLED }, 6048 { { NULL }, "fr_udptimeout", 1, 0x7fffffff, 6049 0, IPFT_WRDISABLED }, 6050 { { NULL }, "fr_udpacktimeout", 1, 0x7fffffff, 6051 0, IPFT_WRDISABLED }, 6052 { { NULL }, "fr_icmptimeout", 1, 0x7fffffff, 6053 0, IPFT_WRDISABLED }, 6054 { { NULL }, "fr_icmpacktimeout", 1, 0x7fffffff, 6055 0, IPFT_WRDISABLED }, 6056 { { NULL }, "fr_iptimeout", 1, 0x7fffffff, 6057 0, IPFT_WRDISABLED }, 6058 { { NULL }, "fr_statemax", 1, 0x7fffffff, 6059 0, 0 }, 6060 { { NULL }, "fr_statesize", 1, 0x7fffffff, 6061 0, IPFT_WRDISABLED }, 6062 { { NULL }, "fr_state_lock", 0, 1, 6063 0, IPFT_RDONLY }, 6064 { { NULL }, "fr_state_maxbucket", 1, 0x7fffffff, 6065 0, IPFT_WRDISABLED }, 6066 { { NULL }, "fr_state_maxbucket_reset", 0, 1, 6067 0, IPFT_WRDISABLED }, 6068 { { NULL }, "ipstate_logging", 0, 1, 6069 0, 0 }, 6070 { { NULL }, "state_flush_level_hi", 1, 100, 6071 0, 0 }, 6072 { { NULL }, "state_flush_level_lo", 1, 100, 6073 0, 0 }, 6074 /* nat */ 6075 { { NULL }, "fr_nat_lock", 0, 1, 6076 0, IPFT_RDONLY }, 6077 { { NULL }, "ipf_nattable_sz", 1, 0x7fffffff, 6078 0, IPFT_WRDISABLED }, 6079 { { NULL }, "ipf_nattable_max", 1, 0x7fffffff, 6080 0, 0 }, 6081 { { NULL }, "ipf_natrules_sz", 1, 0x7fffffff, 6082 0, IPFT_WRDISABLED }, 6083 { { NULL }, "ipf_rdrrules_sz", 1, 0x7fffffff, 6084 0, IPFT_WRDISABLED }, 6085 { { NULL }, "ipf_hostmap_sz", 1, 0x7fffffff, 6086 0, IPFT_WRDISABLED }, 6087 { { NULL }, "fr_nat_maxbucket", 1, 0x7fffffff, 6088 0, IPFT_WRDISABLED }, 6089 { { NULL }, "fr_nat_maxbucket_reset", 0, 1, 6090 0, IPFT_WRDISABLED }, 6091 { { NULL }, "nat_logging", 0, 1, 6092 0, 0 }, 6093 { { NULL }, "fr_defnatage", 1, 0x7fffffff, 6094 0, IPFT_WRDISABLED }, 6095 { { NULL }, "fr_defnatipage", 1, 0x7fffffff, 6096 0, IPFT_WRDISABLED }, 6097 { { NULL }, "fr_defnaticmpage", 1, 0x7fffffff, 6098 0, IPFT_WRDISABLED }, 6099 { { NULL }, "nat_flush_level_hi", 1, 100, 6100 0, 0 }, 6101 { { NULL }, "nat_flush_level_lo", 1, 100, 6102 0, 0 }, 6103 /* frag */ 6104 { { NULL }, "ipfr_size", 1, 0x7fffffff, 6105 0, IPFT_WRDISABLED }, 6106 { { NULL }, "fr_ipfrttl", 1, 0x7fffffff, 6107 0, IPFT_WRDISABLED }, 6108 #ifdef IPFILTER_LOG 6109 /* log */ 6110 { { NULL }, "ipl_suppress", 0, 1, 6111 0, 0 }, 6112 { { NULL }, "ipl_buffer_sz", 0, 0, 6113 0, IPFT_RDONLY }, 6114 { { NULL }, "ipl_logmax", 0, 0x7fffffff, 6115 0, IPFT_WRDISABLED }, 6116 { { NULL }, "ipl_logall", 0, 1, 6117 0, 0 }, 6118 { { NULL }, "ipl_logsize", 0, 0x80000, 6119 0, 0 }, 6120 #endif 6121 { { NULL }, NULL, 0, 0 } 6122 }; 6123 6124 static ipftuneable_t * 6125 tune_lookup(ipf_stack_t *ifs, char *name) 6126 { 6127 int i; 6128 6129 for (i = 0; ifs->ifs_ipf_tuneables[i].ipft_name != NULL; i++) { 6130 if (strcmp(ifs->ifs_ipf_tuneables[i].ipft_name, name) == 0) 6131 return (&ifs->ifs_ipf_tuneables[i]); 6132 } 6133 return (NULL); 6134 } 6135 6136 #ifdef _KERNEL 6137 extern dev_info_t *ipf_dev_info; 6138 extern int ipf_property_update __P((dev_info_t *, ipf_stack_t *)); 6139 #endif 6140 6141 /* -------------------------------------------------------------------- */ 6142 /* Function: ipftuneable_setdefs() */ 6143 /* Returns: void */ 6144 /* Parameters: ifs - pointer to newly allocated IPF instance */ 6145 /* assigned to IP instance */ 6146 /* */ 6147 /* Function initializes IPF instance variables. Function is invoked */ 6148 /* from ipftuneable_alloc(). ipftuneable_alloc() is called only one */ 6149 /* time during IP instance lifetime - at the time of IP instance */ 6150 /* creation. Anytime IP instance is being created new private IPF */ 6151 /* instance is allocated and assigned to it. The moment of IP */ 6152 /* instance creation is the right time to initialize those IPF */ 6153 /* variables. */ 6154 /* */ 6155 /* -------------------------------------------------------------------- */ 6156 static void ipftuneable_setdefs(ipf_stack_t *ifs) 6157 { 6158 ifs->ifs_ipfr_size = IPFT_SIZE; 6159 ifs->ifs_fr_ipfrttl = 120; /* 60 seconds */ 6160 6161 /* it comes from fr_authinit() in IPF auth */ 6162 ifs->ifs_fr_authsize = FR_NUMAUTH; 6163 ifs->ifs_fr_defaultauthage = 600; 6164 6165 /* it comes from fr_stateinit() in IPF state */ 6166 ifs->ifs_fr_tcpidletimeout = IPF_TTLVAL(3600 * 24 * 5); /* five days */ 6167 ifs->ifs_fr_tcpclosewait = IPF_TTLVAL(TCP_MSL); 6168 ifs->ifs_fr_tcplastack = IPF_TTLVAL(TCP_MSL); 6169 ifs->ifs_fr_tcptimeout = IPF_TTLVAL(TCP_MSL); 6170 ifs->ifs_fr_tcpclosed = IPF_TTLVAL(60); 6171 ifs->ifs_fr_tcphalfclosed = IPF_TTLVAL(2 * 3600); /* 2 hours */ 6172 ifs->ifs_fr_udptimeout = IPF_TTLVAL(120); 6173 ifs->ifs_fr_udpacktimeout = IPF_TTLVAL(12); 6174 ifs->ifs_fr_icmptimeout = IPF_TTLVAL(60); 6175 ifs->ifs_fr_icmpacktimeout = IPF_TTLVAL(6); 6176 ifs->ifs_fr_iptimeout = IPF_TTLVAL(60); 6177 ifs->ifs_fr_statemax = IPSTATE_MAX; 6178 ifs->ifs_fr_statesize = IPSTATE_SIZE; 6179 ifs->ifs_fr_state_maxbucket_reset = 1; 6180 ifs->ifs_state_flush_level_hi = ST_FLUSH_HI; 6181 ifs->ifs_state_flush_level_lo = ST_FLUSH_LO; 6182 6183 /* it comes from fr_natinit() in ipnat */ 6184 ifs->ifs_ipf_nattable_sz = NAT_TABLE_SZ; 6185 ifs->ifs_ipf_nattable_max = NAT_TABLE_MAX; 6186 ifs->ifs_ipf_natrules_sz = NAT_SIZE; 6187 ifs->ifs_ipf_rdrrules_sz = RDR_SIZE; 6188 ifs->ifs_ipf_hostmap_sz = HOSTMAP_SIZE; 6189 ifs->ifs_fr_nat_maxbucket_reset = 1; 6190 ifs->ifs_fr_defnatage = DEF_NAT_AGE; 6191 ifs->ifs_fr_defnatipage = 120; /* 60 seconds */ 6192 ifs->ifs_fr_defnaticmpage = 6; /* 3 seconds */ 6193 ifs->ifs_nat_flush_level_hi = NAT_FLUSH_HI; 6194 ifs->ifs_nat_flush_level_lo = NAT_FLUSH_LO; 6195 6196 #ifdef IPFILTER_LOG 6197 /* it comes from fr_loginit() in IPF log */ 6198 ifs->ifs_ipl_suppress = 1; 6199 ifs->ifs_ipl_logmax = IPL_LOGMAX; 6200 ifs->ifs_ipl_logsize = IPFILTER_LOGSIZE; 6201 6202 /* from fr_natinit() */ 6203 ifs->ifs_nat_logging = 1; 6204 6205 /* from fr_stateinit() */ 6206 ifs->ifs_ipstate_logging = 1; 6207 #else 6208 /* from fr_natinit() */ 6209 ifs->ifs_nat_logging = 0; 6210 6211 /* from fr_stateinit() */ 6212 ifs->ifs_ipstate_logging = 0; 6213 #endif 6214 ifs->ifs_ipf_loopback = 0; 6215 6216 } 6217 /* 6218 * Allocate a per-stack tuneable and copy in the names. Then 6219 * set it to point to each of the per-stack tunables. 6220 */ 6221 void 6222 ipftuneable_alloc(ipf_stack_t *ifs) 6223 { 6224 ipftuneable_t *item; 6225 6226 KMALLOCS(ifs->ifs_ipf_tuneables, ipftuneable_t *, 6227 sizeof (lcl_ipf_tuneables)); 6228 bcopy(lcl_ipf_tuneables, ifs->ifs_ipf_tuneables, 6229 sizeof (lcl_ipf_tuneables)); 6230 6231 #define TUNE_SET(_ifs, _name, _field) \ 6232 item = tune_lookup((_ifs), (_name)); \ 6233 if (item != NULL) { \ 6234 item->ipft_una.ipftp_int = (unsigned int *)&((_ifs)->_field); \ 6235 item->ipft_sz = sizeof ((_ifs)->_field); \ 6236 } 6237 6238 TUNE_SET(ifs, "fr_flags", ifs_fr_flags); 6239 TUNE_SET(ifs, "fr_active", ifs_fr_active); 6240 TUNE_SET(ifs, "fr_control_forwarding", ifs_fr_control_forwarding); 6241 TUNE_SET(ifs, "fr_update_ipid", ifs_fr_update_ipid); 6242 TUNE_SET(ifs, "fr_chksrc", ifs_fr_chksrc); 6243 TUNE_SET(ifs, "fr_minttl", ifs_fr_minttl); 6244 TUNE_SET(ifs, "fr_icmpminfragmtu", ifs_fr_icmpminfragmtu); 6245 TUNE_SET(ifs, "fr_pass", ifs_fr_pass); 6246 TUNE_SET(ifs, "fr_tcpidletimeout", ifs_fr_tcpidletimeout); 6247 TUNE_SET(ifs, "fr_tcpclosewait", ifs_fr_tcpclosewait); 6248 TUNE_SET(ifs, "fr_tcplastack", ifs_fr_tcplastack); 6249 TUNE_SET(ifs, "fr_tcptimeout", ifs_fr_tcptimeout); 6250 TUNE_SET(ifs, "fr_tcpclosed", ifs_fr_tcpclosed); 6251 TUNE_SET(ifs, "fr_tcphalfclosed", ifs_fr_tcphalfclosed); 6252 TUNE_SET(ifs, "fr_udptimeout", ifs_fr_udptimeout); 6253 TUNE_SET(ifs, "fr_udpacktimeout", ifs_fr_udpacktimeout); 6254 TUNE_SET(ifs, "fr_icmptimeout", ifs_fr_icmptimeout); 6255 TUNE_SET(ifs, "fr_icmpacktimeout", ifs_fr_icmpacktimeout); 6256 TUNE_SET(ifs, "fr_iptimeout", ifs_fr_iptimeout); 6257 TUNE_SET(ifs, "fr_statemax", ifs_fr_statemax); 6258 TUNE_SET(ifs, "fr_statesize", ifs_fr_statesize); 6259 TUNE_SET(ifs, "fr_state_lock", ifs_fr_state_lock); 6260 TUNE_SET(ifs, "fr_state_maxbucket", ifs_fr_state_maxbucket); 6261 TUNE_SET(ifs, "fr_state_maxbucket_reset", ifs_fr_state_maxbucket_reset); 6262 TUNE_SET(ifs, "ipstate_logging", ifs_ipstate_logging); 6263 TUNE_SET(ifs, "fr_nat_lock", ifs_fr_nat_lock); 6264 TUNE_SET(ifs, "ipf_nattable_sz", ifs_ipf_nattable_sz); 6265 TUNE_SET(ifs, "ipf_nattable_max", ifs_ipf_nattable_max); 6266 TUNE_SET(ifs, "ipf_natrules_sz", ifs_ipf_natrules_sz); 6267 TUNE_SET(ifs, "ipf_rdrrules_sz", ifs_ipf_rdrrules_sz); 6268 TUNE_SET(ifs, "ipf_hostmap_sz", ifs_ipf_hostmap_sz); 6269 TUNE_SET(ifs, "fr_nat_maxbucket", ifs_fr_nat_maxbucket); 6270 TUNE_SET(ifs, "fr_nat_maxbucket_reset", ifs_fr_nat_maxbucket_reset); 6271 TUNE_SET(ifs, "nat_logging", ifs_nat_logging); 6272 TUNE_SET(ifs, "fr_defnatage", ifs_fr_defnatage); 6273 TUNE_SET(ifs, "fr_defnatipage", ifs_fr_defnatipage); 6274 TUNE_SET(ifs, "fr_defnaticmpage", ifs_fr_defnaticmpage); 6275 TUNE_SET(ifs, "nat_flush_level_hi", ifs_nat_flush_level_hi); 6276 TUNE_SET(ifs, "nat_flush_level_lo", ifs_nat_flush_level_lo); 6277 TUNE_SET(ifs, "state_flush_level_hi", ifs_state_flush_level_hi); 6278 TUNE_SET(ifs, "state_flush_level_lo", ifs_state_flush_level_lo); 6279 TUNE_SET(ifs, "ipfr_size", ifs_ipfr_size); 6280 TUNE_SET(ifs, "fr_ipfrttl", ifs_fr_ipfrttl); 6281 TUNE_SET(ifs, "ipf_loopback", ifs_ipf_loopback); 6282 #ifdef IPFILTER_LOG 6283 TUNE_SET(ifs, "ipl_suppress", ifs_ipl_suppress); 6284 TUNE_SET(ifs, "ipl_buffer_sz", ifs_ipl_buffer_sz); 6285 TUNE_SET(ifs, "ipl_logmax", ifs_ipl_logmax); 6286 TUNE_SET(ifs, "ipl_logall", ifs_ipl_logall); 6287 TUNE_SET(ifs, "ipl_logsize", ifs_ipl_logsize); 6288 #endif 6289 #undef TUNE_SET 6290 6291 ipftuneable_setdefs(ifs); 6292 6293 #ifdef _KERNEL 6294 (void) ipf_property_update(ipf_dev_info, ifs); 6295 #endif 6296 } 6297 6298 void 6299 ipftuneable_free(ipf_stack_t *ifs) 6300 { 6301 KFREES(ifs->ifs_ipf_tuneables, sizeof (lcl_ipf_tuneables)); 6302 ifs->ifs_ipf_tuneables = NULL; 6303 } 6304 6305 /* ------------------------------------------------------------------------ */ 6306 /* Function: fr_findtunebycookie */ 6307 /* Returns: NULL = search failed, else pointer to tune struct */ 6308 /* Parameters: cookie(I) - cookie value to search for amongst tuneables */ 6309 /* next(O) - pointer to place to store the cookie for the */ 6310 /* "next" tuneable, if it is desired. */ 6311 /* */ 6312 /* This function is used to walk through all of the existing tunables with */ 6313 /* successive calls. It searches the known tunables for the one which has */ 6314 /* a matching value for "cookie" - ie its address. When returning a match, */ 6315 /* the next one to be found may be returned inside next. */ 6316 /* ------------------------------------------------------------------------ */ 6317 static ipftuneable_t *fr_findtunebycookie(cookie, next, ifs) 6318 void *cookie, **next; 6319 ipf_stack_t * ifs; 6320 { 6321 ipftuneable_t *ta, **tap; 6322 6323 for (ta = ifs->ifs_ipf_tuneables; ta->ipft_name != NULL; ta++) 6324 if (ta == cookie) { 6325 if (next != NULL) { 6326 /* 6327 * If the next entry in the array has a name 6328 * present, then return a pointer to it for 6329 * where to go next, else return a pointer to 6330 * the dynaminc list as a key to search there 6331 * next. This facilitates a weak linking of 6332 * the two "lists" together. 6333 */ 6334 if ((ta + 1)->ipft_name != NULL) 6335 *next = ta + 1; 6336 else 6337 *next = &ifs->ifs_ipf_tunelist; 6338 } 6339 return ta; 6340 } 6341 6342 for (tap = &ifs->ifs_ipf_tunelist; (ta = *tap) != NULL; tap = &ta->ipft_next) 6343 if (tap == cookie) { 6344 if (next != NULL) 6345 *next = &ta->ipft_next; 6346 return ta; 6347 } 6348 6349 if (next != NULL) 6350 *next = NULL; 6351 return NULL; 6352 } 6353 6354 6355 /* ------------------------------------------------------------------------ */ 6356 /* Function: fr_findtunebyname */ 6357 /* Returns: NULL = search failed, else pointer to tune struct */ 6358 /* Parameters: name(I) - name of the tuneable entry to find. */ 6359 /* */ 6360 /* Search the static array of tuneables and the list of dynamic tuneables */ 6361 /* for an entry with a matching name. If we can find one, return a pointer */ 6362 /* to the matching structure. */ 6363 /* ------------------------------------------------------------------------ */ 6364 static ipftuneable_t *fr_findtunebyname(name, ifs) 6365 const char *name; 6366 ipf_stack_t *ifs; 6367 { 6368 ipftuneable_t *ta; 6369 6370 for (ta = ifs->ifs_ipf_tuneables; ta->ipft_name != NULL; ta++) 6371 if (!strcmp(ta->ipft_name, name)) { 6372 return ta; 6373 } 6374 6375 for (ta = ifs->ifs_ipf_tunelist; ta != NULL; ta = ta->ipft_next) 6376 if (!strcmp(ta->ipft_name, name)) { 6377 return ta; 6378 } 6379 6380 return NULL; 6381 } 6382 6383 6384 /* ------------------------------------------------------------------------ */ 6385 /* Function: fr_addipftune */ 6386 /* Returns: int - 0 == success, else failure */ 6387 /* Parameters: newtune - pointer to new tune struct to add to tuneables */ 6388 /* */ 6389 /* Appends the tune structure pointer to by "newtune" to the end of the */ 6390 /* current list of "dynamic" tuneable parameters. Once added, the owner */ 6391 /* of the object is not expected to ever change "ipft_next". */ 6392 /* ------------------------------------------------------------------------ */ 6393 int fr_addipftune(newtune, ifs) 6394 ipftuneable_t *newtune; 6395 ipf_stack_t *ifs; 6396 { 6397 ipftuneable_t *ta, **tap; 6398 6399 ta = fr_findtunebyname(newtune->ipft_name, ifs); 6400 if (ta != NULL) 6401 return EEXIST; 6402 6403 for (tap = &ifs->ifs_ipf_tunelist; *tap != NULL; tap = &(*tap)->ipft_next) 6404 ; 6405 6406 newtune->ipft_next = NULL; 6407 *tap = newtune; 6408 return 0; 6409 } 6410 6411 6412 /* ------------------------------------------------------------------------ */ 6413 /* Function: fr_delipftune */ 6414 /* Returns: int - 0 == success, else failure */ 6415 /* Parameters: oldtune - pointer to tune struct to remove from the list of */ 6416 /* current dynamic tuneables */ 6417 /* */ 6418 /* Search for the tune structure, by pointer, in the list of those that are */ 6419 /* dynamically added at run time. If found, adjust the list so that this */ 6420 /* structure is no longer part of it. */ 6421 /* ------------------------------------------------------------------------ */ 6422 int fr_delipftune(oldtune, ifs) 6423 ipftuneable_t *oldtune; 6424 ipf_stack_t *ifs; 6425 { 6426 ipftuneable_t *ta, **tap; 6427 6428 for (tap = &ifs->ifs_ipf_tunelist; (ta = *tap) != NULL; tap = &ta->ipft_next) 6429 if (ta == oldtune) { 6430 *tap = oldtune->ipft_next; 6431 oldtune->ipft_next = NULL; 6432 return 0; 6433 } 6434 6435 return ESRCH; 6436 } 6437 6438 6439 /* ------------------------------------------------------------------------ */ 6440 /* Function: fr_ipftune */ 6441 /* Returns: int - 0 == success, else failure */ 6442 /* Parameters: cmd(I) - ioctl command number */ 6443 /* data(I) - pointer to ioctl data structure */ 6444 /* */ 6445 /* Implement handling of SIOCIPFGETNEXT, SIOCIPFGET and SIOCIPFSET. These */ 6446 /* three ioctls provide the means to access and control global variables */ 6447 /* within IPFilter, allowing (for example) timeouts and table sizes to be */ 6448 /* changed without rebooting, reloading or recompiling. The initialisation */ 6449 /* and 'destruction' routines of the various components of ipfilter are all */ 6450 /* each responsible for handling their own values being too big. */ 6451 /* ------------------------------------------------------------------------ */ 6452 int fr_ipftune(cmd, data, ifs) 6453 ioctlcmd_t cmd; 6454 void *data; 6455 ipf_stack_t *ifs; 6456 { 6457 ipftuneable_t *ta; 6458 ipftune_t tu; 6459 void *cookie; 6460 int error; 6461 6462 error = fr_inobj(data, &tu, IPFOBJ_TUNEABLE); 6463 if (error != 0) 6464 return error; 6465 6466 tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0'; 6467 cookie = tu.ipft_cookie; 6468 ta = NULL; 6469 6470 switch (cmd) 6471 { 6472 case SIOCIPFGETNEXT : 6473 /* 6474 * If cookie is non-NULL, assume it to be a pointer to the last 6475 * entry we looked at, so find it (if possible) and return a 6476 * pointer to the next one after it. The last entry in the 6477 * the table is a NULL entry, so when we get to it, set cookie 6478 * to NULL and return that, indicating end of list, erstwhile 6479 * if we come in with cookie set to NULL, we are starting anew 6480 * at the front of the list. 6481 */ 6482 if (cookie != NULL) { 6483 ta = fr_findtunebycookie(cookie, &tu.ipft_cookie, ifs); 6484 } else { 6485 ta = ifs->ifs_ipf_tuneables; 6486 tu.ipft_cookie = ta + 1; 6487 } 6488 if (ta != NULL) { 6489 /* 6490 * Entry found, but does the data pointed to by that 6491 * row fit in what we can return? 6492 */ 6493 if (ta->ipft_sz > sizeof(tu.ipft_un)) 6494 return EINVAL; 6495 6496 tu.ipft_vlong = 0; 6497 if (ta->ipft_sz == sizeof(u_long)) 6498 tu.ipft_vlong = *ta->ipft_plong; 6499 else if (ta->ipft_sz == sizeof(u_int)) 6500 tu.ipft_vint = *ta->ipft_pint; 6501 else if (ta->ipft_sz == sizeof(u_short)) 6502 tu.ipft_vshort = *ta->ipft_pshort; 6503 else if (ta->ipft_sz == sizeof(u_char)) 6504 tu.ipft_vchar = *ta->ipft_pchar; 6505 6506 tu.ipft_sz = ta->ipft_sz; 6507 tu.ipft_min = ta->ipft_min; 6508 tu.ipft_max = ta->ipft_max; 6509 tu.ipft_flags = ta->ipft_flags; 6510 bcopy(ta->ipft_name, tu.ipft_name, 6511 MIN(sizeof(tu.ipft_name), 6512 strlen(ta->ipft_name) + 1)); 6513 } 6514 error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE); 6515 break; 6516 6517 case SIOCIPFGET : 6518 case SIOCIPFSET : 6519 /* 6520 * Search by name or by cookie value for a particular entry 6521 * in the tuning paramter table. 6522 */ 6523 error = ESRCH; 6524 if (cookie != NULL) { 6525 ta = fr_findtunebycookie(cookie, NULL, ifs); 6526 if (ta != NULL) 6527 error = 0; 6528 } else if (tu.ipft_name[0] != '\0') { 6529 ta = fr_findtunebyname(tu.ipft_name, ifs); 6530 if (ta != NULL) 6531 error = 0; 6532 } 6533 if (error != 0) 6534 break; 6535 6536 if (cmd == (ioctlcmd_t)SIOCIPFGET) { 6537 /* 6538 * Fetch the tuning parameters for a particular value 6539 */ 6540 tu.ipft_vlong = 0; 6541 if (ta->ipft_sz == sizeof(u_long)) 6542 tu.ipft_vlong = *ta->ipft_plong; 6543 else if (ta->ipft_sz == sizeof(u_int)) 6544 tu.ipft_vint = *ta->ipft_pint; 6545 else if (ta->ipft_sz == sizeof(u_short)) 6546 tu.ipft_vshort = *ta->ipft_pshort; 6547 else if (ta->ipft_sz == sizeof(u_char)) 6548 tu.ipft_vchar = *ta->ipft_pchar; 6549 tu.ipft_cookie = ta; 6550 tu.ipft_sz = ta->ipft_sz; 6551 tu.ipft_min = ta->ipft_min; 6552 tu.ipft_max = ta->ipft_max; 6553 tu.ipft_flags = ta->ipft_flags; 6554 error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE); 6555 6556 } else if (cmd == (ioctlcmd_t)SIOCIPFSET) { 6557 /* 6558 * Set an internal parameter. The hard part here is 6559 * getting the new value safely and correctly out of 6560 * the kernel (given we only know its size, not type.) 6561 */ 6562 u_long in; 6563 6564 if (((ta->ipft_flags & IPFT_WRDISABLED) != 0) && 6565 (ifs->ifs_fr_running > 0)) { 6566 error = EBUSY; 6567 break; 6568 } 6569 6570 in = tu.ipft_vlong; 6571 if (in < ta->ipft_min || in > ta->ipft_max) { 6572 error = EINVAL; 6573 break; 6574 } 6575 6576 if (ta->ipft_sz == sizeof(u_long)) { 6577 tu.ipft_vlong = *ta->ipft_plong; 6578 *ta->ipft_plong = in; 6579 } else if (ta->ipft_sz == sizeof(u_int)) { 6580 tu.ipft_vint = *ta->ipft_pint; 6581 *ta->ipft_pint = (u_int)(in & 0xffffffff); 6582 } else if (ta->ipft_sz == sizeof(u_short)) { 6583 tu.ipft_vshort = *ta->ipft_pshort; 6584 *ta->ipft_pshort = (u_short)(in & 0xffff); 6585 } else if (ta->ipft_sz == sizeof(u_char)) { 6586 tu.ipft_vchar = *ta->ipft_pchar; 6587 *ta->ipft_pchar = (u_char)(in & 0xff); 6588 } 6589 error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE); 6590 } 6591 break; 6592 6593 default : 6594 error = EINVAL; 6595 break; 6596 } 6597 6598 return error; 6599 } 6600 6601 6602 /* ------------------------------------------------------------------------ */ 6603 /* Function: fr_initialise */ 6604 /* Returns: int - 0 == success, < 0 == failure */ 6605 /* Parameters: None. */ 6606 /* */ 6607 /* Call of the initialise functions for all the various subsystems inside */ 6608 /* of IPFilter. If any of them should fail, return immeadiately a failure */ 6609 /* BUT do not try to recover from the error here. */ 6610 /* ------------------------------------------------------------------------ */ 6611 int fr_initialise(ifs) 6612 ipf_stack_t *ifs; 6613 { 6614 int i; 6615 6616 #ifdef IPFILTER_LOG 6617 i = fr_loginit(ifs); 6618 if (i < 0) 6619 return -10 + i; 6620 #endif 6621 i = fr_natinit(ifs); 6622 if (i < 0) 6623 return -20 + i; 6624 6625 i = fr_stateinit(ifs); 6626 if (i < 0) 6627 return -30 + i; 6628 6629 i = fr_authinit(ifs); 6630 if (i < 0) 6631 return -40 + i; 6632 6633 i = fr_fraginit(ifs); 6634 if (i < 0) 6635 return -50 + i; 6636 6637 i = appr_init(ifs); 6638 if (i < 0) 6639 return -60 + i; 6640 6641 #ifdef IPFILTER_SYNC 6642 i = ipfsync_init(ifs); 6643 if (i < 0) 6644 return -70 + i; 6645 #endif 6646 #ifdef IPFILTER_SCAN 6647 i = ipsc_init(ifs); 6648 if (i < 0) 6649 return -80 + i; 6650 #endif 6651 #ifdef IPFILTER_LOOKUP 6652 i = ip_lookup_init(ifs); 6653 if (i < 0) 6654 return -90 + i; 6655 #endif 6656 #ifdef IPFILTER_COMPILED 6657 ipfrule_add(ifs); 6658 #endif 6659 return 0; 6660 } 6661 6662 6663 /* ------------------------------------------------------------------------ */ 6664 /* Function: fr_deinitialise */ 6665 /* Returns: None. */ 6666 /* Parameters: None. */ 6667 /* */ 6668 /* Call all the various subsystem cleanup routines to deallocate memory or */ 6669 /* destroy locks or whatever they've done that they need to now undo. */ 6670 /* The order here IS important as there are some cross references of */ 6671 /* internal data structures. */ 6672 /* ------------------------------------------------------------------------ */ 6673 void fr_deinitialise(ifs) 6674 ipf_stack_t *ifs; 6675 { 6676 fr_fragunload(ifs); 6677 fr_authunload(ifs); 6678 fr_natunload(ifs); 6679 fr_stateunload(ifs); 6680 #ifdef IPFILTER_SCAN 6681 fr_scanunload(ifs); 6682 #endif 6683 appr_unload(ifs); 6684 6685 #ifdef IPFILTER_COMPILED 6686 ipfrule_remove(ifs); 6687 #endif 6688 6689 (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE, ifs); 6690 (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE, ifs); 6691 (void) frflush(IPL_LOGCOUNT, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE, ifs); 6692 (void) frflush(IPL_LOGCOUNT, 0, FR_INQUE|FR_OUTQUE, ifs); 6693 6694 #ifdef IPFILTER_LOOKUP 6695 ip_lookup_unload(ifs); 6696 #endif 6697 6698 #ifdef IPFILTER_LOG 6699 fr_logunload(ifs); 6700 #endif 6701 } 6702 6703 6704 /* ------------------------------------------------------------------------ */ 6705 /* Function: fr_zerostats */ 6706 /* Returns: int - 0 = success, else failure */ 6707 /* Parameters: data(O) - pointer to pointer for copying data back to */ 6708 /* */ 6709 /* Copies the current statistics out to userspace and then zero's the */ 6710 /* current ones in the kernel. The lock is only held across the bzero() as */ 6711 /* the copyout may result in paging (ie network activity.) */ 6712 /* ------------------------------------------------------------------------ */ 6713 int fr_zerostats(data, ifs) 6714 caddr_t data; 6715 ipf_stack_t *ifs; 6716 { 6717 friostat_t fio; 6718 int error; 6719 6720 fr_getstat(&fio, ifs); 6721 error = copyoutptr(&fio, data, sizeof(fio)); 6722 if (error) 6723 return EFAULT; 6724 6725 WRITE_ENTER(&ifs->ifs_ipf_mutex); 6726 bzero((char *)ifs->ifs_frstats, sizeof(*ifs->ifs_frstats) * 2); 6727 RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 6728 6729 return 0; 6730 } 6731 6732 6733 #ifdef _KERNEL 6734 /* ------------------------------------------------------------------------ */ 6735 /* Function: fr_resolvedest */ 6736 /* Returns: Nil */ 6737 /* Parameters: fdp(IO) - pointer to destination information to resolve */ 6738 /* v(I) - IP protocol version to match */ 6739 /* */ 6740 /* Looks up an interface name in the frdest structure pointed to by fdp and */ 6741 /* if a matching name can be found for the particular IP protocol version */ 6742 /* then store the interface pointer in the frdest struct. If no match is */ 6743 /* found, then set the interface pointer to be -1 as NULL is considered to */ 6744 /* indicate there is no information at all in the structure. */ 6745 /* ------------------------------------------------------------------------ */ 6746 void fr_resolvedest(fdp, v, ifs) 6747 frdest_t *fdp; 6748 int v; 6749 ipf_stack_t *ifs; 6750 { 6751 fdp->fd_ifp = NULL; 6752 6753 if (*fdp->fd_ifname != '\0') { 6754 fdp->fd_ifp = GETIFP(fdp->fd_ifname, v, ifs); 6755 if (fdp->fd_ifp == NULL) 6756 fdp->fd_ifp = (void *)-1; 6757 } 6758 } 6759 #endif /* _KERNEL */ 6760 6761 6762 /* ------------------------------------------------------------------------ */ 6763 /* Function: fr_resolvenic */ 6764 /* Returns: void* - NULL = wildcard name, -1 = failed to find NIC, else */ 6765 /* pointer to interface structure for NIC */ 6766 /* Parameters: name(I) - complete interface name */ 6767 /* v(I) - IP protocol version */ 6768 /* */ 6769 /* Look for a network interface structure that firstly has a matching name */ 6770 /* to that passed in and that is also being used for that IP protocol */ 6771 /* version (necessary on some platforms where there are separate listings */ 6772 /* for both IPv4 and IPv6 on the same physical NIC. */ 6773 /* */ 6774 /* One might wonder why name gets terminated with a \0 byte in here. The */ 6775 /* reason is an interface name could get into the kernel structures of ipf */ 6776 /* in any number of ways and so long as they all use the same sized array */ 6777 /* to put the name in, it makes sense to ensure it gets null terminated */ 6778 /* before it is used for its intended purpose - finding its match in the */ 6779 /* kernel's list of configured interfaces. */ 6780 /* */ 6781 /* NOTE: This SHOULD ONLY be used with IPFilter structures that have an */ 6782 /* array for the name that is LIFNAMSIZ bytes (at least) in length. */ 6783 /* ------------------------------------------------------------------------ */ 6784 void *fr_resolvenic(name, v, ifs) 6785 char *name; 6786 int v; 6787 ipf_stack_t *ifs; 6788 { 6789 void *nic; 6790 6791 if (name[0] == '\0') 6792 return NULL; 6793 6794 if ((name[1] == '\0') && ((name[0] == '-') || (name[0] == '*'))) { 6795 return NULL; 6796 } 6797 6798 name[LIFNAMSIZ - 1] = '\0'; 6799 6800 nic = GETIFP(name, v, ifs); 6801 if (nic == NULL) 6802 nic = (void *)-1; 6803 return nic; 6804 } 6805 6806 6807 /* ------------------------------------------------------------------------ */ 6808 /* Function: ipf_expiretokens */ 6809 /* Returns: None. */ 6810 /* Parameters: ifs - ipf stack instance */ 6811 /* */ 6812 /* This function is run every ipf tick to see if there are any tokens that */ 6813 /* have been held for too long and need to be freed up. */ 6814 /* ------------------------------------------------------------------------ */ 6815 void ipf_expiretokens(ifs) 6816 ipf_stack_t *ifs; 6817 { 6818 ipftoken_t *it; 6819 6820 WRITE_ENTER(&ifs->ifs_ipf_tokens); 6821 while ((it = ifs->ifs_ipftokenhead) != NULL) { 6822 if (it->ipt_die > ifs->ifs_fr_ticks) 6823 break; 6824 6825 ipf_freetoken(it, ifs); 6826 } 6827 RWLOCK_EXIT(&ifs->ifs_ipf_tokens); 6828 } 6829 6830 6831 /* ------------------------------------------------------------------------ */ 6832 /* Function: ipf_deltoken */ 6833 /* Returns: int - 0 = success, else error */ 6834 /* Parameters: type(I) - the token type to match */ 6835 /* uid(I) - uid owning the token */ 6836 /* ptr(I) - context pointer for the token */ 6837 /* ifs - ipf stack instance */ 6838 /* */ 6839 /* This function looks for a a token in the current list that matches up */ 6840 /* the fields (type, uid, ptr). If none is found, ESRCH is returned, else */ 6841 /* call ipf_freetoken() to remove it from the list. */ 6842 /* ------------------------------------------------------------------------ */ 6843 int ipf_deltoken(type, uid, ptr, ifs) 6844 int type, uid; 6845 void *ptr; 6846 ipf_stack_t *ifs; 6847 { 6848 ipftoken_t *it; 6849 int error = ESRCH; 6850 6851 WRITE_ENTER(&ifs->ifs_ipf_tokens); 6852 for (it = ifs->ifs_ipftokenhead; it != NULL; it = it->ipt_next) 6853 if (ptr == it->ipt_ctx && type == it->ipt_type && 6854 uid == it->ipt_uid) { 6855 ipf_freetoken(it, ifs); 6856 error = 0; 6857 break; 6858 } 6859 RWLOCK_EXIT(&ifs->ifs_ipf_tokens); 6860 6861 return error; 6862 } 6863 6864 6865 /* ------------------------------------------------------------------------ */ 6866 /* Function: ipf_unlinktoken */ 6867 /* Returns: None. */ 6868 /* Parameters: token(I) - pointer to token structure */ 6869 /* ifs - ipf stack instance */ 6870 /* */ 6871 /* This function unlinks a token structure from the linked list of tokens */ 6872 /* that it belongs to. The head pointer never needs to be explicitly */ 6873 /* adjusted, but the tail does due to the linked list implementation. */ 6874 /* ------------------------------------------------------------------------ */ 6875 static void ipf_unlinktoken(token, ifs) 6876 ipftoken_t *token; 6877 ipf_stack_t *ifs; 6878 { 6879 6880 if (ifs->ifs_ipftokentail == &token->ipt_next) 6881 ifs->ifs_ipftokentail = token->ipt_pnext; 6882 6883 *token->ipt_pnext = token->ipt_next; 6884 if (token->ipt_next != NULL) 6885 token->ipt_next->ipt_pnext = token->ipt_pnext; 6886 } 6887 6888 6889 /* ------------------------------------------------------------------------ */ 6890 /* Function: ipf_findtoken */ 6891 /* Returns: ipftoken_t * - NULL if no memory, else pointer to token */ 6892 /* Parameters: type(I) - the token type to match */ 6893 /* uid(I) - uid owning the token */ 6894 /* ptr(I) - context pointer for the token */ 6895 /* ifs - ipf stack instance */ 6896 /* */ 6897 /* This function looks for a live token in the list of current tokens that */ 6898 /* matches the tuple (type, uid, ptr). If one cannot be found then one is */ 6899 /* allocated. If one is found then it is moved to the top of the list of */ 6900 /* currently active tokens. */ 6901 /* */ 6902 /* NOTE: It is by design that this function returns holding a read lock on */ 6903 /* ipf_tokens. Callers must make sure they release it! */ 6904 /* ------------------------------------------------------------------------ */ 6905 ipftoken_t *ipf_findtoken(type, uid, ptr, ifs) 6906 int type, uid; 6907 void *ptr; 6908 ipf_stack_t *ifs; 6909 { 6910 ipftoken_t *it, *new; 6911 6912 KMALLOC(new, ipftoken_t *); 6913 6914 WRITE_ENTER(&ifs->ifs_ipf_tokens); 6915 for (it = ifs->ifs_ipftokenhead; it != NULL; it = it->ipt_next) { 6916 if (it->ipt_alive == 0) 6917 continue; 6918 if (ptr == it->ipt_ctx && type == it->ipt_type && 6919 uid == it->ipt_uid) 6920 break; 6921 } 6922 6923 if (it == NULL) { 6924 it = new; 6925 new = NULL; 6926 if (it == NULL) 6927 return NULL; 6928 it->ipt_data = NULL; 6929 it->ipt_ctx = ptr; 6930 it->ipt_uid = uid; 6931 it->ipt_type = type; 6932 it->ipt_next = NULL; 6933 it->ipt_alive = 1; 6934 } else { 6935 if (new != NULL) { 6936 KFREE(new); 6937 new = NULL; 6938 } 6939 6940 ipf_unlinktoken(it, ifs); 6941 } 6942 it->ipt_pnext = ifs->ifs_ipftokentail; 6943 *ifs->ifs_ipftokentail = it; 6944 ifs->ifs_ipftokentail = &it->ipt_next; 6945 it->ipt_next = NULL; 6946 6947 it->ipt_die = ifs->ifs_fr_ticks + 2; 6948 6949 MUTEX_DOWNGRADE(&ifs->ifs_ipf_tokens); 6950 6951 return it; 6952 } 6953 6954 6955 /* ------------------------------------------------------------------------ */ 6956 /* Function: ipf_freetoken */ 6957 /* Returns: None. */ 6958 /* Parameters: token(I) - pointer to token structure */ 6959 /* ifs - ipf stack instance */ 6960 /* */ 6961 /* This function unlinks a token from the linked list and on the path to */ 6962 /* free'ing the data, it calls the dereference function that is associated */ 6963 /* with the type of data pointed to by the token as it is considered to */ 6964 /* hold a reference to it. */ 6965 /* ------------------------------------------------------------------------ */ 6966 void ipf_freetoken(token, ifs) 6967 ipftoken_t *token; 6968 ipf_stack_t *ifs; 6969 { 6970 void *data, **datap; 6971 6972 ipf_unlinktoken(token, ifs); 6973 6974 data = token->ipt_data; 6975 datap = &data; 6976 6977 if ((data != NULL) && (data != (void *)-1)) { 6978 switch (token->ipt_type) 6979 { 6980 case IPFGENITER_IPF : 6981 (void)fr_derefrule((frentry_t **)datap, ifs); 6982 break; 6983 case IPFGENITER_IPNAT : 6984 WRITE_ENTER(&ifs->ifs_ipf_nat); 6985 fr_ipnatderef((ipnat_t **)datap, ifs); 6986 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 6987 break; 6988 case IPFGENITER_NAT : 6989 fr_natderef((nat_t **)datap, ifs); 6990 break; 6991 case IPFGENITER_STATE : 6992 fr_statederef((ipstate_t **)datap, ifs); 6993 break; 6994 case IPFGENITER_FRAG : 6995 fr_fragderef((ipfr_t **)datap, &ifs->ifs_ipf_frag, ifs); 6996 break; 6997 case IPFGENITER_NATFRAG : 6998 fr_fragderef((ipfr_t **)datap, 6999 &ifs->ifs_ipf_natfrag, ifs); 7000 break; 7001 case IPFGENITER_HOSTMAP : 7002 WRITE_ENTER(&ifs->ifs_ipf_nat); 7003 fr_hostmapdel((hostmap_t **)datap); 7004 RWLOCK_EXIT(&ifs->ifs_ipf_nat); 7005 break; 7006 default : 7007 (void) ip_lookup_iterderef(token->ipt_type, data, ifs); 7008 break; 7009 } 7010 } 7011 7012 KFREE(token); 7013 } 7014 7015 7016 /* ------------------------------------------------------------------------ */ 7017 /* Function: ipf_getnextrule */ 7018 /* Returns: int - 0 = success, else error */ 7019 /* Parameters: t(I) - pointer to destination information to resolve */ 7020 /* ptr(I) - pointer to ipfobj_t to copyin from user space */ 7021 /* ifs - ipf stack instance */ 7022 /* */ 7023 /* This function's first job is to bring in the ipfruleiter_t structure via */ 7024 /* the ipfobj_t structure to determine what should be the next rule to */ 7025 /* return. Once the ipfruleiter_t has been brought in, it then tries to */ 7026 /* find the 'next rule'. This may include searching rule group lists or */ 7027 /* just be as simple as looking at the 'next' field in the rule structure. */ 7028 /* When we have found the rule to return, increase its reference count and */ 7029 /* if we used an existing rule to get here, decrease its reference count. */ 7030 /* ------------------------------------------------------------------------ */ 7031 int ipf_getnextrule(t, ptr, ifs) 7032 ipftoken_t *t; 7033 void *ptr; 7034 ipf_stack_t *ifs; 7035 { 7036 frentry_t *fr, *next, zero; 7037 int error, out, count; 7038 ipfruleiter_t it; 7039 frgroup_t *fg; 7040 char *dst; 7041 7042 if (t == NULL || ptr == NULL) 7043 return EFAULT; 7044 error = fr_inobj(ptr, &it, IPFOBJ_IPFITER); 7045 if (error != 0) 7046 return error; 7047 if ((it.iri_ver != AF_INET) && (it.iri_ver != AF_INET6)) 7048 return EINVAL; 7049 if ((it.iri_inout < 0) || (it.iri_inout > 3)) 7050 return EINVAL; 7051 if (it.iri_nrules == 0) 7052 return EINVAL; 7053 if ((it.iri_active != 0) && (it.iri_active != 1)) 7054 return EINVAL; 7055 if (it.iri_rule == NULL) 7056 return EFAULT; 7057 7058 /* 7059 * Use bitmask on it.iri_inout to determine direction. 7060 * F_OUT (1) and F_ACOUT (3) mask to out = 1, while 7061 * F_IN (0) and F_ACIN (2) mask to out = 0. 7062 */ 7063 out = it.iri_inout & F_OUT; 7064 READ_ENTER(&ifs->ifs_ipf_mutex); 7065 7066 /* 7067 * Retrieve "previous" entry from token and find the next entry. 7068 */ 7069 fr = t->ipt_data; 7070 if (fr == NULL) { 7071 if (*it.iri_group == '\0') { 7072 /* 7073 * Use bitmask again to determine accounting or not. 7074 * F_ACIN will mask to accounting cases F_ACIN (2) 7075 * or F_ACOUT (3), but not F_IN or F_OUT. 7076 */ 7077 if ((it.iri_inout & F_ACIN) != 0) { 7078 if (it.iri_ver == AF_INET) 7079 next = ifs->ifs_ipacct 7080 [out][it.iri_active]; 7081 else 7082 next = ifs->ifs_ipacct6 7083 [out][it.iri_active]; 7084 } else { 7085 if (it.iri_ver == AF_INET) 7086 next = ifs->ifs_ipfilter 7087 [out][it.iri_active]; 7088 else 7089 next = ifs->ifs_ipfilter6 7090 [out][it.iri_active]; 7091 } 7092 } else { 7093 fg = fr_findgroup(it.iri_group, IPL_LOGIPF, 7094 it.iri_active, NULL, ifs); 7095 if (fg != NULL) 7096 next = fg->fg_start; 7097 else 7098 next = NULL; 7099 } 7100 } else { 7101 next = fr->fr_next; 7102 } 7103 7104 dst = (char *)it.iri_rule; 7105 /* 7106 * The ipfruleiter may ask for more than 1 rule at a time to be 7107 * copied out, so long as that many exist in the list to start with! 7108 */ 7109 for (count = it.iri_nrules; count > 0; count--) { 7110 /* 7111 * If we found an entry, add reference to it and update token. 7112 * Otherwise, zero out data to be returned and NULL out token. 7113 */ 7114 if (next != NULL) { 7115 MUTEX_ENTER(&next->fr_lock); 7116 next->fr_ref++; 7117 MUTEX_EXIT(&next->fr_lock); 7118 t->ipt_data = next; 7119 } else { 7120 bzero(&zero, sizeof(zero)); 7121 next = &zero; 7122 t->ipt_data = NULL; 7123 } 7124 7125 /* 7126 * Now that we have ref, it's save to give up lock. 7127 */ 7128 RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 7129 7130 /* 7131 * Copy out data and clean up references and token as needed. 7132 */ 7133 error = COPYOUT(next, dst, sizeof(*next)); 7134 if (error != 0) 7135 error = EFAULT; 7136 if (t->ipt_data == NULL) { 7137 ipf_freetoken(t, ifs); 7138 break; 7139 } else { 7140 if (fr != NULL) 7141 (void) fr_derefrule(&fr, ifs); 7142 if (next->fr_data != NULL) { 7143 dst += sizeof(*next); 7144 error = COPYOUT(next->fr_data, dst, 7145 next->fr_dsize); 7146 if (error != 0) 7147 error = EFAULT; 7148 else 7149 dst += next->fr_dsize; 7150 } 7151 if (next->fr_next == NULL) { 7152 ipf_freetoken(t, ifs); 7153 break; 7154 } 7155 } 7156 7157 if ((count == 1) || (error != 0)) 7158 break; 7159 7160 READ_ENTER(&ifs->ifs_ipf_mutex); 7161 fr = next; 7162 next = fr->fr_next; 7163 } 7164 7165 return error; 7166 } 7167 7168 7169 /* ------------------------------------------------------------------------ */ 7170 /* Function: fr_frruleiter */ 7171 /* Returns: int - 0 = success, else error */ 7172 /* Parameters: data(I) - the token type to match */ 7173 /* uid(I) - uid owning the token */ 7174 /* ptr(I) - context pointer for the token */ 7175 /* ifs - ipf stack instance */ 7176 /* */ 7177 /* This function serves as a stepping stone between fr_ipf_ioctl and */ 7178 /* ipf_getnextrule. It's role is to find the right token in the kernel for */ 7179 /* the process doing the ioctl and use that to ask for the next rule. */ 7180 /* ------------------------------------------------------------------------ */ 7181 int ipf_frruleiter(data, uid, ctx, ifs) 7182 void *data, *ctx; 7183 int uid; 7184 ipf_stack_t *ifs; 7185 { 7186 ipftoken_t *token; 7187 int error; 7188 7189 token = ipf_findtoken(IPFGENITER_IPF, uid, ctx, ifs); 7190 if (token != NULL) 7191 error = ipf_getnextrule(token, data, ifs); 7192 else 7193 error = EFAULT; 7194 RWLOCK_EXIT(&ifs->ifs_ipf_tokens); 7195 7196 return error; 7197 } 7198 7199 7200 /* ------------------------------------------------------------------------ */ 7201 /* Function: ipf_geniter */ 7202 /* Returns: int - 0 = success, else error */ 7203 /* Parameters: token(I) - pointer to ipftoken structure */ 7204 /* itp(I) - pointer to ipfgeniter structure */ 7205 /* ifs - ipf stack instance */ 7206 /* */ 7207 /* Generic iterator called from ipf_genericiter. Currently only used for */ 7208 /* walking through list of fragments. */ 7209 /* ------------------------------------------------------------------------ */ 7210 int ipf_geniter(token, itp, ifs) 7211 ipftoken_t *token; 7212 ipfgeniter_t *itp; 7213 ipf_stack_t *ifs; 7214 { 7215 int error; 7216 7217 switch (itp->igi_type) 7218 { 7219 case IPFGENITER_FRAG : 7220 error = fr_nextfrag(token, itp, &ifs->ifs_ipfr_list, 7221 &ifs->ifs_ipfr_tail, &ifs->ifs_ipf_frag, 7222 ifs); 7223 break; 7224 default : 7225 error = EINVAL; 7226 break; 7227 } 7228 7229 return error; 7230 } 7231 7232 7233 /* ------------------------------------------------------------------------ */ 7234 /* Function: ipf_genericiter */ 7235 /* Returns: int - 0 = success, else error */ 7236 /* Parameters: data(I) - the token type to match */ 7237 /* uid(I) - uid owning the token */ 7238 /* ptr(I) - context pointer for the token */ 7239 /* ifs - ipf stack instance */ 7240 /* */ 7241 /* This function serves as a stepping stone between fr_ipf_ioctl and */ 7242 /* ipf_geniter when handling SIOCGENITER. It's role is to find the right */ 7243 /* token in the kernel for the process using the ioctl, and to use that */ 7244 /* token when calling ipf_geniter. */ 7245 /* ------------------------------------------------------------------------ */ 7246 int ipf_genericiter(data, uid, ctx, ifs) 7247 void *data, *ctx; 7248 int uid; 7249 ipf_stack_t *ifs; 7250 { 7251 ipftoken_t *token; 7252 ipfgeniter_t iter; 7253 int error; 7254 7255 error = fr_inobj(data, &iter, IPFOBJ_GENITER); 7256 if (error != 0) 7257 return error; 7258 7259 token = ipf_findtoken(iter.igi_type, uid, ctx, ifs); 7260 if (token != NULL) { 7261 token->ipt_subtype = iter.igi_type; 7262 error = ipf_geniter(token, &iter, ifs); 7263 } else 7264 error = EFAULT; 7265 RWLOCK_EXIT(&ifs->ifs_ipf_tokens); 7266 7267 return error; 7268 } 7269 7270 7271 /* --------------------------------------------------------------------- */ 7272 /* Function: ipf_earlydrop */ 7273 /* Returns: number of dropped/removed entries from the queue */ 7274 /* Parameters: flushtype - which table we're cleaning (NAT or State) */ 7275 /* ifq - pointer to queue with entries to be deleted */ 7276 /* idletime - entry must be idle this long to be deleted */ 7277 /* ifs - ipf stack instance */ 7278 /* */ 7279 /* Function is invoked from state/NAT flush routines to remove entries */ 7280 /* from specified timeout queue, based on how long they've sat idle, */ 7281 /* without waiting for it to happen on its own. */ 7282 /* --------------------------------------------------------------------- */ 7283 int ipf_earlydrop(flushtype, ifq, idletime, ifs) 7284 int flushtype; 7285 ipftq_t *ifq; 7286 int idletime; 7287 ipf_stack_t *ifs; 7288 { 7289 ipftqent_t *tqe, *tqn; 7290 unsigned int dropped; 7291 int droptick; 7292 void *ent; 7293 7294 if (ifq == NULL) 7295 return (0); 7296 7297 dropped = 0; 7298 7299 /* 7300 * Determine the tick representing the idle time we're interested 7301 * in. If an entry exists in the queue, and it was touched before 7302 * that tick, then it's been idle longer than idletime, so it should 7303 * be deleted. 7304 */ 7305 droptick = ifs->ifs_fr_ticks - idletime; 7306 tqn = ifq->ifq_head; 7307 while ((tqe = tqn) != NULL && tqe->tqe_touched < droptick) { 7308 tqn = tqe->tqe_next; 7309 ent = tqe->tqe_parent; 7310 switch (flushtype) 7311 { 7312 case NAT_FLUSH: 7313 if (nat_delete((nat_t *)ent, NL_FLUSH, ifs) == 0) 7314 dropped++; 7315 break; 7316 case STATE_FLUSH: 7317 if (fr_delstate((ipstate_t *)ent, ISL_FLUSH, ifs) == 0) 7318 dropped++; 7319 break; 7320 default: 7321 return (0); 7322 } 7323 } 7324 return (dropped); 7325 } 7326 7327 7328 /* --------------------------------------------------------------------- */ 7329 /* Function: ipf_flushclosing */ 7330 /* Returns: int - number of entries deleted */ 7331 /* Parameters: flushtype - which table we're cleaning (NAT or State) */ 7332 /* stateval - TCP state at which to start removing entries */ 7333 /* ipfqs - pointer to timeout queues */ 7334 /* userqs - pointer to user defined queues */ 7335 /* ifs - ipf stack instance */ 7336 /* */ 7337 /* Remove state/NAT table entries for TCP connections which are in the */ 7338 /* process of closing, and have at least reached the state specified by */ 7339 /* the 'stateval' parameter. */ 7340 /* --------------------------------------------------------------------- */ 7341 int ipf_flushclosing(flushtype, stateval, ipfqs, userqs, ifs) 7342 int flushtype, stateval; 7343 ipftq_t *ipfqs, *userqs; 7344 ipf_stack_t *ifs; 7345 { 7346 ipftq_t *ifq, *ifqn; 7347 ipftqent_t *tqe, *tqn; 7348 int dropped; 7349 void *ent; 7350 nat_t *nat; 7351 ipstate_t *is; 7352 7353 dropped = 0; 7354 7355 /* 7356 * Start by deleting any entries in specific timeout queues. 7357 */ 7358 ifqn = &ipfqs[stateval]; 7359 while ((ifq = ifqn) != NULL) { 7360 ifqn = ifq->ifq_next; 7361 dropped += ipf_earlydrop(flushtype, ifq, (int)0, ifs); 7362 } 7363 7364 /* 7365 * Next, look through user defined queues for closing entries. 7366 */ 7367 ifqn = userqs; 7368 while ((ifq = ifqn) != NULL) { 7369 ifqn = ifq->ifq_next; 7370 tqn = ifq->ifq_head; 7371 while ((tqe = tqn) != NULL) { 7372 tqn = tqe->tqe_next; 7373 ent = tqe->tqe_parent; 7374 switch (flushtype) 7375 { 7376 case NAT_FLUSH: 7377 nat = (nat_t *)ent; 7378 if ((nat->nat_p == IPPROTO_TCP) && 7379 (nat->nat_tcpstate[0] >= stateval) && 7380 (nat->nat_tcpstate[1] >= stateval) && 7381 (nat_delete(nat, NL_EXPIRE, ifs) == 0)) 7382 dropped++; 7383 break; 7384 case STATE_FLUSH: 7385 is = (ipstate_t *)ent; 7386 if ((is->is_p == IPPROTO_TCP) && 7387 (is->is_state[0] >= stateval) && 7388 (is->is_state[1] >= stateval) && 7389 (fr_delstate(is, ISL_EXPIRE, ifs) == 0)) 7390 dropped++; 7391 break; 7392 default: 7393 return (0); 7394 } 7395 } 7396 } 7397 return (dropped); 7398 } 7399 7400 7401 /* --------------------------------------------------------------------- */ 7402 /* Function: ipf_extraflush */ 7403 /* Returns: int - number of entries flushed (0 = none) */ 7404 /* Parameters: flushtype - which table we're cleaning (NAT or State) */ 7405 /* ipfqs - pointer to 'established' timeout queue */ 7406 /* userqs - pointer to user defined queues */ 7407 /* ifs - ipf stack instance */ 7408 /* */ 7409 /* This function gets called when either NAT or state tables fill up. */ 7410 /* We need to try a bit harder to free up some space. The function will */ 7411 /* flush entries for TCP connections which have been idle a long time. */ 7412 /* */ 7413 /* Currently, the idle time is checked using values from ideltime_tab[] */ 7414 /* --------------------------------------------------------------------- */ 7415 int ipf_extraflush(flushtype, ipfqs, userqs, ifs) 7416 int flushtype; 7417 ipftq_t *ipfqs, *userqs; 7418 ipf_stack_t *ifs; 7419 { 7420 ipftq_t *ifq, *ifqn; 7421 int idletime, removed, idle_idx; 7422 7423 removed = 0; 7424 7425 /* 7426 * Determine initial threshold for minimum idle time based on 7427 * how long ipfilter has been running. Ipfilter needs to have 7428 * been up as long as the smallest interval to continue on. 7429 * 7430 * Minimum idle times stored in idletime_tab and indexed by 7431 * idle_idx. Start at upper end of array and work backwards. 7432 * 7433 * Once the index is found, set the initial idle time to the 7434 * first interval before the current ipfilter run time. 7435 */ 7436 if (ifs->ifs_fr_ticks < idletime_tab[0]) 7437 return (0); 7438 idle_idx = (sizeof (idletime_tab) / sizeof (int)) - 1; 7439 if (ifs->ifs_fr_ticks > idletime_tab[idle_idx]) { 7440 idletime = idletime_tab[idle_idx]; 7441 } else { 7442 while ((idle_idx > 0) && 7443 (ifs->ifs_fr_ticks < idletime_tab[idle_idx])) 7444 idle_idx--; 7445 7446 idletime = (ifs->ifs_fr_ticks / 7447 idletime_tab[idle_idx]) * 7448 idletime_tab[idle_idx]; 7449 } 7450 7451 while (idle_idx >= 0) { 7452 /* 7453 * Check to see if we need to delete more entries. 7454 * If we do, start with appropriate timeout queue. 7455 */ 7456 if (flushtype == NAT_FLUSH) { 7457 if (NAT_TAB_WATER_LEVEL(ifs) <= 7458 ifs->ifs_nat_flush_level_lo) 7459 break; 7460 } else if (flushtype == STATE_FLUSH) { 7461 if (ST_TAB_WATER_LEVEL(ifs) <= 7462 ifs->ifs_state_flush_level_lo) 7463 break; 7464 } else { 7465 break; 7466 } 7467 7468 removed += ipf_earlydrop(flushtype, ipfqs, idletime, ifs); 7469 7470 /* 7471 * Next, check the user defined queues. But first, make 7472 * certain that timeout queue deletions didn't do enough. 7473 */ 7474 if (flushtype == NAT_FLUSH) { 7475 if (NAT_TAB_WATER_LEVEL(ifs) <= 7476 ifs->ifs_nat_flush_level_lo) 7477 break; 7478 } else { 7479 if (ST_TAB_WATER_LEVEL(ifs) <= 7480 ifs->ifs_state_flush_level_lo) 7481 break; 7482 } 7483 ifqn = userqs; 7484 while ((ifq = ifqn) != NULL) { 7485 ifqn = ifq->ifq_next; 7486 removed += ipf_earlydrop(flushtype, ifq, idletime, ifs); 7487 } 7488 7489 /* 7490 * Adjust the granularity of idle time. 7491 * 7492 * If we reach an interval boundary, we need to 7493 * either adjust the idle time accordingly or exit 7494 * the loop altogether (if this is very last check). 7495 */ 7496 idletime -= idletime_tab[idle_idx]; 7497 if (idletime < idletime_tab[idle_idx]) { 7498 if (idle_idx != 0) { 7499 idletime = idletime_tab[idle_idx] - 7500 idletime_tab[idle_idx - 1]; 7501 idle_idx--; 7502 } else { 7503 break; 7504 } 7505 } 7506 } 7507 7508 return (removed); 7509 } 7510