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