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