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