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