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