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