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