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