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