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