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