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