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