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