fil.c revision 153084
1/* $FreeBSD: head/sys/contrib/ipfilter/netinet/fil.c 153084 2005-12-04 10:06:06Z ru $ */ 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 153084 2005-12-04 10:06:06Z ru $"; 140/* static 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 (defined(OpenBSD) && 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 defined(OpenBSD) && 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 ftail = fprev; 4002 for (f = *ftail; (f = *ftail) != NULL; ftail = &f->fr_next) { 4003 if (fp->fr_collect <= f->fr_collect) { 4004 ftail = fprev; 4005 f = NULL; 4006 break; 4007 } 4008 fprev = ftail; 4009 } 4010 4011 /* 4012 * Copy in extra data for the rule. 4013 */ 4014 if (fp->fr_dsize != 0) { 4015 if (makecopy != 0) { 4016 KMALLOCS(ptr, void *, fp->fr_dsize); 4017 if (!ptr) 4018 return ENOMEM; 4019 error = COPYIN(uptr, ptr, fp->fr_dsize); 4020 } else { 4021 ptr = uptr; 4022 error = 0; 4023 } 4024 if (error != 0) { 4025 KFREES(ptr, fp->fr_dsize); 4026 return ENOMEM; 4027 } 4028 fp->fr_data = ptr; 4029 } else 4030 fp->fr_data = NULL; 4031 4032 /* 4033 * Perform per-rule type sanity checks of their members. 4034 */ 4035 switch (fp->fr_type & ~FR_T_BUILTIN) 4036 { 4037#if defined(IPFILTER_BPF) 4038 case FR_T_BPFOPC : 4039 if (fp->fr_dsize == 0) 4040 return EINVAL; 4041 if (!bpf_validate(ptr, fp->fr_dsize/sizeof(struct bpf_insn))) { 4042 if (makecopy && fp->fr_data != NULL) { 4043 KFREES(fp->fr_data, fp->fr_dsize); 4044 } 4045 return EINVAL; 4046 } 4047 break; 4048#endif 4049 case FR_T_IPF : 4050 if (fp->fr_dsize != sizeof(fripf_t)) 4051 return EINVAL; 4052 4053 /* 4054 * Allowing a rule with both "keep state" and "with oow" is 4055 * pointless because adding a state entry to the table will 4056 * fail with the out of window (oow) flag set. 4057 */ 4058 if ((fp->fr_flags & FR_KEEPSTATE) && (fp->fr_flx & FI_OOW)) 4059 return EINVAL; 4060 4061 switch (fp->fr_satype) 4062 { 4063 case FRI_BROADCAST : 4064 case FRI_DYNAMIC : 4065 case FRI_NETWORK : 4066 case FRI_NETMASKED : 4067 case FRI_PEERADDR : 4068 if (fp->fr_sifpidx < 0 || fp->fr_sifpidx > 3) { 4069 if (makecopy && fp->fr_data != NULL) { 4070 KFREES(fp->fr_data, fp->fr_dsize); 4071 } 4072 return EINVAL; 4073 } 4074 break; 4075#ifdef IPFILTER_LOOKUP 4076 case FRI_LOOKUP : 4077 fp->fr_srcptr = fr_resolvelookup(fp->fr_srctype, 4078 fp->fr_srcnum, 4079 &fp->fr_srcfunc); 4080 break; 4081#endif 4082 default : 4083 break; 4084 } 4085 4086 switch (fp->fr_datype) 4087 { 4088 case FRI_BROADCAST : 4089 case FRI_DYNAMIC : 4090 case FRI_NETWORK : 4091 case FRI_NETMASKED : 4092 case FRI_PEERADDR : 4093 if (fp->fr_difpidx < 0 || fp->fr_difpidx > 3) { 4094 if (makecopy && fp->fr_data != NULL) { 4095 KFREES(fp->fr_data, fp->fr_dsize); 4096 } 4097 return EINVAL; 4098 } 4099 break; 4100#ifdef IPFILTER_LOOKUP 4101 case FRI_LOOKUP : 4102 fp->fr_dstptr = fr_resolvelookup(fp->fr_dsttype, 4103 fp->fr_dstnum, 4104 &fp->fr_dstfunc); 4105 break; 4106#endif 4107 default : 4108 4109 break; 4110 } 4111 break; 4112 case FR_T_NONE : 4113 break; 4114 case FR_T_CALLFUNC : 4115 break; 4116 case FR_T_COMPIPF : 4117 break; 4118 default : 4119 if (makecopy && fp->fr_data != NULL) { 4120 KFREES(fp->fr_data, fp->fr_dsize); 4121 } 4122 return EINVAL; 4123 } 4124 4125 /* 4126 * Lookup all the interface names that are part of the rule. 4127 */ 4128 frsynclist(fp, NULL); 4129 fp->fr_statecnt = 0; 4130 4131 /* 4132 * Look for an existing matching filter rule, but don't include the 4133 * next or interface pointer in the comparison (fr_next, fr_ifa). 4134 * This elminates rules which are indentical being loaded. Checksum 4135 * the constant part of the filter rule to make comparisons quicker 4136 * (this meaning no pointers are included). 4137 */ 4138 for (fp->fr_cksum = 0, p = (u_int *)&fp->fr_func, pp = &fp->fr_cksum; 4139 p < pp; p++) 4140 fp->fr_cksum += *p; 4141 pp = (u_int *)(fp->fr_caddr + fp->fr_dsize); 4142 for (p = (u_int *)fp->fr_data; p < pp; p++) 4143 fp->fr_cksum += *p; 4144 4145 WRITE_ENTER(&ipf_mutex); 4146 bzero((char *)frcache, sizeof(frcache)); 4147 4148 for (; (f = *ftail) != NULL; ftail = &f->fr_next) { 4149 if ((fp->fr_cksum != f->fr_cksum) || 4150 (f->fr_dsize != fp->fr_dsize)) 4151 continue; 4152 if (bcmp((char *)&f->fr_func, (char *)&fp->fr_func, FR_CMPSIZ)) 4153 continue; 4154 if ((!ptr && !f->fr_data) || 4155 (ptr && f->fr_data && 4156 !bcmp((char *)ptr, (char *)f->fr_data, f->fr_dsize))) 4157 break; 4158 } 4159 4160 /* 4161 * If zero'ing statistics, copy current to caller and zero. 4162 */ 4163 if (req == (ioctlcmd_t)SIOCZRLST) { 4164 if (f == NULL) 4165 error = ESRCH; 4166 else { 4167 /* 4168 * Copy and reduce lock because of impending copyout. 4169 * Well we should, but if we do then the atomicity of 4170 * this call and the correctness of fr_hits and 4171 * fr_bytes cannot be guaranteed. As it is, this code 4172 * only resets them to 0 if they are successfully 4173 * copied out into user space. 4174 */ 4175 bcopy((char *)f, (char *)fp, sizeof(*f)); 4176 /* MUTEX_DOWNGRADE(&ipf_mutex); */ 4177 4178 /* 4179 * When we copy this rule back out, set the data 4180 * pointer to be what it was in user space. 4181 */ 4182 fp->fr_data = uptr; 4183 error = fr_outobj(data, fp, IPFOBJ_FRENTRY); 4184 4185 if (error == 0) { 4186 if ((f->fr_dsize != 0) && (uptr != NULL)) 4187 error = COPYOUT(f->fr_data, uptr, 4188 f->fr_dsize); 4189 if (error == 0) { 4190 f->fr_hits = 0; 4191 f->fr_bytes = 0; 4192 } 4193 } 4194 } 4195 4196 if ((ptr != NULL) && (makecopy != 0)) { 4197 KFREES(ptr, fp->fr_dsize); 4198 } 4199 RWLOCK_EXIT(&ipf_mutex); 4200 return error; 4201 } 4202 4203 if (!f) { 4204 /* 4205 * At the end of this, ftail must point to the place where the 4206 * new rule is to be saved/inserted/added. 4207 * For SIOCAD*FR, this should be the last rule in the group of 4208 * rules that have equal fr_collect fields. 4209 * For SIOCIN*FR, ... 4210 */ 4211 if (req == (ioctlcmd_t)SIOCADAFR || 4212 req == (ioctlcmd_t)SIOCADIFR) { 4213 4214 for (ftail = fprev; (f = *ftail) != NULL; ) { 4215 if (f->fr_collect > fp->fr_collect) 4216 break; 4217 ftail = &f->fr_next; 4218 } 4219 f = NULL; 4220 ptr = NULL; 4221 error = 0; 4222 } else if (req == (ioctlcmd_t)SIOCINAFR || 4223 req == (ioctlcmd_t)SIOCINIFR) { 4224 while ((f = *fprev) != NULL) { 4225 if (f->fr_collect >= fp->fr_collect) 4226 break; 4227 fprev = &f->fr_next; 4228 } 4229 ftail = fprev; 4230 if (fp->fr_hits != 0) { 4231 while (fp->fr_hits && (f = *ftail)) { 4232 if (f->fr_collect != fp->fr_collect) 4233 break; 4234 fprev = ftail; 4235 ftail = &f->fr_next; 4236 fp->fr_hits--; 4237 } 4238 } 4239 f = NULL; 4240 ptr = NULL; 4241 error = 0; 4242 } 4243 } 4244 4245 /* 4246 * Request to remove a rule. 4247 */ 4248 if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR) { 4249 if (!f) 4250 error = ESRCH; 4251 else { 4252 /* 4253 * Do not allow activity from user space to interfere 4254 * with rules not loaded that way. 4255 */ 4256 if ((makecopy == 1) && !(f->fr_flags & FR_COPIED)) { 4257 error = EPERM; 4258 goto done; 4259 } 4260 4261 /* 4262 * Return EBUSY if the rule is being reference by 4263 * something else (eg state information. 4264 */ 4265 if (f->fr_ref > 1) { 4266 error = EBUSY; 4267 goto done; 4268 } 4269#ifdef IPFILTER_SCAN 4270 if (f->fr_isctag[0] != '\0' && 4271 (f->fr_isc != (struct ipscan *)-1)) 4272 ipsc_detachfr(f); 4273#endif 4274 if ((fg != NULL) && (fg->fg_head != NULL)) 4275 fg->fg_head->fr_ref--; 4276 if (unit == IPL_LOGAUTH) { 4277 error = fr_preauthcmd(req, f, ftail); 4278 goto done; 4279 } 4280 if (*f->fr_grhead != '\0') 4281 fr_delgroup(f->fr_grhead, unit, set); 4282 fr_fixskip(ftail, f, -1); 4283 *ftail = f->fr_next; 4284 f->fr_next = NULL; 4285 (void)fr_derefrule(&f); 4286 } 4287 } else { 4288 /* 4289 * Not removing, so we must be adding/inserting a rule. 4290 */ 4291 if (f) 4292 error = EEXIST; 4293 else { 4294 if (unit == IPL_LOGAUTH) { 4295 error = fr_preauthcmd(req, fp, ftail); 4296 goto done; 4297 } 4298 if (makecopy) { 4299 KMALLOC(f, frentry_t *); 4300 } else 4301 f = fp; 4302 if (f != NULL) { 4303 if (fg != NULL && fg->fg_head!= NULL ) 4304 fg->fg_head->fr_ref++; 4305 if (fp != f) 4306 bcopy((char *)fp, (char *)f, 4307 sizeof(*f)); 4308 MUTEX_NUKE(&f->fr_lock); 4309 MUTEX_INIT(&f->fr_lock, "filter rule lock"); 4310#ifdef IPFILTER_SCAN 4311 if (f->fr_isctag[0] != '\0' && 4312 ipsc_attachfr(f)) 4313 f->fr_isc = (struct ipscan *)-1; 4314#endif 4315 f->fr_hits = 0; 4316 if (makecopy != 0) 4317 f->fr_ref = 1; 4318 f->fr_next = *ftail; 4319 *ftail = f; 4320 if (req == (ioctlcmd_t)SIOCINIFR || 4321 req == (ioctlcmd_t)SIOCINAFR) 4322 fr_fixskip(ftail, f, 1); 4323 f->fr_grp = NULL; 4324 group = f->fr_grhead; 4325 if (*group != '\0') { 4326 fg = fr_addgroup(group, f, f->fr_flags, 4327 unit, set); 4328 if (fg != NULL) 4329 f->fr_grp = &fg->fg_start; 4330 } 4331 } else 4332 error = ENOMEM; 4333 } 4334 } 4335done: 4336 RWLOCK_EXIT(&ipf_mutex); 4337 if ((ptr != NULL) && (error != 0) && (makecopy != 0)) { 4338 KFREES(ptr, fp->fr_dsize); 4339 } 4340 return (error); 4341} 4342 4343 4344/* ------------------------------------------------------------------------ */ 4345/* Function: fr_funcinit */ 4346/* Returns: int - 0 == success, else ESRCH: cannot resolve rule details */ 4347/* Parameters: fr(I) - pointer to filter rule */ 4348/* */ 4349/* If a rule is a call rule, then check if the function it points to needs */ 4350/* an init function to be called now the rule has been loaded. */ 4351/* ------------------------------------------------------------------------ */ 4352static int fr_funcinit(fr) 4353frentry_t *fr; 4354{ 4355 ipfunc_resolve_t *ft; 4356 int err; 4357 4358 err = ESRCH; 4359 4360 for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++) 4361 if (ft->ipfu_addr == fr->fr_func) { 4362 err = 0; 4363 if (ft->ipfu_init != NULL) 4364 err = (*ft->ipfu_init)(fr); 4365 break; 4366 } 4367 return err; 4368} 4369 4370 4371/* ------------------------------------------------------------------------ */ 4372/* Function: fr_findfunc */ 4373/* Returns: ipfunc_t - pointer to function if found, else NULL */ 4374/* Parameters: funcptr(I) - function pointer to lookup */ 4375/* */ 4376/* Look for a function in the table of known functions. */ 4377/* ------------------------------------------------------------------------ */ 4378static ipfunc_t fr_findfunc(funcptr) 4379ipfunc_t funcptr; 4380{ 4381 ipfunc_resolve_t *ft; 4382 4383 for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++) 4384 if (ft->ipfu_addr == funcptr) 4385 return funcptr; 4386 return NULL; 4387} 4388 4389 4390/* ------------------------------------------------------------------------ */ 4391/* Function: fr_resolvefunc */ 4392/* Returns: int - 0 == success, else error */ 4393/* Parameters: data(IO) - ioctl data pointer to ipfunc_resolve_t struct */ 4394/* */ 4395/* Copy in a ipfunc_resolve_t structure and then fill in the missing field. */ 4396/* This will either be the function name (if the pointer is set) or the */ 4397/* function pointer if the name is set. When found, fill in the other one */ 4398/* so that the entire, complete, structure can be copied back to user space.*/ 4399/* ------------------------------------------------------------------------ */ 4400int fr_resolvefunc(data) 4401void *data; 4402{ 4403 ipfunc_resolve_t res, *ft; 4404 4405 BCOPYIN(data, &res, sizeof(res)); 4406 4407 if (res.ipfu_addr == NULL && res.ipfu_name[0] != '\0') { 4408 for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++) 4409 if (strncmp(res.ipfu_name, ft->ipfu_name, 4410 sizeof(res.ipfu_name)) == 0) { 4411 res.ipfu_addr = ft->ipfu_addr; 4412 res.ipfu_init = ft->ipfu_init; 4413 if (COPYOUT(&res, data, sizeof(res)) != 0) 4414 return EFAULT; 4415 return 0; 4416 } 4417 } 4418 if (res.ipfu_addr != NULL && res.ipfu_name[0] == '\0') { 4419 for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++) 4420 if (ft->ipfu_addr == res.ipfu_addr) { 4421 (void) strncpy(res.ipfu_name, ft->ipfu_name, 4422 sizeof(res.ipfu_name)); 4423 res.ipfu_init = ft->ipfu_init; 4424 if (COPYOUT(&res, data, sizeof(res)) != 0) 4425 return EFAULT; 4426 return 0; 4427 } 4428 } 4429 return ESRCH; 4430} 4431 4432 4433#if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__FreeBSD__)) || \ 4434 (defined(__FreeBSD__) && (__FreeBSD_version < 490000)) || \ 4435 (defined(__NetBSD__) && (__NetBSD_Version__ < 105000000)) || \ 4436 (defined(__OpenBSD__) && (OpenBSD < 200006)) 4437/* 4438 * From: NetBSD 4439 * ppsratecheck(): packets (or events) per second limitation. 4440 */ 4441int 4442ppsratecheck(lasttime, curpps, maxpps) 4443 struct timeval *lasttime; 4444 int *curpps; 4445 int maxpps; /* maximum pps allowed */ 4446{ 4447 struct timeval tv, delta; 4448 int rv; 4449 4450 GETKTIME(&tv); 4451 4452 delta.tv_sec = tv.tv_sec - lasttime->tv_sec; 4453 delta.tv_usec = tv.tv_usec - lasttime->tv_usec; 4454 if (delta.tv_usec < 0) { 4455 delta.tv_sec--; 4456 delta.tv_usec += 1000000; 4457 } 4458 4459 /* 4460 * check for 0,0 is so that the message will be seen at least once. 4461 * if more than one second have passed since the last update of 4462 * lasttime, reset the counter. 4463 * 4464 * we do increment *curpps even in *curpps < maxpps case, as some may 4465 * try to use *curpps for stat purposes as well. 4466 */ 4467 if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) || 4468 delta.tv_sec >= 1) { 4469 *lasttime = tv; 4470 *curpps = 0; 4471 rv = 1; 4472 } else if (maxpps < 0) 4473 rv = 1; 4474 else if (*curpps < maxpps) 4475 rv = 1; 4476 else 4477 rv = 0; 4478 *curpps = *curpps + 1; 4479 4480 return (rv); 4481} 4482#endif 4483 4484 4485/* ------------------------------------------------------------------------ */ 4486/* Function: fr_derefrule */ 4487/* Returns: int - 0 == rule freed up, else rule not freed */ 4488/* Parameters: fr(I) - pointer to filter rule */ 4489/* */ 4490/* Decrement the reference counter to a rule by one. If it reaches zero, */ 4491/* free it and any associated storage space being used by it. */ 4492/* ------------------------------------------------------------------------ */ 4493int fr_derefrule(frp) 4494frentry_t **frp; 4495{ 4496 frentry_t *fr; 4497 4498 fr = *frp; 4499 4500 MUTEX_ENTER(&fr->fr_lock); 4501 fr->fr_ref--; 4502 if (fr->fr_ref == 0) { 4503 MUTEX_EXIT(&fr->fr_lock); 4504 MUTEX_DESTROY(&fr->fr_lock); 4505 4506#ifdef IPFILTER_LOOKUP 4507 if (fr->fr_type == FR_T_IPF && fr->fr_satype == FRI_LOOKUP) 4508 ip_lookup_deref(fr->fr_srctype, fr->fr_srcptr); 4509 if (fr->fr_type == FR_T_IPF && fr->fr_datype == FRI_LOOKUP) 4510 ip_lookup_deref(fr->fr_dsttype, fr->fr_dstptr); 4511#endif 4512 4513 if (fr->fr_dsize) { 4514 KFREES(fr->fr_data, fr->fr_dsize); 4515 } 4516 if ((fr->fr_flags & FR_COPIED) != 0) { 4517 KFREE(fr); 4518 return 0; 4519 } 4520 return 1; 4521 } else { 4522 MUTEX_EXIT(&fr->fr_lock); 4523 } 4524 *frp = NULL; 4525 return -1; 4526} 4527 4528 4529#ifdef IPFILTER_LOOKUP 4530/* ------------------------------------------------------------------------ */ 4531/* Function: fr_grpmapinit */ 4532/* Returns: int - 0 == success, else ESRCH because table entry not found*/ 4533/* Parameters: fr(I) - pointer to rule to find hash table for */ 4534/* */ 4535/* Looks for group hash table fr_arg and stores a pointer to it in fr_ptr. */ 4536/* fr_ptr is later used by fr_srcgrpmap and fr_dstgrpmap. */ 4537/* ------------------------------------------------------------------------ */ 4538static int fr_grpmapinit(fr) 4539frentry_t *fr; 4540{ 4541 char name[FR_GROUPLEN]; 4542 iphtable_t *iph; 4543 4544#if defined(SNPRINTF) && defined(_KERNEL) 4545 SNPRINTF(name, sizeof(name), "%d", fr->fr_arg); 4546#else 4547 (void) sprintf(name, "%d", fr->fr_arg); 4548#endif 4549 iph = fr_findhtable(IPL_LOGIPF, name); 4550 if (iph == NULL) 4551 return ESRCH; 4552 if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT)) 4553 return ESRCH; 4554 fr->fr_ptr = iph; 4555 return 0; 4556} 4557 4558 4559/* ------------------------------------------------------------------------ */ 4560/* Function: fr_srcgrpmap */ 4561/* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ 4562/* Parameters: fin(I) - pointer to packet information */ 4563/* passp(IO) - pointer to current/new filter decision (unused) */ 4564/* */ 4565/* Look for a rule group head in a hash table, using the source address as */ 4566/* the key, and descend into that group and continue matching rules against */ 4567/* the packet. */ 4568/* ------------------------------------------------------------------------ */ 4569frentry_t *fr_srcgrpmap(fin, passp) 4570fr_info_t *fin; 4571u_32_t *passp; 4572{ 4573 frgroup_t *fg; 4574 void *rval; 4575 4576 rval = fr_iphmfindgroup(fin->fin_fr->fr_ptr, &fin->fin_src); 4577 if (rval == NULL) 4578 return NULL; 4579 4580 fg = rval; 4581 fin->fin_fr = fg->fg_start; 4582 (void) fr_scanlist(fin, *passp); 4583 return fin->fin_fr; 4584} 4585 4586 4587/* ------------------------------------------------------------------------ */ 4588/* Function: fr_dstgrpmap */ 4589/* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ 4590/* Parameters: fin(I) - pointer to packet information */ 4591/* passp(IO) - pointer to current/new filter decision (unused) */ 4592/* */ 4593/* Look for a rule group head in a hash table, using the destination */ 4594/* address as the key, and descend into that group and continue matching */ 4595/* rules against the packet. */ 4596/* ------------------------------------------------------------------------ */ 4597frentry_t *fr_dstgrpmap(fin, passp) 4598fr_info_t *fin; 4599u_32_t *passp; 4600{ 4601 frgroup_t *fg; 4602 void *rval; 4603 4604 rval = fr_iphmfindgroup(fin->fin_fr->fr_ptr, &fin->fin_dst); 4605 if (rval == NULL) 4606 return NULL; 4607 4608 fg = rval; 4609 fin->fin_fr = fg->fg_start; 4610 (void) fr_scanlist(fin, *passp); 4611 return fin->fin_fr; 4612} 4613#endif /* IPFILTER_LOOKUP */ 4614 4615/* 4616 * Queue functions 4617 * =============== 4618 * These functions manage objects on queues for efficient timeouts. There are 4619 * a number of system defined queues as well as user defined timeouts. It is 4620 * expected that a lock is held in the domain in which the queue belongs 4621 * (i.e. either state or NAT) when calling any of these functions that prevents 4622 * fr_freetimeoutqueue() from being called at the same time as any other. 4623 */ 4624 4625 4626/* ------------------------------------------------------------------------ */ 4627/* Function: fr_addtimeoutqueue */ 4628/* Returns: struct ifqtq * - NULL if malloc fails, else pointer to */ 4629/* timeout queue with given interval. */ 4630/* Parameters: parent(I) - pointer to pointer to parent node of this list */ 4631/* of interface queues. */ 4632/* seconds(I) - timeout value in seconds for this queue. */ 4633/* */ 4634/* This routine first looks for a timeout queue that matches the interval */ 4635/* being requested. If it finds one, increments the reference counter and */ 4636/* returns a pointer to it. If none are found, it allocates a new one and */ 4637/* inserts it at the top of the list. */ 4638/* */ 4639/* Locking. */ 4640/* It is assumed that the caller of this function has an appropriate lock */ 4641/* held (exclusively) in the domain that encompases 'parent'. */ 4642/* ------------------------------------------------------------------------ */ 4643ipftq_t *fr_addtimeoutqueue(parent, seconds) 4644ipftq_t **parent; 4645u_int seconds; 4646{ 4647 ipftq_t *ifq; 4648 u_int period; 4649 4650 period = seconds * IPF_HZ_DIVIDE; 4651 4652 MUTEX_ENTER(&ipf_timeoutlock); 4653 for (ifq = *parent; ifq != NULL; ifq = ifq->ifq_next) { 4654 if (ifq->ifq_ttl == period) { 4655 /* 4656 * Reset the delete flag, if set, so the structure 4657 * gets reused rather than freed and reallocated. 4658 */ 4659 MUTEX_ENTER(&ifq->ifq_lock); 4660 ifq->ifq_flags &= ~IFQF_DELETE; 4661 ifq->ifq_ref++; 4662 MUTEX_EXIT(&ifq->ifq_lock); 4663 MUTEX_EXIT(&ipf_timeoutlock); 4664 4665 return ifq; 4666 } 4667 } 4668 4669 KMALLOC(ifq, ipftq_t *); 4670 if (ifq != NULL) { 4671 ifq->ifq_ttl = period; 4672 ifq->ifq_head = NULL; 4673 ifq->ifq_tail = &ifq->ifq_head; 4674 ifq->ifq_next = *parent; 4675 ifq->ifq_pnext = parent; 4676 ifq->ifq_ref = 1; 4677 ifq->ifq_flags = IFQF_USER; 4678 *parent = ifq; 4679 fr_userifqs++; 4680 MUTEX_NUKE(&ifq->ifq_lock); 4681 MUTEX_INIT(&ifq->ifq_lock, "ipftq mutex"); 4682 } 4683 MUTEX_EXIT(&ipf_timeoutlock); 4684 return ifq; 4685} 4686 4687 4688/* ------------------------------------------------------------------------ */ 4689/* Function: fr_deletetimeoutqueue */ 4690/* Returns: int - new reference count value of the timeout queue */ 4691/* Parameters: ifq(I) - timeout queue which is losing a reference. */ 4692/* Locks: ifq->ifq_lock */ 4693/* */ 4694/* This routine must be called when we're discarding a pointer to a timeout */ 4695/* queue object, taking care of the reference counter. */ 4696/* */ 4697/* Now that this just sets a DELETE flag, it requires the expire code to */ 4698/* check the list of user defined timeout queues and call the free function */ 4699/* below (currently commented out) to stop memory leaking. It is done this */ 4700/* way because the locking may not be sufficient to safely do a free when */ 4701/* this function is called. */ 4702/* ------------------------------------------------------------------------ */ 4703int fr_deletetimeoutqueue(ifq) 4704ipftq_t *ifq; 4705{ 4706 4707 ifq->ifq_ref--; 4708 if ((ifq->ifq_ref == 0) && ((ifq->ifq_flags & IFQF_USER) != 0)) { 4709 ifq->ifq_flags |= IFQF_DELETE; 4710 } 4711 4712 return ifq->ifq_ref; 4713} 4714 4715 4716/* ------------------------------------------------------------------------ */ 4717/* Function: fr_freetimeoutqueue */ 4718/* Parameters: ifq(I) - timeout queue which is losing a reference. */ 4719/* Returns: Nil */ 4720/* */ 4721/* Locking: */ 4722/* It is assumed that the caller of this function has an appropriate lock */ 4723/* held (exclusively) in the domain that encompases the callers "domain". */ 4724/* The ifq_lock for this structure should not be held. */ 4725/* */ 4726/* Remove a user definde timeout queue from the list of queues it is in and */ 4727/* tidy up after this is done. */ 4728/* ------------------------------------------------------------------------ */ 4729void fr_freetimeoutqueue(ifq) 4730ipftq_t *ifq; 4731{ 4732 4733 4734 if (((ifq->ifq_flags & IFQF_DELETE) == 0) || (ifq->ifq_ref != 0) || 4735 ((ifq->ifq_flags & IFQF_USER) == 0)) { 4736 printf("fr_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n", 4737 (u_long)ifq, ifq->ifq_flags, ifq->ifq_ttl, 4738 ifq->ifq_ref); 4739 return; 4740 } 4741 4742 /* 4743 * Remove from its position in the list. 4744 */ 4745 *ifq->ifq_pnext = ifq->ifq_next; 4746 if (ifq->ifq_next != NULL) 4747 ifq->ifq_next->ifq_pnext = ifq->ifq_pnext; 4748 4749 MUTEX_DESTROY(&ifq->ifq_lock); 4750 fr_userifqs--; 4751 KFREE(ifq); 4752} 4753 4754 4755/* ------------------------------------------------------------------------ */ 4756/* Function: fr_deletequeueentry */ 4757/* Returns: Nil */ 4758/* Parameters: tqe(I) - timeout queue entry to delete */ 4759/* ifq(I) - timeout queue to remove entry from */ 4760/* */ 4761/* Remove a tail queue entry from its queue and make it an orphan. */ 4762/* fr_deletetimeoutqueue is called to make sure the reference count on the */ 4763/* queue is correct. We can't, however, call fr_freetimeoutqueue because */ 4764/* the correct lock(s) may not be held that would make it safe to do so. */ 4765/* ------------------------------------------------------------------------ */ 4766void fr_deletequeueentry(tqe) 4767ipftqent_t *tqe; 4768{ 4769 ipftq_t *ifq; 4770 4771 ifq = tqe->tqe_ifq; 4772 if (ifq == NULL) 4773 return; 4774 4775 MUTEX_ENTER(&ifq->ifq_lock); 4776 4777 if (tqe->tqe_pnext != NULL) { 4778 *tqe->tqe_pnext = tqe->tqe_next; 4779 if (tqe->tqe_next != NULL) 4780 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 4781 else /* we must be the tail anyway */ 4782 ifq->ifq_tail = tqe->tqe_pnext; 4783 4784 tqe->tqe_pnext = NULL; 4785 tqe->tqe_ifq = NULL; 4786 } 4787 4788 (void) fr_deletetimeoutqueue(ifq); 4789 4790 MUTEX_EXIT(&ifq->ifq_lock); 4791} 4792 4793 4794/* ------------------------------------------------------------------------ */ 4795/* Function: fr_queuefront */ 4796/* Returns: Nil */ 4797/* Parameters: tqe(I) - pointer to timeout queue entry */ 4798/* */ 4799/* Move a queue entry to the front of the queue, if it isn't already there. */ 4800/* ------------------------------------------------------------------------ */ 4801void fr_queuefront(tqe) 4802ipftqent_t *tqe; 4803{ 4804 ipftq_t *ifq; 4805 4806 ifq = tqe->tqe_ifq; 4807 if (ifq == NULL) 4808 return; 4809 4810 MUTEX_ENTER(&ifq->ifq_lock); 4811 if (ifq->ifq_head != tqe) { 4812 *tqe->tqe_pnext = tqe->tqe_next; 4813 if (tqe->tqe_next) 4814 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 4815 else 4816 ifq->ifq_tail = tqe->tqe_pnext; 4817 4818 tqe->tqe_next = ifq->ifq_head; 4819 ifq->ifq_head->tqe_pnext = &tqe->tqe_next; 4820 ifq->ifq_head = tqe; 4821 tqe->tqe_pnext = &ifq->ifq_head; 4822 } 4823 MUTEX_EXIT(&ifq->ifq_lock); 4824} 4825 4826 4827/* ------------------------------------------------------------------------ */ 4828/* Function: fr_queueback */ 4829/* Returns: Nil */ 4830/* Parameters: tqe(I) - pointer to timeout queue entry */ 4831/* */ 4832/* Move a queue entry to the back of the queue, if it isn't already there. */ 4833/* ------------------------------------------------------------------------ */ 4834void fr_queueback(tqe) 4835ipftqent_t *tqe; 4836{ 4837 ipftq_t *ifq; 4838 4839 ifq = tqe->tqe_ifq; 4840 if (ifq == NULL) 4841 return; 4842 tqe->tqe_die = fr_ticks + ifq->ifq_ttl; 4843 4844 MUTEX_ENTER(&ifq->ifq_lock); 4845 if (tqe->tqe_next == NULL) { /* at the end already ? */ 4846 MUTEX_EXIT(&ifq->ifq_lock); 4847 return; 4848 } 4849 4850 /* 4851 * Remove from list 4852 */ 4853 *tqe->tqe_pnext = tqe->tqe_next; 4854 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 4855 4856 /* 4857 * Make it the last entry. 4858 */ 4859 tqe->tqe_next = NULL; 4860 tqe->tqe_pnext = ifq->ifq_tail; 4861 *ifq->ifq_tail = tqe; 4862 ifq->ifq_tail = &tqe->tqe_next; 4863 MUTEX_EXIT(&ifq->ifq_lock); 4864} 4865 4866 4867/* ------------------------------------------------------------------------ */ 4868/* Function: fr_queueappend */ 4869/* Returns: Nil */ 4870/* Parameters: tqe(I) - pointer to timeout queue entry */ 4871/* ifq(I) - pointer to timeout queue */ 4872/* parent(I) - owing object pointer */ 4873/* */ 4874/* Add a new item to this queue and put it on the very end. */ 4875/* ------------------------------------------------------------------------ */ 4876void fr_queueappend(tqe, ifq, parent) 4877ipftqent_t *tqe; 4878ipftq_t *ifq; 4879void *parent; 4880{ 4881 4882 MUTEX_ENTER(&ifq->ifq_lock); 4883 tqe->tqe_parent = parent; 4884 tqe->tqe_pnext = ifq->ifq_tail; 4885 *ifq->ifq_tail = tqe; 4886 ifq->ifq_tail = &tqe->tqe_next; 4887 tqe->tqe_next = NULL; 4888 tqe->tqe_ifq = ifq; 4889 tqe->tqe_die = fr_ticks + ifq->ifq_ttl; 4890 ifq->ifq_ref++; 4891 MUTEX_EXIT(&ifq->ifq_lock); 4892} 4893 4894 4895/* ------------------------------------------------------------------------ */ 4896/* Function: fr_movequeue */ 4897/* Returns: Nil */ 4898/* Parameters: tq(I) - pointer to timeout queue information */ 4899/* oifp(I) - old timeout queue entry was on */ 4900/* nifp(I) - new timeout queue to put entry on */ 4901/* */ 4902/* Move a queue entry from one timeout queue to another timeout queue. */ 4903/* If it notices that the current entry is already last and does not need */ 4904/* to move queue, the return. */ 4905/* ------------------------------------------------------------------------ */ 4906void fr_movequeue(tqe, oifq, nifq) 4907ipftqent_t *tqe; 4908ipftq_t *oifq, *nifq; 4909{ 4910 /* 4911 * Is the operation here going to be a no-op ? 4912 */ 4913 MUTEX_ENTER(&oifq->ifq_lock); 4914 if (oifq == nifq && *oifq->ifq_tail == tqe) { 4915 MUTEX_EXIT(&oifq->ifq_lock); 4916 return; 4917 } 4918 4919 /* 4920 * Remove from the old queue 4921 */ 4922 *tqe->tqe_pnext = tqe->tqe_next; 4923 if (tqe->tqe_next) 4924 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 4925 else 4926 oifq->ifq_tail = tqe->tqe_pnext; 4927 tqe->tqe_next = NULL; 4928 4929 /* 4930 * If we're moving from one queue to another, release the lock on the 4931 * old queue and get a lock on the new queue. For user defined queues, 4932 * if we're moving off it, call delete in case it can now be freed. 4933 */ 4934 if (oifq != nifq) { 4935 tqe->tqe_ifq = NULL; 4936 4937 (void) fr_deletetimeoutqueue(oifq); 4938 4939 MUTEX_EXIT(&oifq->ifq_lock); 4940 4941 MUTEX_ENTER(&nifq->ifq_lock); 4942 4943 tqe->tqe_ifq = nifq; 4944 nifq->ifq_ref++; 4945 } 4946 4947 /* 4948 * Add to the bottom of the new queue 4949 */ 4950 tqe->tqe_die = fr_ticks + nifq->ifq_ttl; 4951 tqe->tqe_pnext = nifq->ifq_tail; 4952 *nifq->ifq_tail = tqe; 4953 nifq->ifq_tail = &tqe->tqe_next; 4954 MUTEX_EXIT(&nifq->ifq_lock); 4955} 4956 4957 4958/* ------------------------------------------------------------------------ */ 4959/* Function: fr_updateipid */ 4960/* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 4961/* Parameters: fin(I) - pointer to packet information */ 4962/* */ 4963/* When we are doing NAT, change the IP of every packet to represent a */ 4964/* single sequence of packets coming from the host, hiding any host */ 4965/* specific sequencing that might otherwise be revealed. If the packet is */ 4966/* a fragment, then store the 'new' IPid in the fragment cache and look up */ 4967/* the fragment cache for non-leading fragments. If a non-leading fragment */ 4968/* has no match in the cache, return an error. */ 4969/* ------------------------------------------------------------------------ */ 4970static INLINE int fr_updateipid(fin) 4971fr_info_t *fin; 4972{ 4973 u_short id, ido, sums; 4974 u_32_t sumd, sum; 4975 ip_t *ip; 4976 4977 if (fin->fin_off != 0) { 4978 sum = fr_ipid_knownfrag(fin); 4979 if (sum == 0xffffffff) 4980 return -1; 4981 sum &= 0xffff; 4982 id = (u_short)sum; 4983 } else { 4984 id = fr_nextipid(fin); 4985 if (fin->fin_off == 0 && (fin->fin_flx & FI_FRAG) != 0) 4986 (void) fr_ipid_newfrag(fin, (u_32_t)id); 4987 } 4988 4989 ip = fin->fin_ip; 4990 ido = ntohs(ip->ip_id); 4991 if (id == ido) 4992 return 0; 4993 ip->ip_id = htons(id); 4994 CALC_SUMD(ido, id, sumd); /* DESTRUCTIVE MACRO! id,ido change */ 4995 sum = (~ntohs(ip->ip_sum)) & 0xffff; 4996 sum += sumd; 4997 sum = (sum >> 16) + (sum & 0xffff); 4998 sum = (sum >> 16) + (sum & 0xffff); 4999 sums = ~(u_short)sum; 5000 ip->ip_sum = htons(sums); 5001 return 0; 5002} 5003 5004 5005#ifdef NEED_FRGETIFNAME 5006/* ------------------------------------------------------------------------ */ 5007/* Function: fr_getifname */ 5008/* Returns: char * - pointer to interface name */ 5009/* Parameters: ifp(I) - pointer to network interface */ 5010/* buffer(O) - pointer to where to store interface name */ 5011/* */ 5012/* Constructs an interface name in the buffer passed. The buffer passed is */ 5013/* expected to be at least LIFNAMSIZ in bytes big. If buffer is passed in */ 5014/* as a NULL pointer then return a pointer to a static array. */ 5015/* ------------------------------------------------------------------------ */ 5016char *fr_getifname(ifp, buffer) 5017struct ifnet *ifp; 5018char *buffer; 5019{ 5020 static char namebuf[LIFNAMSIZ]; 5021# if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \ 5022 defined(__sgi) || defined(linux) || \ 5023 (defined(sun) && !defined(__SVR4) && !defined(__svr4__)) 5024 int unit, space; 5025 char temp[20]; 5026 char *s; 5027# endif 5028 5029 if (buffer == NULL) 5030 buffer = namebuf; 5031 (void) strncpy(buffer, ifp->if_name, LIFNAMSIZ); 5032 buffer[LIFNAMSIZ - 1] = '\0'; 5033# if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \ 5034 defined(__sgi) || \ 5035 (defined(sun) && !defined(__SVR4) && !defined(__svr4__)) 5036 for (s = buffer; *s; s++) 5037 ; 5038 unit = ifp->if_unit; 5039 space = LIFNAMSIZ - (s - buffer); 5040 if (space > 0) { 5041# if defined(SNPRINTF) && defined(_KERNEL) 5042 SNPRINTF(temp, sizeof(temp), "%d", unit); 5043# else 5044 (void) sprintf(temp, "%d", unit); 5045# endif 5046 (void) strncpy(s, temp, space); 5047 } 5048# endif 5049 return buffer; 5050} 5051#endif 5052 5053 5054/* ------------------------------------------------------------------------ */ 5055/* Function: fr_ioctlswitch */ 5056/* Returns: int - -1 continue processing, else ioctl return value */ 5057/* Parameters: unit(I) - device unit opened */ 5058/* data(I) - pointer to ioctl data */ 5059/* cmd(I) - ioctl command */ 5060/* mode(I) - mode value */ 5061/* */ 5062/* Based on the value of unit, call the appropriate ioctl handler or return */ 5063/* EIO if ipfilter is not running. Also checks if write perms are req'd */ 5064/* for the device in order to execute the ioctl. */ 5065/* ------------------------------------------------------------------------ */ 5066int fr_ioctlswitch(unit, data, cmd, mode) 5067int unit, mode; 5068ioctlcmd_t cmd; 5069void *data; 5070{ 5071 int error = 0; 5072 5073 switch (unit) 5074 { 5075 case IPL_LOGIPF : 5076 error = -1; 5077 break; 5078 case IPL_LOGNAT : 5079 if (fr_running > 0) 5080 error = fr_nat_ioctl(data, cmd, mode); 5081 else 5082 error = EIO; 5083 break; 5084 case IPL_LOGSTATE : 5085 if (fr_running > 0) 5086 error = fr_state_ioctl(data, cmd, mode); 5087 else 5088 error = EIO; 5089 break; 5090 case IPL_LOGAUTH : 5091 if (fr_running > 0) { 5092 if ((cmd == (ioctlcmd_t)SIOCADAFR) || 5093 (cmd == (ioctlcmd_t)SIOCRMAFR)) { 5094 if (!(mode & FWRITE)) { 5095 error = EPERM; 5096 } else { 5097 error = frrequest(unit, cmd, data, 5098 fr_active, 1); 5099 } 5100 } else { 5101 error = fr_auth_ioctl(data, cmd, mode); 5102 } 5103 } else 5104 error = EIO; 5105 break; 5106 case IPL_LOGSYNC : 5107#ifdef IPFILTER_SYNC 5108 if (fr_running > 0) 5109 error = fr_sync_ioctl(data, cmd, mode); 5110 else 5111#endif 5112 error = EIO; 5113 break; 5114 case IPL_LOGSCAN : 5115#ifdef IPFILTER_SCAN 5116 if (fr_running > 0) 5117 error = fr_scan_ioctl(data, cmd, mode); 5118 else 5119#endif 5120 error = EIO; 5121 break; 5122 case IPL_LOGLOOKUP : 5123#ifdef IPFILTER_LOOKUP 5124 if (fr_running > 0) 5125 error = ip_lookup_ioctl(data, cmd, mode); 5126 else 5127#endif 5128 error = EIO; 5129 break; 5130 default : 5131 error = EIO; 5132 break; 5133 } 5134 5135 return error; 5136} 5137 5138 5139/* 5140 * This array defines the expected size of objects coming into the kernel 5141 * for the various recognised object types. 5142 */ 5143#define NUM_OBJ_TYPES 14 5144 5145static int fr_objbytes[NUM_OBJ_TYPES][2] = { 5146 { 1, sizeof(struct frentry) }, /* frentry */ 5147 { 0, sizeof(struct friostat) }, 5148 { 0, sizeof(struct fr_info) }, 5149 { 0, sizeof(struct fr_authstat) }, 5150 { 0, sizeof(struct ipfrstat) }, 5151 { 0, sizeof(struct ipnat) }, 5152 { 0, sizeof(struct natstat) }, 5153 { 0, sizeof(struct ipstate_save) }, 5154 { 1, sizeof(struct nat_save) }, /* nat_save */ 5155 { 0, sizeof(struct natlookup) }, 5156 { 1, sizeof(struct ipstate) }, /* ipstate */ 5157 { 0, sizeof(struct ips_stat) }, 5158 { 0, sizeof(struct frauth) }, 5159 { 0, sizeof(struct ipftune) } 5160}; 5161 5162 5163/* ------------------------------------------------------------------------ */ 5164/* Function: fr_inobj */ 5165/* Returns: int - 0 = success, else failure */ 5166/* Parameters: data(I) - pointer to ioctl data */ 5167/* ptr(I) - pointer to store real data in */ 5168/* type(I) - type of structure being moved */ 5169/* */ 5170/* Copy in the contents of what the ipfobj_t points to. In future, we */ 5171/* add things to check for version numbers, sizes, etc, to make it backward */ 5172/* compatible at the ABI for user land. */ 5173/* ------------------------------------------------------------------------ */ 5174int fr_inobj(data, ptr, type) 5175void *data; 5176void *ptr; 5177int type; 5178{ 5179 ipfobj_t obj; 5180 int error = 0; 5181 5182 if ((type < 0) || (type > NUM_OBJ_TYPES-1)) 5183 return EINVAL; 5184 5185 BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj)); 5186 5187 if (obj.ipfo_type != type) 5188 return EINVAL; 5189 5190#ifndef IPFILTER_COMPAT 5191 if ((fr_objbytes[type][0] & 1) != 0) { 5192 if (obj.ipfo_size < fr_objbytes[type][1]) 5193 return EINVAL; 5194 } else if (obj.ipfo_size != fr_objbytes[type][1]) 5195 return EINVAL; 5196#else 5197 if (obj.ipfo_rev != IPFILTER_VERSION) 5198 /* XXX compatibility hook here */ 5199 ; 5200 if ((fr_objbytes[type][0] & 1) != 0) { 5201 if (obj.ipfo_size < fr_objbytes[type][1]) 5202 /* XXX compatibility hook here */ 5203 return EINVAL; 5204 } else if (obj.ipfo_size != fr_objbytes[type][1]) 5205 /* XXX compatibility hook here */ 5206 return EINVAL; 5207#endif 5208 5209 if ((fr_objbytes[type][0] & 1) != 0) { 5210 error = COPYIN((caddr_t)obj.ipfo_ptr, (caddr_t)ptr, 5211 fr_objbytes[type][1]); 5212 } else { 5213 error = COPYIN((caddr_t)obj.ipfo_ptr, (caddr_t)ptr, 5214 obj.ipfo_size); 5215 } 5216 return error; 5217} 5218 5219 5220/* ------------------------------------------------------------------------ */ 5221/* Function: fr_inobjsz */ 5222/* Returns: int - 0 = success, else failure */ 5223/* Parameters: data(I) - pointer to ioctl data */ 5224/* ptr(I) - pointer to store real data in */ 5225/* type(I) - type of structure being moved */ 5226/* sz(I) - size of data to copy */ 5227/* */ 5228/* As per fr_inobj, except the size of the object to copy in is passed in */ 5229/* but it must not be smaller than the size defined for the type and the */ 5230/* type must allow for varied sized objects. The extra requirement here is */ 5231/* that sz must match the size of the object being passed in - this is not */ 5232/* not possible nor required in fr_inobj(). */ 5233/* ------------------------------------------------------------------------ */ 5234int fr_inobjsz(data, ptr, type, sz) 5235void *data; 5236void *ptr; 5237int type, sz; 5238{ 5239 ipfobj_t obj; 5240 int error; 5241 5242 if ((type < 0) || (type > NUM_OBJ_TYPES-1)) 5243 return EINVAL; 5244 if (((fr_objbytes[type][0] & 1) == 0) || (sz < fr_objbytes[type][1])) 5245 return EINVAL; 5246 5247 BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj)); 5248 5249 if (obj.ipfo_type != type) 5250 return EINVAL; 5251 5252#ifndef IPFILTER_COMPAT 5253 if (obj.ipfo_size != sz) 5254 return EINVAL; 5255#else 5256 if (obj.ipfo_rev != IPFILTER_VERSION) 5257 /* XXX compatibility hook here */ 5258 ; 5259 if (obj.ipfo_size != sz) 5260 /* XXX compatibility hook here */ 5261 return EINVAL; 5262#endif 5263 5264 error = COPYIN((caddr_t)obj.ipfo_ptr, (caddr_t)ptr, sz); 5265 return error; 5266} 5267 5268 5269/* ------------------------------------------------------------------------ */ 5270/* Function: fr_outobjsz */ 5271/* Returns: int - 0 = success, else failure */ 5272/* Parameters: data(I) - pointer to ioctl data */ 5273/* ptr(I) - pointer to store real data in */ 5274/* type(I) - type of structure being moved */ 5275/* sz(I) - size of data to copy */ 5276/* */ 5277/* As per fr_outobj, except the size of the object to copy out is passed in */ 5278/* but it must not be smaller than the size defined for the type and the */ 5279/* type must allow for varied sized objects. The extra requirement here is */ 5280/* that sz must match the size of the object being passed in - this is not */ 5281/* not possible nor required in fr_outobj(). */ 5282/* ------------------------------------------------------------------------ */ 5283int fr_outobjsz(data, ptr, type, sz) 5284void *data; 5285void *ptr; 5286int type, sz; 5287{ 5288 ipfobj_t obj; 5289 int error; 5290 5291 if ((type < 0) || (type > NUM_OBJ_TYPES-1) || 5292 ((fr_objbytes[type][0] & 1) == 0) || 5293 (sz < fr_objbytes[type][1])) 5294 return EINVAL; 5295 5296 BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj)); 5297 5298 if (obj.ipfo_type != type) 5299 return EINVAL; 5300 5301#ifndef IPFILTER_COMPAT 5302 if (obj.ipfo_size != sz) 5303 return EINVAL; 5304#else 5305 if (obj.ipfo_rev != IPFILTER_VERSION) 5306 /* XXX compatibility hook here */ 5307 ; 5308 if (obj.ipfo_size != sz) 5309 /* XXX compatibility hook here */ 5310 return EINVAL; 5311#endif 5312 5313 error = COPYOUT((caddr_t)ptr, (caddr_t)obj.ipfo_ptr, sz); 5314 return error; 5315} 5316 5317 5318/* ------------------------------------------------------------------------ */ 5319/* Function: fr_outobj */ 5320/* Returns: int - 0 = success, else failure */ 5321/* Parameters: data(I) - pointer to ioctl data */ 5322/* ptr(I) - pointer to store real data in */ 5323/* type(I) - type of structure being moved */ 5324/* */ 5325/* Copy out the contents of what ptr is to where ipfobj points to. In */ 5326/* future, we add things to check for version numbers, sizes, etc, to make */ 5327/* it backward compatible at the ABI for user land. */ 5328/* ------------------------------------------------------------------------ */ 5329int fr_outobj(data, ptr, type) 5330void *data; 5331void *ptr; 5332int type; 5333{ 5334 ipfobj_t obj; 5335 int error; 5336 5337 if ((type < 0) || (type > NUM_OBJ_TYPES-1)) 5338 return EINVAL; 5339 5340 BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj)); 5341 5342 if (obj.ipfo_type != type) 5343 return EINVAL; 5344 5345#ifndef IPFILTER_COMPAT 5346 if ((fr_objbytes[type][0] & 1) != 0) { 5347 if (obj.ipfo_size < fr_objbytes[type][1]) 5348 return EINVAL; 5349 } else if (obj.ipfo_size != fr_objbytes[type][1]) 5350 return EINVAL; 5351#else 5352 if (obj.ipfo_rev != IPFILTER_VERSION) 5353 /* XXX compatibility hook here */ 5354 ; 5355 if ((fr_objbytes[type][0] & 1) != 0) { 5356 if (obj.ipfo_size < fr_objbytes[type][1]) 5357 /* XXX compatibility hook here */ 5358 return EINVAL; 5359 } else if (obj.ipfo_size != fr_objbytes[type][1]) 5360 /* XXX compatibility hook here */ 5361 return EINVAL; 5362#endif 5363 5364 error = COPYOUT((caddr_t)ptr, (caddr_t)obj.ipfo_ptr, obj.ipfo_size); 5365 return error; 5366} 5367 5368 5369/* ------------------------------------------------------------------------ */ 5370/* Function: fr_checkl4sum */ 5371/* Returns: int - 0 = good, -1 = bad, 1 = cannot check */ 5372/* Parameters: fin(I) - pointer to packet information */ 5373/* */ 5374/* If possible, calculate the layer 4 checksum for the packet. If this is */ 5375/* not possible, return without indicating a failure or success but in a */ 5376/* way that is ditinguishable. */ 5377/* ------------------------------------------------------------------------ */ 5378int fr_checkl4sum(fin) 5379fr_info_t *fin; 5380{ 5381 u_short sum, hdrsum, *csump; 5382 udphdr_t *udp; 5383 int dosum; 5384 5385 if ((fin->fin_flx & FI_NOCKSUM) != 0) 5386 return 0; 5387 5388 /* 5389 * If the TCP packet isn't a fragment, isn't too short and otherwise 5390 * isn't already considered "bad", then validate the checksum. If 5391 * this check fails then considered the packet to be "bad". 5392 */ 5393 if ((fin->fin_flx & (FI_FRAG|FI_SHORT|FI_BAD)) != 0) 5394 return 1; 5395 5396 csump = NULL; 5397 hdrsum = 0; 5398 dosum = 0; 5399 sum = 0; 5400 5401#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID) 5402 if (dohwcksum && ((*fin->fin_mp)->b_ick_flag == ICK_VALID)) { 5403 hdrsum = 0; 5404 sum = 0; 5405 } else { 5406#endif 5407 switch (fin->fin_p) 5408 { 5409 case IPPROTO_TCP : 5410 csump = &((tcphdr_t *)fin->fin_dp)->th_sum; 5411 dosum = 1; 5412 break; 5413 5414 case IPPROTO_UDP : 5415 udp = fin->fin_dp; 5416 if (udp->uh_sum != 0) { 5417 csump = &udp->uh_sum; 5418 dosum = 1; 5419 } 5420 break; 5421 5422 case IPPROTO_ICMP : 5423 csump = &((struct icmp *)fin->fin_dp)->icmp_cksum; 5424 dosum = 1; 5425 break; 5426 5427 default : 5428 return 1; 5429 /*NOTREACHED*/ 5430 } 5431 5432 if (csump != NULL) 5433 hdrsum = *csump; 5434 5435 if (dosum) 5436 sum = fr_cksum(fin->fin_m, fin->fin_ip, 5437 fin->fin_p, fin->fin_dp); 5438#if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) && defined(ICK_VALID) 5439 } 5440#endif 5441#if !defined(_KERNEL) 5442 if (sum == hdrsum) { 5443 FR_DEBUG(("checkl4sum: %hx == %hx\n", sum, hdrsum)); 5444 } else { 5445 FR_DEBUG(("checkl4sum: %hx != %hx\n", sum, hdrsum)); 5446 } 5447#endif 5448 if (hdrsum == sum) 5449 return 0; 5450 return -1; 5451} 5452 5453 5454/* ------------------------------------------------------------------------ */ 5455/* Function: fr_ifpfillv4addr */ 5456/* Returns: int - 0 = address update, -1 = address not updated */ 5457/* Parameters: atype(I) - type of network address update to perform */ 5458/* sin(I) - pointer to source of address information */ 5459/* mask(I) - pointer to source of netmask information */ 5460/* inp(I) - pointer to destination address store */ 5461/* inpmask(I) - pointer to destination netmask store */ 5462/* */ 5463/* Given a type of network address update (atype) to perform, copy */ 5464/* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ 5465/* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ 5466/* which case the operation fails. For all values of atype other than */ 5467/* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ 5468/* value. */ 5469/* ------------------------------------------------------------------------ */ 5470int fr_ifpfillv4addr(atype, sin, mask, inp, inpmask) 5471int atype; 5472struct sockaddr_in *sin, *mask; 5473struct in_addr *inp, *inpmask; 5474{ 5475 if (inpmask != NULL && atype != FRI_NETMASKED) 5476 inpmask->s_addr = 0xffffffff; 5477 5478 if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { 5479 if (atype == FRI_NETMASKED) { 5480 if (inpmask == NULL) 5481 return -1; 5482 inpmask->s_addr = mask->sin_addr.s_addr; 5483 } 5484 inp->s_addr = sin->sin_addr.s_addr & mask->sin_addr.s_addr; 5485 } else { 5486 inp->s_addr = sin->sin_addr.s_addr; 5487 } 5488 return 0; 5489} 5490 5491 5492#ifdef USE_INET6 5493/* ------------------------------------------------------------------------ */ 5494/* Function: fr_ifpfillv6addr */ 5495/* Returns: int - 0 = address update, -1 = address not updated */ 5496/* Parameters: atype(I) - type of network address update to perform */ 5497/* sin(I) - pointer to source of address information */ 5498/* mask(I) - pointer to source of netmask information */ 5499/* inp(I) - pointer to destination address store */ 5500/* inpmask(I) - pointer to destination netmask store */ 5501/* */ 5502/* Given a type of network address update (atype) to perform, copy */ 5503/* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ 5504/* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ 5505/* which case the operation fails. For all values of atype other than */ 5506/* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ 5507/* value. */ 5508/* ------------------------------------------------------------------------ */ 5509int fr_ifpfillv6addr(atype, sin, mask, inp, inpmask) 5510int atype; 5511struct sockaddr_in6 *sin, *mask; 5512struct in_addr *inp, *inpmask; 5513{ 5514 i6addr_t *src, *dst, *and, *dmask; 5515 5516 src = (i6addr_t *)&sin->sin6_addr; 5517 and = (i6addr_t *)&mask->sin6_addr; 5518 dst = (i6addr_t *)inp; 5519 dmask = (i6addr_t *)inpmask; 5520 5521 if (inpmask != NULL && atype != FRI_NETMASKED) { 5522 dmask->i6[0] = 0xffffffff; 5523 dmask->i6[1] = 0xffffffff; 5524 dmask->i6[2] = 0xffffffff; 5525 dmask->i6[3] = 0xffffffff; 5526 } 5527 5528 if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { 5529 if (atype == FRI_NETMASKED) { 5530 if (inpmask == NULL) 5531 return -1; 5532 dmask->i6[0] = and->i6[0]; 5533 dmask->i6[1] = and->i6[1]; 5534 dmask->i6[2] = and->i6[2]; 5535 dmask->i6[3] = and->i6[3]; 5536 } 5537 5538 dst->i6[0] = src->i6[0] & and->i6[0]; 5539 dst->i6[1] = src->i6[1] & and->i6[1]; 5540 dst->i6[2] = src->i6[2] & and->i6[2]; 5541 dst->i6[3] = src->i6[3] & and->i6[3]; 5542 } else { 5543 dst->i6[0] = src->i6[0]; 5544 dst->i6[1] = src->i6[1]; 5545 dst->i6[2] = src->i6[2]; 5546 dst->i6[3] = src->i6[3]; 5547 } 5548 return 0; 5549} 5550#endif 5551 5552 5553/* ------------------------------------------------------------------------ */ 5554/* Function: fr_matchtag */ 5555/* Returns: 0 == mismatch, 1 == match. */ 5556/* Parameters: tag1(I) - pointer to first tag to compare */ 5557/* tag2(I) - pointer to second tag to compare */ 5558/* */ 5559/* Returns true (non-zero) or false(0) if the two tag structures can be */ 5560/* considered to be a match or not match, respectively. The tag is 16 */ 5561/* bytes long (16 characters) but that is overlayed with 4 32bit ints so */ 5562/* compare the ints instead, for speed. tag1 is the master of the */ 5563/* comparison. This function should only be called with both tag1 and tag2 */ 5564/* as non-NULL pointers. */ 5565/* ------------------------------------------------------------------------ */ 5566int fr_matchtag(tag1, tag2) 5567ipftag_t *tag1, *tag2; 5568{ 5569 if (tag1 == tag2) 5570 return 1; 5571 5572 if ((tag1->ipt_num[0] == 0) && (tag2->ipt_num[0] == 0)) 5573 return 1; 5574 5575 if ((tag1->ipt_num[0] == tag2->ipt_num[0]) && 5576 (tag1->ipt_num[1] == tag2->ipt_num[1]) && 5577 (tag1->ipt_num[2] == tag2->ipt_num[2]) && 5578 (tag1->ipt_num[3] == tag2->ipt_num[3])) 5579 return 1; 5580 return 0; 5581} 5582 5583 5584/* ------------------------------------------------------------------------ */ 5585/* Function: fr_coalesce */ 5586/* Returns: 1 == success, -1 == failure, 0 == no change */ 5587/* Parameters: fin(I) - pointer to packet information */ 5588/* */ 5589/* Attempt to get all of the packet data into a single, contiguous buffer. */ 5590/* If this call returns a failure then the buffers have also been freed. */ 5591/* ------------------------------------------------------------------------ */ 5592int fr_coalesce(fin) 5593fr_info_t *fin; 5594{ 5595 if ((fin->fin_flx & FI_COALESCE) != 0) 5596 return 1; 5597 5598 /* 5599 * If the mbuf pointers indicate that there is no mbuf to work with, 5600 * return but do not indicate success or failure. 5601 */ 5602 if (fin->fin_m == NULL || fin->fin_mp == NULL) 5603 return 0; 5604 5605#if defined(_KERNEL) 5606 if (fr_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) { 5607 ATOMIC_INCL(fr_badcoalesces[fin->fin_out]); 5608# ifdef MENTAT 5609 FREE_MB_T(*fin->fin_mp); 5610# endif 5611 *fin->fin_mp = NULL; 5612 fin->fin_m = NULL; 5613 return -1; 5614 } 5615#else 5616 fin = fin; /* LINT */ 5617#endif 5618 return 1; 5619} 5620 5621 5622/* 5623 * The following table lists all of the tunable variables that can be 5624 * accessed via SIOCIPFGET/SIOCIPFSET/SIOCIPFGETNEXt. The format of each row 5625 * in the table below is as follows: 5626 * 5627 * pointer to value, name of value, minimum, maximum, size of the value's 5628 * container, value attribute flags 5629 * 5630 * For convienience, IPFT_RDONLY means the value is read-only, IPFT_WRDISABLED 5631 * means the value can only be written to when IPFilter is loaded but disabled. 5632 * The obvious implication is if neither of these are set then the value can be 5633 * changed at any time without harm. 5634 */ 5635ipftuneable_t ipf_tuneables[] = { 5636 /* filtering */ 5637 { { &fr_flags }, "fr_flags", 0, 0xffffffff, 5638 sizeof(fr_flags), 0 }, 5639 { { &fr_active }, "fr_active", 0, 0, 5640 sizeof(fr_active), IPFT_RDONLY }, 5641 { { &fr_control_forwarding }, "fr_control_forwarding", 0, 1, 5642 sizeof(fr_control_forwarding), 0 }, 5643 { { &fr_update_ipid }, "fr_update_ipid", 0, 1, 5644 sizeof(fr_update_ipid), 0 }, 5645 { { &fr_chksrc }, "fr_chksrc", 0, 1, 5646 sizeof(fr_chksrc), 0 }, 5647 { { &fr_pass }, "fr_pass", 0, 0xffffffff, 5648 sizeof(fr_pass), 0 }, 5649 /* state */ 5650 { { &fr_tcpidletimeout }, "fr_tcpidletimeout", 1, 0x7fffffff, 5651 sizeof(fr_tcpidletimeout), IPFT_WRDISABLED }, 5652 { { &fr_tcpclosewait }, "fr_tcpclosewait", 1, 0x7fffffff, 5653 sizeof(fr_tcpclosewait), IPFT_WRDISABLED }, 5654 { { &fr_tcplastack }, "fr_tcplastack", 1, 0x7fffffff, 5655 sizeof(fr_tcplastack), IPFT_WRDISABLED }, 5656 { { &fr_tcptimeout }, "fr_tcptimeout", 1, 0x7fffffff, 5657 sizeof(fr_tcptimeout), IPFT_WRDISABLED }, 5658 { { &fr_tcpclosed }, "fr_tcpclosed", 1, 0x7fffffff, 5659 sizeof(fr_tcpclosed), IPFT_WRDISABLED }, 5660 { { &fr_tcphalfclosed }, "fr_tcphalfclosed", 1, 0x7fffffff, 5661 sizeof(fr_tcphalfclosed), IPFT_WRDISABLED }, 5662 { { &fr_udptimeout }, "fr_udptimeout", 1, 0x7fffffff, 5663 sizeof(fr_udptimeout), IPFT_WRDISABLED }, 5664 { { &fr_udpacktimeout }, "fr_udpacktimeout", 1, 0x7fffffff, 5665 sizeof(fr_udpacktimeout), IPFT_WRDISABLED }, 5666 { { &fr_icmptimeout }, "fr_icmptimeout", 1, 0x7fffffff, 5667 sizeof(fr_icmptimeout), IPFT_WRDISABLED }, 5668 { { &fr_icmpacktimeout }, "fr_icmpacktimeout", 1, 0x7fffffff, 5669 sizeof(fr_icmpacktimeout), IPFT_WRDISABLED }, 5670 { { &fr_iptimeout }, "fr_iptimeout", 1, 0x7fffffff, 5671 sizeof(fr_iptimeout), IPFT_WRDISABLED }, 5672 { { &fr_statemax }, "fr_statemax", 1, 0x7fffffff, 5673 sizeof(fr_statemax), 0 }, 5674 { { &fr_statesize }, "fr_statesize", 1, 0x7fffffff, 5675 sizeof(fr_statesize), IPFT_WRDISABLED }, 5676 { { &fr_state_lock }, "fr_state_lock", 0, 1, 5677 sizeof(fr_state_lock), IPFT_RDONLY }, 5678 { { &fr_state_maxbucket }, "fr_state_maxbucket", 1, 0x7fffffff, 5679 sizeof(fr_state_maxbucket), IPFT_WRDISABLED }, 5680 { { &fr_state_maxbucket_reset }, "fr_state_maxbucket_reset", 0, 1, 5681 sizeof(fr_state_maxbucket_reset), IPFT_WRDISABLED }, 5682 { { &ipstate_logging }, "ipstate_logging", 0, 1, 5683 sizeof(ipstate_logging), 0 }, 5684 /* nat */ 5685 { { &fr_nat_lock }, "fr_nat_lock", 0, 1, 5686 sizeof(fr_nat_lock), IPFT_RDONLY }, 5687 { { &ipf_nattable_sz }, "ipf_nattable_sz", 1, 0x7fffffff, 5688 sizeof(ipf_nattable_sz), IPFT_WRDISABLED }, 5689 { { &ipf_nattable_max }, "ipf_nattable_max", 1, 0x7fffffff, 5690 sizeof(ipf_nattable_max), 0 }, 5691 { { &ipf_natrules_sz }, "ipf_natrules_sz", 1, 0x7fffffff, 5692 sizeof(ipf_natrules_sz), IPFT_WRDISABLED }, 5693 { { &ipf_rdrrules_sz }, "ipf_rdrrules_sz", 1, 0x7fffffff, 5694 sizeof(ipf_rdrrules_sz), IPFT_WRDISABLED }, 5695 { { &ipf_hostmap_sz }, "ipf_hostmap_sz", 1, 0x7fffffff, 5696 sizeof(ipf_hostmap_sz), IPFT_WRDISABLED }, 5697 { { &fr_nat_maxbucket }, "fr_nat_maxbucket", 1, 0x7fffffff, 5698 sizeof(fr_nat_maxbucket), IPFT_WRDISABLED }, 5699 { { &fr_nat_maxbucket_reset }, "fr_nat_maxbucket_reset", 0, 1, 5700 sizeof(fr_nat_maxbucket_reset), IPFT_WRDISABLED }, 5701 { { &nat_logging }, "nat_logging", 0, 1, 5702 sizeof(nat_logging), 0 }, 5703 { { &fr_defnatage }, "fr_defnatage", 1, 0x7fffffff, 5704 sizeof(fr_defnatage), IPFT_WRDISABLED }, 5705 { { &fr_defnatipage }, "fr_defnatipage", 1, 0x7fffffff, 5706 sizeof(fr_defnatipage), IPFT_WRDISABLED }, 5707 { { &fr_defnaticmpage }, "fr_defnaticmpage", 1, 0x7fffffff, 5708 sizeof(fr_defnaticmpage), IPFT_WRDISABLED }, 5709 /* frag */ 5710 { { &ipfr_size }, "ipfr_size", 1, 0x7fffffff, 5711 sizeof(ipfr_size), IPFT_WRDISABLED }, 5712 { { &fr_ipfrttl }, "fr_ipfrttl", 1, 0x7fffffff, 5713 sizeof(fr_ipfrttl), IPFT_WRDISABLED }, 5714#ifdef IPFILTER_LOG 5715 /* log */ 5716 { { &ipl_suppress }, "ipl_suppress", 0, 1, 5717 sizeof(ipl_suppress), 0 }, 5718 { { &ipl_buffer_sz }, "ipl_buffer_sz", 0, 0, 5719 sizeof(ipl_buffer_sz), IPFT_RDONLY }, 5720 { { &ipl_logmax }, "ipl_logmax", 0, 0x7fffffff, 5721 sizeof(ipl_logmax), IPFT_WRDISABLED }, 5722 { { &ipl_logall }, "ipl_logall", 0, 1, 5723 sizeof(ipl_logall), 0 }, 5724 { { &ipl_logsize }, "ipl_logsize", 0, 0x80000, 5725 sizeof(ipl_logsize), 0 }, 5726#endif 5727 { { NULL }, NULL, 0, 0 } 5728}; 5729 5730static ipftuneable_t *ipf_tunelist = NULL; 5731 5732 5733/* ------------------------------------------------------------------------ */ 5734/* Function: fr_findtunebycookie */ 5735/* Returns: NULL = search failed, else pointer to tune struct */ 5736/* Parameters: cookie(I) - cookie value to search for amongst tuneables */ 5737/* next(O) - pointer to place to store the cookie for the */ 5738/* "next" tuneable, if it is desired. */ 5739/* */ 5740/* This function is used to walk through all of the existing tunables with */ 5741/* successive calls. It searches the known tunables for the one which has */ 5742/* a matching value for "cookie" - ie its address. When returning a match, */ 5743/* the next one to be found may be returned inside next. */ 5744/* ------------------------------------------------------------------------ */ 5745static ipftuneable_t *fr_findtunebycookie(cookie, next) 5746void *cookie, **next; 5747{ 5748 ipftuneable_t *ta, **tap; 5749 5750 for (ta = ipf_tuneables; ta->ipft_name != NULL; ta++) 5751 if (ta == cookie) { 5752 if (next != NULL) { 5753 /* 5754 * If the next entry in the array has a name 5755 * present, then return a pointer to it for 5756 * where to go next, else return a pointer to 5757 * the dynaminc list as a key to search there 5758 * next. This facilitates a weak linking of 5759 * the two "lists" together. 5760 */ 5761 if ((ta + 1)->ipft_name != NULL) 5762 *next = ta + 1; 5763 else 5764 *next = &ipf_tunelist; 5765 } 5766 return ta; 5767 } 5768 5769 for (tap = &ipf_tunelist; (ta = *tap) != NULL; tap = &ta->ipft_next) 5770 if (tap == cookie) { 5771 if (next != NULL) 5772 *next = &ta->ipft_next; 5773 return ta; 5774 } 5775 5776 if (next != NULL) 5777 *next = NULL; 5778 return NULL; 5779} 5780 5781 5782/* ------------------------------------------------------------------------ */ 5783/* Function: fr_findtunebyname */ 5784/* Returns: NULL = search failed, else pointer to tune struct */ 5785/* Parameters: name(I) - name of the tuneable entry to find. */ 5786/* */ 5787/* Search the static array of tuneables and the list of dynamic tuneables */ 5788/* for an entry with a matching name. If we can find one, return a pointer */ 5789/* to the matching structure. */ 5790/* ------------------------------------------------------------------------ */ 5791static ipftuneable_t *fr_findtunebyname(name) 5792char *name; 5793{ 5794 ipftuneable_t *ta; 5795 5796 for (ta = ipf_tuneables; ta->ipft_name != NULL; ta++) 5797 if (!strcmp(ta->ipft_name, name)) { 5798 return ta; 5799 } 5800 5801 for (ta = ipf_tunelist; ta != NULL; ta = ta->ipft_next) 5802 if (!strcmp(ta->ipft_name, name)) { 5803 return ta; 5804 } 5805 5806 return NULL; 5807} 5808 5809 5810/* ------------------------------------------------------------------------ */ 5811/* Function: fr_addipftune */ 5812/* Returns: int - 0 == success, else failure */ 5813/* Parameters: newtune - pointer to new tune struct to add to tuneables */ 5814/* */ 5815/* Appends the tune structure pointer to by "newtune" to the end of the */ 5816/* current list of "dynamic" tuneable parameters. Once added, the owner */ 5817/* of the object is not expected to ever change "ipft_next". */ 5818/* ------------------------------------------------------------------------ */ 5819int fr_addipftune(newtune) 5820ipftuneable_t *newtune; 5821{ 5822 ipftuneable_t *ta, **tap; 5823 5824 ta = fr_findtunebyname(newtune->ipft_name); 5825 if (ta != NULL) 5826 return EEXIST; 5827 5828 for (tap = &ipf_tunelist; *tap != NULL; tap = &(*tap)->ipft_next) 5829 ; 5830 5831 newtune->ipft_next = NULL; 5832 *tap = newtune; 5833 return 0; 5834} 5835 5836 5837/* ------------------------------------------------------------------------ */ 5838/* Function: fr_delipftune */ 5839/* Returns: int - 0 == success, else failure */ 5840/* Parameters: oldtune - pointer to tune struct to remove from the list of */ 5841/* current dynamic tuneables */ 5842/* */ 5843/* Search for the tune structure, by pointer, in the list of those that are */ 5844/* dynamically added at run time. If found, adjust the list so that this */ 5845/* structure is no longer part of it. */ 5846/* ------------------------------------------------------------------------ */ 5847int fr_delipftune(oldtune) 5848ipftuneable_t *oldtune; 5849{ 5850 ipftuneable_t *ta, **tap; 5851 5852 for (tap = &ipf_tunelist; (ta = *tap) != NULL; tap = &ta->ipft_next) 5853 if (ta == oldtune) { 5854 *tap = oldtune->ipft_next; 5855 oldtune->ipft_next = NULL; 5856 return 0; 5857 } 5858 5859 return ESRCH; 5860} 5861 5862 5863/* ------------------------------------------------------------------------ */ 5864/* Function: fr_ipftune */ 5865/* Returns: int - 0 == success, else failure */ 5866/* Parameters: cmd(I) - ioctl command number */ 5867/* data(I) - pointer to ioctl data structure */ 5868/* */ 5869/* Implement handling of SIOCIPFGETNEXT, SIOCIPFGET and SIOCIPFSET. These */ 5870/* three ioctls provide the means to access and control global variables */ 5871/* within IPFilter, allowing (for example) timeouts and table sizes to be */ 5872/* changed without rebooting, reloading or recompiling. The initialisation */ 5873/* and 'destruction' routines of the various components of ipfilter are all */ 5874/* each responsible for handling their own values being too big. */ 5875/* ------------------------------------------------------------------------ */ 5876int fr_ipftune(cmd, data) 5877ioctlcmd_t cmd; 5878void *data; 5879{ 5880 ipftuneable_t *ta; 5881 ipftune_t tu; 5882 void *cookie; 5883 int error; 5884 5885 error = fr_inobj(data, &tu, IPFOBJ_TUNEABLE); 5886 if (error != 0) 5887 return error; 5888 5889 tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0'; 5890 cookie = tu.ipft_cookie; 5891 ta = NULL; 5892 5893 switch (cmd) 5894 { 5895 case SIOCIPFGETNEXT : 5896 /* 5897 * If cookie is non-NULL, assume it to be a pointer to the last 5898 * entry we looked at, so find it (if possible) and return a 5899 * pointer to the next one after it. The last entry in the 5900 * the table is a NULL entry, so when we get to it, set cookie 5901 * to NULL and return that, indicating end of list, erstwhile 5902 * if we come in with cookie set to NULL, we are starting anew 5903 * at the front of the list. 5904 */ 5905 if (cookie != NULL) { 5906 ta = fr_findtunebycookie(cookie, &tu.ipft_cookie); 5907 } else { 5908 ta = ipf_tuneables; 5909 tu.ipft_cookie = ta + 1; 5910 } 5911 if (ta != NULL) { 5912 /* 5913 * Entry found, but does the data pointed to by that 5914 * row fit in what we can return? 5915 */ 5916 if (ta->ipft_sz > sizeof(tu.ipft_un)) 5917 return EINVAL; 5918 5919 tu.ipft_vlong = 0; 5920 if (ta->ipft_sz == sizeof(u_long)) 5921 tu.ipft_vlong = *ta->ipft_plong; 5922 else if (ta->ipft_sz == sizeof(u_int)) 5923 tu.ipft_vint = *ta->ipft_pint; 5924 else if (ta->ipft_sz == sizeof(u_short)) 5925 tu.ipft_vshort = *ta->ipft_pshort; 5926 else if (ta->ipft_sz == sizeof(u_char)) 5927 tu.ipft_vchar = *ta->ipft_pchar; 5928 5929 tu.ipft_sz = ta->ipft_sz; 5930 tu.ipft_min = ta->ipft_min; 5931 tu.ipft_max = ta->ipft_max; 5932 tu.ipft_flags = ta->ipft_flags; 5933 bcopy(ta->ipft_name, tu.ipft_name, 5934 MIN(sizeof(tu.ipft_name), 5935 strlen(ta->ipft_name) + 1)); 5936 } 5937 error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE); 5938 break; 5939 5940 case SIOCIPFGET : 5941 case SIOCIPFSET : 5942 /* 5943 * Search by name or by cookie value for a particular entry 5944 * in the tuning paramter table. 5945 */ 5946 error = ESRCH; 5947 if (cookie != NULL) { 5948 ta = fr_findtunebycookie(cookie, NULL); 5949 if (ta != NULL) 5950 error = 0; 5951 } else if (tu.ipft_name[0] != '\0') { 5952 ta = fr_findtunebyname(tu.ipft_name); 5953 if (ta != NULL) 5954 error = 0; 5955 } 5956 if (error != 0) 5957 break; 5958 5959 if (cmd == (ioctlcmd_t)SIOCIPFGET) { 5960 /* 5961 * Fetch the tuning parameters for a particular value 5962 */ 5963 tu.ipft_vlong = 0; 5964 if (ta->ipft_sz == sizeof(u_long)) 5965 tu.ipft_vlong = *ta->ipft_plong; 5966 else if (ta->ipft_sz == sizeof(u_int)) 5967 tu.ipft_vint = *ta->ipft_pint; 5968 else if (ta->ipft_sz == sizeof(u_short)) 5969 tu.ipft_vshort = *ta->ipft_pshort; 5970 else if (ta->ipft_sz == sizeof(u_char)) 5971 tu.ipft_vchar = *ta->ipft_pchar; 5972 tu.ipft_cookie = ta; 5973 tu.ipft_sz = ta->ipft_sz; 5974 tu.ipft_min = ta->ipft_min; 5975 tu.ipft_max = ta->ipft_max; 5976 tu.ipft_flags = ta->ipft_flags; 5977 error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE); 5978 5979 } else if (cmd == (ioctlcmd_t)SIOCIPFSET) { 5980 /* 5981 * Set an internal parameter. The hard part here is 5982 * getting the new value safely and correctly out of 5983 * the kernel (given we only know its size, not type.) 5984 */ 5985 u_long in; 5986 5987 if (((ta->ipft_flags & IPFT_WRDISABLED) != 0) && 5988 (fr_running > 0)) { 5989 error = EBUSY; 5990 break; 5991 } 5992 5993 in = tu.ipft_vlong; 5994 if (in < ta->ipft_min || in > ta->ipft_max) { 5995 error = EINVAL; 5996 break; 5997 } 5998 5999 if (ta->ipft_sz == sizeof(u_long)) { 6000 tu.ipft_vlong = *ta->ipft_plong; 6001 *ta->ipft_plong = in; 6002 } else if (ta->ipft_sz == sizeof(u_int)) { 6003 tu.ipft_vint = *ta->ipft_pint; 6004 *ta->ipft_pint = (u_int)(in & 0xffffffff); 6005 } else if (ta->ipft_sz == sizeof(u_short)) { 6006 tu.ipft_vshort = *ta->ipft_pshort; 6007 *ta->ipft_pshort = (u_short)(in & 0xffff); 6008 } else if (ta->ipft_sz == sizeof(u_char)) { 6009 tu.ipft_vchar = *ta->ipft_pchar; 6010 *ta->ipft_pchar = (u_char)(in & 0xff); 6011 } 6012 error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE); 6013 } 6014 break; 6015 6016 default : 6017 error = EINVAL; 6018 break; 6019 } 6020 6021 return error; 6022} 6023 6024 6025/* ------------------------------------------------------------------------ */ 6026/* Function: fr_initialise */ 6027/* Returns: int - 0 == success, < 0 == failure */ 6028/* Parameters: None. */ 6029/* */ 6030/* Call of the initialise functions for all the various subsystems inside */ 6031/* of IPFilter. If any of them should fail, return immeadiately a failure */ 6032/* BUT do not try to recover from the error here. */ 6033/* ------------------------------------------------------------------------ */ 6034int fr_initialise() 6035{ 6036 int i; 6037 6038#ifdef IPFILTER_LOG 6039 i = fr_loginit(); 6040 if (i < 0) 6041 return -10 + i; 6042#endif 6043 i = fr_natinit(); 6044 if (i < 0) 6045 return -20 + i; 6046 6047 i = fr_stateinit(); 6048 if (i < 0) 6049 return -30 + i; 6050 6051 i = fr_authinit(); 6052 if (i < 0) 6053 return -40 + i; 6054 6055 i = fr_fraginit(); 6056 if (i < 0) 6057 return -50 + i; 6058 6059 i = appr_init(); 6060 if (i < 0) 6061 return -60 + i; 6062 6063#ifdef IPFILTER_SYNC 6064 i = ipfsync_init(); 6065 if (i < 0) 6066 return -70 + i; 6067#endif 6068#ifdef IPFILTER_SCAN 6069 i = ipsc_init(); 6070 if (i < 0) 6071 return -80 + i; 6072#endif 6073#ifdef IPFILTER_LOOKUP 6074 i = ip_lookup_init(); 6075 if (i < 0) 6076 return -90 + i; 6077#endif 6078#ifdef IPFILTER_COMPILED 6079 ipfrule_add(); 6080#endif 6081 return 0; 6082} 6083 6084 6085/* ------------------------------------------------------------------------ */ 6086/* Function: fr_deinitialise */ 6087/* Returns: None. */ 6088/* Parameters: None. */ 6089/* */ 6090/* Call all the various subsystem cleanup routines to deallocate memory or */ 6091/* destroy locks or whatever they've done that they need to now undo. */ 6092/* The order here IS important as there are some cross references of */ 6093/* internal data structures. */ 6094/* ------------------------------------------------------------------------ */ 6095void fr_deinitialise() 6096{ 6097 fr_fragunload(); 6098 fr_authunload(); 6099 fr_natunload(); 6100 fr_stateunload(); 6101#ifdef IPFILTER_SCAN 6102 fr_scanunload(); 6103#endif 6104 appr_unload(); 6105 6106#ifdef IPFILTER_COMPILED 6107 ipfrule_remove(); 6108#endif 6109 6110 (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE); 6111 (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE); 6112 (void) frflush(IPL_LOGCOUNT, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE); 6113 (void) frflush(IPL_LOGCOUNT, 0, FR_INQUE|FR_OUTQUE); 6114 6115#ifdef IPFILTER_LOOKUP 6116 ip_lookup_unload(); 6117#endif 6118 6119#ifdef IPFILTER_LOG 6120 fr_logunload(); 6121#endif 6122} 6123 6124 6125/* ------------------------------------------------------------------------ */ 6126/* Function: fr_zerostats */ 6127/* Returns: int - 0 = success, else failure */ 6128/* Parameters: data(O) - pointer to pointer for copying data back to */ 6129/* */ 6130/* Copies the current statistics out to userspace and then zero's the */ 6131/* current ones in the kernel. The lock is only held across the bzero() as */ 6132/* the copyout may result in paging (ie network activity.) */ 6133/* ------------------------------------------------------------------------ */ 6134int fr_zerostats(data) 6135caddr_t data; 6136{ 6137 friostat_t fio; 6138 int error; 6139 6140 fr_getstat(&fio); 6141 error = copyoutptr(&fio, data, sizeof(fio)); 6142 if (error) 6143 return EFAULT; 6144 6145 WRITE_ENTER(&ipf_mutex); 6146 bzero((char *)frstats, sizeof(*frstats) * 2); 6147 RWLOCK_EXIT(&ipf_mutex); 6148 6149 return 0; 6150} 6151 6152 6153/* ------------------------------------------------------------------------ */ 6154/* Function: fr_resolvedest */ 6155/* Returns: Nil */ 6156/* Parameters: fdp(IO) - pointer to destination information to resolve */ 6157/* v(I) - IP protocol version to match */ 6158/* */ 6159/* Looks up an interface name in the frdest structure pointed to by fdp and */ 6160/* if a matching name can be found for the particular IP protocol version */ 6161/* then store the interface pointer in the frdest struct. If no match is */ 6162/* found, then set the interface pointer to be -1 as NULL is considered to */ 6163/* indicate there is no information at all in the structure. */ 6164/* ------------------------------------------------------------------------ */ 6165void fr_resolvedest(fdp, v) 6166frdest_t *fdp; 6167int v; 6168{ 6169 void *ifp; 6170 6171 ifp = NULL; 6172 v = v; /* LINT */ 6173 6174 if (*fdp->fd_ifname != '\0') { 6175 ifp = GETIFP(fdp->fd_ifname, v); 6176 if (ifp == NULL) 6177 ifp = (void *)-1; 6178 } 6179 fdp->fd_ifp = ifp; 6180} 6181 6182 6183/* ------------------------------------------------------------------------ */ 6184/* Function: fr_icmp4errortype */ 6185/* Returns: int - 1 == success, 0 == failure */ 6186/* Parameters: icmptype(I) - ICMP type number */ 6187/* */ 6188/* Tests to see if the ICMP type number passed is an error type or not. */ 6189/* ------------------------------------------------------------------------ */ 6190int fr_icmp4errortype(icmptype) 6191int icmptype; 6192{ 6193 6194 switch (icmptype) 6195 { 6196 case ICMP_SOURCEQUENCH : 6197 case ICMP_PARAMPROB : 6198 case ICMP_REDIRECT : 6199 case ICMP_TIMXCEED : 6200 case ICMP_UNREACH : 6201 return 1; 6202 default: 6203 return 0; 6204 } 6205} 6206 6207 6208/* ------------------------------------------------------------------------ */ 6209/* Function: fr_resolvenic */ 6210/* Returns: void* - NULL = wildcard name, -1 = failed to find NIC, else */ 6211/* pointer to interface structure for NIC */ 6212/* Parameters: name(I) - complete interface name */ 6213/* v(I) - IP protocol version */ 6214/* */ 6215/* Look for a network interface structure that firstly has a matching name */ 6216/* to that passed in and that is also being used for that IP protocol */ 6217/* version (necessary on some platforms where there are separate listings */ 6218/* for both IPv4 and IPv6 on the same physical NIC. */ 6219/* */ 6220/* One might wonder why name gets terminated with a \0 byte in here. The */ 6221/* reason is an interface name could get into the kernel structures of ipf */ 6222/* in any number of ways and so long as they all use the same sized array */ 6223/* to put the name in, it makes sense to ensure it gets null terminated */ 6224/* before it is used for its intended purpose - finding its match in the */ 6225/* kernel's list of configured interfaces. */ 6226/* */ 6227/* NOTE: This SHOULD ONLY be used with IPFilter structures that have an */ 6228/* array for the name that is LIFNAMSIZ bytes (at least) in length. */ 6229/* ------------------------------------------------------------------------ */ 6230void *fr_resolvenic(name, v) 6231char *name; 6232int v; 6233{ 6234 void *nic; 6235 6236 if (name[0] == '\0') 6237 return NULL; 6238 6239 if ((name[1] == '\0') && ((name[0] == '-') || (name[0] == '*'))) { 6240 return NULL; 6241 } 6242 6243 name[LIFNAMSIZ - 1] = '\0'; 6244 6245 nic = GETIFP(name, v); 6246 if (nic == NULL) 6247 nic = (void *)-1; 6248 return nic; 6249} 6250