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