17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * Copyright (C) 1993-2003 by Darren Reed. 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * See the IPFILTER.LICENCE file for details on licencing. 5ab25eeb5Syz * 6de22af4eSJohn Ojemann * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 7*94bdecd9SRob Gulewich * 8*94bdecd9SRob Gulewich * Copyright (c) 2014, Joyent, Inc. All rights reserved. 97c478bd9Sstevel@tonic-gate */ 107c478bd9Sstevel@tonic-gate 117c478bd9Sstevel@tonic-gate #if defined(KERNEL) || defined(_KERNEL) 127c478bd9Sstevel@tonic-gate # undef KERNEL 137c478bd9Sstevel@tonic-gate # undef _KERNEL 147c478bd9Sstevel@tonic-gate # define KERNEL 1 157c478bd9Sstevel@tonic-gate # define _KERNEL 1 167c478bd9Sstevel@tonic-gate #endif 177c478bd9Sstevel@tonic-gate #include <sys/errno.h> 187c478bd9Sstevel@tonic-gate #include <sys/types.h> 197c478bd9Sstevel@tonic-gate #include <sys/param.h> 207c478bd9Sstevel@tonic-gate #include <sys/time.h> 217c478bd9Sstevel@tonic-gate #if defined(__NetBSD__) 227c478bd9Sstevel@tonic-gate # if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL) 237c478bd9Sstevel@tonic-gate # include "opt_ipfilter_log.h" 247c478bd9Sstevel@tonic-gate # endif 257c478bd9Sstevel@tonic-gate #endif 267c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && defined(__FreeBSD_version) && \ 277c478bd9Sstevel@tonic-gate (__FreeBSD_version >= 220000) 287c478bd9Sstevel@tonic-gate # if (__FreeBSD_version >= 400000) 297c478bd9Sstevel@tonic-gate # if !defined(IPFILTER_LKM) 307c478bd9Sstevel@tonic-gate # include "opt_inet6.h" 317c478bd9Sstevel@tonic-gate # endif 327c478bd9Sstevel@tonic-gate # if (__FreeBSD_version == 400019) 337c478bd9Sstevel@tonic-gate # define CSUM_DELAY_DATA 347c478bd9Sstevel@tonic-gate # endif 357c478bd9Sstevel@tonic-gate # endif 367c478bd9Sstevel@tonic-gate # include <sys/filio.h> 377c478bd9Sstevel@tonic-gate #else 387c478bd9Sstevel@tonic-gate # include <sys/ioctl.h> 397c478bd9Sstevel@tonic-gate #endif 40ab25eeb5Syz #if !defined(_AIX51) 41ab25eeb5Syz # include <sys/fcntl.h> 42ab25eeb5Syz #endif 437c478bd9Sstevel@tonic-gate #if defined(_KERNEL) 447c478bd9Sstevel@tonic-gate # include <sys/systm.h> 457c478bd9Sstevel@tonic-gate # include <sys/file.h> 467c478bd9Sstevel@tonic-gate #else 477c478bd9Sstevel@tonic-gate # include <stdio.h> 487c478bd9Sstevel@tonic-gate # include <string.h> 497c478bd9Sstevel@tonic-gate # include <stdlib.h> 50ab25eeb5Syz # include <stddef.h> 517c478bd9Sstevel@tonic-gate # include <sys/file.h> 527c478bd9Sstevel@tonic-gate # define _KERNEL 537c478bd9Sstevel@tonic-gate # ifdef __OpenBSD__ 547c478bd9Sstevel@tonic-gate struct file; 557c478bd9Sstevel@tonic-gate # endif 567c478bd9Sstevel@tonic-gate # include <sys/uio.h> 577c478bd9Sstevel@tonic-gate # undef _KERNEL 587c478bd9Sstevel@tonic-gate #endif 59ab25eeb5Syz #if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux) && \ 60ab25eeb5Syz !defined(linux) 617c478bd9Sstevel@tonic-gate # include <sys/mbuf.h> 627c478bd9Sstevel@tonic-gate #else 63ab25eeb5Syz # if !defined(linux) 64ab25eeb5Syz # include <sys/byteorder.h> 65ab25eeb5Syz # endif 667c478bd9Sstevel@tonic-gate # if (SOLARIS2 < 5) && defined(sun) 677c478bd9Sstevel@tonic-gate # include <sys/dditypes.h> 687c478bd9Sstevel@tonic-gate # endif 697c478bd9Sstevel@tonic-gate #endif 707c478bd9Sstevel@tonic-gate #ifdef __hpux 717c478bd9Sstevel@tonic-gate # define _NET_ROUTE_INCLUDED 727c478bd9Sstevel@tonic-gate #endif 73ab25eeb5Syz #if !defined(linux) 74ab25eeb5Syz # include <sys/protosw.h> 75ab25eeb5Syz #endif 767c478bd9Sstevel@tonic-gate #include <sys/socket.h> 777c478bd9Sstevel@tonic-gate #include <net/if.h> 787c478bd9Sstevel@tonic-gate #ifdef sun 797c478bd9Sstevel@tonic-gate # include <net/af.h> 807c478bd9Sstevel@tonic-gate #endif 81ab25eeb5Syz #if !defined(_KERNEL) && defined(__FreeBSD__) 82ab25eeb5Syz # include "radix_ipf.h" 83ab25eeb5Syz #endif 847c478bd9Sstevel@tonic-gate #include <net/route.h> 857c478bd9Sstevel@tonic-gate #include <netinet/in.h> 867c478bd9Sstevel@tonic-gate #include <netinet/in_systm.h> 877c478bd9Sstevel@tonic-gate #include <netinet/ip.h> 88ab25eeb5Syz #if !defined(linux) 89ab25eeb5Syz # include <netinet/ip_var.h> 90ab25eeb5Syz #endif 917c478bd9Sstevel@tonic-gate #if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */ 927c478bd9Sstevel@tonic-gate # include <sys/hashing.h> 937c478bd9Sstevel@tonic-gate # include <netinet/in_var.h> 947c478bd9Sstevel@tonic-gate #endif 957c478bd9Sstevel@tonic-gate #include <netinet/tcp.h> 96ab25eeb5Syz #if (!defined(__sgi) && !defined(AIX)) || defined(_KERNEL) 97ab25eeb5Syz # include <netinet/udp.h> 98ab25eeb5Syz # include <netinet/ip_icmp.h> 99ab25eeb5Syz #endif 1007c478bd9Sstevel@tonic-gate #ifdef __hpux 1017c478bd9Sstevel@tonic-gate # undef _NET_ROUTE_INCLUDED 1027c478bd9Sstevel@tonic-gate #endif 103ab25eeb5Syz #include "netinet/ip_compat.h" 1047c478bd9Sstevel@tonic-gate #ifdef USE_INET6 1057c478bd9Sstevel@tonic-gate # include <netinet/icmp6.h> 106ab25eeb5Syz # if !SOLARIS && defined(_KERNEL) && !defined(__osf__) && !defined(__hpux) 1077c478bd9Sstevel@tonic-gate # include <netinet6/in6_var.h> 1087c478bd9Sstevel@tonic-gate # endif 1097c478bd9Sstevel@tonic-gate #endif 1107c478bd9Sstevel@tonic-gate #include <netinet/tcpip.h> 1117c478bd9Sstevel@tonic-gate #include "netinet/ip_fil.h" 1127c478bd9Sstevel@tonic-gate #include "netinet/ip_nat.h" 1137c478bd9Sstevel@tonic-gate #include "netinet/ip_frag.h" 1147c478bd9Sstevel@tonic-gate #include "netinet/ip_state.h" 1157c478bd9Sstevel@tonic-gate #include "netinet/ip_proxy.h" 1167c478bd9Sstevel@tonic-gate #include "netinet/ip_auth.h" 117f4b3ec61Sdh #include "netinet/ipf_stack.h" 1187c478bd9Sstevel@tonic-gate #ifdef IPFILTER_SCAN 1197c478bd9Sstevel@tonic-gate # include "netinet/ip_scan.h" 1207c478bd9Sstevel@tonic-gate #endif 121ab25eeb5Syz #ifdef IPFILTER_SYNC 122ab25eeb5Syz # include "netinet/ip_sync.h" 123ab25eeb5Syz #endif 1247c478bd9Sstevel@tonic-gate #include "netinet/ip_pool.h" 1257c478bd9Sstevel@tonic-gate #include "netinet/ip_htable.h" 126ab25eeb5Syz #ifdef IPFILTER_COMPILED 127ab25eeb5Syz # include "netinet/ip_rules.h" 1287c478bd9Sstevel@tonic-gate #endif 129ab25eeb5Syz #if defined(IPFILTER_BPF) && defined(_KERNEL) 1307c478bd9Sstevel@tonic-gate # include <net/bpf.h> 1317c478bd9Sstevel@tonic-gate #endif 1327c478bd9Sstevel@tonic-gate #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 1337c478bd9Sstevel@tonic-gate # include <sys/malloc.h> 1347c478bd9Sstevel@tonic-gate # if defined(_KERNEL) && !defined(IPFILTER_LKM) 1357c478bd9Sstevel@tonic-gate # include "opt_ipfilter.h" 1367c478bd9Sstevel@tonic-gate # endif 1377c478bd9Sstevel@tonic-gate #endif 1387c478bd9Sstevel@tonic-gate #include "netinet/ipl.h" 139*94bdecd9SRob Gulewich #if defined(_KERNEL) 140*94bdecd9SRob Gulewich #include <sys/sunddi.h> 141*94bdecd9SRob Gulewich #endif 142ab25eeb5Syz /* END OF INCLUDES */ 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate #if !defined(lint) 1457c478bd9Sstevel@tonic-gate static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed"; 146ab25eeb5Syz static const char rcsid[] = "@(#)$Id: fil.c,v 2.243.2.64 2005/08/13 05:19:59 darrenr Exp $"; 1477c478bd9Sstevel@tonic-gate #endif 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate #ifndef _KERNEL 1507c478bd9Sstevel@tonic-gate # include "ipf.h" 1517c478bd9Sstevel@tonic-gate # include "ipt.h" 152ab25eeb5Syz # include "bpf-ipf.h" 1537c478bd9Sstevel@tonic-gate extern int opts; 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate # define FR_VERBOSE(verb_pr) verbose verb_pr 1567c478bd9Sstevel@tonic-gate # define FR_DEBUG(verb_pr) debug verb_pr 1577c478bd9Sstevel@tonic-gate #else /* #ifndef _KERNEL */ 1587c478bd9Sstevel@tonic-gate # define FR_VERBOSE(verb_pr) 1597c478bd9Sstevel@tonic-gate # define FR_DEBUG(verb_pr) 1607c478bd9Sstevel@tonic-gate #endif /* _KERNEL */ 1617c478bd9Sstevel@tonic-gate 1627c478bd9Sstevel@tonic-gate 163ab25eeb5Syz char ipfilter_version[] = IPL_VERSION; 164ab25eeb5Syz int fr_features = 0 165ab25eeb5Syz #ifdef IPFILTER_LKM 166ab25eeb5Syz | IPF_FEAT_LKM 1677c478bd9Sstevel@tonic-gate #endif 168ab25eeb5Syz #ifdef IPFILTER_LOG 169ab25eeb5Syz | IPF_FEAT_LOG 170ab25eeb5Syz #endif 171ab25eeb5Syz #ifdef IPFILTER_LOOKUP 172ab25eeb5Syz | IPF_FEAT_LOOKUP 173ab25eeb5Syz #endif 174ab25eeb5Syz #ifdef IPFILTER_BPF 175ab25eeb5Syz | IPF_FEAT_BPF 176ab25eeb5Syz #endif 177ab25eeb5Syz #ifdef IPFILTER_COMPILED 178ab25eeb5Syz | IPF_FEAT_COMPILED 179ab25eeb5Syz #endif 180ab25eeb5Syz #ifdef IPFILTER_CKSUM 181ab25eeb5Syz | IPF_FEAT_CKSUM 182ab25eeb5Syz #endif 183ab25eeb5Syz #ifdef IPFILTER_SYNC 184ab25eeb5Syz | IPF_FEAT_SYNC 185ab25eeb5Syz #endif 186ab25eeb5Syz #ifdef IPFILTER_SCAN 187ab25eeb5Syz | IPF_FEAT_SCAN 188ab25eeb5Syz #endif 189ab25eeb5Syz #ifdef USE_INET6 190ab25eeb5Syz | IPF_FEAT_IPV6 191ab25eeb5Syz #endif 192ab25eeb5Syz ; 1937c478bd9Sstevel@tonic-gate 194cbded9aeSdr #define IPF_BUMP(x) (x)++ 195cbded9aeSdr 196cbded9aeSdr static INLINE int fr_ipfcheck __P((fr_info_t *, frentry_t *, int)); 1977c478bd9Sstevel@tonic-gate static INLINE int fr_ipfcheck __P((fr_info_t *, frentry_t *, int)); 1987c478bd9Sstevel@tonic-gate static int fr_portcheck __P((frpcmp_t *, u_short *)); 199f4b3ec61Sdh static int frflushlist __P((int, minor_t, int *, frentry_t **, 200f4b3ec61Sdh ipf_stack_t *)); 2017c478bd9Sstevel@tonic-gate static ipfunc_t fr_findfunc __P((ipfunc_t)); 2027c478bd9Sstevel@tonic-gate static frentry_t *fr_firewall __P((fr_info_t *, u_32_t *)); 203f4b3ec61Sdh static int fr_funcinit __P((frentry_t *fr, ipf_stack_t *)); 204ab25eeb5Syz static INLINE void frpr_ah __P((fr_info_t *)); 2057663b816Sml static INLINE void frpr_esp __P((fr_info_t *)); 2067663b816Sml static INLINE void frpr_gre __P((fr_info_t *)); 2077c478bd9Sstevel@tonic-gate static INLINE void frpr_udp __P((fr_info_t *)); 2087c478bd9Sstevel@tonic-gate static INLINE void frpr_tcp __P((fr_info_t *)); 2097c478bd9Sstevel@tonic-gate static INLINE void frpr_icmp __P((fr_info_t *)); 2107c478bd9Sstevel@tonic-gate static INLINE void frpr_ipv4hdr __P((fr_info_t *)); 2117663b816Sml static INLINE int frpr_pullup __P((fr_info_t *, int)); 2127663b816Sml static INLINE void frpr_short __P((fr_info_t *, int)); 2137c478bd9Sstevel@tonic-gate static INLINE void frpr_tcpcommon __P((fr_info_t *)); 2147c478bd9Sstevel@tonic-gate static INLINE void frpr_udpcommon __P((fr_info_t *)); 2157c478bd9Sstevel@tonic-gate static INLINE int fr_updateipid __P((fr_info_t *)); 2167c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOOKUP 217f4b3ec61Sdh static int fr_grpmapinit __P((frentry_t *fr, ipf_stack_t *)); 218f4b3ec61Sdh static INLINE void *fr_resolvelookup __P((u_int, u_int, lookupfunc_t *, 219f4b3ec61Sdh ipf_stack_t *)); 2207c478bd9Sstevel@tonic-gate #endif 221f4b3ec61Sdh static void frsynclist __P((int, int, void *, char *, frentry_t *, 222f4b3ec61Sdh ipf_stack_t *)); 223381a2a9aSdr static void *fr_ifsync __P((int, int, char *, char *, 224f4b3ec61Sdh void *, void *, ipf_stack_t *)); 225f4b3ec61Sdh static ipftuneable_t *fr_findtunebyname __P((const char *, ipf_stack_t *)); 226f4b3ec61Sdh static ipftuneable_t *fr_findtunebycookie __P((void *, void **, ipf_stack_t *)); 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate /* 2297c478bd9Sstevel@tonic-gate * bit values for identifying presence of individual IP options 230ab25eeb5Syz * All of these tables should be ordered by increasing key value on the left 231ab25eeb5Syz * hand side to allow for binary searching of the array and include a trailer 232ab25eeb5Syz * with a 0 for the bitmask for linear searches to easily find the end with. 2337c478bd9Sstevel@tonic-gate */ 234ab25eeb5Syz const struct optlist ipopts[20] = { 2357c478bd9Sstevel@tonic-gate { IPOPT_NOP, 0x000001 }, 2367c478bd9Sstevel@tonic-gate { IPOPT_RR, 0x000002 }, 2377c478bd9Sstevel@tonic-gate { IPOPT_ZSU, 0x000004 }, 2387c478bd9Sstevel@tonic-gate { IPOPT_MTUP, 0x000008 }, 2397c478bd9Sstevel@tonic-gate { IPOPT_MTUR, 0x000010 }, 2407c478bd9Sstevel@tonic-gate { IPOPT_ENCODE, 0x000020 }, 2417c478bd9Sstevel@tonic-gate { IPOPT_TS, 0x000040 }, 2427c478bd9Sstevel@tonic-gate { IPOPT_TR, 0x000080 }, 2437c478bd9Sstevel@tonic-gate { IPOPT_SECURITY, 0x000100 }, 2447c478bd9Sstevel@tonic-gate { IPOPT_LSRR, 0x000200 }, 2457c478bd9Sstevel@tonic-gate { IPOPT_E_SEC, 0x000400 }, 2467c478bd9Sstevel@tonic-gate { IPOPT_CIPSO, 0x000800 }, 2477c478bd9Sstevel@tonic-gate { IPOPT_SATID, 0x001000 }, 2487c478bd9Sstevel@tonic-gate { IPOPT_SSRR, 0x002000 }, 2497c478bd9Sstevel@tonic-gate { IPOPT_ADDEXT, 0x004000 }, 2507c478bd9Sstevel@tonic-gate { IPOPT_VISA, 0x008000 }, 2517c478bd9Sstevel@tonic-gate { IPOPT_IMITD, 0x010000 }, 2527c478bd9Sstevel@tonic-gate { IPOPT_EIP, 0x020000 }, 2537c478bd9Sstevel@tonic-gate { IPOPT_FINN, 0x040000 }, 2547c478bd9Sstevel@tonic-gate { 0, 0x000000 } 2557c478bd9Sstevel@tonic-gate }; 2567c478bd9Sstevel@tonic-gate 2577c478bd9Sstevel@tonic-gate #ifdef USE_INET6 2587c478bd9Sstevel@tonic-gate struct optlist ip6exthdr[] = { 2597c478bd9Sstevel@tonic-gate { IPPROTO_HOPOPTS, 0x000001 }, 2607663b816Sml { IPPROTO_IPV6, 0x000002 }, 2617663b816Sml { IPPROTO_ROUTING, 0x000004 }, 2627663b816Sml { IPPROTO_FRAGMENT, 0x000008 }, 2637663b816Sml { IPPROTO_ESP, 0x000010 }, 2647663b816Sml { IPPROTO_AH, 0x000020 }, 2657663b816Sml { IPPROTO_NONE, 0x000040 }, 2667663b816Sml { IPPROTO_DSTOPTS, 0x000080 }, 2677663b816Sml { 0, 0 } 2687c478bd9Sstevel@tonic-gate }; 2697c478bd9Sstevel@tonic-gate #endif 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate struct optlist tcpopts[] = { 2727c478bd9Sstevel@tonic-gate { TCPOPT_NOP, 0x000001 }, 2737c478bd9Sstevel@tonic-gate { TCPOPT_MAXSEG, 0x000002 }, 2747c478bd9Sstevel@tonic-gate { TCPOPT_WINDOW, 0x000004 }, 2757c478bd9Sstevel@tonic-gate { TCPOPT_SACK_PERMITTED, 0x000008 }, 2767c478bd9Sstevel@tonic-gate { TCPOPT_SACK, 0x000010 }, 2777c478bd9Sstevel@tonic-gate { TCPOPT_TIMESTAMP, 0x000020 }, 2787c478bd9Sstevel@tonic-gate { 0, 0x000000 } 2797c478bd9Sstevel@tonic-gate }; 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate /* 2827c478bd9Sstevel@tonic-gate * bit values for identifying presence of individual IP security options 2837c478bd9Sstevel@tonic-gate */ 284ab25eeb5Syz const struct optlist secopt[8] = { 2857c478bd9Sstevel@tonic-gate { IPSO_CLASS_RES4, 0x01 }, 2867c478bd9Sstevel@tonic-gate { IPSO_CLASS_TOPS, 0x02 }, 2877c478bd9Sstevel@tonic-gate { IPSO_CLASS_SECR, 0x04 }, 2887c478bd9Sstevel@tonic-gate { IPSO_CLASS_RES3, 0x08 }, 2897c478bd9Sstevel@tonic-gate { IPSO_CLASS_CONF, 0x10 }, 2907c478bd9Sstevel@tonic-gate { IPSO_CLASS_UNCL, 0x20 }, 2917c478bd9Sstevel@tonic-gate { IPSO_CLASS_RES2, 0x40 }, 2927c478bd9Sstevel@tonic-gate { IPSO_CLASS_RES1, 0x80 } 2937c478bd9Sstevel@tonic-gate }; 2947c478bd9Sstevel@tonic-gate 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate /* 2977c478bd9Sstevel@tonic-gate * Table of functions available for use with call rules. 2987c478bd9Sstevel@tonic-gate */ 2997c478bd9Sstevel@tonic-gate static ipfunc_resolve_t fr_availfuncs[] = { 3007c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOOKUP 3017c478bd9Sstevel@tonic-gate { "fr_srcgrpmap", fr_srcgrpmap, fr_grpmapinit }, 3027c478bd9Sstevel@tonic-gate { "fr_dstgrpmap", fr_dstgrpmap, fr_grpmapinit }, 3037c478bd9Sstevel@tonic-gate #endif 3047c478bd9Sstevel@tonic-gate { "", NULL } 3057c478bd9Sstevel@tonic-gate }; 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate 308ea8244dcSJohn Ojemann /* 309ea8244dcSJohn Ojemann * Below we declare a list of constants used only by the ipf_extraflush() 310ea8244dcSJohn Ojemann * routine. We are placing it here, instead of in ipf_extraflush() itself, 311ea8244dcSJohn Ojemann * because we want to make it visible to tools such as mdb, nm etc., so the 312ea8244dcSJohn Ojemann * values can easily be altered during debugging. 313ea8244dcSJohn Ojemann */ 314ea8244dcSJohn Ojemann static const int idletime_tab[] = { 315ea8244dcSJohn Ojemann IPF_TTLVAL(30), /* 30 seconds */ 316ea8244dcSJohn Ojemann IPF_TTLVAL(1800), /* 30 minutes */ 317ea8244dcSJohn Ojemann IPF_TTLVAL(43200), /* 12 hours */ 318ea8244dcSJohn Ojemann IPF_TTLVAL(345600), /* 4 days */ 319ea8244dcSJohn Ojemann }; 320ea8244dcSJohn Ojemann 321ea8244dcSJohn Ojemann 3227c478bd9Sstevel@tonic-gate /* 3237c478bd9Sstevel@tonic-gate * The next section of code is a a collection of small routines that set 3247c478bd9Sstevel@tonic-gate * fields in the fr_info_t structure passed based on properties of the 3257c478bd9Sstevel@tonic-gate * current packet. There are different routines for the same protocol 3267c478bd9Sstevel@tonic-gate * for each of IPv4 and IPv6. Adding a new protocol, for which there 3277c478bd9Sstevel@tonic-gate * will "special" inspection for setup, is now more easily done by adding 3287c478bd9Sstevel@tonic-gate * a new routine and expanding the frpr_ipinit*() function rather than by 3297c478bd9Sstevel@tonic-gate * adding more code to a growing switch statement. 3307c478bd9Sstevel@tonic-gate */ 3317c478bd9Sstevel@tonic-gate #ifdef USE_INET6 332ab25eeb5Syz static INLINE int frpr_ah6 __P((fr_info_t *)); 333ab25eeb5Syz static INLINE void frpr_esp6 __P((fr_info_t *)); 334ab25eeb5Syz static INLINE void frpr_gre6 __P((fr_info_t *)); 3357c478bd9Sstevel@tonic-gate static INLINE void frpr_udp6 __P((fr_info_t *)); 3367c478bd9Sstevel@tonic-gate static INLINE void frpr_tcp6 __P((fr_info_t *)); 3377c478bd9Sstevel@tonic-gate static INLINE void frpr_icmp6 __P((fr_info_t *)); 33833f2fefdSDarren Reed static INLINE void frpr_ipv6hdr __P((fr_info_t *)); 3397c478bd9Sstevel@tonic-gate static INLINE void frpr_short6 __P((fr_info_t *, int)); 3407663b816Sml static INLINE int frpr_hopopts6 __P((fr_info_t *)); 3417663b816Sml static INLINE int frpr_routing6 __P((fr_info_t *)); 3427663b816Sml static INLINE int frpr_dstopts6 __P((fr_info_t *)); 3437663b816Sml static INLINE int frpr_fragment6 __P((fr_info_t *)); 344ab25eeb5Syz static INLINE int frpr_ipv6exthdr __P((fr_info_t *, int, int)); 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate 3477c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 3487c478bd9Sstevel@tonic-gate /* Function: frpr_short6 */ 3497c478bd9Sstevel@tonic-gate /* Returns: void */ 3507c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 3517c478bd9Sstevel@tonic-gate /* */ 3527c478bd9Sstevel@tonic-gate /* IPv6 Only */ 3537c478bd9Sstevel@tonic-gate /* This is function enforces the 'is a packet too short to be legit' rule */ 354ab25eeb5Syz /* for IPv6 and marks the packet with FI_SHORT if so. See function comment */ 355ab25eeb5Syz /* for frpr_short() for more details. */ 3567c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 357ab25eeb5Syz static INLINE void frpr_short6(fin, xmin) 3587c478bd9Sstevel@tonic-gate fr_info_t *fin; 359ab25eeb5Syz int xmin; 3607c478bd9Sstevel@tonic-gate { 3617c478bd9Sstevel@tonic-gate 362ab25eeb5Syz if (fin->fin_dlen < xmin) 363ab25eeb5Syz fin->fin_flx |= FI_SHORT; 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 3687c478bd9Sstevel@tonic-gate /* Function: frpr_ipv6hdr */ 36933f2fefdSDarren Reed /* Returns: Nil */ 3707c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 3717c478bd9Sstevel@tonic-gate /* */ 3727c478bd9Sstevel@tonic-gate /* IPv6 Only */ 3737c478bd9Sstevel@tonic-gate /* Copy values from the IPv6 header into the fr_info_t struct and call the */ 3747c478bd9Sstevel@tonic-gate /* per-protocol analyzer if it exists. */ 3757c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 37633f2fefdSDarren Reed static INLINE void frpr_ipv6hdr(fin) 3777c478bd9Sstevel@tonic-gate fr_info_t *fin; 3787c478bd9Sstevel@tonic-gate { 3797c478bd9Sstevel@tonic-gate ip6_t *ip6 = (ip6_t *)fin->fin_ip; 380ab25eeb5Syz int p, go = 1, i, hdrcount; 3817c478bd9Sstevel@tonic-gate fr_ip_t *fi = &fin->fin_fi; 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate fin->fin_off = 0; 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate fi->fi_tos = 0; 3867c478bd9Sstevel@tonic-gate fi->fi_optmsk = 0; 3877c478bd9Sstevel@tonic-gate fi->fi_secmsk = 0; 3887c478bd9Sstevel@tonic-gate fi->fi_auth = 0; 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate p = ip6->ip6_nxt; 3917c478bd9Sstevel@tonic-gate fi->fi_ttl = ip6->ip6_hlim; 3927c478bd9Sstevel@tonic-gate fi->fi_src.in6 = ip6->ip6_src; 3937c478bd9Sstevel@tonic-gate fi->fi_dst.in6 = ip6->ip6_dst; 3947663b816Sml fin->fin_id = 0; 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate hdrcount = 0; 3977663b816Sml while (go && !(fin->fin_flx & (FI_BAD|FI_SHORT))) { 3987c478bd9Sstevel@tonic-gate switch (p) 3997c478bd9Sstevel@tonic-gate { 4007c478bd9Sstevel@tonic-gate case IPPROTO_UDP : 4017c478bd9Sstevel@tonic-gate frpr_udp6(fin); 4027c478bd9Sstevel@tonic-gate go = 0; 4037c478bd9Sstevel@tonic-gate break; 4047663b816Sml 4057c478bd9Sstevel@tonic-gate case IPPROTO_TCP : 4067c478bd9Sstevel@tonic-gate frpr_tcp6(fin); 4077c478bd9Sstevel@tonic-gate go = 0; 4087c478bd9Sstevel@tonic-gate break; 4097663b816Sml 4107c478bd9Sstevel@tonic-gate case IPPROTO_ICMPV6 : 4117c478bd9Sstevel@tonic-gate frpr_icmp6(fin); 4127c478bd9Sstevel@tonic-gate go = 0; 4137c478bd9Sstevel@tonic-gate break; 4147663b816Sml 4157663b816Sml case IPPROTO_GRE : 416ab25eeb5Syz frpr_gre6(fin); 4177663b816Sml go = 0; 4187663b816Sml break; 4197663b816Sml 4207c478bd9Sstevel@tonic-gate case IPPROTO_HOPOPTS : 4217c478bd9Sstevel@tonic-gate /* 422ab25eeb5Syz * hop by hop ext header is only allowed 423ab25eeb5Syz * right after IPv6 header. 4247c478bd9Sstevel@tonic-gate */ 425ab25eeb5Syz if (hdrcount != 0) { 4267663b816Sml fin->fin_flx |= FI_BAD; 427ab25eeb5Syz p = IPPROTO_NONE; 428ab25eeb5Syz } else { 429ab25eeb5Syz p = frpr_hopopts6(fin); 4307c478bd9Sstevel@tonic-gate } 4317c478bd9Sstevel@tonic-gate break; 4327663b816Sml 4337c478bd9Sstevel@tonic-gate case IPPROTO_DSTOPTS : 4347663b816Sml p = frpr_dstopts6(fin); 4357c478bd9Sstevel@tonic-gate break; 4367663b816Sml 4377c478bd9Sstevel@tonic-gate case IPPROTO_ROUTING : 4387663b816Sml p = frpr_routing6(fin); 4397c478bd9Sstevel@tonic-gate break; 4407663b816Sml 441ab25eeb5Syz case IPPROTO_AH : 442ab25eeb5Syz p = frpr_ah6(fin); 443ab25eeb5Syz break; 444ab25eeb5Syz 4457c478bd9Sstevel@tonic-gate case IPPROTO_ESP : 446ab25eeb5Syz frpr_esp6(fin); 4477663b816Sml go = 0; 4487663b816Sml break; 4497663b816Sml 450ab25eeb5Syz case IPPROTO_IPV6 : 4517663b816Sml for (i = 0; ip6exthdr[i].ol_bit != 0; i++) 4527663b816Sml if (ip6exthdr[i].ol_val == p) { 453ab25eeb5Syz fin->fin_flx |= ip6exthdr[i].ol_bit; 4547c478bd9Sstevel@tonic-gate break; 4557663b816Sml } 4567c478bd9Sstevel@tonic-gate go = 0; 4577c478bd9Sstevel@tonic-gate break; 4587663b816Sml 459ab25eeb5Syz case IPPROTO_NONE : 4607c478bd9Sstevel@tonic-gate go = 0; 4617c478bd9Sstevel@tonic-gate break; 4627663b816Sml 4637c478bd9Sstevel@tonic-gate case IPPROTO_FRAGMENT : 464ab25eeb5Syz p = frpr_fragment6(fin); 465ab25eeb5Syz if (fin->fin_off != 0) /* Not the first frag */ 4667663b816Sml go = 0; 4677663b816Sml break; 4687663b816Sml 4697c478bd9Sstevel@tonic-gate default : 4707c478bd9Sstevel@tonic-gate go = 0; 4717c478bd9Sstevel@tonic-gate break; 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate hdrcount++; 4747663b816Sml 475ab25eeb5Syz /* 476ab25eeb5Syz * It is important to note that at this point, for the 477ab25eeb5Syz * extension headers (go != 0), the entire header may not have 478ab25eeb5Syz * been pulled up when the code gets to this point. This is 479ab25eeb5Syz * only done for "go != 0" because the other header handlers 480ab25eeb5Syz * will all pullup their complete header. The other indicator 481ab25eeb5Syz * of an incomplete packet is that this was just an extension 482ab25eeb5Syz * header. 483ab25eeb5Syz */ 484ab25eeb5Syz if ((go != 0) && (p != IPPROTO_NONE) && 485ab25eeb5Syz (frpr_pullup(fin, 0) == -1)) { 486ab25eeb5Syz p = IPPROTO_NONE; 487ab25eeb5Syz go = 0; 488ab25eeb5Syz } 489ab25eeb5Syz } 4907663b816Sml fi->fi_p = p; 4917c478bd9Sstevel@tonic-gate } 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 495ab25eeb5Syz /* Function: frpr_ipv6exthdr */ 4967663b816Sml /* Returns: int - value of the next header or IPPROTO_NONE if error */ 497ab25eeb5Syz /* Parameters: fin(I) - pointer to packet information */ 498ab25eeb5Syz /* multiple(I) - flag indicating yes/no if multiple occurances */ 499ab25eeb5Syz /* of this extension header are allowed. */ 500ab25eeb5Syz /* proto(I) - protocol number for this extension header */ 5017c478bd9Sstevel@tonic-gate /* */ 5027c478bd9Sstevel@tonic-gate /* IPv6 Only */ 50372680cf5SDarren Reed /* This function expects to find an IPv6 extension header at fin_dp. */ 50472680cf5SDarren Reed /* There must be at least 8 bytes of data at fin_dp for there to be a valid */ 50572680cf5SDarren Reed /* extension header present. If a good one is found, fin_dp is advanced to */ 50672680cf5SDarren Reed /* point at the first piece of data after the extension header, fin_exthdr */ 50772680cf5SDarren Reed /* points to the start of the extension header and the "protocol" of the */ 50872680cf5SDarren Reed /* *NEXT* header is returned. */ 5097c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 510ab25eeb5Syz static INLINE int frpr_ipv6exthdr(fin, multiple, proto) 5117c478bd9Sstevel@tonic-gate fr_info_t *fin; 512ab25eeb5Syz int multiple, proto; 5137c478bd9Sstevel@tonic-gate { 5147c478bd9Sstevel@tonic-gate struct ip6_ext *hdr; 5157c478bd9Sstevel@tonic-gate u_short shift; 5167c478bd9Sstevel@tonic-gate int i; 5177c478bd9Sstevel@tonic-gate 5187c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_V6EXTHDR; 5197c478bd9Sstevel@tonic-gate 520ab25eeb5Syz /* 8 is default length of extension hdr */ 521ab25eeb5Syz if ((fin->fin_dlen - 8) < 0) { 522ab25eeb5Syz fin->fin_flx |= FI_SHORT; 5237663b816Sml return IPPROTO_NONE; 524ab25eeb5Syz } 5257663b816Sml 5267663b816Sml if (frpr_pullup(fin, 8) == -1) 5277663b816Sml return IPPROTO_NONE; 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate hdr = fin->fin_dp; 5307c478bd9Sstevel@tonic-gate shift = 8 + (hdr->ip6e_len << 3); 5317c478bd9Sstevel@tonic-gate if (shift > fin->fin_dlen) { /* Nasty extension header length? */ 5327c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_BAD; 5337663b816Sml return IPPROTO_NONE; 5347c478bd9Sstevel@tonic-gate } 5357c478bd9Sstevel@tonic-gate 5367663b816Sml for (i = 0; ip6exthdr[i].ol_bit != 0; i++) 537ab25eeb5Syz if (ip6exthdr[i].ol_val == proto) { 538ab25eeb5Syz /* 539ab25eeb5Syz * Most IPv6 extension headers are only allowed once. 540ab25eeb5Syz */ 541ab25eeb5Syz if ((multiple == 0) && 542ab25eeb5Syz ((fin->fin_optmsk & ip6exthdr[i].ol_bit) != 0)) 543ab25eeb5Syz fin->fin_flx |= FI_BAD; 544ab25eeb5Syz else 545ab25eeb5Syz fin->fin_optmsk |= ip6exthdr[i].ol_bit; 5467c478bd9Sstevel@tonic-gate break; 5477663b816Sml } 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate fin->fin_dp = (char *)fin->fin_dp + shift; 5507c478bd9Sstevel@tonic-gate fin->fin_dlen -= shift; 5517c478bd9Sstevel@tonic-gate 5527663b816Sml return hdr->ip6e_nxt; 5537c478bd9Sstevel@tonic-gate } 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate 556ab25eeb5Syz /* ------------------------------------------------------------------------ */ 557ab25eeb5Syz /* Function: frpr_hopopts6 */ 558ab25eeb5Syz /* Returns: int - value of the next header or IPPROTO_NONE if error */ 559ab25eeb5Syz /* Parameters: fin(I) - pointer to packet information */ 560ab25eeb5Syz /* */ 561ab25eeb5Syz /* IPv6 Only */ 562ab25eeb5Syz /* This is function checks pending hop by hop options extension header */ 563ab25eeb5Syz /* ------------------------------------------------------------------------ */ 564ab25eeb5Syz static INLINE int frpr_hopopts6(fin) 565ab25eeb5Syz fr_info_t *fin; 566ab25eeb5Syz { 567ab25eeb5Syz return frpr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS); 568ab25eeb5Syz } 569ab25eeb5Syz 570ab25eeb5Syz 5717c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 5727c478bd9Sstevel@tonic-gate /* Function: frpr_routing6 */ 5737663b816Sml /* Returns: int - value of the next header or IPPROTO_NONE if error */ 5747c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 5757c478bd9Sstevel@tonic-gate /* */ 5767c478bd9Sstevel@tonic-gate /* IPv6 Only */ 5777c478bd9Sstevel@tonic-gate /* This is function checks pending routing extension header */ 5787c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 5797663b816Sml static INLINE int frpr_routing6(fin) 5807c478bd9Sstevel@tonic-gate fr_info_t *fin; 5817c478bd9Sstevel@tonic-gate { 5827c478bd9Sstevel@tonic-gate struct ip6_ext *hdr; 583ab25eeb5Syz int shift; 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate hdr = fin->fin_dp; 586ab25eeb5Syz if (frpr_ipv6exthdr(fin, 0, IPPROTO_ROUTING) == IPPROTO_NONE) 587ab25eeb5Syz return IPPROTO_NONE; 5887663b816Sml 5897c478bd9Sstevel@tonic-gate shift = 8 + (hdr->ip6e_len << 3); 5907c478bd9Sstevel@tonic-gate /* 5917c478bd9Sstevel@tonic-gate * Nasty extension header length? 5927c478bd9Sstevel@tonic-gate */ 593ab25eeb5Syz if ((hdr->ip6e_len << 3) & 15) { 5947c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_BAD; 595ab25eeb5Syz /* 596ab25eeb5Syz * Compensate for the changes made in frpr_ipv6exthdr() 597ab25eeb5Syz */ 598ab25eeb5Syz fin->fin_dlen += shift; 599ab25eeb5Syz fin->fin_dp = (char *)fin->fin_dp - shift; 6007663b816Sml return IPPROTO_NONE; 6017c478bd9Sstevel@tonic-gate } 6027c478bd9Sstevel@tonic-gate 6037663b816Sml return hdr->ip6e_nxt; 6047c478bd9Sstevel@tonic-gate } 6057c478bd9Sstevel@tonic-gate 6067c478bd9Sstevel@tonic-gate 6077c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 6087c478bd9Sstevel@tonic-gate /* Function: frpr_fragment6 */ 6097663b816Sml /* Returns: int - value of the next header or IPPROTO_NONE if error */ 6107c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 6117c478bd9Sstevel@tonic-gate /* */ 6127c478bd9Sstevel@tonic-gate /* IPv6 Only */ 6137c478bd9Sstevel@tonic-gate /* Examine the IPv6 fragment header and extract fragment offset information.*/ 614ab25eeb5Syz /* */ 615ab25eeb5Syz /* We don't know where the transport layer header (or whatever is next is), */ 616ab25eeb5Syz /* as it could be behind destination options (amongst others). Because */ 617ab25eeb5Syz /* there is no fragment cache, there is no knowledge about whether or not an*/ 618ab25eeb5Syz /* upper layer header has been seen (or where it ends) and thus we are not */ 619ab25eeb5Syz /* able to continue processing beyond this header with any confidence. */ 6207c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 6217663b816Sml static INLINE int frpr_fragment6(fin) 6227c478bd9Sstevel@tonic-gate fr_info_t *fin; 6237c478bd9Sstevel@tonic-gate { 6247c478bd9Sstevel@tonic-gate struct ip6_frag *frag; 6257663b816Sml 626ab25eeb5Syz fin->fin_flx |= FI_FRAG; 6277c478bd9Sstevel@tonic-gate 62872680cf5SDarren Reed /* 62972680cf5SDarren Reed * A fragmented IPv6 packet implies that there must be something 63072680cf5SDarren Reed * else after the fragment. 63172680cf5SDarren Reed */ 632ab25eeb5Syz if (frpr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT) == IPPROTO_NONE) 633b7fbedc2SDarren Reed return IPPROTO_NONE; 6347c478bd9Sstevel@tonic-gate 635ab25eeb5Syz frag = (struct ip6_frag *)((char *)fin->fin_dp - sizeof(*frag)); 6367663b816Sml 637ab25eeb5Syz /* 638b7fbedc2SDarren Reed * If this fragment isn't the last then the packet length must 639b7fbedc2SDarren Reed * be a multiple of 8. 640ab25eeb5Syz */ 641b7fbedc2SDarren Reed if ((frag->ip6f_offlg & IP6F_MORE_FRAG) != 0) { 642b7fbedc2SDarren Reed fin->fin_flx |= FI_MOREFRAG; 643b7fbedc2SDarren Reed 644b7fbedc2SDarren Reed if ((fin->fin_plen & 0x7) != 0) 645b7fbedc2SDarren Reed fin->fin_flx |= FI_BAD; 646ab25eeb5Syz } 647ab25eeb5Syz 648b7fbedc2SDarren Reed fin->fin_id = frag->ip6f_ident; 64972680cf5SDarren Reed fin->fin_off = ntohs(frag->ip6f_offlg & IP6F_OFF_MASK); 65072680cf5SDarren Reed if (fin->fin_off != 0) 65172680cf5SDarren Reed fin->fin_flx |= FI_FRAGBODY; 65272680cf5SDarren Reed 6537663b816Sml return frag->ip6f_nxt; 6547c478bd9Sstevel@tonic-gate } 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 6587c478bd9Sstevel@tonic-gate /* Function: frpr_dstopts6 */ 6597663b816Sml /* Returns: int - value of the next header or IPPROTO_NONE if error */ 6607c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 6617c478bd9Sstevel@tonic-gate /* nextheader(I) - stores next header value */ 6627c478bd9Sstevel@tonic-gate /* */ 6637c478bd9Sstevel@tonic-gate /* IPv6 Only */ 6647c478bd9Sstevel@tonic-gate /* This is function checks pending destination options extension header */ 6657c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 6667663b816Sml static INLINE int frpr_dstopts6(fin) 6677c478bd9Sstevel@tonic-gate fr_info_t *fin; 6687c478bd9Sstevel@tonic-gate { 669ab25eeb5Syz return frpr_ipv6exthdr(fin, 1, IPPROTO_DSTOPTS); 6707c478bd9Sstevel@tonic-gate } 6717c478bd9Sstevel@tonic-gate 6727c478bd9Sstevel@tonic-gate 6737c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 6747c478bd9Sstevel@tonic-gate /* Function: frpr_icmp6 */ 6757c478bd9Sstevel@tonic-gate /* Returns: void */ 6767c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 6777c478bd9Sstevel@tonic-gate /* */ 6787c478bd9Sstevel@tonic-gate /* IPv6 Only */ 6797c478bd9Sstevel@tonic-gate /* This routine is mainly concerned with determining the minimum valid size */ 6807c478bd9Sstevel@tonic-gate /* for an ICMPv6 packet. */ 6817c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 6827c478bd9Sstevel@tonic-gate static INLINE void frpr_icmp6(fin) 6837c478bd9Sstevel@tonic-gate fr_info_t *fin; 6847c478bd9Sstevel@tonic-gate { 6857c478bd9Sstevel@tonic-gate int minicmpsz = sizeof(struct icmp6_hdr); 6867c478bd9Sstevel@tonic-gate struct icmp6_hdr *icmp6; 6877c478bd9Sstevel@tonic-gate 688ab25eeb5Syz if (frpr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1) 6897663b816Sml return; 6907663b816Sml 6917c478bd9Sstevel@tonic-gate if (fin->fin_dlen > 1) { 6927c478bd9Sstevel@tonic-gate icmp6 = fin->fin_dp; 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate fin->fin_data[0] = *(u_short *)icmp6; 6957c478bd9Sstevel@tonic-gate 696d6c23f6fSyx if ((icmp6->icmp6_type & ICMP6_INFOMSG_MASK) != 0) 697d6c23f6fSyx fin->fin_flx |= FI_ICMPQUERY; 698d6c23f6fSyx 6997c478bd9Sstevel@tonic-gate switch (icmp6->icmp6_type) 7007c478bd9Sstevel@tonic-gate { 7017c478bd9Sstevel@tonic-gate case ICMP6_ECHO_REPLY : 7027c478bd9Sstevel@tonic-gate case ICMP6_ECHO_REQUEST : 703d6c23f6fSyx if (fin->fin_dlen >= 6) 704d6c23f6fSyx fin->fin_data[1] = icmp6->icmp6_id; 7057c478bd9Sstevel@tonic-gate minicmpsz = ICMP6ERR_MINPKTLEN - sizeof(ip6_t); 7067c478bd9Sstevel@tonic-gate break; 7077c478bd9Sstevel@tonic-gate case ICMP6_DST_UNREACH : 7087c478bd9Sstevel@tonic-gate case ICMP6_PACKET_TOO_BIG : 7097c478bd9Sstevel@tonic-gate case ICMP6_TIME_EXCEEDED : 7107c478bd9Sstevel@tonic-gate case ICMP6_PARAM_PROB : 7117c478bd9Sstevel@tonic-gate if ((fin->fin_m != NULL) && 7127c478bd9Sstevel@tonic-gate (M_LEN(fin->fin_m) < fin->fin_plen)) { 7137663b816Sml if (fr_coalesce(fin) != 1) 7147c478bd9Sstevel@tonic-gate return; 7157c478bd9Sstevel@tonic-gate } 7167c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_ICMPERR; 7177c478bd9Sstevel@tonic-gate minicmpsz = ICMP6ERR_IPICMPHLEN - sizeof(ip6_t); 7187c478bd9Sstevel@tonic-gate break; 7197c478bd9Sstevel@tonic-gate default : 7207c478bd9Sstevel@tonic-gate break; 7217c478bd9Sstevel@tonic-gate } 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate frpr_short6(fin, minicmpsz); 7257c478bd9Sstevel@tonic-gate } 7267c478bd9Sstevel@tonic-gate 7277c478bd9Sstevel@tonic-gate 7287c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 7297c478bd9Sstevel@tonic-gate /* Function: frpr_udp6 */ 7307c478bd9Sstevel@tonic-gate /* Returns: void */ 7317c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 7327c478bd9Sstevel@tonic-gate /* */ 7337c478bd9Sstevel@tonic-gate /* IPv6 Only */ 7347c478bd9Sstevel@tonic-gate /* Analyse the packet for IPv6/UDP properties. */ 735ab25eeb5Syz /* Is not expected to be called for fragmented packets. */ 7367c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 7377c478bd9Sstevel@tonic-gate static INLINE void frpr_udp6(fin) 7387c478bd9Sstevel@tonic-gate fr_info_t *fin; 7397c478bd9Sstevel@tonic-gate { 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate fr_checkv6sum(fin); 7427c478bd9Sstevel@tonic-gate 7437c478bd9Sstevel@tonic-gate frpr_short6(fin, sizeof(struct udphdr)); 74408254dd3Syz if (frpr_pullup(fin, sizeof(struct udphdr)) == -1) 74508254dd3Syz return; 7467c478bd9Sstevel@tonic-gate 7477c478bd9Sstevel@tonic-gate frpr_udpcommon(fin); 7487c478bd9Sstevel@tonic-gate } 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate 7517c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 7527c478bd9Sstevel@tonic-gate /* Function: frpr_tcp6 */ 7537c478bd9Sstevel@tonic-gate /* Returns: void */ 7547c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 7557c478bd9Sstevel@tonic-gate /* */ 7567c478bd9Sstevel@tonic-gate /* IPv6 Only */ 7577c478bd9Sstevel@tonic-gate /* Analyse the packet for IPv6/TCP properties. */ 758ab25eeb5Syz /* Is not expected to be called for fragmented packets. */ 7597c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 7607c478bd9Sstevel@tonic-gate static INLINE void frpr_tcp6(fin) 7617c478bd9Sstevel@tonic-gate fr_info_t *fin; 7627c478bd9Sstevel@tonic-gate { 7637c478bd9Sstevel@tonic-gate 7647c478bd9Sstevel@tonic-gate fr_checkv6sum(fin); 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate frpr_short6(fin, sizeof(struct tcphdr)); 76708254dd3Syz if (frpr_pullup(fin, sizeof(struct tcphdr)) == -1) 76808254dd3Syz return; 7697c478bd9Sstevel@tonic-gate 7707c478bd9Sstevel@tonic-gate frpr_tcpcommon(fin); 7717c478bd9Sstevel@tonic-gate } 772ab25eeb5Syz 773ab25eeb5Syz 774ab25eeb5Syz /* ------------------------------------------------------------------------ */ 775ab25eeb5Syz /* Function: frpr_esp6 */ 776ab25eeb5Syz /* Returns: void */ 777ab25eeb5Syz /* Parameters: fin(I) - pointer to packet information */ 778ab25eeb5Syz /* */ 779ab25eeb5Syz /* IPv6 Only */ 780ab25eeb5Syz /* Analyse the packet for ESP properties. */ 781ab25eeb5Syz /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ 782ab25eeb5Syz /* even though the newer ESP packets must also have a sequence number that */ 783ab25eeb5Syz /* is 32bits as well, it is not possible(?) to determine the version from a */ 784ab25eeb5Syz /* simple packet header. */ 785ab25eeb5Syz /* ------------------------------------------------------------------------ */ 786ab25eeb5Syz static INLINE void frpr_esp6(fin) 787ab25eeb5Syz fr_info_t *fin; 788ab25eeb5Syz { 789ab25eeb5Syz int i; 790ab25eeb5Syz frpr_short6(fin, sizeof(grehdr_t)); 791ab25eeb5Syz 792ab25eeb5Syz (void) frpr_pullup(fin, 8); 793ab25eeb5Syz 794ab25eeb5Syz for (i = 0; ip6exthdr[i].ol_bit != 0; i++) 795ab25eeb5Syz if (ip6exthdr[i].ol_val == IPPROTO_ESP) { 796ab25eeb5Syz fin->fin_optmsk |= ip6exthdr[i].ol_bit; 797ab25eeb5Syz break; 798ab25eeb5Syz } 799ab25eeb5Syz } 800ab25eeb5Syz 801ab25eeb5Syz 802ab25eeb5Syz /* ------------------------------------------------------------------------ */ 803ab25eeb5Syz /* Function: frpr_ah6 */ 804ab25eeb5Syz /* Returns: void */ 805ab25eeb5Syz /* Parameters: fin(I) - pointer to packet information */ 806ab25eeb5Syz /* */ 807ab25eeb5Syz /* IPv6 Only */ 808ab25eeb5Syz /* Analyse the packet for AH properties. */ 809ab25eeb5Syz /* The minimum length is taken to be the combination of all fields in the */ 810ab25eeb5Syz /* header being present and no authentication data (null algorithm used.) */ 811ab25eeb5Syz /* ------------------------------------------------------------------------ */ 812ab25eeb5Syz static INLINE int frpr_ah6(fin) 813ab25eeb5Syz fr_info_t *fin; 814ab25eeb5Syz { 815ab25eeb5Syz authhdr_t *ah; 816ab25eeb5Syz int i, shift; 817ab25eeb5Syz 818ab25eeb5Syz frpr_short6(fin, 12); 819ab25eeb5Syz 820ab25eeb5Syz if (frpr_pullup(fin, sizeof(*ah)) == -1) 821ab25eeb5Syz return IPPROTO_NONE; 822ab25eeb5Syz 823ab25eeb5Syz for (i = 0; ip6exthdr[i].ol_bit != 0; i++) 824ab25eeb5Syz if (ip6exthdr[i].ol_val == IPPROTO_AH) { 825ab25eeb5Syz fin->fin_optmsk |= ip6exthdr[i].ol_bit; 826ab25eeb5Syz break; 827ab25eeb5Syz } 828ab25eeb5Syz 829ab25eeb5Syz ah = (authhdr_t *)fin->fin_dp; 830ab25eeb5Syz 831ab25eeb5Syz shift = (ah->ah_plen + 2) * 4; 832ab25eeb5Syz fin->fin_dlen -= shift; 833ab25eeb5Syz fin->fin_dp = (char*)fin->fin_dp + shift; 834ab25eeb5Syz 835ab25eeb5Syz return ah->ah_next; 836ab25eeb5Syz } 837ab25eeb5Syz 838ab25eeb5Syz 839ab25eeb5Syz /* ------------------------------------------------------------------------ */ 840ab25eeb5Syz /* Function: frpr_gre6 */ 841ab25eeb5Syz /* Returns: void */ 842ab25eeb5Syz /* Parameters: fin(I) - pointer to packet information */ 843ab25eeb5Syz /* */ 844ab25eeb5Syz /* Analyse the packet for GRE properties. */ 845ab25eeb5Syz /* ------------------------------------------------------------------------ */ 846ab25eeb5Syz static INLINE void frpr_gre6(fin) 847ab25eeb5Syz fr_info_t *fin; 848ab25eeb5Syz { 849ab25eeb5Syz grehdr_t *gre; 850ab25eeb5Syz 851ab25eeb5Syz frpr_short6(fin, sizeof(grehdr_t)); 852ab25eeb5Syz 853ab25eeb5Syz if (frpr_pullup(fin, sizeof(grehdr_t)) == -1) 854ab25eeb5Syz return; 855ab25eeb5Syz 856ab25eeb5Syz gre = fin->fin_dp; 857ab25eeb5Syz if (GRE_REV(gre->gr_flags) == 1) 858ab25eeb5Syz fin->fin_data[0] = gre->gr_call; 859ab25eeb5Syz } 8607c478bd9Sstevel@tonic-gate #endif /* USE_INET6 */ 8617c478bd9Sstevel@tonic-gate 8627c478bd9Sstevel@tonic-gate 8637663b816Sml /* ------------------------------------------------------------------------ */ 8647663b816Sml /* Function: frpr_pullup */ 8657663b816Sml /* Returns: int - 0 == pullup succeeded, -1 == failure */ 8667663b816Sml /* Parameters: fin(I) - pointer to packet information */ 8677663b816Sml /* plen(I) - length (excluding L3 header) to pullup */ 8687663b816Sml /* */ 8697663b816Sml /* Short inline function to cut down on code duplication to perform a call */ 8707663b816Sml /* to fr_pullup to ensure there is the required amount of data, */ 8717663b816Sml /* consecutively in the packet buffer. */ 8727663b816Sml /* ------------------------------------------------------------------------ */ 8737663b816Sml static INLINE int frpr_pullup(fin, plen) 8747663b816Sml fr_info_t *fin; 8757663b816Sml int plen; 8767663b816Sml { 877ab25eeb5Syz #if defined(_KERNEL) 8787663b816Sml if (fin->fin_m != NULL) { 87940cdc2e8SAlexandr Nedvedicky int ipoff; 88040cdc2e8SAlexandr Nedvedicky 88140cdc2e8SAlexandr Nedvedicky ipoff = (char *)fin->fin_ip - MTOD(fin->fin_m, char *); 88240cdc2e8SAlexandr Nedvedicky 8837663b816Sml if (fin->fin_dp != NULL) 8847663b816Sml plen += (char *)fin->fin_dp - 8857663b816Sml ((char *)fin->fin_ip + fin->fin_hlen); 88640cdc2e8SAlexandr Nedvedicky plen += fin->fin_hlen; 88740cdc2e8SAlexandr Nedvedicky /* 88840cdc2e8SAlexandr Nedvedicky * We don't do 'plen += ipoff;' here. The fr_pullup() will 88940cdc2e8SAlexandr Nedvedicky * do it for us. 89040cdc2e8SAlexandr Nedvedicky */ 89140cdc2e8SAlexandr Nedvedicky if (M_LEN(fin->fin_m) < plen + ipoff) { 8927663b816Sml if (fr_pullup(fin->fin_m, fin, plen) == NULL) 8937663b816Sml return -1; 8947663b816Sml } 8957663b816Sml } 8967663b816Sml #endif 8977663b816Sml return 0; 8987663b816Sml } 8997663b816Sml 9007663b816Sml 9017c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 9027c478bd9Sstevel@tonic-gate /* Function: frpr_short */ 9037c478bd9Sstevel@tonic-gate /* Returns: void */ 904ab25eeb5Syz /* Parameters: fin(I) - pointer to packet information */ 905ab25eeb5Syz /* xmin(I) - minimum header size */ 9067c478bd9Sstevel@tonic-gate /* */ 907ab25eeb5Syz /* Check if a packet is "short" as defined by xmin. The rule we are */ 908ab25eeb5Syz /* applying here is that the packet must not be fragmented within the layer */ 909ab25eeb5Syz /* 4 header. That is, it must not be a fragment that has its offset set to */ 910ab25eeb5Syz /* start within the layer 4 header (hdrmin) or if it is at offset 0, the */ 911ab25eeb5Syz /* entire layer 4 header must be present (min). */ 9127c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 913ab25eeb5Syz static INLINE void frpr_short(fin, xmin) 9147c478bd9Sstevel@tonic-gate fr_info_t *fin; 915ab25eeb5Syz int xmin; 9167c478bd9Sstevel@tonic-gate { 9177c478bd9Sstevel@tonic-gate 918ab25eeb5Syz if (fin->fin_off == 0) { 919ab25eeb5Syz if (fin->fin_dlen < xmin) 920ab25eeb5Syz fin->fin_flx |= FI_SHORT; 921ab25eeb5Syz } else if (fin->fin_off < xmin) { 922ab25eeb5Syz fin->fin_flx |= FI_SHORT; 9237c478bd9Sstevel@tonic-gate } 9247c478bd9Sstevel@tonic-gate } 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 9287c478bd9Sstevel@tonic-gate /* Function: frpr_icmp */ 9297c478bd9Sstevel@tonic-gate /* Returns: void */ 9307c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 9317c478bd9Sstevel@tonic-gate /* */ 9327c478bd9Sstevel@tonic-gate /* IPv4 Only */ 9337c478bd9Sstevel@tonic-gate /* Do a sanity check on the packet for ICMP (v4). In nearly all cases, */ 9347c478bd9Sstevel@tonic-gate /* except extrememly bad packets, both type and code will be present. */ 935ab25eeb5Syz /* The expected minimum size of an ICMP packet is very much dependent on */ 9367c478bd9Sstevel@tonic-gate /* the type of it. */ 9377c478bd9Sstevel@tonic-gate /* */ 9387c478bd9Sstevel@tonic-gate /* XXX - other ICMP sanity checks? */ 9397c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 9407c478bd9Sstevel@tonic-gate static INLINE void frpr_icmp(fin) 9417c478bd9Sstevel@tonic-gate fr_info_t *fin; 9427c478bd9Sstevel@tonic-gate { 9437c478bd9Sstevel@tonic-gate int minicmpsz = sizeof(struct icmp); 9447c478bd9Sstevel@tonic-gate icmphdr_t *icmp; 945ab25eeb5Syz ip_t *oip; 946f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 9477c478bd9Sstevel@tonic-gate 94862685e53Sml if (fin->fin_off != 0) { 94962685e53Sml frpr_short(fin, ICMPERR_ICMPHLEN); 95062685e53Sml return; 95162685e53Sml } 95262685e53Sml 953ab25eeb5Syz if (frpr_pullup(fin, ICMPERR_ICMPHLEN) == -1) 954ab25eeb5Syz return; 955ab25eeb5Syz 9567c478bd9Sstevel@tonic-gate fr_checkv4sum(fin); 9577c478bd9Sstevel@tonic-gate 958f524e99bSAlexandr Nedvedicky /* 959f524e99bSAlexandr Nedvedicky * This is a right place to set icmp pointer, since the memory 960f524e99bSAlexandr Nedvedicky * referenced by fin_dp could get reallocated. The code down below can 961f524e99bSAlexandr Nedvedicky * rely on fact icmp variable always points to ICMP header. 962f524e99bSAlexandr Nedvedicky */ 963f524e99bSAlexandr Nedvedicky icmp = fin->fin_dp; 964f524e99bSAlexandr Nedvedicky fin->fin_data[0] = *(u_short *)icmp; 965f524e99bSAlexandr Nedvedicky fin->fin_data[1] = icmp->icmp_id; 966f524e99bSAlexandr Nedvedicky 967f524e99bSAlexandr Nedvedicky switch (icmp->icmp_type) 968f524e99bSAlexandr Nedvedicky { 969f524e99bSAlexandr Nedvedicky case ICMP_ECHOREPLY : 970f524e99bSAlexandr Nedvedicky case ICMP_ECHO : 971f524e99bSAlexandr Nedvedicky /* Router discovery messaes - RFC 1256 */ 972f524e99bSAlexandr Nedvedicky case ICMP_ROUTERADVERT : 973f524e99bSAlexandr Nedvedicky case ICMP_ROUTERSOLICIT : 974f524e99bSAlexandr Nedvedicky minicmpsz = ICMP_MINLEN; 975f524e99bSAlexandr Nedvedicky break; 976f524e99bSAlexandr Nedvedicky /* 977f524e99bSAlexandr Nedvedicky * type(1) + code(1) + cksum(2) + id(2) seq(2) + 978f524e99bSAlexandr Nedvedicky * 3 * timestamp(3 * 4) 979f524e99bSAlexandr Nedvedicky */ 980f524e99bSAlexandr Nedvedicky case ICMP_TSTAMP : 981f524e99bSAlexandr Nedvedicky case ICMP_TSTAMPREPLY : 982f524e99bSAlexandr Nedvedicky minicmpsz = 20; 983f524e99bSAlexandr Nedvedicky break; 984f524e99bSAlexandr Nedvedicky /* 985f524e99bSAlexandr Nedvedicky * type(1) + code(1) + cksum(2) + id(2) seq(2) + 986f524e99bSAlexandr Nedvedicky * mask(4) 987f524e99bSAlexandr Nedvedicky */ 988f524e99bSAlexandr Nedvedicky case ICMP_MASKREQ : 989f524e99bSAlexandr Nedvedicky case ICMP_MASKREPLY : 9907c478bd9Sstevel@tonic-gate minicmpsz = 12; 9917c478bd9Sstevel@tonic-gate break; 992f524e99bSAlexandr Nedvedicky /* 993f524e99bSAlexandr Nedvedicky * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+) 994f524e99bSAlexandr Nedvedicky */ 995f524e99bSAlexandr Nedvedicky case ICMP_UNREACH : 996f524e99bSAlexandr Nedvedicky if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG) { 997f524e99bSAlexandr Nedvedicky if (icmp->icmp_nextmtu < ifs->ifs_fr_icmpminfragmtu) 998ab25eeb5Syz fin->fin_flx |= FI_BAD; 9997c478bd9Sstevel@tonic-gate } 1000f524e99bSAlexandr Nedvedicky /* FALLTHRU */ 1001f524e99bSAlexandr Nedvedicky case ICMP_SOURCEQUENCH : 1002f524e99bSAlexandr Nedvedicky case ICMP_REDIRECT : 1003f524e99bSAlexandr Nedvedicky case ICMP_TIMXCEED : 1004f524e99bSAlexandr Nedvedicky case ICMP_PARAMPROB : 1005f524e99bSAlexandr Nedvedicky fin->fin_flx |= FI_ICMPERR; 1006f524e99bSAlexandr Nedvedicky if (fr_coalesce(fin) != 1) 1007f524e99bSAlexandr Nedvedicky return; 1008f524e99bSAlexandr Nedvedicky /* 1009f524e99bSAlexandr Nedvedicky * ICMP error packets should not be generated for IP 1010f524e99bSAlexandr Nedvedicky * packets that are a fragment that isn't the first 1011f524e99bSAlexandr Nedvedicky * fragment. 1012f524e99bSAlexandr Nedvedicky */ 1013f524e99bSAlexandr Nedvedicky oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN); 1014f524e99bSAlexandr Nedvedicky if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0) 1015f524e99bSAlexandr Nedvedicky fin->fin_flx |= FI_BAD; 1016f524e99bSAlexandr Nedvedicky break; 1017f524e99bSAlexandr Nedvedicky default : 1018f524e99bSAlexandr Nedvedicky break; 10197c478bd9Sstevel@tonic-gate } 10207c478bd9Sstevel@tonic-gate 10217663b816Sml frpr_short(fin, minicmpsz); 10227c478bd9Sstevel@tonic-gate } 10237c478bd9Sstevel@tonic-gate 10247c478bd9Sstevel@tonic-gate 10257c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 10267c478bd9Sstevel@tonic-gate /* Function: frpr_tcpcommon */ 10277c478bd9Sstevel@tonic-gate /* Returns: void */ 10287c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 10297c478bd9Sstevel@tonic-gate /* */ 10307c478bd9Sstevel@tonic-gate /* TCP header sanity checking. Look for bad combinations of TCP flags, */ 10317c478bd9Sstevel@tonic-gate /* and make some checks with how they interact with other fields. */ 10327c478bd9Sstevel@tonic-gate /* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is */ 10337c478bd9Sstevel@tonic-gate /* valid and mark the packet as bad if not. */ 10347c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 10357c478bd9Sstevel@tonic-gate static INLINE void frpr_tcpcommon(fin) 10367c478bd9Sstevel@tonic-gate fr_info_t *fin; 10377c478bd9Sstevel@tonic-gate { 10387c478bd9Sstevel@tonic-gate int flags, tlen; 10397c478bd9Sstevel@tonic-gate tcphdr_t *tcp; 10407c478bd9Sstevel@tonic-gate 104162685e53Sml fin->fin_flx |= FI_TCPUDP; 104262685e53Sml if (fin->fin_off != 0) 104362685e53Sml return; 104462685e53Sml 1045ab25eeb5Syz if (frpr_pullup(fin, sizeof(*tcp)) == -1) 1046ab25eeb5Syz return; 10477c478bd9Sstevel@tonic-gate tcp = fin->fin_dp; 10487c478bd9Sstevel@tonic-gate 1049ab25eeb5Syz if (fin->fin_dlen > 3) { 1050ab25eeb5Syz fin->fin_sport = ntohs(tcp->th_sport); 1051ab25eeb5Syz fin->fin_dport = ntohs(tcp->th_dport); 10527c478bd9Sstevel@tonic-gate } 1053ab25eeb5Syz 1054ab25eeb5Syz if ((fin->fin_flx & FI_SHORT) != 0) 1055ab25eeb5Syz return; 10567c478bd9Sstevel@tonic-gate 10577c478bd9Sstevel@tonic-gate /* 10587c478bd9Sstevel@tonic-gate * Use of the TCP data offset *must* result in a value that is at 10597c478bd9Sstevel@tonic-gate * least the same size as the TCP header. 10607c478bd9Sstevel@tonic-gate */ 1061ab25eeb5Syz tlen = TCP_OFF(tcp) << 2; 1062ab25eeb5Syz if (tlen < sizeof(tcphdr_t)) { 10637c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_BAD; 1064ab25eeb5Syz return; 1065ab25eeb5Syz } 1066ab25eeb5Syz 1067ab25eeb5Syz flags = tcp->th_flags; 1068ab25eeb5Syz fin->fin_tcpf = tcp->th_flags; 10697c478bd9Sstevel@tonic-gate 1070ab25eeb5Syz /* 1071ab25eeb5Syz * If the urgent flag is set, then the urgent pointer must 1072ab25eeb5Syz * also be set and vice versa. Good TCP packets do not have 1073ab25eeb5Syz * just one of these set. 1074ab25eeb5Syz */ 1075ab25eeb5Syz if ((flags & TH_URG) != 0 && (tcp->th_urp == 0)) { 1076ab25eeb5Syz fin->fin_flx |= FI_BAD; 1077ab25eeb5Syz } else if ((flags & TH_URG) == 0 && (tcp->th_urp != 0)) { 1078ab25eeb5Syz /* Ignore this case, it shows up in "real" traffic with */ 1079ab25eeb5Syz /* bogus values in the urgent pointer field. */ 1080ab25eeb5Syz flags = flags; /* LINT */ 1081ab25eeb5Syz } else if (((flags & (TH_SYN|TH_FIN)) != 0) && 1082ab25eeb5Syz ((flags & (TH_RST|TH_ACK)) == TH_RST)) { 1083ab25eeb5Syz /* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */ 1084ab25eeb5Syz fin->fin_flx |= FI_BAD; 1085ab25eeb5Syz } else if (!(flags & TH_ACK)) { 10867c478bd9Sstevel@tonic-gate /* 1087ab25eeb5Syz * If the ack bit isn't set, then either the SYN or 1088ab25eeb5Syz * RST bit must be set. If the SYN bit is set, then 1089ab25eeb5Syz * we expect the ACK field to be 0. If the ACK is 1090ab25eeb5Syz * not set and if URG, PSH or FIN are set, consdier 1091ab25eeb5Syz * that to indicate a bad TCP packet. 10927c478bd9Sstevel@tonic-gate */ 1093ab25eeb5Syz if ((flags == TH_SYN) && (tcp->th_ack != 0)) { 10947c478bd9Sstevel@tonic-gate /* 1095ab25eeb5Syz * Cisco PIX sets the ACK field to a random value. 1096ab25eeb5Syz * In light of this, do not set FI_BAD until a patch 1097ab25eeb5Syz * is available from Cisco to ensure that 1098ab25eeb5Syz * interoperability between existing systems is 1099ab25eeb5Syz * achieved. 11007c478bd9Sstevel@tonic-gate */ 1101ab25eeb5Syz /*fin->fin_flx |= FI_BAD*/; 1102ab25eeb5Syz flags = flags; /* LINT */ 1103ab25eeb5Syz } else if (!(flags & (TH_RST|TH_SYN))) { 1104ab25eeb5Syz fin->fin_flx |= FI_BAD; 1105ab25eeb5Syz } else if ((flags & (TH_URG|TH_PUSH|TH_FIN)) != 0) { 1106ab25eeb5Syz fin->fin_flx |= FI_BAD; 11077c478bd9Sstevel@tonic-gate } 11087c478bd9Sstevel@tonic-gate } 11097c478bd9Sstevel@tonic-gate 11107c478bd9Sstevel@tonic-gate /* 11117c478bd9Sstevel@tonic-gate * At this point, it's not exactly clear what is to be gained by 11127c478bd9Sstevel@tonic-gate * marking up which TCP options are and are not present. The one we 11137c478bd9Sstevel@tonic-gate * are most interested in is the TCP window scale. This is only in 11147c478bd9Sstevel@tonic-gate * a SYN packet [RFC1323] so we don't need this here...? 11157c478bd9Sstevel@tonic-gate * Now if we were to analyse the header for passive fingerprinting, 11167c478bd9Sstevel@tonic-gate * then that might add some weight to adding this... 11177c478bd9Sstevel@tonic-gate */ 1118ab25eeb5Syz if (tlen == sizeof(tcphdr_t)) 1119ab25eeb5Syz return; 1120ab25eeb5Syz 1121ab25eeb5Syz if (frpr_pullup(fin, tlen) == -1) 11227c478bd9Sstevel@tonic-gate return; 1123ab25eeb5Syz 1124ab25eeb5Syz #if 0 1125ab25eeb5Syz ip = fin->fin_ip; 1126ab25eeb5Syz s = (u_char *)(tcp + 1); 11277c478bd9Sstevel@tonic-gate off = IP_HL(ip) << 2; 11287c478bd9Sstevel@tonic-gate # ifdef _KERNEL 11297c478bd9Sstevel@tonic-gate if (fin->fin_mp != NULL) { 11307c478bd9Sstevel@tonic-gate mb_t *m = *fin->fin_mp; 11317c478bd9Sstevel@tonic-gate 1132ab25eeb5Syz if (off + tlen > M_LEN(m)) 11337c478bd9Sstevel@tonic-gate return; 11347c478bd9Sstevel@tonic-gate } 11357c478bd9Sstevel@tonic-gate # endif 1136ab25eeb5Syz for (tlen -= (int)sizeof(*tcp); tlen > 0; ) { 11377c478bd9Sstevel@tonic-gate opt = *s; 11387c478bd9Sstevel@tonic-gate if (opt == '\0') 11397c478bd9Sstevel@tonic-gate break; 11407c478bd9Sstevel@tonic-gate else if (opt == TCPOPT_NOP) 11417c478bd9Sstevel@tonic-gate ol = 1; 11427c478bd9Sstevel@tonic-gate else { 1143ab25eeb5Syz if (tlen < 2) 11447c478bd9Sstevel@tonic-gate break; 11457c478bd9Sstevel@tonic-gate ol = (int)*(s + 1); 1146ab25eeb5Syz if (ol < 2 || ol > tlen) 11477c478bd9Sstevel@tonic-gate break; 11487c478bd9Sstevel@tonic-gate } 11497c478bd9Sstevel@tonic-gate 11507c478bd9Sstevel@tonic-gate for (i = 9, mv = 4; mv >= 0; ) { 11517c478bd9Sstevel@tonic-gate op = ipopts + i; 11527c478bd9Sstevel@tonic-gate if (opt == (u_char)op->ol_val) { 11537c478bd9Sstevel@tonic-gate optmsk |= op->ol_bit; 11547c478bd9Sstevel@tonic-gate break; 11557c478bd9Sstevel@tonic-gate } 11567c478bd9Sstevel@tonic-gate } 1157ab25eeb5Syz tlen -= ol; 11587c478bd9Sstevel@tonic-gate s += ol; 11597c478bd9Sstevel@tonic-gate } 11607c478bd9Sstevel@tonic-gate #endif /* 0 */ 11617c478bd9Sstevel@tonic-gate } 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate 11647c478bd9Sstevel@tonic-gate 11657c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 11667c478bd9Sstevel@tonic-gate /* Function: frpr_udpcommon */ 11677c478bd9Sstevel@tonic-gate /* Returns: void */ 11687c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 11697c478bd9Sstevel@tonic-gate /* */ 11707c478bd9Sstevel@tonic-gate /* Extract the UDP source and destination ports, if present. If compiled */ 11717c478bd9Sstevel@tonic-gate /* with IPFILTER_CKSUM, check to see if the UDP checksum is valid. */ 11727c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 11737c478bd9Sstevel@tonic-gate static INLINE void frpr_udpcommon(fin) 11747c478bd9Sstevel@tonic-gate fr_info_t *fin; 11757c478bd9Sstevel@tonic-gate { 11767c478bd9Sstevel@tonic-gate udphdr_t *udp; 11777c478bd9Sstevel@tonic-gate 117862685e53Sml fin->fin_flx |= FI_TCPUDP; 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate if (!fin->fin_off && (fin->fin_dlen > 3)) { 1181ab25eeb5Syz if (frpr_pullup(fin, sizeof(*udp)) == -1) { 1182ab25eeb5Syz fin->fin_flx |= FI_SHORT; 1183ab25eeb5Syz return; 1184ab25eeb5Syz } 1185ab25eeb5Syz 118662685e53Sml udp = fin->fin_dp; 118762685e53Sml 11887c478bd9Sstevel@tonic-gate fin->fin_sport = ntohs(udp->uh_sport); 11897c478bd9Sstevel@tonic-gate fin->fin_dport = ntohs(udp->uh_dport); 11907c478bd9Sstevel@tonic-gate } 11917c478bd9Sstevel@tonic-gate } 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 11957c478bd9Sstevel@tonic-gate /* Function: frpr_tcp */ 11967c478bd9Sstevel@tonic-gate /* Returns: void */ 11977c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 11987c478bd9Sstevel@tonic-gate /* */ 11997c478bd9Sstevel@tonic-gate /* IPv4 Only */ 12007c478bd9Sstevel@tonic-gate /* Analyse the packet for IPv4/TCP properties. */ 12017c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 12027c478bd9Sstevel@tonic-gate static INLINE void frpr_tcp(fin) 12037c478bd9Sstevel@tonic-gate fr_info_t *fin; 12047c478bd9Sstevel@tonic-gate { 12057c478bd9Sstevel@tonic-gate 12067c478bd9Sstevel@tonic-gate fr_checkv4sum(fin); 12077c478bd9Sstevel@tonic-gate 1208ab25eeb5Syz frpr_short(fin, sizeof(tcphdr_t)); 12097c478bd9Sstevel@tonic-gate 12107c478bd9Sstevel@tonic-gate frpr_tcpcommon(fin); 12117c478bd9Sstevel@tonic-gate } 12127c478bd9Sstevel@tonic-gate 12137c478bd9Sstevel@tonic-gate 12147c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 12157c478bd9Sstevel@tonic-gate /* Function: frpr_udp */ 12167c478bd9Sstevel@tonic-gate /* Returns: void */ 12177c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 12187c478bd9Sstevel@tonic-gate /* */ 12197c478bd9Sstevel@tonic-gate /* IPv4 Only */ 12207c478bd9Sstevel@tonic-gate /* Analyse the packet for IPv4/UDP properties. */ 12217c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 12227c478bd9Sstevel@tonic-gate static INLINE void frpr_udp(fin) 12237c478bd9Sstevel@tonic-gate fr_info_t *fin; 12247c478bd9Sstevel@tonic-gate { 12257c478bd9Sstevel@tonic-gate 12267c478bd9Sstevel@tonic-gate fr_checkv4sum(fin); 12277c478bd9Sstevel@tonic-gate 1228ab25eeb5Syz frpr_short(fin, sizeof(udphdr_t)); 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate frpr_udpcommon(fin); 12317c478bd9Sstevel@tonic-gate } 12327c478bd9Sstevel@tonic-gate 12337c478bd9Sstevel@tonic-gate 12347663b816Sml /* ------------------------------------------------------------------------ */ 12357663b816Sml /* Function: frpr_esp */ 12367663b816Sml /* Returns: void */ 12377663b816Sml /* Parameters: fin(I) - pointer to packet information */ 12387663b816Sml /* */ 12397663b816Sml /* Analyse the packet for ESP properties. */ 12407663b816Sml /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ 12417663b816Sml /* even though the newer ESP packets must also have a sequence number that */ 12427663b816Sml /* is 32bits as well, it is not possible(?) to determine the version from a */ 12437663b816Sml /* simple packet header. */ 12447663b816Sml /* ------------------------------------------------------------------------ */ 12457663b816Sml static INLINE void frpr_esp(fin) 12467663b816Sml fr_info_t *fin; 12477663b816Sml { 1248ab25eeb5Syz if ((fin->fin_off == 0) && (frpr_pullup(fin, 8) == -1)) 12497663b816Sml return; 12507663b816Sml 1251ab25eeb5Syz frpr_short(fin, 8); 1252ab25eeb5Syz } 1253ab25eeb5Syz 1254ab25eeb5Syz 1255ab25eeb5Syz /* ------------------------------------------------------------------------ */ 1256ab25eeb5Syz /* Function: frpr_ah */ 1257ab25eeb5Syz /* Returns: void */ 1258ab25eeb5Syz /* Parameters: fin(I) - pointer to packet information */ 1259ab25eeb5Syz /* */ 1260ab25eeb5Syz /* Analyse the packet for AH properties. */ 1261ab25eeb5Syz /* The minimum length is taken to be the combination of all fields in the */ 1262ab25eeb5Syz /* header being present and no authentication data (null algorithm used.) */ 1263ab25eeb5Syz /* ------------------------------------------------------------------------ */ 1264ab25eeb5Syz static INLINE void frpr_ah(fin) 1265ab25eeb5Syz fr_info_t *fin; 1266ab25eeb5Syz { 1267ab25eeb5Syz authhdr_t *ah; 1268ab25eeb5Syz int len; 1269ab25eeb5Syz 1270ab25eeb5Syz if ((fin->fin_off == 0) && (frpr_pullup(fin, sizeof(*ah)) == -1)) 1271ab25eeb5Syz return; 1272ab25eeb5Syz 1273ab25eeb5Syz ah = (authhdr_t *)fin->fin_dp; 1274ab25eeb5Syz 1275ab25eeb5Syz len = (ah->ah_plen + 2) << 2; 1276ab25eeb5Syz frpr_short(fin, len); 12777663b816Sml } 12787663b816Sml 12797663b816Sml 12807663b816Sml /* ------------------------------------------------------------------------ */ 12817663b816Sml /* Function: frpr_gre */ 12827663b816Sml /* Returns: void */ 12837663b816Sml /* Parameters: fin(I) - pointer to packet information */ 12847663b816Sml /* */ 12857663b816Sml /* Analyse the packet for GRE properties. */ 12867663b816Sml /* ------------------------------------------------------------------------ */ 12877663b816Sml static INLINE void frpr_gre(fin) 12887663b816Sml fr_info_t *fin; 12897663b816Sml { 1290ab25eeb5Syz grehdr_t *gre; 1291ab25eeb5Syz 1292ab25eeb5Syz if ((fin->fin_off == 0) && (frpr_pullup(fin, sizeof(grehdr_t)) == -1)) 12937663b816Sml return; 12947663b816Sml 1295ab25eeb5Syz frpr_short(fin, sizeof(grehdr_t)); 1296ab25eeb5Syz 1297ab25eeb5Syz if (fin->fin_off == 0) { 1298ab25eeb5Syz gre = fin->fin_dp; 1299ab25eeb5Syz if (GRE_REV(gre->gr_flags) == 1) 1300ab25eeb5Syz fin->fin_data[0] = gre->gr_call; 1301ab25eeb5Syz } 13027663b816Sml } 13037663b816Sml 13047663b816Sml 13057c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 13067c478bd9Sstevel@tonic-gate /* Function: frpr_ipv4hdr */ 13077c478bd9Sstevel@tonic-gate /* Returns: void */ 13087c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 13097c478bd9Sstevel@tonic-gate /* */ 13107c478bd9Sstevel@tonic-gate /* IPv4 Only */ 13117c478bd9Sstevel@tonic-gate /* Analyze the IPv4 header and set fields in the fr_info_t structure. */ 13127c478bd9Sstevel@tonic-gate /* Check all options present and flag their presence if any exist. */ 13137c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 13147c478bd9Sstevel@tonic-gate static INLINE void frpr_ipv4hdr(fin) 13157c478bd9Sstevel@tonic-gate fr_info_t *fin; 13167c478bd9Sstevel@tonic-gate { 13177c478bd9Sstevel@tonic-gate u_short optmsk = 0, secmsk = 0, auth = 0; 13187c478bd9Sstevel@tonic-gate int hlen, ol, mv, p, i; 1319ab25eeb5Syz const struct optlist *op; 13207c478bd9Sstevel@tonic-gate u_char *s, opt; 13217c478bd9Sstevel@tonic-gate u_short off; 13227c478bd9Sstevel@tonic-gate fr_ip_t *fi; 13237c478bd9Sstevel@tonic-gate ip_t *ip; 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate fi = &fin->fin_fi; 13267c478bd9Sstevel@tonic-gate hlen = fin->fin_hlen; 13277c478bd9Sstevel@tonic-gate 13287c478bd9Sstevel@tonic-gate ip = fin->fin_ip; 13297c478bd9Sstevel@tonic-gate p = ip->ip_p; 13307c478bd9Sstevel@tonic-gate fi->fi_p = p; 13317c478bd9Sstevel@tonic-gate fi->fi_tos = ip->ip_tos; 13327c478bd9Sstevel@tonic-gate fin->fin_id = ip->ip_id; 13337c478bd9Sstevel@tonic-gate off = ip->ip_off; 13347c478bd9Sstevel@tonic-gate 13357c478bd9Sstevel@tonic-gate /* Get both TTL and protocol */ 13367c478bd9Sstevel@tonic-gate fi->fi_p = ip->ip_p; 13377c478bd9Sstevel@tonic-gate fi->fi_ttl = ip->ip_ttl; 13387c478bd9Sstevel@tonic-gate #if 0 13397c478bd9Sstevel@tonic-gate (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4)); 13407c478bd9Sstevel@tonic-gate #endif 13417c478bd9Sstevel@tonic-gate 13427c478bd9Sstevel@tonic-gate /* Zero out bits not used in IPv6 address */ 13437c478bd9Sstevel@tonic-gate fi->fi_src.i6[1] = 0; 13447c478bd9Sstevel@tonic-gate fi->fi_src.i6[2] = 0; 13457c478bd9Sstevel@tonic-gate fi->fi_src.i6[3] = 0; 13467c478bd9Sstevel@tonic-gate fi->fi_dst.i6[1] = 0; 13477c478bd9Sstevel@tonic-gate fi->fi_dst.i6[2] = 0; 13487c478bd9Sstevel@tonic-gate fi->fi_dst.i6[3] = 0; 13497c478bd9Sstevel@tonic-gate 13507c478bd9Sstevel@tonic-gate fi->fi_saddr = ip->ip_src.s_addr; 13517c478bd9Sstevel@tonic-gate fi->fi_daddr = ip->ip_dst.s_addr; 13527c478bd9Sstevel@tonic-gate 13537c478bd9Sstevel@tonic-gate /* 13547c478bd9Sstevel@tonic-gate * set packet attribute flags based on the offset and 13557c478bd9Sstevel@tonic-gate * calculate the byte offset that it represents. 13567c478bd9Sstevel@tonic-gate */ 13577c478bd9Sstevel@tonic-gate off &= IP_MF|IP_OFFMASK; 13587c478bd9Sstevel@tonic-gate if (off != 0) { 135972680cf5SDarren Reed int morefrag = off & IP_MF; 136072680cf5SDarren Reed 13617c478bd9Sstevel@tonic-gate fi->fi_flx |= FI_FRAG; 136272680cf5SDarren Reed if (morefrag) 136372680cf5SDarren Reed fi->fi_flx |= FI_MOREFRAG; 13647c478bd9Sstevel@tonic-gate off &= IP_OFFMASK; 13657c478bd9Sstevel@tonic-gate if (off != 0) { 1366ab25eeb5Syz fin->fin_flx |= FI_FRAGBODY; 13677c478bd9Sstevel@tonic-gate off <<= 3; 1368ab25eeb5Syz if ((off + fin->fin_dlen > 65535) || 1369ab25eeb5Syz (fin->fin_dlen == 0) || 137072680cf5SDarren Reed ((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) { 1371ab25eeb5Syz /* 1372ab25eeb5Syz * The length of the packet, starting at its 1373ab25eeb5Syz * offset cannot exceed 65535 (0xffff) as the 1374ab25eeb5Syz * length of an IP packet is only 16 bits. 1375ab25eeb5Syz * 1376ab25eeb5Syz * Any fragment that isn't the last fragment 1377ab25eeb5Syz * must have a length greater than 0 and it 1378ab25eeb5Syz * must be an even multiple of 8. 1379ab25eeb5Syz */ 13807c478bd9Sstevel@tonic-gate fi->fi_flx |= FI_BAD; 1381ab25eeb5Syz } 13827c478bd9Sstevel@tonic-gate } 13837c478bd9Sstevel@tonic-gate } 13847c478bd9Sstevel@tonic-gate fin->fin_off = off; 13857c478bd9Sstevel@tonic-gate 13867c478bd9Sstevel@tonic-gate /* 13877c478bd9Sstevel@tonic-gate * Call per-protocol setup and checking 13887c478bd9Sstevel@tonic-gate */ 13897c478bd9Sstevel@tonic-gate switch (p) 13907c478bd9Sstevel@tonic-gate { 13917c478bd9Sstevel@tonic-gate case IPPROTO_UDP : 13927c478bd9Sstevel@tonic-gate frpr_udp(fin); 13937c478bd9Sstevel@tonic-gate break; 13947c478bd9Sstevel@tonic-gate case IPPROTO_TCP : 13957c478bd9Sstevel@tonic-gate frpr_tcp(fin); 13967c478bd9Sstevel@tonic-gate break; 13977c478bd9Sstevel@tonic-gate case IPPROTO_ICMP : 13987c478bd9Sstevel@tonic-gate frpr_icmp(fin); 13997c478bd9Sstevel@tonic-gate break; 1400ab25eeb5Syz case IPPROTO_AH : 1401ab25eeb5Syz frpr_ah(fin); 1402ab25eeb5Syz break; 1403ab25eeb5Syz case IPPROTO_ESP : 1404ab25eeb5Syz frpr_esp(fin); 1405ab25eeb5Syz break; 1406ab25eeb5Syz case IPPROTO_GRE : 1407ab25eeb5Syz frpr_gre(fin); 1408ab25eeb5Syz break; 14097c478bd9Sstevel@tonic-gate } 14107c478bd9Sstevel@tonic-gate 14117c478bd9Sstevel@tonic-gate ip = fin->fin_ip; 14127c478bd9Sstevel@tonic-gate if (ip == NULL) 14137c478bd9Sstevel@tonic-gate return; 14147c478bd9Sstevel@tonic-gate 14157c478bd9Sstevel@tonic-gate /* 14167c478bd9Sstevel@tonic-gate * If it is a standard IP header (no options), set the flag fields 14177c478bd9Sstevel@tonic-gate * which relate to options to 0. 14187c478bd9Sstevel@tonic-gate */ 14197c478bd9Sstevel@tonic-gate if (hlen == sizeof(*ip)) { 14207c478bd9Sstevel@tonic-gate fi->fi_optmsk = 0; 14217c478bd9Sstevel@tonic-gate fi->fi_secmsk = 0; 14227c478bd9Sstevel@tonic-gate fi->fi_auth = 0; 14237c478bd9Sstevel@tonic-gate return; 14247c478bd9Sstevel@tonic-gate } 14257c478bd9Sstevel@tonic-gate 14267c478bd9Sstevel@tonic-gate /* 14277c478bd9Sstevel@tonic-gate * So the IP header has some IP options attached. Walk the entire 14287c478bd9Sstevel@tonic-gate * list of options present with this packet and set flags to indicate 14297c478bd9Sstevel@tonic-gate * which ones are here and which ones are not. For the somewhat out 14307c478bd9Sstevel@tonic-gate * of date and obscure security classification options, set a flag to 14317c478bd9Sstevel@tonic-gate * represent which classification is present. 14327c478bd9Sstevel@tonic-gate */ 14337c478bd9Sstevel@tonic-gate fi->fi_flx |= FI_OPTIONS; 14347c478bd9Sstevel@tonic-gate 14357c478bd9Sstevel@tonic-gate for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) { 14367c478bd9Sstevel@tonic-gate opt = *s; 14377c478bd9Sstevel@tonic-gate if (opt == '\0') 14387c478bd9Sstevel@tonic-gate break; 14397c478bd9Sstevel@tonic-gate else if (opt == IPOPT_NOP) 14407c478bd9Sstevel@tonic-gate ol = 1; 14417c478bd9Sstevel@tonic-gate else { 14427c478bd9Sstevel@tonic-gate if (hlen < 2) 14437c478bd9Sstevel@tonic-gate break; 14447c478bd9Sstevel@tonic-gate ol = (int)*(s + 1); 14457c478bd9Sstevel@tonic-gate if (ol < 2 || ol > hlen) 14467c478bd9Sstevel@tonic-gate break; 14477c478bd9Sstevel@tonic-gate } 14487c478bd9Sstevel@tonic-gate for (i = 9, mv = 4; mv >= 0; ) { 14497c478bd9Sstevel@tonic-gate op = ipopts + i; 14507c478bd9Sstevel@tonic-gate if ((opt == (u_char)op->ol_val) && (ol > 4)) { 14517c478bd9Sstevel@tonic-gate optmsk |= op->ol_bit; 14527c478bd9Sstevel@tonic-gate if (opt == IPOPT_SECURITY) { 1453ab25eeb5Syz const struct optlist *sp; 14547c478bd9Sstevel@tonic-gate u_char sec; 14557c478bd9Sstevel@tonic-gate int j, m; 14567c478bd9Sstevel@tonic-gate 14577c478bd9Sstevel@tonic-gate sec = *(s + 2); /* classification */ 14587c478bd9Sstevel@tonic-gate for (j = 3, m = 2; m >= 0; ) { 14597c478bd9Sstevel@tonic-gate sp = secopt + j; 14607c478bd9Sstevel@tonic-gate if (sec == sp->ol_val) { 14617c478bd9Sstevel@tonic-gate secmsk |= sp->ol_bit; 14627c478bd9Sstevel@tonic-gate auth = *(s + 3); 14637c478bd9Sstevel@tonic-gate auth *= 256; 14647c478bd9Sstevel@tonic-gate auth += *(s + 4); 14657c478bd9Sstevel@tonic-gate break; 14667c478bd9Sstevel@tonic-gate } 14677c478bd9Sstevel@tonic-gate if (sec < sp->ol_val) 14687c478bd9Sstevel@tonic-gate j -= m; 14697c478bd9Sstevel@tonic-gate else 14707c478bd9Sstevel@tonic-gate j += m; 14717c478bd9Sstevel@tonic-gate m--; 14727c478bd9Sstevel@tonic-gate } 14737c478bd9Sstevel@tonic-gate } 14747c478bd9Sstevel@tonic-gate break; 14757c478bd9Sstevel@tonic-gate } 14767c478bd9Sstevel@tonic-gate if (opt < op->ol_val) 14777c478bd9Sstevel@tonic-gate i -= mv; 14787c478bd9Sstevel@tonic-gate else 14797c478bd9Sstevel@tonic-gate i += mv; 14807c478bd9Sstevel@tonic-gate mv--; 14817c478bd9Sstevel@tonic-gate } 14827c478bd9Sstevel@tonic-gate hlen -= ol; 14837c478bd9Sstevel@tonic-gate s += ol; 14847c478bd9Sstevel@tonic-gate } 14857c478bd9Sstevel@tonic-gate 14867c478bd9Sstevel@tonic-gate /* 1487ab25eeb5Syz * 14887c478bd9Sstevel@tonic-gate */ 14897c478bd9Sstevel@tonic-gate if (auth && !(auth & 0x0100)) 14907c478bd9Sstevel@tonic-gate auth &= 0xff00; 14917c478bd9Sstevel@tonic-gate fi->fi_optmsk = optmsk; 14927c478bd9Sstevel@tonic-gate fi->fi_secmsk = secmsk; 14937c478bd9Sstevel@tonic-gate fi->fi_auth = auth; 14947c478bd9Sstevel@tonic-gate } 14957c478bd9Sstevel@tonic-gate 14967c478bd9Sstevel@tonic-gate 14977c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 14987c478bd9Sstevel@tonic-gate /* Function: fr_makefrip */ 149908254dd3Syz /* Returns: int - 1 == hdr checking error, 0 == OK */ 15007c478bd9Sstevel@tonic-gate /* Parameters: hlen(I) - length of IP packet header */ 15017c478bd9Sstevel@tonic-gate /* ip(I) - pointer to the IP header */ 1502ab25eeb5Syz /* fin(IO) - pointer to packet information */ 15037c478bd9Sstevel@tonic-gate /* */ 15047c478bd9Sstevel@tonic-gate /* Compact the IP header into a structure which contains just the info. */ 15057c478bd9Sstevel@tonic-gate /* which is useful for comparing IP headers with and store this information */ 15067c478bd9Sstevel@tonic-gate /* in the fr_info_t structure pointer to by fin. At present, it is assumed */ 15077c478bd9Sstevel@tonic-gate /* this function will be called with either an IPv4 or IPv6 packet. */ 15087c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 15097c478bd9Sstevel@tonic-gate int fr_makefrip(hlen, ip, fin) 15107c478bd9Sstevel@tonic-gate int hlen; 15117c478bd9Sstevel@tonic-gate ip_t *ip; 15127c478bd9Sstevel@tonic-gate fr_info_t *fin; 15137c478bd9Sstevel@tonic-gate { 15147c478bd9Sstevel@tonic-gate int v; 15157c478bd9Sstevel@tonic-gate 15167c478bd9Sstevel@tonic-gate fin->fin_depth = 0; 15177c478bd9Sstevel@tonic-gate fin->fin_hlen = (u_short)hlen; 15187c478bd9Sstevel@tonic-gate fin->fin_ip = ip; 15197c478bd9Sstevel@tonic-gate fin->fin_rule = 0xffffffff; 15207c478bd9Sstevel@tonic-gate fin->fin_group[0] = -1; 15217c478bd9Sstevel@tonic-gate fin->fin_group[1] = '\0'; 15227c478bd9Sstevel@tonic-gate fin->fin_dlen = fin->fin_plen - hlen; 15237c478bd9Sstevel@tonic-gate fin->fin_dp = (char *)ip + hlen; 15247c478bd9Sstevel@tonic-gate 15257c478bd9Sstevel@tonic-gate v = fin->fin_v; 15267c478bd9Sstevel@tonic-gate if (v == 4) 15277c478bd9Sstevel@tonic-gate frpr_ipv4hdr(fin); 15287c478bd9Sstevel@tonic-gate #ifdef USE_INET6 152933f2fefdSDarren Reed else if (v == 6) 153033f2fefdSDarren Reed frpr_ipv6hdr(fin); 15317c478bd9Sstevel@tonic-gate #endif 15327c478bd9Sstevel@tonic-gate if (fin->fin_ip == NULL) 15337c478bd9Sstevel@tonic-gate return -1; 15347c478bd9Sstevel@tonic-gate return 0; 15357c478bd9Sstevel@tonic-gate } 15367c478bd9Sstevel@tonic-gate 15377c478bd9Sstevel@tonic-gate 15387c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 15397c478bd9Sstevel@tonic-gate /* Function: fr_portcheck */ 15407c478bd9Sstevel@tonic-gate /* Returns: int - 1 == port matched, 0 == port match failed */ 15417c478bd9Sstevel@tonic-gate /* Parameters: frp(I) - pointer to port check `expression' */ 15427c478bd9Sstevel@tonic-gate /* pop(I) - pointer to port number to evaluate */ 15437c478bd9Sstevel@tonic-gate /* */ 15447c478bd9Sstevel@tonic-gate /* Perform a comparison of a port number against some other(s), using a */ 15457c478bd9Sstevel@tonic-gate /* structure with compare information stored in it. */ 15467c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 15477c478bd9Sstevel@tonic-gate static INLINE int fr_portcheck(frp, pop) 15487c478bd9Sstevel@tonic-gate frpcmp_t *frp; 15497c478bd9Sstevel@tonic-gate u_short *pop; 15507c478bd9Sstevel@tonic-gate { 15517c478bd9Sstevel@tonic-gate u_short tup, po; 15527c478bd9Sstevel@tonic-gate int err = 1; 15537c478bd9Sstevel@tonic-gate 15547c478bd9Sstevel@tonic-gate tup = *pop; 15557c478bd9Sstevel@tonic-gate po = frp->frp_port; 15567c478bd9Sstevel@tonic-gate 15577c478bd9Sstevel@tonic-gate /* 15587c478bd9Sstevel@tonic-gate * Do opposite test to that required and continue if that succeeds. 15597c478bd9Sstevel@tonic-gate */ 15607c478bd9Sstevel@tonic-gate switch (frp->frp_cmp) 15617c478bd9Sstevel@tonic-gate { 15627c478bd9Sstevel@tonic-gate case FR_EQUAL : 15637c478bd9Sstevel@tonic-gate if (tup != po) /* EQUAL */ 15647c478bd9Sstevel@tonic-gate err = 0; 15657c478bd9Sstevel@tonic-gate break; 15667c478bd9Sstevel@tonic-gate case FR_NEQUAL : 15677c478bd9Sstevel@tonic-gate if (tup == po) /* NOTEQUAL */ 15687c478bd9Sstevel@tonic-gate err = 0; 15697c478bd9Sstevel@tonic-gate break; 15707c478bd9Sstevel@tonic-gate case FR_LESST : 15717c478bd9Sstevel@tonic-gate if (tup >= po) /* LESSTHAN */ 15727c478bd9Sstevel@tonic-gate err = 0; 15737c478bd9Sstevel@tonic-gate break; 15747c478bd9Sstevel@tonic-gate case FR_GREATERT : 15757c478bd9Sstevel@tonic-gate if (tup <= po) /* GREATERTHAN */ 15767c478bd9Sstevel@tonic-gate err = 0; 15777c478bd9Sstevel@tonic-gate break; 15787c478bd9Sstevel@tonic-gate case FR_LESSTE : 15797c478bd9Sstevel@tonic-gate if (tup > po) /* LT or EQ */ 15807c478bd9Sstevel@tonic-gate err = 0; 15817c478bd9Sstevel@tonic-gate break; 15827c478bd9Sstevel@tonic-gate case FR_GREATERTE : 15837c478bd9Sstevel@tonic-gate if (tup < po) /* GT or EQ */ 15847c478bd9Sstevel@tonic-gate err = 0; 15857c478bd9Sstevel@tonic-gate break; 15867c478bd9Sstevel@tonic-gate case FR_OUTRANGE : 15877c478bd9Sstevel@tonic-gate if (tup >= po && tup <= frp->frp_top) /* Out of range */ 15887c478bd9Sstevel@tonic-gate err = 0; 15897c478bd9Sstevel@tonic-gate break; 15907c478bd9Sstevel@tonic-gate case FR_INRANGE : 15917c478bd9Sstevel@tonic-gate if (tup <= po || tup >= frp->frp_top) /* In range */ 15927c478bd9Sstevel@tonic-gate err = 0; 15937c478bd9Sstevel@tonic-gate break; 15947c478bd9Sstevel@tonic-gate case FR_INCRANGE : 15957c478bd9Sstevel@tonic-gate if (tup < po || tup > frp->frp_top) /* Inclusive range */ 15967c478bd9Sstevel@tonic-gate err = 0; 15977c478bd9Sstevel@tonic-gate break; 15987c478bd9Sstevel@tonic-gate default : 15997c478bd9Sstevel@tonic-gate break; 16007c478bd9Sstevel@tonic-gate } 16017c478bd9Sstevel@tonic-gate return err; 16027c478bd9Sstevel@tonic-gate } 16037c478bd9Sstevel@tonic-gate 16047c478bd9Sstevel@tonic-gate 16057c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 16067c478bd9Sstevel@tonic-gate /* Function: fr_tcpudpchk */ 16077c478bd9Sstevel@tonic-gate /* Returns: int - 1 == protocol matched, 0 == check failed */ 16087c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 16097c478bd9Sstevel@tonic-gate /* ft(I) - pointer to structure with comparison data */ 16107c478bd9Sstevel@tonic-gate /* */ 16117c478bd9Sstevel@tonic-gate /* Compares the current pcket (assuming it is TCP/UDP) information with a */ 16127c478bd9Sstevel@tonic-gate /* structure containing information that we want to match against. */ 16137c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 16147c478bd9Sstevel@tonic-gate int fr_tcpudpchk(fin, ft) 16157c478bd9Sstevel@tonic-gate fr_info_t *fin; 16167c478bd9Sstevel@tonic-gate frtuc_t *ft; 16177c478bd9Sstevel@tonic-gate { 16187c478bd9Sstevel@tonic-gate int err = 1; 16197c478bd9Sstevel@tonic-gate 16207c478bd9Sstevel@tonic-gate /* 16217c478bd9Sstevel@tonic-gate * Both ports should *always* be in the first fragment. 16227c478bd9Sstevel@tonic-gate * So far, I cannot find any cases where they can not be. 16237c478bd9Sstevel@tonic-gate * 16247c478bd9Sstevel@tonic-gate * compare destination ports 16257c478bd9Sstevel@tonic-gate */ 16267c478bd9Sstevel@tonic-gate if (ft->ftu_dcmp) 16277c478bd9Sstevel@tonic-gate err = fr_portcheck(&ft->ftu_dst, &fin->fin_dport); 16287c478bd9Sstevel@tonic-gate 16297c478bd9Sstevel@tonic-gate /* 16307c478bd9Sstevel@tonic-gate * compare source ports 16317c478bd9Sstevel@tonic-gate */ 16327c478bd9Sstevel@tonic-gate if (err && ft->ftu_scmp) 16337c478bd9Sstevel@tonic-gate err = fr_portcheck(&ft->ftu_src, &fin->fin_sport); 16347c478bd9Sstevel@tonic-gate 16357c478bd9Sstevel@tonic-gate /* 16367c478bd9Sstevel@tonic-gate * If we don't have all the TCP/UDP header, then how can we 16377c478bd9Sstevel@tonic-gate * expect to do any sort of match on it ? If we were looking for 16387c478bd9Sstevel@tonic-gate * TCP flags, then NO match. If not, then match (which should 16397c478bd9Sstevel@tonic-gate * satisfy the "short" class too). 16407c478bd9Sstevel@tonic-gate */ 16417c478bd9Sstevel@tonic-gate if (err && (fin->fin_p == IPPROTO_TCP)) { 16427c478bd9Sstevel@tonic-gate if (fin->fin_flx & FI_SHORT) 16437c478bd9Sstevel@tonic-gate return !(ft->ftu_tcpf | ft->ftu_tcpfm); 16447c478bd9Sstevel@tonic-gate /* 16457c478bd9Sstevel@tonic-gate * Match the flags ? If not, abort this match. 16467c478bd9Sstevel@tonic-gate */ 16477c478bd9Sstevel@tonic-gate if (ft->ftu_tcpfm && 16487c478bd9Sstevel@tonic-gate ft->ftu_tcpf != (fin->fin_tcpf & ft->ftu_tcpfm)) { 16497c478bd9Sstevel@tonic-gate FR_DEBUG(("f. %#x & %#x != %#x\n", fin->fin_tcpf, 16507c478bd9Sstevel@tonic-gate ft->ftu_tcpfm, ft->ftu_tcpf)); 16517c478bd9Sstevel@tonic-gate err = 0; 16527c478bd9Sstevel@tonic-gate } 16537c478bd9Sstevel@tonic-gate } 16547c478bd9Sstevel@tonic-gate return err; 16557c478bd9Sstevel@tonic-gate } 16567c478bd9Sstevel@tonic-gate 16577c478bd9Sstevel@tonic-gate 16587c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 16597c478bd9Sstevel@tonic-gate /* Function: fr_ipfcheck */ 16607c478bd9Sstevel@tonic-gate /* Returns: int - 0 == match, 1 == no match */ 16617c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 16627c478bd9Sstevel@tonic-gate /* fr(I) - pointer to filter rule */ 16637c478bd9Sstevel@tonic-gate /* portcmp(I) - flag indicating whether to attempt matching on */ 16647c478bd9Sstevel@tonic-gate /* TCP/UDP port data. */ 16657c478bd9Sstevel@tonic-gate /* */ 16667c478bd9Sstevel@tonic-gate /* Check to see if a packet matches an IPFilter rule. Checks of addresses, */ 16677c478bd9Sstevel@tonic-gate /* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */ 16687c478bd9Sstevel@tonic-gate /* this function. */ 16697c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 16707c478bd9Sstevel@tonic-gate static INLINE int fr_ipfcheck(fin, fr, portcmp) 16717c478bd9Sstevel@tonic-gate fr_info_t *fin; 16727c478bd9Sstevel@tonic-gate frentry_t *fr; 16737c478bd9Sstevel@tonic-gate int portcmp; 16747c478bd9Sstevel@tonic-gate { 16757c478bd9Sstevel@tonic-gate u_32_t *ld, *lm, *lip; 16767c478bd9Sstevel@tonic-gate fripf_t *fri; 16777c478bd9Sstevel@tonic-gate fr_ip_t *fi; 16787c478bd9Sstevel@tonic-gate int i; 1679f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 16807c478bd9Sstevel@tonic-gate 16817c478bd9Sstevel@tonic-gate fi = &fin->fin_fi; 16827c478bd9Sstevel@tonic-gate fri = fr->fr_ipf; 16837c478bd9Sstevel@tonic-gate lip = (u_32_t *)fi; 16847c478bd9Sstevel@tonic-gate lm = (u_32_t *)&fri->fri_mip; 16857c478bd9Sstevel@tonic-gate ld = (u_32_t *)&fri->fri_ip; 16867c478bd9Sstevel@tonic-gate 16877c478bd9Sstevel@tonic-gate /* 16887c478bd9Sstevel@tonic-gate * first 32 bits to check coversion: 16897c478bd9Sstevel@tonic-gate * IP version, TOS, TTL, protocol 16907c478bd9Sstevel@tonic-gate */ 16917c478bd9Sstevel@tonic-gate i = ((*lip & *lm) != *ld); 16927c478bd9Sstevel@tonic-gate FR_DEBUG(("0. %#08x & %#08x != %#08x\n", 16937c478bd9Sstevel@tonic-gate *lip, *lm, *ld)); 16947c478bd9Sstevel@tonic-gate if (i) 16957c478bd9Sstevel@tonic-gate return 1; 16967c478bd9Sstevel@tonic-gate 16977c478bd9Sstevel@tonic-gate /* 16987c478bd9Sstevel@tonic-gate * Next 32 bits is a constructed bitmask indicating which IP options 16997c478bd9Sstevel@tonic-gate * are present (if any) in this packet. 17007c478bd9Sstevel@tonic-gate */ 17017c478bd9Sstevel@tonic-gate lip++, lm++, ld++; 17027c478bd9Sstevel@tonic-gate i |= ((*lip & *lm) != *ld); 17037c478bd9Sstevel@tonic-gate FR_DEBUG(("1. %#08x & %#08x != %#08x\n", 17047c478bd9Sstevel@tonic-gate *lip, *lm, *ld)); 17057c478bd9Sstevel@tonic-gate if (i) 17067c478bd9Sstevel@tonic-gate return 1; 17077c478bd9Sstevel@tonic-gate 17087c478bd9Sstevel@tonic-gate lip++, lm++, ld++; 17097c478bd9Sstevel@tonic-gate /* 17107c478bd9Sstevel@tonic-gate * Unrolled loops (4 each, for 32 bits) for address checks. 17117c478bd9Sstevel@tonic-gate */ 17127c478bd9Sstevel@tonic-gate /* 17137c478bd9Sstevel@tonic-gate * Check the source address. 17147c478bd9Sstevel@tonic-gate */ 17157c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOOKUP 17167c478bd9Sstevel@tonic-gate if (fr->fr_satype == FRI_LOOKUP) { 1717de22af4eSJohn Ojemann fin->fin_flx |= FI_DONTCACHE; 1718de22af4eSJohn Ojemann i = (*fr->fr_srcfunc)(fr->fr_srcptr, fi->fi_v, lip, fin, ifs); 17197c478bd9Sstevel@tonic-gate if (i == -1) 17207c478bd9Sstevel@tonic-gate return 1; 17217c478bd9Sstevel@tonic-gate lip += 3; 17227c478bd9Sstevel@tonic-gate lm += 3; 17237c478bd9Sstevel@tonic-gate ld += 3; 17247c478bd9Sstevel@tonic-gate } else { 17257c478bd9Sstevel@tonic-gate #endif 17267c478bd9Sstevel@tonic-gate i = ((*lip & *lm) != *ld); 17277c478bd9Sstevel@tonic-gate FR_DEBUG(("2a. %#08x & %#08x != %#08x\n", 17287c478bd9Sstevel@tonic-gate *lip, *lm, *ld)); 17297c478bd9Sstevel@tonic-gate if (fi->fi_v == 6) { 17307c478bd9Sstevel@tonic-gate lip++, lm++, ld++; 17317c478bd9Sstevel@tonic-gate i |= ((*lip & *lm) != *ld); 17327c478bd9Sstevel@tonic-gate FR_DEBUG(("2b. %#08x & %#08x != %#08x\n", 17337c478bd9Sstevel@tonic-gate *lip, *lm, *ld)); 17347c478bd9Sstevel@tonic-gate lip++, lm++, ld++; 17357c478bd9Sstevel@tonic-gate i |= ((*lip & *lm) != *ld); 17367c478bd9Sstevel@tonic-gate FR_DEBUG(("2c. %#08x & %#08x != %#08x\n", 17377c478bd9Sstevel@tonic-gate *lip, *lm, *ld)); 17387c478bd9Sstevel@tonic-gate lip++, lm++, ld++; 17397c478bd9Sstevel@tonic-gate i |= ((*lip & *lm) != *ld); 17407c478bd9Sstevel@tonic-gate FR_DEBUG(("2d. %#08x & %#08x != %#08x\n", 17417c478bd9Sstevel@tonic-gate *lip, *lm, *ld)); 17427c478bd9Sstevel@tonic-gate } else { 17437c478bd9Sstevel@tonic-gate lip += 3; 17447c478bd9Sstevel@tonic-gate lm += 3; 17457c478bd9Sstevel@tonic-gate ld += 3; 17467c478bd9Sstevel@tonic-gate } 17477c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOOKUP 17487c478bd9Sstevel@tonic-gate } 17497c478bd9Sstevel@tonic-gate #endif 17507c478bd9Sstevel@tonic-gate i ^= (fr->fr_flags & FR_NOTSRCIP) >> 6; 17517c478bd9Sstevel@tonic-gate if (i) 17527c478bd9Sstevel@tonic-gate return 1; 17537c478bd9Sstevel@tonic-gate 17547c478bd9Sstevel@tonic-gate /* 17557c478bd9Sstevel@tonic-gate * Check the destination address. 17567c478bd9Sstevel@tonic-gate */ 17577c478bd9Sstevel@tonic-gate lip++, lm++, ld++; 17587c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOOKUP 17597c478bd9Sstevel@tonic-gate if (fr->fr_datype == FRI_LOOKUP) { 1760de22af4eSJohn Ojemann fin->fin_flx |= FI_DONTCACHE; 1761de22af4eSJohn Ojemann i = (*fr->fr_dstfunc)(fr->fr_dstptr, fi->fi_v, lip, fin, ifs); 17627c478bd9Sstevel@tonic-gate if (i == -1) 17637c478bd9Sstevel@tonic-gate return 1; 17647c478bd9Sstevel@tonic-gate lip += 3; 17657c478bd9Sstevel@tonic-gate lm += 3; 17667c478bd9Sstevel@tonic-gate ld += 3; 17677c478bd9Sstevel@tonic-gate } else { 17687c478bd9Sstevel@tonic-gate #endif 17697c478bd9Sstevel@tonic-gate i = ((*lip & *lm) != *ld); 17707c478bd9Sstevel@tonic-gate FR_DEBUG(("3a. %#08x & %#08x != %#08x\n", 17717c478bd9Sstevel@tonic-gate *lip, *lm, *ld)); 17727c478bd9Sstevel@tonic-gate if (fi->fi_v == 6) { 17737c478bd9Sstevel@tonic-gate lip++, lm++, ld++; 17747c478bd9Sstevel@tonic-gate i |= ((*lip & *lm) != *ld); 17757c478bd9Sstevel@tonic-gate FR_DEBUG(("3b. %#08x & %#08x != %#08x\n", 17767c478bd9Sstevel@tonic-gate *lip, *lm, *ld)); 17777c478bd9Sstevel@tonic-gate lip++, lm++, ld++; 17787c478bd9Sstevel@tonic-gate i |= ((*lip & *lm) != *ld); 17797c478bd9Sstevel@tonic-gate FR_DEBUG(("3c. %#08x & %#08x != %#08x\n", 17807c478bd9Sstevel@tonic-gate *lip, *lm, *ld)); 17817c478bd9Sstevel@tonic-gate lip++, lm++, ld++; 17827c478bd9Sstevel@tonic-gate i |= ((*lip & *lm) != *ld); 17837c478bd9Sstevel@tonic-gate FR_DEBUG(("3d. %#08x & %#08x != %#08x\n", 17847c478bd9Sstevel@tonic-gate *lip, *lm, *ld)); 17857c478bd9Sstevel@tonic-gate } else { 17867c478bd9Sstevel@tonic-gate lip += 3; 17877c478bd9Sstevel@tonic-gate lm += 3; 17887c478bd9Sstevel@tonic-gate ld += 3; 17897c478bd9Sstevel@tonic-gate } 17907c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOOKUP 17917c478bd9Sstevel@tonic-gate } 17927c478bd9Sstevel@tonic-gate #endif 17937c478bd9Sstevel@tonic-gate i ^= (fr->fr_flags & FR_NOTDSTIP) >> 7; 17947c478bd9Sstevel@tonic-gate if (i) 17957c478bd9Sstevel@tonic-gate return 1; 17967c478bd9Sstevel@tonic-gate /* 17977c478bd9Sstevel@tonic-gate * IP addresses matched. The next 32bits contains: 17987c478bd9Sstevel@tonic-gate * mast of old IP header security & authentication bits. 17997c478bd9Sstevel@tonic-gate */ 18007c478bd9Sstevel@tonic-gate lip++, lm++, ld++; 18017c478bd9Sstevel@tonic-gate i |= ((*lip & *lm) != *ld); 18027c478bd9Sstevel@tonic-gate FR_DEBUG(("4. %#08x & %#08x != %#08x\n", 18037c478bd9Sstevel@tonic-gate *lip, *lm, *ld)); 18047c478bd9Sstevel@tonic-gate 18057c478bd9Sstevel@tonic-gate /* 18067c478bd9Sstevel@tonic-gate * Next we have 32 bits of packet flags. 18077c478bd9Sstevel@tonic-gate */ 18087c478bd9Sstevel@tonic-gate lip++, lm++, ld++; 18097c478bd9Sstevel@tonic-gate i |= ((*lip & *lm) != *ld); 18107c478bd9Sstevel@tonic-gate FR_DEBUG(("5. %#08x & %#08x != %#08x\n", 18117c478bd9Sstevel@tonic-gate *lip, *lm, *ld)); 18127c478bd9Sstevel@tonic-gate 18137c478bd9Sstevel@tonic-gate if (i == 0) { 18147c478bd9Sstevel@tonic-gate /* 18157c478bd9Sstevel@tonic-gate * If a fragment, then only the first has what we're 18167c478bd9Sstevel@tonic-gate * looking for here... 18177c478bd9Sstevel@tonic-gate */ 18187c478bd9Sstevel@tonic-gate if (portcmp) { 18197c478bd9Sstevel@tonic-gate if (!fr_tcpudpchk(fin, &fr->fr_tuc)) 18207c478bd9Sstevel@tonic-gate i = 1; 18217c478bd9Sstevel@tonic-gate } else { 18227c478bd9Sstevel@tonic-gate if (fr->fr_dcmp || fr->fr_scmp || 18237c478bd9Sstevel@tonic-gate fr->fr_tcpf || fr->fr_tcpfm) 18247c478bd9Sstevel@tonic-gate i = 1; 18257c478bd9Sstevel@tonic-gate if (fr->fr_icmpm || fr->fr_icmp) { 18267c478bd9Sstevel@tonic-gate if (((fi->fi_p != IPPROTO_ICMP) && 18277c478bd9Sstevel@tonic-gate (fi->fi_p != IPPROTO_ICMPV6)) || 18287c478bd9Sstevel@tonic-gate fin->fin_off || (fin->fin_dlen < 2)) 18297c478bd9Sstevel@tonic-gate i = 1; 18307c478bd9Sstevel@tonic-gate else if ((fin->fin_data[0] & fr->fr_icmpm) != 18317c478bd9Sstevel@tonic-gate fr->fr_icmp) { 18327c478bd9Sstevel@tonic-gate FR_DEBUG(("i. %#x & %#x != %#x\n", 18337c478bd9Sstevel@tonic-gate fin->fin_data[0], 18347c478bd9Sstevel@tonic-gate fr->fr_icmpm, fr->fr_icmp)); 18357c478bd9Sstevel@tonic-gate i = 1; 18367c478bd9Sstevel@tonic-gate } 18377c478bd9Sstevel@tonic-gate } 18387c478bd9Sstevel@tonic-gate } 18397c478bd9Sstevel@tonic-gate } 18407c478bd9Sstevel@tonic-gate return i; 18417c478bd9Sstevel@tonic-gate } 18427c478bd9Sstevel@tonic-gate 18437c478bd9Sstevel@tonic-gate 18447c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 18457c478bd9Sstevel@tonic-gate /* Function: fr_scanlist */ 18467c478bd9Sstevel@tonic-gate /* Returns: int - result flags of scanning filter list */ 18477c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 18487c478bd9Sstevel@tonic-gate /* pass(I) - default result to return for filtering */ 18497c478bd9Sstevel@tonic-gate /* */ 18507c478bd9Sstevel@tonic-gate /* Check the input/output list of rules for a match to the current packet. */ 18517c478bd9Sstevel@tonic-gate /* If a match is found, the value of fr_flags from the rule becomes the */ 18527c478bd9Sstevel@tonic-gate /* return value and fin->fin_fr points to the matched rule. */ 18537c478bd9Sstevel@tonic-gate /* */ 18547c478bd9Sstevel@tonic-gate /* This function may be called recusively upto 16 times (limit inbuilt.) */ 18557c478bd9Sstevel@tonic-gate /* When unwinding, it should finish up with fin_depth as 0. */ 18567c478bd9Sstevel@tonic-gate /* */ 18577c478bd9Sstevel@tonic-gate /* Could be per interface, but this gets real nasty when you don't have, */ 18587c478bd9Sstevel@tonic-gate /* or can't easily change, the kernel source code to . */ 18597c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 18607c478bd9Sstevel@tonic-gate int fr_scanlist(fin, pass) 18617c478bd9Sstevel@tonic-gate fr_info_t *fin; 18627c478bd9Sstevel@tonic-gate u_32_t pass; 18637c478bd9Sstevel@tonic-gate { 18647c478bd9Sstevel@tonic-gate int rulen, portcmp, off, logged, skip; 18657c478bd9Sstevel@tonic-gate struct frentry *fr, *fnext; 1866ab25eeb5Syz u_32_t passt, passo; 1867f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 18687c478bd9Sstevel@tonic-gate 18697c478bd9Sstevel@tonic-gate /* 18707c478bd9Sstevel@tonic-gate * Do not allow nesting deeper than 16 levels. 18717c478bd9Sstevel@tonic-gate */ 18727c478bd9Sstevel@tonic-gate if (fin->fin_depth >= 16) 18737c478bd9Sstevel@tonic-gate return pass; 18747c478bd9Sstevel@tonic-gate 18757c478bd9Sstevel@tonic-gate fr = fin->fin_fr; 18767c478bd9Sstevel@tonic-gate 18777c478bd9Sstevel@tonic-gate /* 18787c478bd9Sstevel@tonic-gate * If there are no rules in this list, return now. 18797c478bd9Sstevel@tonic-gate */ 18807c478bd9Sstevel@tonic-gate if (fr == NULL) 18817c478bd9Sstevel@tonic-gate return pass; 18827c478bd9Sstevel@tonic-gate 18837c478bd9Sstevel@tonic-gate skip = 0; 18847c478bd9Sstevel@tonic-gate logged = 0; 18857c478bd9Sstevel@tonic-gate portcmp = 0; 18867c478bd9Sstevel@tonic-gate fin->fin_depth++; 18877c478bd9Sstevel@tonic-gate fin->fin_fr = NULL; 18887c478bd9Sstevel@tonic-gate off = fin->fin_off; 18897c478bd9Sstevel@tonic-gate 18907c478bd9Sstevel@tonic-gate if ((fin->fin_flx & FI_TCPUDP) && (fin->fin_dlen > 3) && !off) 18917c478bd9Sstevel@tonic-gate portcmp = 1; 18927c478bd9Sstevel@tonic-gate 18937c478bd9Sstevel@tonic-gate for (rulen = 0; fr; fr = fnext, rulen++) { 18947c478bd9Sstevel@tonic-gate fnext = fr->fr_next; 18957c478bd9Sstevel@tonic-gate if (skip != 0) { 18967c478bd9Sstevel@tonic-gate FR_VERBOSE(("%d (%#x)\n", skip, fr->fr_flags)); 18977c478bd9Sstevel@tonic-gate skip--; 18987c478bd9Sstevel@tonic-gate continue; 18997c478bd9Sstevel@tonic-gate } 19007c478bd9Sstevel@tonic-gate 19017c478bd9Sstevel@tonic-gate /* 19027c478bd9Sstevel@tonic-gate * In all checks below, a null (zero) value in the 19037c478bd9Sstevel@tonic-gate * filter struture is taken to mean a wildcard. 19047c478bd9Sstevel@tonic-gate * 19057c478bd9Sstevel@tonic-gate * check that we are working for the right interface 19067c478bd9Sstevel@tonic-gate */ 19077c478bd9Sstevel@tonic-gate #ifdef _KERNEL 19087c478bd9Sstevel@tonic-gate if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) 19097c478bd9Sstevel@tonic-gate continue; 19107c478bd9Sstevel@tonic-gate #else 19117c478bd9Sstevel@tonic-gate if (opts & (OPT_VERBOSE|OPT_DEBUG)) 19127c478bd9Sstevel@tonic-gate printf("\n"); 19137c478bd9Sstevel@tonic-gate FR_VERBOSE(("%c", FR_ISSKIP(pass) ? 's' : 1914ab25eeb5Syz FR_ISPASS(pass) ? 'p' : 19157c478bd9Sstevel@tonic-gate FR_ISACCOUNT(pass) ? 'A' : 19167c478bd9Sstevel@tonic-gate FR_ISAUTH(pass) ? 'a' : 19177c478bd9Sstevel@tonic-gate (pass & FR_NOMATCH) ? 'n' :'b')); 19187c478bd9Sstevel@tonic-gate if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) 19197c478bd9Sstevel@tonic-gate continue; 19207c478bd9Sstevel@tonic-gate FR_VERBOSE((":i")); 19217c478bd9Sstevel@tonic-gate #endif 19227c478bd9Sstevel@tonic-gate 19237c478bd9Sstevel@tonic-gate switch (fr->fr_type) 19247c478bd9Sstevel@tonic-gate { 19257c478bd9Sstevel@tonic-gate case FR_T_IPF : 19267c478bd9Sstevel@tonic-gate case FR_T_IPF|FR_T_BUILTIN : 19277c478bd9Sstevel@tonic-gate if (fr_ipfcheck(fin, fr, portcmp)) 19287c478bd9Sstevel@tonic-gate continue; 19297c478bd9Sstevel@tonic-gate break; 1930ab25eeb5Syz #if defined(IPFILTER_BPF) 19317c478bd9Sstevel@tonic-gate case FR_T_BPFOPC : 19327c478bd9Sstevel@tonic-gate case FR_T_BPFOPC|FR_T_BUILTIN : 19337c478bd9Sstevel@tonic-gate { 19347c478bd9Sstevel@tonic-gate u_char *mc; 19357c478bd9Sstevel@tonic-gate 19367c478bd9Sstevel@tonic-gate if (*fin->fin_mp == NULL) 19377c478bd9Sstevel@tonic-gate continue; 19387c478bd9Sstevel@tonic-gate if (fin->fin_v != fr->fr_v) 19397c478bd9Sstevel@tonic-gate continue; 19407c478bd9Sstevel@tonic-gate mc = (u_char *)fin->fin_m; 1941ab25eeb5Syz if (!bpf_filter(fr->fr_data, mc, fin->fin_plen, 0)) 19427c478bd9Sstevel@tonic-gate continue; 19437c478bd9Sstevel@tonic-gate break; 19447c478bd9Sstevel@tonic-gate } 19457c478bd9Sstevel@tonic-gate #endif 19467c478bd9Sstevel@tonic-gate case FR_T_CALLFUNC|FR_T_BUILTIN : 19477c478bd9Sstevel@tonic-gate { 19487c478bd9Sstevel@tonic-gate frentry_t *f; 19497c478bd9Sstevel@tonic-gate 19507c478bd9Sstevel@tonic-gate f = (*fr->fr_func)(fin, &pass); 19517c478bd9Sstevel@tonic-gate if (f != NULL) 19527c478bd9Sstevel@tonic-gate fr = f; 19537c478bd9Sstevel@tonic-gate else 19547c478bd9Sstevel@tonic-gate continue; 19557c478bd9Sstevel@tonic-gate break; 19567c478bd9Sstevel@tonic-gate } 19577c478bd9Sstevel@tonic-gate default : 19587c478bd9Sstevel@tonic-gate break; 19597c478bd9Sstevel@tonic-gate } 19607c478bd9Sstevel@tonic-gate 19617c478bd9Sstevel@tonic-gate if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) { 19627c478bd9Sstevel@tonic-gate if (fin->fin_nattag == NULL) 19637c478bd9Sstevel@tonic-gate continue; 19647c478bd9Sstevel@tonic-gate if (fr_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0) 19657c478bd9Sstevel@tonic-gate continue; 19667c478bd9Sstevel@tonic-gate } 19677c478bd9Sstevel@tonic-gate FR_VERBOSE(("=%s.%d *", fr->fr_group, rulen)); 19687c478bd9Sstevel@tonic-gate 19697c478bd9Sstevel@tonic-gate passt = fr->fr_flags; 19707c478bd9Sstevel@tonic-gate 1971ab25eeb5Syz /* 1972ab25eeb5Syz * Allowing a rule with the "keep state" flag set to match 1973ab25eeb5Syz * packets that have been tagged "out of window" by the TCP 1974ab25eeb5Syz * state tracking is foolish as the attempt to add a new 1975ab25eeb5Syz * state entry to the table will fail. 1976ab25eeb5Syz */ 1977ab25eeb5Syz if ((passt & FR_KEEPSTATE) && (fin->fin_flx & FI_OOW)) 1978ab25eeb5Syz continue; 1979ab25eeb5Syz 19807c478bd9Sstevel@tonic-gate /* 19817c478bd9Sstevel@tonic-gate * If the rule is a "call now" rule, then call the function 19827c478bd9Sstevel@tonic-gate * in the rule, if it exists and use the results from that. 19837c478bd9Sstevel@tonic-gate * If the function pointer is bad, just make like we ignore 19847c478bd9Sstevel@tonic-gate * it, except for increasing the hit counter. 19857c478bd9Sstevel@tonic-gate */ 1986de22af4eSJohn Ojemann IPF_BUMP(fr->fr_hits); 1987de22af4eSJohn Ojemann fr->fr_bytes += (U_QUAD_T)fin->fin_plen; 19887c478bd9Sstevel@tonic-gate if ((passt & FR_CALLNOW) != 0) { 19897c478bd9Sstevel@tonic-gate if ((fr->fr_func != NULL) && 19907c478bd9Sstevel@tonic-gate (fr->fr_func != (ipfunc_t)-1)) { 19917c478bd9Sstevel@tonic-gate frentry_t *frs; 19927c478bd9Sstevel@tonic-gate 19937c478bd9Sstevel@tonic-gate frs = fin->fin_fr; 19947c478bd9Sstevel@tonic-gate fin->fin_fr = fr; 19957c478bd9Sstevel@tonic-gate fr = (*fr->fr_func)(fin, &passt); 19967c478bd9Sstevel@tonic-gate if (fr == NULL) { 19977c478bd9Sstevel@tonic-gate fin->fin_fr = frs; 19987c478bd9Sstevel@tonic-gate continue; 19997c478bd9Sstevel@tonic-gate } 20007c478bd9Sstevel@tonic-gate passt = fr->fr_flags; 20017c478bd9Sstevel@tonic-gate fin->fin_fr = fr; 20027c478bd9Sstevel@tonic-gate } 20037c478bd9Sstevel@tonic-gate } else { 20047c478bd9Sstevel@tonic-gate fin->fin_fr = fr; 20057c478bd9Sstevel@tonic-gate } 20067c478bd9Sstevel@tonic-gate 20077c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 20087c478bd9Sstevel@tonic-gate /* 20097c478bd9Sstevel@tonic-gate * Just log this packet... 20107c478bd9Sstevel@tonic-gate */ 20117c478bd9Sstevel@tonic-gate if ((passt & FR_LOGMASK) == FR_LOG) { 20127c478bd9Sstevel@tonic-gate if (ipflog(fin, passt) == -1) { 20137c478bd9Sstevel@tonic-gate if (passt & FR_LOGORBLOCK) { 20147c478bd9Sstevel@tonic-gate passt &= ~FR_CMDMASK; 20157c478bd9Sstevel@tonic-gate passt |= FR_BLOCK|FR_QUICK; 20167c478bd9Sstevel@tonic-gate } 2017cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[fin->fin_out].fr_skip); 20187c478bd9Sstevel@tonic-gate } 2019cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[fin->fin_out].fr_pkl); 20207c478bd9Sstevel@tonic-gate logged = 1; 20217c478bd9Sstevel@tonic-gate } 20227c478bd9Sstevel@tonic-gate #endif /* IPFILTER_LOG */ 2023ab25eeb5Syz passo = pass; 20247c478bd9Sstevel@tonic-gate if (FR_ISSKIP(passt)) 20257c478bd9Sstevel@tonic-gate skip = fr->fr_arg; 20267c478bd9Sstevel@tonic-gate else if ((passt & FR_LOGMASK) != FR_LOG) 20277c478bd9Sstevel@tonic-gate pass = passt; 20287c478bd9Sstevel@tonic-gate if (passt & (FR_RETICMP|FR_FAKEICMP)) 20297c478bd9Sstevel@tonic-gate fin->fin_icode = fr->fr_icode; 20307c478bd9Sstevel@tonic-gate FR_DEBUG(("pass %#x\n", pass)); 20317c478bd9Sstevel@tonic-gate fin->fin_rule = rulen; 20327c478bd9Sstevel@tonic-gate (void) strncpy(fin->fin_group, fr->fr_group, FR_GROUPLEN); 20337c478bd9Sstevel@tonic-gate if (fr->fr_grp != NULL) { 20347c478bd9Sstevel@tonic-gate fin->fin_fr = *fr->fr_grp; 20357c478bd9Sstevel@tonic-gate pass = fr_scanlist(fin, pass); 20367c478bd9Sstevel@tonic-gate if (fin->fin_fr == NULL) { 20377c478bd9Sstevel@tonic-gate fin->fin_rule = rulen; 20387c478bd9Sstevel@tonic-gate (void) strncpy(fin->fin_group, fr->fr_group, 20397c478bd9Sstevel@tonic-gate FR_GROUPLEN); 20407c478bd9Sstevel@tonic-gate fin->fin_fr = fr; 20417c478bd9Sstevel@tonic-gate } 20427c478bd9Sstevel@tonic-gate if (fin->fin_flx & FI_DONTCACHE) 20437c478bd9Sstevel@tonic-gate logged = 1; 20447c478bd9Sstevel@tonic-gate } 2045ab25eeb5Syz 2046ab25eeb5Syz if (pass & FR_QUICK) { 2047ab25eeb5Syz /* 2048ab25eeb5Syz * Finally, if we've asked to track state for this 2049ab25eeb5Syz * packet, set it up. Add state for "quick" rules 2050ab25eeb5Syz * here so that if the action fails we can consider 2051ab25eeb5Syz * the rule to "not match" and keep on processing 2052ab25eeb5Syz * filter rules. 2053ab25eeb5Syz */ 2054ab25eeb5Syz if ((pass & FR_KEEPSTATE) && 2055ab25eeb5Syz !(fin->fin_flx & FI_STATE)) { 2056ab25eeb5Syz int out = fin->fin_out; 2057ab25eeb5Syz 2058ab25eeb5Syz if (fr_addstate(fin, NULL, 0) != NULL) { 2059cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[out].fr_ads); 2060ab25eeb5Syz } else { 2061cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[out].fr_bads); 2062ab25eeb5Syz pass = passo; 2063ab25eeb5Syz continue; 2064ab25eeb5Syz } 2065ab25eeb5Syz } 20667c478bd9Sstevel@tonic-gate break; 2067ab25eeb5Syz } 20687c478bd9Sstevel@tonic-gate } 20697c478bd9Sstevel@tonic-gate if (logged) 20707c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_DONTCACHE; 20717c478bd9Sstevel@tonic-gate fin->fin_depth--; 20727c478bd9Sstevel@tonic-gate return pass; 20737c478bd9Sstevel@tonic-gate } 20747c478bd9Sstevel@tonic-gate 20757c478bd9Sstevel@tonic-gate 20767c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 20777c478bd9Sstevel@tonic-gate /* Function: fr_acctpkt */ 20787c478bd9Sstevel@tonic-gate /* Returns: frentry_t* - always returns NULL */ 20797c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 20807c478bd9Sstevel@tonic-gate /* passp(IO) - pointer to current/new filter decision (unused) */ 20817c478bd9Sstevel@tonic-gate /* */ 20827c478bd9Sstevel@tonic-gate /* Checks a packet against accounting rules, if there are any for the given */ 20837c478bd9Sstevel@tonic-gate /* IP protocol version. */ 20847c478bd9Sstevel@tonic-gate /* */ 20857c478bd9Sstevel@tonic-gate /* N.B.: this function returns NULL to match the prototype used by other */ 20867c478bd9Sstevel@tonic-gate /* functions called from the IPFilter "mainline" in fr_check(). */ 20877c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 20887c478bd9Sstevel@tonic-gate frentry_t *fr_acctpkt(fin, passp) 20897c478bd9Sstevel@tonic-gate fr_info_t *fin; 20907c478bd9Sstevel@tonic-gate u_32_t *passp; 20917c478bd9Sstevel@tonic-gate { 20927c478bd9Sstevel@tonic-gate char group[FR_GROUPLEN]; 20937c478bd9Sstevel@tonic-gate frentry_t *fr, *frsave; 20947c478bd9Sstevel@tonic-gate u_32_t pass, rulen; 2095f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 20967c478bd9Sstevel@tonic-gate 20977c478bd9Sstevel@tonic-gate passp = passp; 20987c478bd9Sstevel@tonic-gate #ifdef USE_INET6 20997c478bd9Sstevel@tonic-gate if (fin->fin_v == 6) 2100f4b3ec61Sdh fr = ifs->ifs_ipacct6[fin->fin_out][ifs->ifs_fr_active]; 21017c478bd9Sstevel@tonic-gate else 21027c478bd9Sstevel@tonic-gate #endif 2103f4b3ec61Sdh fr = ifs->ifs_ipacct[fin->fin_out][ifs->ifs_fr_active]; 21047c478bd9Sstevel@tonic-gate 21057c478bd9Sstevel@tonic-gate if (fr != NULL) { 21067c478bd9Sstevel@tonic-gate frsave = fin->fin_fr; 21077c478bd9Sstevel@tonic-gate bcopy(fin->fin_group, group, FR_GROUPLEN); 21087c478bd9Sstevel@tonic-gate rulen = fin->fin_rule; 21097c478bd9Sstevel@tonic-gate fin->fin_fr = fr; 21107c478bd9Sstevel@tonic-gate pass = fr_scanlist(fin, FR_NOMATCH); 21117c478bd9Sstevel@tonic-gate if (FR_ISACCOUNT(pass)) { 2112cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[0].fr_acct); 21137c478bd9Sstevel@tonic-gate } 21147c478bd9Sstevel@tonic-gate fin->fin_fr = frsave; 21157c478bd9Sstevel@tonic-gate bcopy(group, fin->fin_group, FR_GROUPLEN); 21167c478bd9Sstevel@tonic-gate fin->fin_rule = rulen; 21177c478bd9Sstevel@tonic-gate } 21187c478bd9Sstevel@tonic-gate return NULL; 21197c478bd9Sstevel@tonic-gate } 21207c478bd9Sstevel@tonic-gate 21217c478bd9Sstevel@tonic-gate 21227c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 21237c478bd9Sstevel@tonic-gate /* Function: fr_firewall */ 21247c478bd9Sstevel@tonic-gate /* Returns: frentry_t* - returns pointer to matched rule, if no matches */ 21257c478bd9Sstevel@tonic-gate /* were found, returns NULL. */ 21267c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 21277c478bd9Sstevel@tonic-gate /* passp(IO) - pointer to current/new filter decision (unused) */ 21287c478bd9Sstevel@tonic-gate /* */ 21297c478bd9Sstevel@tonic-gate /* Applies an appropriate set of firewall rules to the packet, to see if */ 21307c478bd9Sstevel@tonic-gate /* there are any matches. The first check is to see if a match can be seen */ 21317c478bd9Sstevel@tonic-gate /* in the cache. If not, then search an appropriate list of rules. Once a */ 21327c478bd9Sstevel@tonic-gate /* matching rule is found, take any appropriate actions as defined by the */ 21337c478bd9Sstevel@tonic-gate /* rule - except logging. */ 21347c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 21357c478bd9Sstevel@tonic-gate static frentry_t *fr_firewall(fin, passp) 21367c478bd9Sstevel@tonic-gate fr_info_t *fin; 21377c478bd9Sstevel@tonic-gate u_32_t *passp; 21387c478bd9Sstevel@tonic-gate { 21397c478bd9Sstevel@tonic-gate frentry_t *fr; 214014d3298eSAlexandr Nedvedicky fr_info_t *fc; 21417c478bd9Sstevel@tonic-gate u_32_t pass; 21427c478bd9Sstevel@tonic-gate int out; 2143f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 21447c478bd9Sstevel@tonic-gate 21457c478bd9Sstevel@tonic-gate out = fin->fin_out; 21467c478bd9Sstevel@tonic-gate pass = *passp; 21477c478bd9Sstevel@tonic-gate 21487c478bd9Sstevel@tonic-gate #ifdef USE_INET6 2149cbded9aeSdr if (fin->fin_v == 6) 2150cbded9aeSdr fin->fin_fr = ifs->ifs_ipfilter6[out][ifs->ifs_fr_active]; 2151cbded9aeSdr else 21527c478bd9Sstevel@tonic-gate #endif 2153cbded9aeSdr fin->fin_fr = ifs->ifs_ipfilter[out][ifs->ifs_fr_active]; 215414d3298eSAlexandr Nedvedicky 215514d3298eSAlexandr Nedvedicky /* 215614d3298eSAlexandr Nedvedicky * If there are no rules loaded skip all checks and return. 215714d3298eSAlexandr Nedvedicky */ 215814d3298eSAlexandr Nedvedicky if (fin->fin_fr == NULL) { 215914d3298eSAlexandr Nedvedicky 216014d3298eSAlexandr Nedvedicky if ((pass & FR_NOMATCH)) { 216114d3298eSAlexandr Nedvedicky IPF_BUMP(ifs->ifs_frstats[out].fr_nom); 216214d3298eSAlexandr Nedvedicky } 216314d3298eSAlexandr Nedvedicky 216414d3298eSAlexandr Nedvedicky return (NULL); 216514d3298eSAlexandr Nedvedicky } 216614d3298eSAlexandr Nedvedicky 216714d3298eSAlexandr Nedvedicky fc = &ifs->ifs_frcache[out][CACHE_HASH(fin)]; 216814d3298eSAlexandr Nedvedicky READ_ENTER(&ifs->ifs_ipf_frcache); 216914d3298eSAlexandr Nedvedicky if (!bcmp((char *)fin, (char *)fc, FI_CSIZE)) { 217014d3298eSAlexandr Nedvedicky /* 217114d3298eSAlexandr Nedvedicky * copy cached data so we can unlock the mutexes earlier. 217214d3298eSAlexandr Nedvedicky */ 217314d3298eSAlexandr Nedvedicky bcopy((char *)fc, (char *)fin, FI_COPYSIZE); 217414d3298eSAlexandr Nedvedicky RWLOCK_EXIT(&ifs->ifs_ipf_frcache); 217514d3298eSAlexandr Nedvedicky IPF_BUMP(ifs->ifs_frstats[out].fr_chit); 217614d3298eSAlexandr Nedvedicky 217714d3298eSAlexandr Nedvedicky if ((fr = fin->fin_fr) != NULL) { 217814d3298eSAlexandr Nedvedicky IPF_BUMP(fr->fr_hits); 2179de22af4eSJohn Ojemann fr->fr_bytes += (U_QUAD_T)fin->fin_plen; 218014d3298eSAlexandr Nedvedicky pass = fr->fr_flags; 218114d3298eSAlexandr Nedvedicky } 218214d3298eSAlexandr Nedvedicky } else { 218314d3298eSAlexandr Nedvedicky RWLOCK_EXIT(&ifs->ifs_ipf_frcache); 218414d3298eSAlexandr Nedvedicky 2185cbded9aeSdr pass = fr_scanlist(fin, ifs->ifs_fr_pass); 2186ab25eeb5Syz 218714d3298eSAlexandr Nedvedicky if (((pass & FR_KEEPSTATE) == 0) && 218814d3298eSAlexandr Nedvedicky ((fin->fin_flx & FI_DONTCACHE) == 0)) { 218914d3298eSAlexandr Nedvedicky WRITE_ENTER(&ifs->ifs_ipf_frcache); 219014d3298eSAlexandr Nedvedicky bcopy((char *)fin, (char *)fc, FI_COPYSIZE); 219114d3298eSAlexandr Nedvedicky RWLOCK_EXIT(&ifs->ifs_ipf_frcache); 219214d3298eSAlexandr Nedvedicky } 219314d3298eSAlexandr Nedvedicky 219414d3298eSAlexandr Nedvedicky fr = fin->fin_fr; 219514d3298eSAlexandr Nedvedicky } 219614d3298eSAlexandr Nedvedicky 2197cbded9aeSdr if ((pass & FR_NOMATCH)) { 2198cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[out].fr_nom); 21997c478bd9Sstevel@tonic-gate } 22007c478bd9Sstevel@tonic-gate 22017c478bd9Sstevel@tonic-gate /* 22027c478bd9Sstevel@tonic-gate * Apply packets per second rate-limiting to a rule as required. 22037c478bd9Sstevel@tonic-gate */ 22047c478bd9Sstevel@tonic-gate if ((fr != NULL) && (fr->fr_pps != 0) && 22057c478bd9Sstevel@tonic-gate !ppsratecheck(&fr->fr_lastpkt, &fr->fr_curpps, fr->fr_pps)) { 22067c478bd9Sstevel@tonic-gate pass &= ~(FR_CMDMASK|FR_DUP|FR_RETICMP|FR_RETRST); 22077c478bd9Sstevel@tonic-gate pass |= FR_BLOCK; 2208cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[out].fr_ppshit); 22097c478bd9Sstevel@tonic-gate } 22107c478bd9Sstevel@tonic-gate 22117c478bd9Sstevel@tonic-gate /* 22127c478bd9Sstevel@tonic-gate * If we fail to add a packet to the authorization queue, then we 22137c478bd9Sstevel@tonic-gate * drop the packet later. However, if it was added then pretend 22147c478bd9Sstevel@tonic-gate * we've dropped it already. 22157c478bd9Sstevel@tonic-gate */ 22167c478bd9Sstevel@tonic-gate if (FR_ISAUTH(pass)) { 22177c478bd9Sstevel@tonic-gate if (fr_newauth(fin->fin_m, fin) != 0) { 22187c478bd9Sstevel@tonic-gate #ifdef _KERNEL 22197c478bd9Sstevel@tonic-gate fin->fin_m = *fin->fin_mp = NULL; 22207c478bd9Sstevel@tonic-gate #else 22217c478bd9Sstevel@tonic-gate ; 22227c478bd9Sstevel@tonic-gate #endif 22237c478bd9Sstevel@tonic-gate fin->fin_error = 0; 22247c478bd9Sstevel@tonic-gate } else 22257c478bd9Sstevel@tonic-gate fin->fin_error = ENOSPC; 22267c478bd9Sstevel@tonic-gate } 22277c478bd9Sstevel@tonic-gate 22287c478bd9Sstevel@tonic-gate if ((fr != NULL) && (fr->fr_func != NULL) && 22297c478bd9Sstevel@tonic-gate (fr->fr_func != (ipfunc_t)-1) && !(pass & FR_CALLNOW)) 22307c478bd9Sstevel@tonic-gate (void) (*fr->fr_func)(fin, &pass); 22317c478bd9Sstevel@tonic-gate 22327c478bd9Sstevel@tonic-gate /* 22337c478bd9Sstevel@tonic-gate * If a rule is a pre-auth rule, check again in the list of rules 22347c478bd9Sstevel@tonic-gate * loaded for authenticated use. It does not particulary matter 22357c478bd9Sstevel@tonic-gate * if this search fails because a "preauth" result, from a rule, 22367c478bd9Sstevel@tonic-gate * is treated as "not a pass", hence the packet is blocked. 22377c478bd9Sstevel@tonic-gate */ 22387c478bd9Sstevel@tonic-gate if (FR_ISPREAUTH(pass)) { 2239f4b3ec61Sdh if ((fin->fin_fr = ifs->ifs_ipauth) != NULL) 2240f4b3ec61Sdh pass = fr_scanlist(fin, ifs->ifs_fr_pass); 22417c478bd9Sstevel@tonic-gate } 22427c478bd9Sstevel@tonic-gate 22437c478bd9Sstevel@tonic-gate /* 22447c478bd9Sstevel@tonic-gate * If the rule has "keep frag" and the packet is actually a fragment, 22457c478bd9Sstevel@tonic-gate * then create a fragment state entry. 22467c478bd9Sstevel@tonic-gate */ 22477c478bd9Sstevel@tonic-gate if ((pass & (FR_KEEPFRAG|FR_KEEPSTATE)) == FR_KEEPFRAG) { 22487c478bd9Sstevel@tonic-gate if (fin->fin_flx & FI_FRAG) { 22497c478bd9Sstevel@tonic-gate if (fr_newfrag(fin, pass) == -1) { 2250cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[out].fr_bnfr); 22517c478bd9Sstevel@tonic-gate } else { 2252cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[out].fr_nfr); 22537c478bd9Sstevel@tonic-gate } 22547c478bd9Sstevel@tonic-gate } else { 2255cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[out].fr_cfr); 22567c478bd9Sstevel@tonic-gate } 22577c478bd9Sstevel@tonic-gate } 22587c478bd9Sstevel@tonic-gate 22597c478bd9Sstevel@tonic-gate /* 22607c478bd9Sstevel@tonic-gate * Finally, if we've asked to track state for this packet, set it up. 22617c478bd9Sstevel@tonic-gate */ 2262ab25eeb5Syz if ((pass & FR_KEEPSTATE) && !(fin->fin_flx & FI_STATE)) { 22637c478bd9Sstevel@tonic-gate if (fr_addstate(fin, NULL, 0) != NULL) { 2264cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[out].fr_ads); 22657c478bd9Sstevel@tonic-gate } else { 2266cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[out].fr_bads); 2267ab25eeb5Syz if (FR_ISPASS(pass)) { 2268ab25eeb5Syz pass &= ~FR_CMDMASK; 2269ab25eeb5Syz pass |= FR_BLOCK; 2270ab25eeb5Syz } 22717c478bd9Sstevel@tonic-gate } 22727c478bd9Sstevel@tonic-gate } 22737c478bd9Sstevel@tonic-gate 22747c478bd9Sstevel@tonic-gate fr = fin->fin_fr; 22757c478bd9Sstevel@tonic-gate 22767c478bd9Sstevel@tonic-gate if (passp != NULL) 22777c478bd9Sstevel@tonic-gate *passp = pass; 22787c478bd9Sstevel@tonic-gate 22797c478bd9Sstevel@tonic-gate return fr; 22807c478bd9Sstevel@tonic-gate } 22817c478bd9Sstevel@tonic-gate 22827c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 22837c478bd9Sstevel@tonic-gate /* Function: fr_check */ 22847c478bd9Sstevel@tonic-gate /* Returns: int - 0 == packet allowed through, */ 22857c478bd9Sstevel@tonic-gate /* User space: */ 22867c478bd9Sstevel@tonic-gate /* -1 == packet blocked */ 22877c478bd9Sstevel@tonic-gate /* 1 == packet not matched */ 2288ab25eeb5Syz /* -2 == requires authentication */ 22897c478bd9Sstevel@tonic-gate /* Kernel: */ 22907c478bd9Sstevel@tonic-gate /* > 0 == filter error # for packet */ 22917c478bd9Sstevel@tonic-gate /* Parameters: ip(I) - pointer to start of IPv4/6 packet */ 22927c478bd9Sstevel@tonic-gate /* hlen(I) - length of header */ 22937c478bd9Sstevel@tonic-gate /* ifp(I) - pointer to interface this packet is on */ 22947c478bd9Sstevel@tonic-gate /* out(I) - 0 == packet going in, 1 == packet going out */ 22957c478bd9Sstevel@tonic-gate /* mp(IO) - pointer to caller's buffer pointer that holds this */ 22967c478bd9Sstevel@tonic-gate /* IP packet. */ 22977c478bd9Sstevel@tonic-gate /* Solaris & HP-UX ONLY : */ 2298ab25eeb5Syz /* qpi(I) - pointer to STREAMS queue information for this */ 22997c478bd9Sstevel@tonic-gate /* interface & direction. */ 23007c478bd9Sstevel@tonic-gate /* */ 23017c478bd9Sstevel@tonic-gate /* fr_check() is the master function for all IPFilter packet processing. */ 23027c478bd9Sstevel@tonic-gate /* It orchestrates: Network Address Translation (NAT), checking for packet */ 23037c478bd9Sstevel@tonic-gate /* authorisation (or pre-authorisation), presence of related state info., */ 23047c478bd9Sstevel@tonic-gate /* generating log entries, IP packet accounting, routing of packets as */ 23057c478bd9Sstevel@tonic-gate /* directed by firewall rules and of course whether or not to allow the */ 23067c478bd9Sstevel@tonic-gate /* packet to be further processed by the kernel. */ 23077c478bd9Sstevel@tonic-gate /* */ 23087c478bd9Sstevel@tonic-gate /* For packets blocked, the contents of "mp" will be NULL'd and the buffer */ 23097c478bd9Sstevel@tonic-gate /* freed. Packets passed may be returned with the pointer pointed to by */ 23107c478bd9Sstevel@tonic-gate /* by "mp" changed to a new buffer. */ 23117c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 23127c478bd9Sstevel@tonic-gate int fr_check(ip, hlen, ifp, out 23137c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && defined(MENTAT) 2314f4b3ec61Sdh , qif, mp, ifs) 2315ab25eeb5Syz void *qif; 23167c478bd9Sstevel@tonic-gate #else 2317f4b3ec61Sdh , mp, ifs) 23187c478bd9Sstevel@tonic-gate #endif 23197c478bd9Sstevel@tonic-gate mb_t **mp; 23207c478bd9Sstevel@tonic-gate ip_t *ip; 23217c478bd9Sstevel@tonic-gate int hlen; 23227c478bd9Sstevel@tonic-gate void *ifp; 23237c478bd9Sstevel@tonic-gate int out; 2324f4b3ec61Sdh ipf_stack_t *ifs; 23257c478bd9Sstevel@tonic-gate { 23267c478bd9Sstevel@tonic-gate /* 23277c478bd9Sstevel@tonic-gate * The above really sucks, but short of writing a diff 23287c478bd9Sstevel@tonic-gate */ 23297c478bd9Sstevel@tonic-gate fr_info_t frinfo; 23307c478bd9Sstevel@tonic-gate fr_info_t *fin = &frinfo; 2331f4b3ec61Sdh u_32_t pass; 23327c478bd9Sstevel@tonic-gate frentry_t *fr = NULL; 2333ab25eeb5Syz int v = IP_V(ip); 23347c478bd9Sstevel@tonic-gate mb_t *mc = NULL; 23357c478bd9Sstevel@tonic-gate mb_t *m; 23367663b816Sml #ifdef USE_INET6 23377663b816Sml ip6_t *ip6; 23387663b816Sml #endif 2339ab25eeb5Syz #ifdef _KERNEL 2340ab25eeb5Syz # ifdef MENTAT 2341ab25eeb5Syz qpktinfo_t *qpi = qif; 2342ab25eeb5Syz #endif 2343ab25eeb5Syz #endif 2344f4b3ec61Sdh 2345ab25eeb5Syz SPL_INT(s); 2346f4b3ec61Sdh pass = ifs->ifs_fr_pass; 23477c478bd9Sstevel@tonic-gate 23487c478bd9Sstevel@tonic-gate /* 23497c478bd9Sstevel@tonic-gate * The first part of fr_check() deals with making sure that what goes 23507c478bd9Sstevel@tonic-gate * into the filtering engine makes some sense. Information about the 23517c478bd9Sstevel@tonic-gate * the packet is distilled, collected into a fr_info_t structure and 23527c478bd9Sstevel@tonic-gate * the an attempt to ensure the buffer the packet is in is big enough 23537c478bd9Sstevel@tonic-gate * to hold all the required packet headers. 23547c478bd9Sstevel@tonic-gate */ 23557c478bd9Sstevel@tonic-gate #ifdef _KERNEL 23567c478bd9Sstevel@tonic-gate # ifdef MENTAT 2357ab25eeb5Syz if (!OK_32PTR(ip)) 23587c478bd9Sstevel@tonic-gate return 2; 23597c478bd9Sstevel@tonic-gate # endif 2360ab25eeb5Syz 23617c478bd9Sstevel@tonic-gate 2362f4b3ec61Sdh if (ifs->ifs_fr_running <= 0) { 23637c478bd9Sstevel@tonic-gate return 0; 23647c478bd9Sstevel@tonic-gate } 23657c478bd9Sstevel@tonic-gate 23667c478bd9Sstevel@tonic-gate bzero((char *)fin, sizeof(*fin)); 23677c478bd9Sstevel@tonic-gate 23687c478bd9Sstevel@tonic-gate # ifdef MENTAT 23691b47e080Sdr fin->fin_flx = qpi->qpi_flags & (FI_NOCKSUM|FI_MBCAST|FI_MULTICAST| 23701b47e080Sdr FI_BROADCAST); 2371ab25eeb5Syz m = qpi->qpi_m; 23727c478bd9Sstevel@tonic-gate fin->fin_qfm = m; 2373ab25eeb5Syz fin->fin_qpi = qpi; 23747c478bd9Sstevel@tonic-gate # else /* MENTAT */ 23757c478bd9Sstevel@tonic-gate 23767c478bd9Sstevel@tonic-gate m = *mp; 2377ab25eeb5Syz 23787c478bd9Sstevel@tonic-gate # if defined(M_MCAST) 23797c478bd9Sstevel@tonic-gate if ((m->m_flags & M_MCAST) != 0) 23807c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 23817c478bd9Sstevel@tonic-gate # endif 2382ab25eeb5Syz # if defined(M_MLOOP) 2383ab25eeb5Syz if ((m->m_flags & M_MLOOP) != 0) 2384ab25eeb5Syz fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2385ab25eeb5Syz # endif 23867c478bd9Sstevel@tonic-gate # if defined(M_BCAST) 23877c478bd9Sstevel@tonic-gate if ((m->m_flags & M_BCAST) != 0) 23887c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_MBCAST|FI_BROADCAST; 23897c478bd9Sstevel@tonic-gate # endif 23907c478bd9Sstevel@tonic-gate # ifdef M_CANFASTFWD 23917c478bd9Sstevel@tonic-gate /* 23927c478bd9Sstevel@tonic-gate * XXX For now, IP Filter and fast-forwarding of cached flows 23937c478bd9Sstevel@tonic-gate * XXX are mutually exclusive. Eventually, IP Filter should 23947c478bd9Sstevel@tonic-gate * XXX get a "can-fast-forward" filter rule. 23957c478bd9Sstevel@tonic-gate */ 23967c478bd9Sstevel@tonic-gate m->m_flags &= ~M_CANFASTFWD; 23977c478bd9Sstevel@tonic-gate # endif /* M_CANFASTFWD */ 23987c478bd9Sstevel@tonic-gate # ifdef CSUM_DELAY_DATA 23997c478bd9Sstevel@tonic-gate /* 24007c478bd9Sstevel@tonic-gate * disable delayed checksums. 24017c478bd9Sstevel@tonic-gate */ 24027c478bd9Sstevel@tonic-gate if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 24037c478bd9Sstevel@tonic-gate in_delayed_cksum(m); 24047c478bd9Sstevel@tonic-gate m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 24057c478bd9Sstevel@tonic-gate } 24067c478bd9Sstevel@tonic-gate # endif /* CSUM_DELAY_DATA */ 24077c478bd9Sstevel@tonic-gate # endif /* MENTAT */ 2408ab25eeb5Syz #else 24097c478bd9Sstevel@tonic-gate 24107c478bd9Sstevel@tonic-gate bzero((char *)fin, sizeof(*fin)); 24117c478bd9Sstevel@tonic-gate m = *mp; 24127c478bd9Sstevel@tonic-gate #endif /* _KERNEL */ 24137c478bd9Sstevel@tonic-gate 2414ab25eeb5Syz fin->fin_v = v; 2415ab25eeb5Syz fin->fin_m = m; 2416ab25eeb5Syz fin->fin_ip = ip; 2417ab25eeb5Syz fin->fin_mp = mp; 2418ab25eeb5Syz fin->fin_out = out; 2419ab25eeb5Syz fin->fin_ifp = ifp; 2420ab25eeb5Syz fin->fin_error = ENETUNREACH; 2421ab25eeb5Syz fin->fin_hlen = (u_short)hlen; 2422ab25eeb5Syz fin->fin_dp = (char *)ip + hlen; 2423ab25eeb5Syz fin->fin_ipoff = (char *)ip - MTOD(m, char *); 2424f4b3ec61Sdh fin->fin_ifs = ifs; 2425ab25eeb5Syz 2426ab25eeb5Syz SPL_NET(s); 2427ab25eeb5Syz 24287c478bd9Sstevel@tonic-gate #ifdef USE_INET6 24297c478bd9Sstevel@tonic-gate if (v == 6) { 2430cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[out].fr_ipv6); 24317c478bd9Sstevel@tonic-gate /* 24327c478bd9Sstevel@tonic-gate * Jumbo grams are quite likely too big for internal buffer 24337c478bd9Sstevel@tonic-gate * structures to handle comfortably, for now, so just drop 2434ab25eeb5Syz * them. 24357c478bd9Sstevel@tonic-gate */ 2436ab25eeb5Syz ip6 = (ip6_t *)ip; 2437ab25eeb5Syz fin->fin_plen = ntohs(ip6->ip6_plen); 2438ab25eeb5Syz if (fin->fin_plen == 0) { 2439f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_mutex); 24407c478bd9Sstevel@tonic-gate pass = FR_BLOCK|FR_NOMATCH; 24417c478bd9Sstevel@tonic-gate goto filtered; 24427c478bd9Sstevel@tonic-gate } 2443ab25eeb5Syz fin->fin_plen += sizeof(ip6_t); 24447c478bd9Sstevel@tonic-gate } else 24457c478bd9Sstevel@tonic-gate #endif 24467c478bd9Sstevel@tonic-gate { 2447ab25eeb5Syz #if (OpenBSD >= 200311) && defined(_KERNEL) 2448ab25eeb5Syz ip->ip_len = ntohs(ip->ip_len); 2449ab25eeb5Syz ip->ip_off = ntohs(ip->ip_off); 24507c478bd9Sstevel@tonic-gate #endif 2451ab25eeb5Syz fin->fin_plen = ip->ip_len; 24527c478bd9Sstevel@tonic-gate } 24537c478bd9Sstevel@tonic-gate 24547663b816Sml if (fr_makefrip(hlen, ip, fin) == -1) { 2455f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_mutex); 24567663b816Sml pass = FR_BLOCK; 24577663b816Sml goto filtered; 24587663b816Sml } 24597c478bd9Sstevel@tonic-gate 24607c478bd9Sstevel@tonic-gate /* 24617c478bd9Sstevel@tonic-gate * For at least IPv6 packets, if a m_pullup() fails then this pointer 24627c478bd9Sstevel@tonic-gate * becomes NULL and so we have no packet to free. 24637c478bd9Sstevel@tonic-gate */ 24647c478bd9Sstevel@tonic-gate if (*fin->fin_mp == NULL) 24657c478bd9Sstevel@tonic-gate goto finished; 24667c478bd9Sstevel@tonic-gate 24677c478bd9Sstevel@tonic-gate if (!out) { 24687c478bd9Sstevel@tonic-gate if (v == 4) { 24697c478bd9Sstevel@tonic-gate #ifdef _KERNEL 2470f4b3ec61Sdh if (ifs->ifs_fr_chksrc && !fr_verifysrc(fin)) { 2471cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[0].fr_badsrc); 24727c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_BADSRC; 24737c478bd9Sstevel@tonic-gate } 24747c478bd9Sstevel@tonic-gate #endif 2475f4b3ec61Sdh if (fin->fin_ip->ip_ttl < ifs->ifs_fr_minttl) { 2476cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[0].fr_badttl); 24777c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_LOWTTL; 24787c478bd9Sstevel@tonic-gate } 24797c478bd9Sstevel@tonic-gate } 24807c478bd9Sstevel@tonic-gate #ifdef USE_INET6 24817c478bd9Sstevel@tonic-gate else if (v == 6) { 24827663b816Sml ip6 = (ip6_t *)ip; 24837663b816Sml #ifdef _KERNEL 2484f4b3ec61Sdh if (ifs->ifs_fr_chksrc && !fr_verifysrc(fin)) { 2485cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[0].fr_badsrc); 24867663b816Sml fin->fin_flx |= FI_BADSRC; 24877663b816Sml } 24887663b816Sml #endif 2489f4b3ec61Sdh if (ip6->ip6_hlim < ifs->ifs_fr_minttl) { 2490cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[0].fr_badttl); 24917c478bd9Sstevel@tonic-gate fin->fin_flx |= FI_LOWTTL; 24927c478bd9Sstevel@tonic-gate } 24937c478bd9Sstevel@tonic-gate } 24947c478bd9Sstevel@tonic-gate #endif 24957c478bd9Sstevel@tonic-gate } 24967c478bd9Sstevel@tonic-gate 24977c478bd9Sstevel@tonic-gate if (fin->fin_flx & FI_SHORT) { 2498cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[out].fr_short); 24997c478bd9Sstevel@tonic-gate } 25007c478bd9Sstevel@tonic-gate 2501f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_mutex); 25027c478bd9Sstevel@tonic-gate 25037c478bd9Sstevel@tonic-gate /* 25047c478bd9Sstevel@tonic-gate * Check auth now. This, combined with the check below to see if apass 25057c478bd9Sstevel@tonic-gate * is 0 is to ensure that we don't count the packet twice, which can 25067c478bd9Sstevel@tonic-gate * otherwise occur when we reprocess it. As it is, we only count it 25077c478bd9Sstevel@tonic-gate * after it has no auth. table matchup. This also stops NAT from 25087c478bd9Sstevel@tonic-gate * occuring until after the packet has been auth'd. 25097c478bd9Sstevel@tonic-gate */ 25107c478bd9Sstevel@tonic-gate fr = fr_checkauth(fin, &pass); 2511ab25eeb5Syz if (!out) { 2512d6c23f6fSyx switch (fin->fin_v) 2513d6c23f6fSyx { 2514d6c23f6fSyx case 4 : 2515d6c23f6fSyx if (fr_checknatin(fin, &pass) == -1) { 2516d6c23f6fSyx RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2517d6c23f6fSyx goto finished; 2518d6c23f6fSyx } 2519d6c23f6fSyx break; 2520d6c23f6fSyx #ifdef USE_INET6 2521d6c23f6fSyx case 6 : 2522d6c23f6fSyx if (fr_checknat6in(fin, &pass) == -1) { 2523d6c23f6fSyx RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2524d6c23f6fSyx goto finished; 2525d6c23f6fSyx } 2526d6c23f6fSyx break; 2527d6c23f6fSyx #endif 2528d6c23f6fSyx default : 2529d6c23f6fSyx break; 2530ab25eeb5Syz } 2531ab25eeb5Syz } 25327c478bd9Sstevel@tonic-gate if (!out) 25337c478bd9Sstevel@tonic-gate (void) fr_acctpkt(fin, NULL); 25347c478bd9Sstevel@tonic-gate 25357c478bd9Sstevel@tonic-gate if (fr == NULL) 25367c478bd9Sstevel@tonic-gate if ((fin->fin_flx & (FI_FRAG|FI_BAD)) == FI_FRAG) 25377c478bd9Sstevel@tonic-gate fr = fr_knownfrag(fin, &pass); 25387c478bd9Sstevel@tonic-gate if (fr == NULL) 25397c478bd9Sstevel@tonic-gate fr = fr_checkstate(fin, &pass); 25407c478bd9Sstevel@tonic-gate 25417c478bd9Sstevel@tonic-gate if ((pass & FR_NOMATCH) || (fr == NULL)) 25427c478bd9Sstevel@tonic-gate fr = fr_firewall(fin, &pass); 25437c478bd9Sstevel@tonic-gate 25447c478bd9Sstevel@tonic-gate fin->fin_fr = fr; 25457c478bd9Sstevel@tonic-gate 25467c478bd9Sstevel@tonic-gate /* 25477c478bd9Sstevel@tonic-gate * Only count/translate packets which will be passed on, out the 25487c478bd9Sstevel@tonic-gate * interface. 25497c478bd9Sstevel@tonic-gate */ 25507c478bd9Sstevel@tonic-gate if (out && FR_ISPASS(pass)) { 25517c478bd9Sstevel@tonic-gate (void) fr_acctpkt(fin, NULL); 25527c478bd9Sstevel@tonic-gate 2553d6c23f6fSyx switch (fin->fin_v) 2554d6c23f6fSyx { 2555d6c23f6fSyx case 4 : 2556d6c23f6fSyx if (fr_checknatout(fin, &pass) == -1) { 2557d6c23f6fSyx RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2558d6c23f6fSyx goto finished; 2559d6c23f6fSyx } 2560d6c23f6fSyx break; 2561d6c23f6fSyx #ifdef USE_INET6 2562d6c23f6fSyx case 6 : 2563d6c23f6fSyx if (fr_checknat6out(fin, &pass) == -1) { 2564d6c23f6fSyx RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2565d6c23f6fSyx goto finished; 2566d6c23f6fSyx } 2567d6c23f6fSyx break; 2568d6c23f6fSyx #endif 2569d6c23f6fSyx default : 2570d6c23f6fSyx break; 2571d6c23f6fSyx } 2572d6c23f6fSyx 2573d6c23f6fSyx if ((ifs->ifs_fr_update_ipid != 0) && (v == 4)) { 25747c478bd9Sstevel@tonic-gate if (fr_updateipid(fin) == -1) { 2575cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[1].fr_ipud); 25767c478bd9Sstevel@tonic-gate pass &= ~FR_CMDMASK; 25777c478bd9Sstevel@tonic-gate pass |= FR_BLOCK; 25787c478bd9Sstevel@tonic-gate } else { 2579cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[0].fr_ipud); 25807c478bd9Sstevel@tonic-gate } 25817c478bd9Sstevel@tonic-gate } 25827c478bd9Sstevel@tonic-gate } 25837c478bd9Sstevel@tonic-gate 25847c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 2585f4b3ec61Sdh if ((ifs->ifs_fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) { 25867c478bd9Sstevel@tonic-gate (void) fr_dolog(fin, &pass); 2587ab25eeb5Syz } 25887c478bd9Sstevel@tonic-gate #endif 25897c478bd9Sstevel@tonic-gate 259033f2fefdSDarren Reed /* 259133f2fefdSDarren Reed * The FI_STATE flag is cleared here so that calling fr_checkstate 259233f2fefdSDarren Reed * will work when called from inside of fr_fastroute. Although 259333f2fefdSDarren Reed * there is a similar flag, FI_NATED, for NAT, it does have the same 259433f2fefdSDarren Reed * impact on code execution. 259533f2fefdSDarren Reed */ 259633f2fefdSDarren Reed fin->fin_flx &= ~FI_STATE; 25977c478bd9Sstevel@tonic-gate 25987c478bd9Sstevel@tonic-gate /* 25997c478bd9Sstevel@tonic-gate * Only allow FR_DUP to work if a rule matched - it makes no sense to 26007c478bd9Sstevel@tonic-gate * set FR_DUP as a "default" as there are no instructions about where 2601ab25eeb5Syz * to send the packet. Use fin_m here because it may have changed 2602ab25eeb5Syz * (without an update of 'm') in prior processing. 26037c478bd9Sstevel@tonic-gate */ 26047c478bd9Sstevel@tonic-gate if ((fr != NULL) && (pass & FR_DUP)) { 2605ab25eeb5Syz mc = M_DUPLICATE(fin->fin_m); 2606201a9dc8SAlexandr Nedvedicky #ifdef _KERNEL 2607201a9dc8SAlexandr Nedvedicky mc->b_rptr += fin->fin_ipoff; 2608201a9dc8SAlexandr Nedvedicky #endif 26097c478bd9Sstevel@tonic-gate } 26107c478bd9Sstevel@tonic-gate 2611d0dd088cSAlexandr Nedvedicky /* 2612d0dd088cSAlexandr Nedvedicky * We don't want to send RST for packets, which are going to be 2613d0dd088cSAlexandr Nedvedicky * dropped, just because they don't fit into TCP window. Those packets 2614d0dd088cSAlexandr Nedvedicky * will be dropped silently. In other words, we want to drop packet, 2615d0dd088cSAlexandr Nedvedicky * while keeping session alive. 2616d0dd088cSAlexandr Nedvedicky */ 2617d0dd088cSAlexandr Nedvedicky if ((pass & (FR_RETRST|FR_RETICMP)) && ((fin->fin_flx & FI_OOW) == 0)) { 26187c478bd9Sstevel@tonic-gate /* 26197c478bd9Sstevel@tonic-gate * Should we return an ICMP packet to indicate error 26207c478bd9Sstevel@tonic-gate * status passing through the packet filter ? 26217c478bd9Sstevel@tonic-gate * WARNING: ICMP error packets AND TCP RST packets should 26227c478bd9Sstevel@tonic-gate * ONLY be sent in repsonse to incoming packets. Sending them 26237c478bd9Sstevel@tonic-gate * in response to outbound packets can result in a panic on 26247c478bd9Sstevel@tonic-gate * some operating systems. 26257c478bd9Sstevel@tonic-gate */ 26267c478bd9Sstevel@tonic-gate if (!out) { 26277c478bd9Sstevel@tonic-gate if (pass & FR_RETICMP) { 26287c478bd9Sstevel@tonic-gate int dst; 26297c478bd9Sstevel@tonic-gate 26307c478bd9Sstevel@tonic-gate if ((pass & FR_RETMASK) == FR_FAKEICMP) 26317c478bd9Sstevel@tonic-gate dst = 1; 26327c478bd9Sstevel@tonic-gate else 26337c478bd9Sstevel@tonic-gate dst = 0; 2634a1173273SAlexandr Nedvedicky #if defined(_KERNEL) && (SOLARIS2 >= 10) 2635a1173273SAlexandr Nedvedicky /* 2636a1173273SAlexandr Nedvedicky * Assume it's possible to enter insane rule: 2637a1173273SAlexandr Nedvedicky * pass return-icmp in proto udp ... 2638a1173273SAlexandr Nedvedicky * then we have no other option than to forward 2639a1173273SAlexandr Nedvedicky * packet on loopback and give up any attempt 2640a1173273SAlexandr Nedvedicky * to create a fake response. 2641a1173273SAlexandr Nedvedicky */ 2642a1173273SAlexandr Nedvedicky if (IPF_IS_LOOPBACK(qpi->qpi_flags) && 2643a1173273SAlexandr Nedvedicky FR_ISBLOCK(pass)) { 2644a1173273SAlexandr Nedvedicky 2645a1173273SAlexandr Nedvedicky if (fr_make_icmp(fin) == 0) { 2646a1173273SAlexandr Nedvedicky IPF_BUMP( 2647a1173273SAlexandr Nedvedicky ifs->ifs_frstats[out].fr_ret); 2648a1173273SAlexandr Nedvedicky } 2649a1173273SAlexandr Nedvedicky /* 2650a1173273SAlexandr Nedvedicky * we drop packet silently in case we 2651a1173273SAlexandr Nedvedicky * failed assemble fake response for it 2652a1173273SAlexandr Nedvedicky */ 2653a1173273SAlexandr Nedvedicky else if (*mp != NULL) { 2654a1173273SAlexandr Nedvedicky FREE_MB_T(*mp); 2655a1173273SAlexandr Nedvedicky m = *mp = NULL; 2656a1173273SAlexandr Nedvedicky } 2657a1173273SAlexandr Nedvedicky 2658a1173273SAlexandr Nedvedicky IPF_BUMP( 2659a1173273SAlexandr Nedvedicky ifs->ifs_frstats[out].fr_block); 2660a1173273SAlexandr Nedvedicky RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2661a1173273SAlexandr Nedvedicky 2662a1173273SAlexandr Nedvedicky return (0); 2663a1173273SAlexandr Nedvedicky } 2664a1173273SAlexandr Nedvedicky #endif /* _KERNEL && SOLARIS2 >= 10 */ 2665a1173273SAlexandr Nedvedicky 26667c478bd9Sstevel@tonic-gate (void) fr_send_icmp_err(ICMP_UNREACH, fin, dst); 2667a1173273SAlexandr Nedvedicky IPF_BUMP(ifs->ifs_frstats[out].fr_ret); 2668a1173273SAlexandr Nedvedicky 26697c478bd9Sstevel@tonic-gate } else if (((pass & FR_RETMASK) == FR_RETRST) && 26707c478bd9Sstevel@tonic-gate !(fin->fin_flx & FI_SHORT)) { 2671a1173273SAlexandr Nedvedicky 2672a1173273SAlexandr Nedvedicky #if defined(_KERNEL) && (SOLARIS2 >= 10) 2673a1173273SAlexandr Nedvedicky /* 2674a1173273SAlexandr Nedvedicky * Assume it's possible to enter insane rule: 2675a1173273SAlexandr Nedvedicky * pass return-rst in proto tcp ... 2676a1173273SAlexandr Nedvedicky * then we have no other option than to forward 2677a1173273SAlexandr Nedvedicky * packet on loopback and give up any attempt 2678a1173273SAlexandr Nedvedicky * to create a fake response. 2679a1173273SAlexandr Nedvedicky */ 2680a1173273SAlexandr Nedvedicky if (IPF_IS_LOOPBACK(qpi->qpi_flags) && 2681a1173273SAlexandr Nedvedicky FR_ISBLOCK(pass)) { 2682a1173273SAlexandr Nedvedicky if (fr_make_rst(fin) == 0) { 2683a1173273SAlexandr Nedvedicky IPF_BUMP( 2684a1173273SAlexandr Nedvedicky ifs->ifs_frstats[out].fr_ret); 2685a1173273SAlexandr Nedvedicky } 2686a1173273SAlexandr Nedvedicky else if (mp != NULL) { 2687a1173273SAlexandr Nedvedicky /* 2688a1173273SAlexandr Nedvedicky * we drop packet silently in case we 2689a1173273SAlexandr Nedvedicky * failed assemble fake response for it 2690a1173273SAlexandr Nedvedicky */ 2691a1173273SAlexandr Nedvedicky FREE_MB_T(*mp); 2692a1173273SAlexandr Nedvedicky m = *mp = NULL; 2693a1173273SAlexandr Nedvedicky } 2694a1173273SAlexandr Nedvedicky 2695a1173273SAlexandr Nedvedicky IPF_BUMP( 2696a1173273SAlexandr Nedvedicky ifs->ifs_frstats[out].fr_block); 2697a1173273SAlexandr Nedvedicky RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2698a1173273SAlexandr Nedvedicky 2699a1173273SAlexandr Nedvedicky return (0); 2700a1173273SAlexandr Nedvedicky } 2701a1173273SAlexandr Nedvedicky #endif /* _KERNEL && _SOLARIS2 >= 10 */ 27027c478bd9Sstevel@tonic-gate if (fr_send_reset(fin) == 0) { 2703cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[1].fr_ret); 27047c478bd9Sstevel@tonic-gate } 27057c478bd9Sstevel@tonic-gate } 27067c478bd9Sstevel@tonic-gate } else { 27077c478bd9Sstevel@tonic-gate if (pass & FR_RETRST) 27087c478bd9Sstevel@tonic-gate fin->fin_error = ECONNRESET; 27097c478bd9Sstevel@tonic-gate } 27107c478bd9Sstevel@tonic-gate } 27117c478bd9Sstevel@tonic-gate 27127c478bd9Sstevel@tonic-gate /* 27137c478bd9Sstevel@tonic-gate * If we didn't drop off the bottom of the list of rules (and thus 27147c478bd9Sstevel@tonic-gate * the 'current' rule fr is not NULL), then we may have some extra 27157c478bd9Sstevel@tonic-gate * instructions about what to do with a packet. 27167c478bd9Sstevel@tonic-gate * Once we're finished return to our caller, freeing the packet if 27177c478bd9Sstevel@tonic-gate * we are dropping it (* BSD ONLY *). 2718ab25eeb5Syz * Reassign m from fin_m as we may have a new buffer, now. 27197c478bd9Sstevel@tonic-gate */ 27207c478bd9Sstevel@tonic-gate filtered: 2721ab25eeb5Syz m = fin->fin_m; 27227c478bd9Sstevel@tonic-gate 27237c478bd9Sstevel@tonic-gate if (fr != NULL) { 27247c478bd9Sstevel@tonic-gate frdest_t *fdp; 27257c478bd9Sstevel@tonic-gate 27267c478bd9Sstevel@tonic-gate fdp = &fr->fr_tifs[fin->fin_rev]; 27277c478bd9Sstevel@tonic-gate 27287c478bd9Sstevel@tonic-gate if (!out && (pass & FR_FASTROUTE)) { 27297c478bd9Sstevel@tonic-gate /* 27307c478bd9Sstevel@tonic-gate * For fastroute rule, no destioation interface defined 27317c478bd9Sstevel@tonic-gate * so pass NULL as the frdest_t parameter 27327c478bd9Sstevel@tonic-gate */ 27337c478bd9Sstevel@tonic-gate (void) fr_fastroute(m, mp, fin, NULL); 27347c478bd9Sstevel@tonic-gate m = *mp = NULL; 27357c478bd9Sstevel@tonic-gate } else if ((fdp->fd_ifp != NULL) && 27367c478bd9Sstevel@tonic-gate (fdp->fd_ifp != (struct ifnet *)-1)) { 27377c478bd9Sstevel@tonic-gate /* this is for to rules: */ 27387c478bd9Sstevel@tonic-gate (void) fr_fastroute(m, mp, fin, fdp); 27397c478bd9Sstevel@tonic-gate m = *mp = NULL; 27407c478bd9Sstevel@tonic-gate } 27417c478bd9Sstevel@tonic-gate 27427c478bd9Sstevel@tonic-gate /* 2743d0dd088cSAlexandr Nedvedicky * Send a duplicated packet. 27447c478bd9Sstevel@tonic-gate */ 2745d0dd088cSAlexandr Nedvedicky if (mc != NULL) { 2746d0dd088cSAlexandr Nedvedicky #if defined(_KERNEL) && (SOLARIS2 >= 10) 2747d0dd088cSAlexandr Nedvedicky /* 2748d0dd088cSAlexandr Nedvedicky * We are going to compute chksum for copies of loopback packets 2749d0dd088cSAlexandr Nedvedicky * only. IP stack does not compute chksums at all for loopback 2750d0dd088cSAlexandr Nedvedicky * packets. We want to get it fixed in their copies, since those 2751d0dd088cSAlexandr Nedvedicky * are going to be sent to network. 2752d0dd088cSAlexandr Nedvedicky */ 2753d0dd088cSAlexandr Nedvedicky if (IPF_IS_LOOPBACK(qpi->qpi_flags)) 2754d0dd088cSAlexandr Nedvedicky fr_calc_chksum(fin, mc); 2755d0dd088cSAlexandr Nedvedicky #endif 27567c478bd9Sstevel@tonic-gate (void) fr_fastroute(mc, &mc, fin, &fr->fr_dif); 2757d0dd088cSAlexandr Nedvedicky } 27587c478bd9Sstevel@tonic-gate } 27597c478bd9Sstevel@tonic-gate 276033f2fefdSDarren Reed if (FR_ISBLOCK(pass) && (fin->fin_flx & FI_NEWNAT)) 276133f2fefdSDarren Reed nat_uncreate(fin); 276233f2fefdSDarren Reed 27637c478bd9Sstevel@tonic-gate /* 27647c478bd9Sstevel@tonic-gate * This late because the likes of fr_fastroute() use fin_fr. 27657c478bd9Sstevel@tonic-gate */ 2766f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 27677c478bd9Sstevel@tonic-gate 2768ab25eeb5Syz finished: 27697c478bd9Sstevel@tonic-gate if (!FR_ISPASS(pass)) { 2770cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[out].fr_block); 2771ab25eeb5Syz if (*mp != NULL) { 27727c478bd9Sstevel@tonic-gate FREE_MB_T(*mp); 27737c478bd9Sstevel@tonic-gate m = *mp = NULL; 27747c478bd9Sstevel@tonic-gate } 2775ab25eeb5Syz } else { 2776cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[out].fr_pass); 27777c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && defined(__sgi) 2778ab25eeb5Syz if ((fin->fin_hbuf != NULL) && 2779ab25eeb5Syz (mtod(fin->fin_m, struct ip *) != fin->fin_ip)) { 2780ab25eeb5Syz COPYBACK(m, 0, fin->fin_plen, fin->fin_hbuf); 27817c478bd9Sstevel@tonic-gate } 27827c478bd9Sstevel@tonic-gate #endif 2783ab25eeb5Syz } 2784ab25eeb5Syz 2785ab25eeb5Syz SPL_X(s); 2786ab25eeb5Syz 27877c478bd9Sstevel@tonic-gate #ifdef _KERNEL 2788ab25eeb5Syz # if OpenBSD >= 200311 2789ab25eeb5Syz if (FR_ISPASS(pass) && (v == 4)) { 2790ab25eeb5Syz ip = fin->fin_ip; 2791ab25eeb5Syz ip->ip_len = ntohs(ip->ip_len); 2792ab25eeb5Syz ip->ip_off = ntohs(ip->ip_off); 2793ab25eeb5Syz } 2794ab25eeb5Syz # endif 27957c478bd9Sstevel@tonic-gate return (FR_ISPASS(pass)) ? 0 : fin->fin_error; 27967c478bd9Sstevel@tonic-gate #else /* _KERNEL */ 2797ab25eeb5Syz FR_VERBOSE(("fin_flx %#x pass %#x ", fin->fin_flx, pass)); 27987c478bd9Sstevel@tonic-gate if ((pass & FR_NOMATCH) != 0) 27997c478bd9Sstevel@tonic-gate return 1; 28007c478bd9Sstevel@tonic-gate 28017c478bd9Sstevel@tonic-gate if ((pass & FR_RETMASK) != 0) 28027c478bd9Sstevel@tonic-gate switch (pass & FR_RETMASK) 28037c478bd9Sstevel@tonic-gate { 28047c478bd9Sstevel@tonic-gate case FR_RETRST : 28057c478bd9Sstevel@tonic-gate return 3; 28067c478bd9Sstevel@tonic-gate case FR_RETICMP : 28077c478bd9Sstevel@tonic-gate return 4; 28087c478bd9Sstevel@tonic-gate case FR_FAKEICMP : 28097c478bd9Sstevel@tonic-gate return 5; 28107c478bd9Sstevel@tonic-gate } 28117c478bd9Sstevel@tonic-gate 28127c478bd9Sstevel@tonic-gate switch (pass & FR_CMDMASK) 28137c478bd9Sstevel@tonic-gate { 28147c478bd9Sstevel@tonic-gate case FR_PASS : 28157c478bd9Sstevel@tonic-gate return 0; 28167c478bd9Sstevel@tonic-gate case FR_BLOCK : 28177c478bd9Sstevel@tonic-gate return -1; 28187c478bd9Sstevel@tonic-gate case FR_AUTH : 28197c478bd9Sstevel@tonic-gate return -2; 28207c478bd9Sstevel@tonic-gate case FR_ACCOUNT : 28217c478bd9Sstevel@tonic-gate return -3; 28227c478bd9Sstevel@tonic-gate case FR_PREAUTH : 28237c478bd9Sstevel@tonic-gate return -4; 28247c478bd9Sstevel@tonic-gate } 28257c478bd9Sstevel@tonic-gate return 2; 28267c478bd9Sstevel@tonic-gate #endif /* _KERNEL */ 28277c478bd9Sstevel@tonic-gate } 28287c478bd9Sstevel@tonic-gate 28297c478bd9Sstevel@tonic-gate 28307c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 28317c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 28327c478bd9Sstevel@tonic-gate /* Function: fr_dolog */ 28337c478bd9Sstevel@tonic-gate /* Returns: frentry_t* - returns contents of fin_fr (no change made) */ 28347c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 28357c478bd9Sstevel@tonic-gate /* passp(IO) - pointer to current/new filter decision (unused) */ 28367c478bd9Sstevel@tonic-gate /* */ 28377c478bd9Sstevel@tonic-gate /* Checks flags set to see how a packet should be logged, if it is to be */ 28387c478bd9Sstevel@tonic-gate /* logged. Adjust statistics based on its success or not. */ 28397c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 28407c478bd9Sstevel@tonic-gate frentry_t *fr_dolog(fin, passp) 28417c478bd9Sstevel@tonic-gate fr_info_t *fin; 28427c478bd9Sstevel@tonic-gate u_32_t *passp; 28437c478bd9Sstevel@tonic-gate { 28447c478bd9Sstevel@tonic-gate u_32_t pass; 28457c478bd9Sstevel@tonic-gate int out; 2846f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 28477c478bd9Sstevel@tonic-gate 28487c478bd9Sstevel@tonic-gate out = fin->fin_out; 28497c478bd9Sstevel@tonic-gate pass = *passp; 28507c478bd9Sstevel@tonic-gate 2851f4b3ec61Sdh if ((ifs->ifs_fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) { 28527c478bd9Sstevel@tonic-gate pass |= FF_LOGNOMATCH; 2853cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[out].fr_npkl); 28547c478bd9Sstevel@tonic-gate goto logit; 28557c478bd9Sstevel@tonic-gate } else if (((pass & FR_LOGMASK) == FR_LOGP) || 2856f4b3ec61Sdh (FR_ISPASS(pass) && (ifs->ifs_fr_flags & FF_LOGPASS))) { 28577c478bd9Sstevel@tonic-gate if ((pass & FR_LOGMASK) != FR_LOGP) 28587c478bd9Sstevel@tonic-gate pass |= FF_LOGPASS; 2859cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[out].fr_ppkl); 28607c478bd9Sstevel@tonic-gate goto logit; 28617c478bd9Sstevel@tonic-gate } else if (((pass & FR_LOGMASK) == FR_LOGB) || 2862f4b3ec61Sdh (FR_ISBLOCK(pass) && (ifs->ifs_fr_flags & FF_LOGBLOCK))) { 28637c478bd9Sstevel@tonic-gate if ((pass & FR_LOGMASK) != FR_LOGB) 28647c478bd9Sstevel@tonic-gate pass |= FF_LOGBLOCK; 2865cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[out].fr_bpkl); 28667c478bd9Sstevel@tonic-gate logit: 28677c478bd9Sstevel@tonic-gate if (ipflog(fin, pass) == -1) { 2868cbded9aeSdr IPF_BUMP(ifs->ifs_frstats[out].fr_skip); 28697c478bd9Sstevel@tonic-gate 28707c478bd9Sstevel@tonic-gate /* 28717c478bd9Sstevel@tonic-gate * If the "or-block" option has been used then 28727c478bd9Sstevel@tonic-gate * block the packet if we failed to log it. 28737c478bd9Sstevel@tonic-gate */ 28747c478bd9Sstevel@tonic-gate if ((pass & FR_LOGORBLOCK) && 28757c478bd9Sstevel@tonic-gate FR_ISPASS(pass)) { 28767c478bd9Sstevel@tonic-gate pass &= ~FR_CMDMASK; 28777c478bd9Sstevel@tonic-gate pass |= FR_BLOCK; 28787c478bd9Sstevel@tonic-gate } 28797c478bd9Sstevel@tonic-gate } 28807c478bd9Sstevel@tonic-gate *passp = pass; 28817c478bd9Sstevel@tonic-gate } 28827c478bd9Sstevel@tonic-gate 28837c478bd9Sstevel@tonic-gate return fin->fin_fr; 28847c478bd9Sstevel@tonic-gate } 28857c478bd9Sstevel@tonic-gate #endif /* IPFILTER_LOG */ 28867c478bd9Sstevel@tonic-gate 28877c478bd9Sstevel@tonic-gate 28887c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 28897c478bd9Sstevel@tonic-gate /* Function: ipf_cksum */ 28907c478bd9Sstevel@tonic-gate /* Returns: u_short - IP header checksum */ 28917c478bd9Sstevel@tonic-gate /* Parameters: addr(I) - pointer to start of buffer to checksum */ 28927c478bd9Sstevel@tonic-gate /* len(I) - length of buffer in bytes */ 28937c478bd9Sstevel@tonic-gate /* */ 28947c478bd9Sstevel@tonic-gate /* Calculate the two's complement 16 bit checksum of the buffer passed. */ 28957c478bd9Sstevel@tonic-gate /* */ 28967c478bd9Sstevel@tonic-gate /* N.B.: addr should be 16bit aligned. */ 28977c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 28987c478bd9Sstevel@tonic-gate u_short ipf_cksum(addr, len) 28997c478bd9Sstevel@tonic-gate u_short *addr; 29007c478bd9Sstevel@tonic-gate int len; 29017c478bd9Sstevel@tonic-gate { 29027c478bd9Sstevel@tonic-gate u_32_t sum = 0; 29037c478bd9Sstevel@tonic-gate 29047c478bd9Sstevel@tonic-gate for (sum = 0; len > 1; len -= 2) 29057c478bd9Sstevel@tonic-gate sum += *addr++; 29067c478bd9Sstevel@tonic-gate 29077c478bd9Sstevel@tonic-gate /* mop up an odd byte, if necessary */ 29087c478bd9Sstevel@tonic-gate if (len == 1) 29097c478bd9Sstevel@tonic-gate sum += *(u_char *)addr; 29107c478bd9Sstevel@tonic-gate 29117c478bd9Sstevel@tonic-gate /* 29127c478bd9Sstevel@tonic-gate * add back carry outs from top 16 bits to low 16 bits 29137c478bd9Sstevel@tonic-gate */ 29147c478bd9Sstevel@tonic-gate sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 29157c478bd9Sstevel@tonic-gate sum += (sum >> 16); /* add carry */ 29167c478bd9Sstevel@tonic-gate return (u_short)(~sum); 29177c478bd9Sstevel@tonic-gate } 29187c478bd9Sstevel@tonic-gate 29197c478bd9Sstevel@tonic-gate 29207c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 29217c478bd9Sstevel@tonic-gate /* Function: fr_cksum */ 29227c478bd9Sstevel@tonic-gate /* Returns: u_short - layer 4 checksum */ 2923ab25eeb5Syz /* Parameters: m(I ) - pointer to buffer holding packet */ 2924ab25eeb5Syz /* ip(I) - pointer to IP header */ 2925ab25eeb5Syz /* l4proto(I) - protocol to caclulate checksum for */ 2926ab25eeb5Syz /* l4hdr(I) - pointer to layer 4 header */ 29277c478bd9Sstevel@tonic-gate /* */ 29287c478bd9Sstevel@tonic-gate /* Calculates the TCP checksum for the packet held in "m", using the data */ 29297c478bd9Sstevel@tonic-gate /* in the IP header "ip" to seed it. */ 29307c478bd9Sstevel@tonic-gate /* */ 29317c478bd9Sstevel@tonic-gate /* NB: This function assumes we've pullup'd enough for all of the IP header */ 29327c478bd9Sstevel@tonic-gate /* and the TCP header. We also assume that data blocks aren't allocated in */ 29337c478bd9Sstevel@tonic-gate /* odd sizes. */ 2934ab25eeb5Syz /* */ 2935ab25eeb5Syz /* Expects ip_len to be in host byte order when called. */ 29367c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 29377c478bd9Sstevel@tonic-gate u_short fr_cksum(m, ip, l4proto, l4hdr) 29387c478bd9Sstevel@tonic-gate mb_t *m; 29397c478bd9Sstevel@tonic-gate ip_t *ip; 29407c478bd9Sstevel@tonic-gate int l4proto; 29417c478bd9Sstevel@tonic-gate void *l4hdr; 29427c478bd9Sstevel@tonic-gate { 29437c478bd9Sstevel@tonic-gate u_short *sp, slen, sumsave, l4hlen, *csump; 29447c478bd9Sstevel@tonic-gate u_int sum, sum2; 29457c478bd9Sstevel@tonic-gate int hlen; 29467c478bd9Sstevel@tonic-gate #ifdef USE_INET6 29477c478bd9Sstevel@tonic-gate ip6_t *ip6; 29487c478bd9Sstevel@tonic-gate #endif 29497c478bd9Sstevel@tonic-gate 29507c478bd9Sstevel@tonic-gate csump = NULL; 29517c478bd9Sstevel@tonic-gate sumsave = 0; 29527c478bd9Sstevel@tonic-gate l4hlen = 0; 29537c478bd9Sstevel@tonic-gate sp = NULL; 29547c478bd9Sstevel@tonic-gate slen = 0; 29557c478bd9Sstevel@tonic-gate hlen = 0; 29567c478bd9Sstevel@tonic-gate sum = 0; 29577c478bd9Sstevel@tonic-gate 29587c478bd9Sstevel@tonic-gate /* 29597c478bd9Sstevel@tonic-gate * Add up IP Header portion 29607c478bd9Sstevel@tonic-gate */ 29617c478bd9Sstevel@tonic-gate #ifdef USE_INET6 29627c478bd9Sstevel@tonic-gate if (IP_V(ip) == 4) { 29637c478bd9Sstevel@tonic-gate #endif 29647c478bd9Sstevel@tonic-gate hlen = IP_HL(ip) << 2; 29657c478bd9Sstevel@tonic-gate slen = ip->ip_len - hlen; 2966ab25eeb5Syz sum = htons((u_short)l4proto); 29677c478bd9Sstevel@tonic-gate sum += htons(slen); 29687c478bd9Sstevel@tonic-gate sp = (u_short *)&ip->ip_src; 29697c478bd9Sstevel@tonic-gate sum += *sp++; /* ip_src */ 29707c478bd9Sstevel@tonic-gate sum += *sp++; 29717c478bd9Sstevel@tonic-gate sum += *sp++; /* ip_dst */ 29727c478bd9Sstevel@tonic-gate sum += *sp++; 29737c478bd9Sstevel@tonic-gate #ifdef USE_INET6 29747c478bd9Sstevel@tonic-gate } else if (IP_V(ip) == 6) { 29757c478bd9Sstevel@tonic-gate ip6 = (ip6_t *)ip; 29767c478bd9Sstevel@tonic-gate hlen = sizeof(*ip6); 29777c478bd9Sstevel@tonic-gate slen = ntohs(ip6->ip6_plen); 2978ab25eeb5Syz sum = htons((u_short)l4proto); 29797c478bd9Sstevel@tonic-gate sum += htons(slen); 29807c478bd9Sstevel@tonic-gate sp = (u_short *)&ip6->ip6_src; 29817c478bd9Sstevel@tonic-gate sum += *sp++; /* ip6_src */ 29827c478bd9Sstevel@tonic-gate sum += *sp++; 29837c478bd9Sstevel@tonic-gate sum += *sp++; 29847c478bd9Sstevel@tonic-gate sum += *sp++; 29857c478bd9Sstevel@tonic-gate sum += *sp++; 29867c478bd9Sstevel@tonic-gate sum += *sp++; 29877c478bd9Sstevel@tonic-gate sum += *sp++; 29887c478bd9Sstevel@tonic-gate sum += *sp++; 29897c478bd9Sstevel@tonic-gate sum += *sp++; /* ip6_dst */ 29907c478bd9Sstevel@tonic-gate sum += *sp++; 29917c478bd9Sstevel@tonic-gate sum += *sp++; 29927c478bd9Sstevel@tonic-gate sum += *sp++; 29937c478bd9Sstevel@tonic-gate sum += *sp++; 29947c478bd9Sstevel@tonic-gate sum += *sp++; 29957c478bd9Sstevel@tonic-gate sum += *sp++; 29967663b816Sml sum += *sp++; 29977c478bd9Sstevel@tonic-gate } 29987c478bd9Sstevel@tonic-gate #endif 29997c478bd9Sstevel@tonic-gate 30007c478bd9Sstevel@tonic-gate switch (l4proto) 30017c478bd9Sstevel@tonic-gate { 30027c478bd9Sstevel@tonic-gate case IPPROTO_UDP : 30037c478bd9Sstevel@tonic-gate csump = &((udphdr_t *)l4hdr)->uh_sum; 30047c478bd9Sstevel@tonic-gate l4hlen = sizeof(udphdr_t); 30057c478bd9Sstevel@tonic-gate break; 30067c478bd9Sstevel@tonic-gate 30077c478bd9Sstevel@tonic-gate case IPPROTO_TCP : 30087c478bd9Sstevel@tonic-gate csump = &((tcphdr_t *)l4hdr)->th_sum; 30097c478bd9Sstevel@tonic-gate l4hlen = sizeof(tcphdr_t); 30107c478bd9Sstevel@tonic-gate break; 30117c478bd9Sstevel@tonic-gate case IPPROTO_ICMP : 30127c478bd9Sstevel@tonic-gate csump = &((icmphdr_t *)l4hdr)->icmp_cksum; 30137c478bd9Sstevel@tonic-gate l4hlen = 4; 3014ab25eeb5Syz sum = 0; 30157c478bd9Sstevel@tonic-gate break; 30167c478bd9Sstevel@tonic-gate default : 30177c478bd9Sstevel@tonic-gate break; 30187c478bd9Sstevel@tonic-gate } 30197c478bd9Sstevel@tonic-gate 30207c478bd9Sstevel@tonic-gate if (csump != NULL) { 30217c478bd9Sstevel@tonic-gate sumsave = *csump; 30227c478bd9Sstevel@tonic-gate *csump = 0; 30237c478bd9Sstevel@tonic-gate } 30247c478bd9Sstevel@tonic-gate 30257c478bd9Sstevel@tonic-gate l4hlen = l4hlen; /* LINT */ 30267c478bd9Sstevel@tonic-gate 30277c478bd9Sstevel@tonic-gate #ifdef _KERNEL 30287c478bd9Sstevel@tonic-gate # ifdef MENTAT 30297c478bd9Sstevel@tonic-gate { 30307c478bd9Sstevel@tonic-gate void *rp = m->b_rptr; 30317c478bd9Sstevel@tonic-gate 30327c478bd9Sstevel@tonic-gate if ((unsigned char *)ip > m->b_rptr && (unsigned char *)ip < m->b_wptr) 30337c478bd9Sstevel@tonic-gate m->b_rptr = (u_char *)ip; 30347c478bd9Sstevel@tonic-gate sum2 = ip_cksum(m, hlen, sum); /* hlen == offset */ 30357c478bd9Sstevel@tonic-gate m->b_rptr = rp; 30367c478bd9Sstevel@tonic-gate sum2 = (sum2 & 0xffff) + (sum2 >> 16); 30377c478bd9Sstevel@tonic-gate sum2 = ~sum2 & 0xffff; 3038ab25eeb5Syz } 30397c478bd9Sstevel@tonic-gate # else /* MENTAT */ 30407c478bd9Sstevel@tonic-gate # if defined(BSD) || defined(sun) 30417c478bd9Sstevel@tonic-gate # if BSD >= 199103 30427c478bd9Sstevel@tonic-gate m->m_data += hlen; 30437c478bd9Sstevel@tonic-gate # else 30447c478bd9Sstevel@tonic-gate m->m_off += hlen; 30457c478bd9Sstevel@tonic-gate # endif 30467c478bd9Sstevel@tonic-gate m->m_len -= hlen; 30477c478bd9Sstevel@tonic-gate sum2 = in_cksum(m, slen); 30487c478bd9Sstevel@tonic-gate m->m_len += hlen; 30497c478bd9Sstevel@tonic-gate # if BSD >= 199103 30507c478bd9Sstevel@tonic-gate m->m_data -= hlen; 30517c478bd9Sstevel@tonic-gate # else 30527c478bd9Sstevel@tonic-gate m->m_off -= hlen; 30537c478bd9Sstevel@tonic-gate # endif 30547c478bd9Sstevel@tonic-gate /* 30557c478bd9Sstevel@tonic-gate * Both sum and sum2 are partial sums, so combine them together. 30567c478bd9Sstevel@tonic-gate */ 30577c478bd9Sstevel@tonic-gate sum += ~sum2 & 0xffff; 30587c478bd9Sstevel@tonic-gate while (sum > 0xffff) 30597c478bd9Sstevel@tonic-gate sum = (sum & 0xffff) + (sum >> 16); 30607c478bd9Sstevel@tonic-gate sum2 = ~sum & 0xffff; 30617c478bd9Sstevel@tonic-gate # else /* defined(BSD) || defined(sun) */ 30627c478bd9Sstevel@tonic-gate { 30637c478bd9Sstevel@tonic-gate union { 30647c478bd9Sstevel@tonic-gate u_char c[2]; 30657c478bd9Sstevel@tonic-gate u_short s; 30667c478bd9Sstevel@tonic-gate } bytes; 30677c478bd9Sstevel@tonic-gate u_short len = ip->ip_len; 30687c478bd9Sstevel@tonic-gate # if defined(__sgi) 30697c478bd9Sstevel@tonic-gate int add; 30707c478bd9Sstevel@tonic-gate # endif 30717c478bd9Sstevel@tonic-gate 30727c478bd9Sstevel@tonic-gate /* 30737c478bd9Sstevel@tonic-gate * Add up IP Header portion 30747c478bd9Sstevel@tonic-gate */ 30757c478bd9Sstevel@tonic-gate if (sp != (u_short *)l4hdr) 30767c478bd9Sstevel@tonic-gate sp = (u_short *)l4hdr; 30777c478bd9Sstevel@tonic-gate 3078ab25eeb5Syz switch (l4proto) 30797c478bd9Sstevel@tonic-gate { 30807c478bd9Sstevel@tonic-gate case IPPROTO_UDP : 30817c478bd9Sstevel@tonic-gate sum += *sp++; /* sport */ 30827c478bd9Sstevel@tonic-gate sum += *sp++; /* dport */ 30837c478bd9Sstevel@tonic-gate sum += *sp++; /* udp length */ 30847c478bd9Sstevel@tonic-gate sum += *sp++; /* checksum */ 30857c478bd9Sstevel@tonic-gate break; 30867c478bd9Sstevel@tonic-gate 30877c478bd9Sstevel@tonic-gate case IPPROTO_TCP : 30887c478bd9Sstevel@tonic-gate sum += *sp++; /* sport */ 30897c478bd9Sstevel@tonic-gate sum += *sp++; /* dport */ 30907c478bd9Sstevel@tonic-gate sum += *sp++; /* seq */ 30917c478bd9Sstevel@tonic-gate sum += *sp++; 30927c478bd9Sstevel@tonic-gate sum += *sp++; /* ack */ 30937c478bd9Sstevel@tonic-gate sum += *sp++; 30947c478bd9Sstevel@tonic-gate sum += *sp++; /* off */ 30957c478bd9Sstevel@tonic-gate sum += *sp++; /* win */ 30967c478bd9Sstevel@tonic-gate sum += *sp++; /* checksum */ 30977c478bd9Sstevel@tonic-gate sum += *sp++; /* urp */ 30987c478bd9Sstevel@tonic-gate break; 3099ab25eeb5Syz case IPPROTO_ICMP : 3100ab25eeb5Syz sum = *sp++; /* type/code */ 3101ab25eeb5Syz sum += *sp++; /* checksum */ 3102ab25eeb5Syz break; 31037c478bd9Sstevel@tonic-gate } 31047c478bd9Sstevel@tonic-gate 31057c478bd9Sstevel@tonic-gate # ifdef __sgi 31067c478bd9Sstevel@tonic-gate /* 31077c478bd9Sstevel@tonic-gate * In case we had to copy the IP & TCP header out of mbufs, 31087c478bd9Sstevel@tonic-gate * skip over the mbuf bits which are the header 31097c478bd9Sstevel@tonic-gate */ 31107c478bd9Sstevel@tonic-gate if ((caddr_t)ip != mtod(m, caddr_t)) { 31117c478bd9Sstevel@tonic-gate hlen = (caddr_t)sp - (caddr_t)ip; 31127c478bd9Sstevel@tonic-gate while (hlen) { 31137c478bd9Sstevel@tonic-gate add = MIN(hlen, m->m_len); 31147c478bd9Sstevel@tonic-gate sp = (u_short *)(mtod(m, caddr_t) + add); 31157c478bd9Sstevel@tonic-gate hlen -= add; 31167c478bd9Sstevel@tonic-gate if (add == m->m_len) { 31177c478bd9Sstevel@tonic-gate m = m->m_next; 31187c478bd9Sstevel@tonic-gate if (!hlen) { 31197c478bd9Sstevel@tonic-gate if (!m) 31207c478bd9Sstevel@tonic-gate break; 31217c478bd9Sstevel@tonic-gate sp = mtod(m, u_short *); 31227c478bd9Sstevel@tonic-gate } 31237c478bd9Sstevel@tonic-gate PANIC((!m),("fr_cksum(1): not enough data")); 31247c478bd9Sstevel@tonic-gate } 31257c478bd9Sstevel@tonic-gate } 31267c478bd9Sstevel@tonic-gate } 31277c478bd9Sstevel@tonic-gate # endif 31287c478bd9Sstevel@tonic-gate 3129ab25eeb5Syz len -= (l4hlen + hlen); 31307c478bd9Sstevel@tonic-gate if (len <= 0) 31317c478bd9Sstevel@tonic-gate goto nodata; 31327c478bd9Sstevel@tonic-gate 31337c478bd9Sstevel@tonic-gate while (len > 1) { 31347c478bd9Sstevel@tonic-gate if (((caddr_t)sp - mtod(m, caddr_t)) >= m->m_len) { 31357c478bd9Sstevel@tonic-gate m = m->m_next; 31367c478bd9Sstevel@tonic-gate PANIC((!m),("fr_cksum(2): not enough data")); 31377c478bd9Sstevel@tonic-gate sp = mtod(m, u_short *); 31387c478bd9Sstevel@tonic-gate } 31397c478bd9Sstevel@tonic-gate if (((caddr_t)(sp + 1) - mtod(m, caddr_t)) > m->m_len) { 31407c478bd9Sstevel@tonic-gate bytes.c[0] = *(u_char *)sp; 31417c478bd9Sstevel@tonic-gate m = m->m_next; 31427c478bd9Sstevel@tonic-gate PANIC((!m),("fr_cksum(3): not enough data")); 31437c478bd9Sstevel@tonic-gate sp = mtod(m, u_short *); 31447c478bd9Sstevel@tonic-gate bytes.c[1] = *(u_char *)sp; 31457c478bd9Sstevel@tonic-gate sum += bytes.s; 31467c478bd9Sstevel@tonic-gate sp = (u_short *)((u_char *)sp + 1); 31477c478bd9Sstevel@tonic-gate } 31487c478bd9Sstevel@tonic-gate if ((u_long)sp & 1) { 31497c478bd9Sstevel@tonic-gate bcopy((char *)sp++, (char *)&bytes.s, sizeof(bytes.s)); 31507c478bd9Sstevel@tonic-gate sum += bytes.s; 31517c478bd9Sstevel@tonic-gate } else 31527c478bd9Sstevel@tonic-gate sum += *sp++; 31537c478bd9Sstevel@tonic-gate len -= 2; 31547c478bd9Sstevel@tonic-gate } 31557c478bd9Sstevel@tonic-gate 31567c478bd9Sstevel@tonic-gate if (len != 0) 31577c478bd9Sstevel@tonic-gate sum += ntohs(*(u_char *)sp << 8); 31587c478bd9Sstevel@tonic-gate nodata: 31597c478bd9Sstevel@tonic-gate while (sum > 0xffff) 31607c478bd9Sstevel@tonic-gate sum = (sum & 0xffff) + (sum >> 16); 31617c478bd9Sstevel@tonic-gate sum2 = (u_short)(~sum & 0xffff); 31627c478bd9Sstevel@tonic-gate } 31637c478bd9Sstevel@tonic-gate # endif /* defined(BSD) || defined(sun) */ 31647c478bd9Sstevel@tonic-gate # endif /* MENTAT */ 31657c478bd9Sstevel@tonic-gate #else /* _KERNEL */ 31667c478bd9Sstevel@tonic-gate for (; slen > 1; slen -= 2) 31677c478bd9Sstevel@tonic-gate sum += *sp++; 31687c478bd9Sstevel@tonic-gate if (slen) 31697c478bd9Sstevel@tonic-gate sum += ntohs(*(u_char *)sp << 8); 31707c478bd9Sstevel@tonic-gate while (sum > 0xffff) 31717c478bd9Sstevel@tonic-gate sum = (sum & 0xffff) + (sum >> 16); 31727c478bd9Sstevel@tonic-gate sum2 = (u_short)(~sum & 0xffff); 31737c478bd9Sstevel@tonic-gate #endif /* _KERNEL */ 31747c478bd9Sstevel@tonic-gate if (csump != NULL) 31757c478bd9Sstevel@tonic-gate *csump = sumsave; 31767c478bd9Sstevel@tonic-gate return sum2; 31777c478bd9Sstevel@tonic-gate } 31787c478bd9Sstevel@tonic-gate 31797c478bd9Sstevel@tonic-gate 31807c478bd9Sstevel@tonic-gate #if defined(_KERNEL) && ( ((BSD < 199103) && !defined(MENTAT)) || \ 3181ab25eeb5Syz defined(__sgi) ) && !defined(linux) && !defined(_AIX51) 31827c478bd9Sstevel@tonic-gate /* 31837c478bd9Sstevel@tonic-gate * Copyright (c) 1982, 1986, 1988, 1991, 1993 31847c478bd9Sstevel@tonic-gate * The Regents of the University of California. All rights reserved. 31857c478bd9Sstevel@tonic-gate * 31867c478bd9Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 31877c478bd9Sstevel@tonic-gate * modification, are permitted provided that the following conditions 31887c478bd9Sstevel@tonic-gate * are met: 31897c478bd9Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 31907c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 31917c478bd9Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 31927c478bd9Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 31937c478bd9Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 31947c478bd9Sstevel@tonic-gate * 3. Neither the name of the University nor the names of its contributors 31957c478bd9Sstevel@tonic-gate * may be used to endorse or promote products derived from this software 31967c478bd9Sstevel@tonic-gate * without specific prior written permission. 31977c478bd9Sstevel@tonic-gate * 31987c478bd9Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 31997c478bd9Sstevel@tonic-gate * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32007c478bd9Sstevel@tonic-gate * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32017c478bd9Sstevel@tonic-gate * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32027c478bd9Sstevel@tonic-gate * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32037c478bd9Sstevel@tonic-gate * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32047c478bd9Sstevel@tonic-gate * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32057c478bd9Sstevel@tonic-gate * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32067c478bd9Sstevel@tonic-gate * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32077c478bd9Sstevel@tonic-gate * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32087c478bd9Sstevel@tonic-gate * SUCH DAMAGE. 32097c478bd9Sstevel@tonic-gate * 32107c478bd9Sstevel@tonic-gate * @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94 3211ab25eeb5Syz * $Id: fil.c,v 2.243.2.64 2005/08/13 05:19:59 darrenr Exp $ 32127c478bd9Sstevel@tonic-gate */ 32137c478bd9Sstevel@tonic-gate /* 32147c478bd9Sstevel@tonic-gate * Copy data from an mbuf chain starting "off" bytes from the beginning, 32157c478bd9Sstevel@tonic-gate * continuing for "len" bytes, into the indicated buffer. 32167c478bd9Sstevel@tonic-gate */ 32177c478bd9Sstevel@tonic-gate void 32187c478bd9Sstevel@tonic-gate m_copydata(m, off, len, cp) 32197c478bd9Sstevel@tonic-gate mb_t *m; 32207c478bd9Sstevel@tonic-gate int off; 32217c478bd9Sstevel@tonic-gate int len; 32227c478bd9Sstevel@tonic-gate caddr_t cp; 32237c478bd9Sstevel@tonic-gate { 32247c478bd9Sstevel@tonic-gate unsigned count; 32257c478bd9Sstevel@tonic-gate 32267c478bd9Sstevel@tonic-gate if (off < 0 || len < 0) 32277c478bd9Sstevel@tonic-gate panic("m_copydata"); 32287c478bd9Sstevel@tonic-gate while (off > 0) { 32297c478bd9Sstevel@tonic-gate if (m == 0) 32307c478bd9Sstevel@tonic-gate panic("m_copydata"); 32317c478bd9Sstevel@tonic-gate if (off < m->m_len) 32327c478bd9Sstevel@tonic-gate break; 32337c478bd9Sstevel@tonic-gate off -= m->m_len; 32347c478bd9Sstevel@tonic-gate m = m->m_next; 32357c478bd9Sstevel@tonic-gate } 32367c478bd9Sstevel@tonic-gate while (len > 0) { 32377c478bd9Sstevel@tonic-gate if (m == 0) 32387c478bd9Sstevel@tonic-gate panic("m_copydata"); 32397c478bd9Sstevel@tonic-gate count = MIN(m->m_len - off, len); 32407c478bd9Sstevel@tonic-gate bcopy(mtod(m, caddr_t) + off, cp, count); 32417c478bd9Sstevel@tonic-gate len -= count; 32427c478bd9Sstevel@tonic-gate cp += count; 32437c478bd9Sstevel@tonic-gate off = 0; 32447c478bd9Sstevel@tonic-gate m = m->m_next; 32457c478bd9Sstevel@tonic-gate } 32467c478bd9Sstevel@tonic-gate } 32477c478bd9Sstevel@tonic-gate 32487c478bd9Sstevel@tonic-gate 32497c478bd9Sstevel@tonic-gate /* 32507c478bd9Sstevel@tonic-gate * Copy data from a buffer back into the indicated mbuf chain, 32517c478bd9Sstevel@tonic-gate * starting "off" bytes from the beginning, extending the mbuf 32527c478bd9Sstevel@tonic-gate * chain if necessary. 32537c478bd9Sstevel@tonic-gate */ 32547c478bd9Sstevel@tonic-gate void 32557c478bd9Sstevel@tonic-gate m_copyback(m0, off, len, cp) 32567c478bd9Sstevel@tonic-gate struct mbuf *m0; 32577c478bd9Sstevel@tonic-gate int off; 32587c478bd9Sstevel@tonic-gate int len; 32597c478bd9Sstevel@tonic-gate caddr_t cp; 32607c478bd9Sstevel@tonic-gate { 32617c478bd9Sstevel@tonic-gate int mlen; 32627c478bd9Sstevel@tonic-gate struct mbuf *m = m0, *n; 32637c478bd9Sstevel@tonic-gate int totlen = 0; 32647c478bd9Sstevel@tonic-gate 32657c478bd9Sstevel@tonic-gate if (m0 == 0) 32667c478bd9Sstevel@tonic-gate return; 32677c478bd9Sstevel@tonic-gate while (off > (mlen = m->m_len)) { 32687c478bd9Sstevel@tonic-gate off -= mlen; 32697c478bd9Sstevel@tonic-gate totlen += mlen; 32707c478bd9Sstevel@tonic-gate if (m->m_next == 0) { 32717c478bd9Sstevel@tonic-gate n = m_getclr(M_DONTWAIT, m->m_type); 32727c478bd9Sstevel@tonic-gate if (n == 0) 32737c478bd9Sstevel@tonic-gate goto out; 32747c478bd9Sstevel@tonic-gate n->m_len = min(MLEN, len + off); 32757c478bd9Sstevel@tonic-gate m->m_next = n; 32767c478bd9Sstevel@tonic-gate } 32777c478bd9Sstevel@tonic-gate m = m->m_next; 32787c478bd9Sstevel@tonic-gate } 32797c478bd9Sstevel@tonic-gate while (len > 0) { 3280ab25eeb5Syz mlen = min(m->m_len - off, len); 32817c478bd9Sstevel@tonic-gate bcopy(cp, off + mtod(m, caddr_t), (unsigned)mlen); 32827c478bd9Sstevel@tonic-gate cp += mlen; 32837c478bd9Sstevel@tonic-gate len -= mlen; 32847c478bd9Sstevel@tonic-gate mlen += off; 32857c478bd9Sstevel@tonic-gate off = 0; 32867c478bd9Sstevel@tonic-gate totlen += mlen; 32877c478bd9Sstevel@tonic-gate if (len == 0) 32887c478bd9Sstevel@tonic-gate break; 32897c478bd9Sstevel@tonic-gate if (m->m_next == 0) { 32907c478bd9Sstevel@tonic-gate n = m_get(M_DONTWAIT, m->m_type); 32917c478bd9Sstevel@tonic-gate if (n == 0) 32927c478bd9Sstevel@tonic-gate break; 32937c478bd9Sstevel@tonic-gate n->m_len = min(MLEN, len); 32947c478bd9Sstevel@tonic-gate m->m_next = n; 32957c478bd9Sstevel@tonic-gate } 32967c478bd9Sstevel@tonic-gate m = m->m_next; 32977c478bd9Sstevel@tonic-gate } 32987c478bd9Sstevel@tonic-gate out: 32997c478bd9Sstevel@tonic-gate #if 0 33007c478bd9Sstevel@tonic-gate if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) 33017c478bd9Sstevel@tonic-gate m->m_pkthdr.len = totlen; 33027c478bd9Sstevel@tonic-gate #endif 33037c478bd9Sstevel@tonic-gate return; 33047c478bd9Sstevel@tonic-gate } 33057c478bd9Sstevel@tonic-gate #endif /* (_KERNEL) && ( ((BSD < 199103) && !MENTAT) || __sgi) */ 33067c478bd9Sstevel@tonic-gate 33077c478bd9Sstevel@tonic-gate 33087c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 33097c478bd9Sstevel@tonic-gate /* Function: fr_findgroup */ 33107c478bd9Sstevel@tonic-gate /* Returns: frgroup_t * - NULL = group not found, else pointer to group */ 33117c478bd9Sstevel@tonic-gate /* Parameters: group(I) - group name to search for */ 33127c478bd9Sstevel@tonic-gate /* unit(I) - device to which this group belongs */ 33137c478bd9Sstevel@tonic-gate /* set(I) - which set of rules (inactive/inactive) this is */ 33147c478bd9Sstevel@tonic-gate /* fgpp(O) - pointer to place to store pointer to the pointer */ 33157c478bd9Sstevel@tonic-gate /* to where to add the next (last) group or where */ 33167c478bd9Sstevel@tonic-gate /* to delete group from. */ 33177c478bd9Sstevel@tonic-gate /* */ 33187c478bd9Sstevel@tonic-gate /* Search amongst the defined groups for a particular group number. */ 33197c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 3320f4b3ec61Sdh frgroup_t *fr_findgroup(group, unit, set, fgpp, ifs) 33217c478bd9Sstevel@tonic-gate char *group; 33227c478bd9Sstevel@tonic-gate minor_t unit; 33237c478bd9Sstevel@tonic-gate int set; 33247c478bd9Sstevel@tonic-gate frgroup_t ***fgpp; 3325f4b3ec61Sdh ipf_stack_t *ifs; 33267c478bd9Sstevel@tonic-gate { 33277c478bd9Sstevel@tonic-gate frgroup_t *fg, **fgp; 33287c478bd9Sstevel@tonic-gate 33297c478bd9Sstevel@tonic-gate /* 3330ab25eeb5Syz * Which list of groups to search in is dependent on which list of 33317c478bd9Sstevel@tonic-gate * rules are being operated on. 33327c478bd9Sstevel@tonic-gate */ 3333f4b3ec61Sdh fgp = &ifs->ifs_ipfgroups[unit][set]; 33347c478bd9Sstevel@tonic-gate 33357c478bd9Sstevel@tonic-gate while ((fg = *fgp) != NULL) { 33367c478bd9Sstevel@tonic-gate if (strncmp(group, fg->fg_name, FR_GROUPLEN) == 0) 33377c478bd9Sstevel@tonic-gate break; 33387c478bd9Sstevel@tonic-gate else 33397c478bd9Sstevel@tonic-gate fgp = &fg->fg_next; 33407c478bd9Sstevel@tonic-gate } 33417c478bd9Sstevel@tonic-gate if (fgpp != NULL) 33427c478bd9Sstevel@tonic-gate *fgpp = fgp; 33437c478bd9Sstevel@tonic-gate return fg; 33447c478bd9Sstevel@tonic-gate } 33457c478bd9Sstevel@tonic-gate 33467c478bd9Sstevel@tonic-gate 33477c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 33487c478bd9Sstevel@tonic-gate /* Function: fr_addgroup */ 33497c478bd9Sstevel@tonic-gate /* Returns: frgroup_t * - NULL == did not create group, */ 33507c478bd9Sstevel@tonic-gate /* != NULL == pointer to the group */ 33517c478bd9Sstevel@tonic-gate /* Parameters: num(I) - group number to add */ 33527c478bd9Sstevel@tonic-gate /* head(I) - rule pointer that is using this as the head */ 33537c478bd9Sstevel@tonic-gate /* flags(I) - rule flags which describe the type of rule it is */ 33547c478bd9Sstevel@tonic-gate /* unit(I) - device to which this group will belong to */ 33557c478bd9Sstevel@tonic-gate /* set(I) - which set of rules (inactive/inactive) this is */ 33567c478bd9Sstevel@tonic-gate /* Write Locks: ipf_mutex */ 33577c478bd9Sstevel@tonic-gate /* */ 33587c478bd9Sstevel@tonic-gate /* Add a new group head, or if it already exists, increase the reference */ 33597c478bd9Sstevel@tonic-gate /* count to it. */ 33607c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 3361f4b3ec61Sdh frgroup_t *fr_addgroup(group, head, flags, unit, set, ifs) 33627c478bd9Sstevel@tonic-gate char *group; 33637c478bd9Sstevel@tonic-gate void *head; 33647c478bd9Sstevel@tonic-gate u_32_t flags; 33657c478bd9Sstevel@tonic-gate minor_t unit; 33667c478bd9Sstevel@tonic-gate int set; 3367f4b3ec61Sdh ipf_stack_t *ifs; 33687c478bd9Sstevel@tonic-gate { 33697c478bd9Sstevel@tonic-gate frgroup_t *fg, **fgp; 33707c478bd9Sstevel@tonic-gate u_32_t gflags; 33717c478bd9Sstevel@tonic-gate 33727c478bd9Sstevel@tonic-gate if (group == NULL) 33737c478bd9Sstevel@tonic-gate return NULL; 33747c478bd9Sstevel@tonic-gate 33757c478bd9Sstevel@tonic-gate if (unit == IPL_LOGIPF && *group == '\0') 33767c478bd9Sstevel@tonic-gate return NULL; 33777c478bd9Sstevel@tonic-gate 33787c478bd9Sstevel@tonic-gate fgp = NULL; 33797c478bd9Sstevel@tonic-gate gflags = flags & FR_INOUT; 33807c478bd9Sstevel@tonic-gate 3381f4b3ec61Sdh fg = fr_findgroup(group, unit, set, &fgp, ifs); 33827c478bd9Sstevel@tonic-gate if (fg != NULL) { 33837c478bd9Sstevel@tonic-gate if (fg->fg_flags == 0) 33847c478bd9Sstevel@tonic-gate fg->fg_flags = gflags; 33857c478bd9Sstevel@tonic-gate else if (gflags != fg->fg_flags) 33867c478bd9Sstevel@tonic-gate return NULL; 33877c478bd9Sstevel@tonic-gate fg->fg_ref++; 33887c478bd9Sstevel@tonic-gate return fg; 33897c478bd9Sstevel@tonic-gate } 33907c478bd9Sstevel@tonic-gate KMALLOC(fg, frgroup_t *); 33917c478bd9Sstevel@tonic-gate if (fg != NULL) { 33927c478bd9Sstevel@tonic-gate fg->fg_head = head; 33937c478bd9Sstevel@tonic-gate fg->fg_start = NULL; 33947c478bd9Sstevel@tonic-gate fg->fg_next = *fgp; 33957c478bd9Sstevel@tonic-gate bcopy(group, fg->fg_name, FR_GROUPLEN); 33967c478bd9Sstevel@tonic-gate fg->fg_flags = gflags; 33977c478bd9Sstevel@tonic-gate fg->fg_ref = 1; 33987c478bd9Sstevel@tonic-gate *fgp = fg; 33997c478bd9Sstevel@tonic-gate } 34007c478bd9Sstevel@tonic-gate return fg; 34017c478bd9Sstevel@tonic-gate } 34027c478bd9Sstevel@tonic-gate 34037c478bd9Sstevel@tonic-gate 34047c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 34057c478bd9Sstevel@tonic-gate /* Function: fr_delgroup */ 34067c478bd9Sstevel@tonic-gate /* Returns: Nil */ 34077c478bd9Sstevel@tonic-gate /* Parameters: group(I) - group name to delete */ 34087c478bd9Sstevel@tonic-gate /* unit(I) - device to which this group belongs */ 34097c478bd9Sstevel@tonic-gate /* set(I) - which set of rules (inactive/inactive) this is */ 34107c478bd9Sstevel@tonic-gate /* Write Locks: ipf_mutex */ 34117c478bd9Sstevel@tonic-gate /* */ 34127c478bd9Sstevel@tonic-gate /* Attempt to delete a group head. */ 34137c478bd9Sstevel@tonic-gate /* Only do this when its reference count reaches 0. */ 34147c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 3415f4b3ec61Sdh void fr_delgroup(group, unit, set, ifs) 34167c478bd9Sstevel@tonic-gate char *group; 34177c478bd9Sstevel@tonic-gate minor_t unit; 34187c478bd9Sstevel@tonic-gate int set; 3419f4b3ec61Sdh ipf_stack_t *ifs; 34207c478bd9Sstevel@tonic-gate { 34217c478bd9Sstevel@tonic-gate frgroup_t *fg, **fgp; 3422ab25eeb5Syz 3423f4b3ec61Sdh fg = fr_findgroup(group, unit, set, &fgp, ifs); 34247c478bd9Sstevel@tonic-gate if (fg == NULL) 34257c478bd9Sstevel@tonic-gate return; 3426ab25eeb5Syz 34277c478bd9Sstevel@tonic-gate fg->fg_ref--; 34287c478bd9Sstevel@tonic-gate if (fg->fg_ref == 0) { 34297c478bd9Sstevel@tonic-gate *fgp = fg->fg_next; 34307c478bd9Sstevel@tonic-gate KFREE(fg); 34317c478bd9Sstevel@tonic-gate } 34327c478bd9Sstevel@tonic-gate } 34337c478bd9Sstevel@tonic-gate 34347c478bd9Sstevel@tonic-gate 34357c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 34367c478bd9Sstevel@tonic-gate /* Function: fr_getrulen */ 34377c478bd9Sstevel@tonic-gate /* Returns: frentry_t * - NULL == not found, else pointer to rule n */ 34387c478bd9Sstevel@tonic-gate /* Parameters: unit(I) - device for which to count the rule's number */ 34397c478bd9Sstevel@tonic-gate /* flags(I) - which set of rules to find the rule in */ 34407c478bd9Sstevel@tonic-gate /* group(I) - group name */ 34417c478bd9Sstevel@tonic-gate /* n(I) - rule number to find */ 34427c478bd9Sstevel@tonic-gate /* */ 34437c478bd9Sstevel@tonic-gate /* Find rule # n in group # g and return a pointer to it. Return NULl if */ 34447c478bd9Sstevel@tonic-gate /* group # g doesn't exist or there are less than n rules in the group. */ 34457c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 3446f4b3ec61Sdh frentry_t *fr_getrulen(unit, group, n, ifs) 34477c478bd9Sstevel@tonic-gate int unit; 34487c478bd9Sstevel@tonic-gate char *group; 34497c478bd9Sstevel@tonic-gate u_32_t n; 3450f4b3ec61Sdh ipf_stack_t *ifs; 34517c478bd9Sstevel@tonic-gate { 34527c478bd9Sstevel@tonic-gate frentry_t *fr; 34537c478bd9Sstevel@tonic-gate frgroup_t *fg; 34547c478bd9Sstevel@tonic-gate 3455f4b3ec61Sdh fg = fr_findgroup(group, unit, ifs->ifs_fr_active, NULL, ifs); 34567c478bd9Sstevel@tonic-gate if (fg == NULL) 34577c478bd9Sstevel@tonic-gate return NULL; 34587c478bd9Sstevel@tonic-gate for (fr = fg->fg_head; fr && n; fr = fr->fr_next, n--) 34597c478bd9Sstevel@tonic-gate ; 34607c478bd9Sstevel@tonic-gate if (n != 0) 34617c478bd9Sstevel@tonic-gate return NULL; 34627c478bd9Sstevel@tonic-gate return fr; 34637c478bd9Sstevel@tonic-gate } 34647c478bd9Sstevel@tonic-gate 34657c478bd9Sstevel@tonic-gate 34667c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 34677c478bd9Sstevel@tonic-gate /* Function: fr_rulen */ 34687c478bd9Sstevel@tonic-gate /* Returns: int - >= 0 - rule number, -1 == search failed */ 34697c478bd9Sstevel@tonic-gate /* Parameters: unit(I) - device for which to count the rule's number */ 34707c478bd9Sstevel@tonic-gate /* fr(I) - pointer to rule to match */ 34717c478bd9Sstevel@tonic-gate /* */ 34727c478bd9Sstevel@tonic-gate /* Return the number for a rule on a specific filtering device. */ 34737c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 3474f4b3ec61Sdh int fr_rulen(unit, fr, ifs) 34757c478bd9Sstevel@tonic-gate int unit; 34767c478bd9Sstevel@tonic-gate frentry_t *fr; 3477f4b3ec61Sdh ipf_stack_t *ifs; 34787c478bd9Sstevel@tonic-gate { 34797c478bd9Sstevel@tonic-gate frentry_t *fh; 34807c478bd9Sstevel@tonic-gate frgroup_t *fg; 34817c478bd9Sstevel@tonic-gate u_32_t n = 0; 34827c478bd9Sstevel@tonic-gate 34837c478bd9Sstevel@tonic-gate if (fr == NULL) 34847c478bd9Sstevel@tonic-gate return -1; 3485f4b3ec61Sdh fg = fr_findgroup(fr->fr_group, unit, ifs->ifs_fr_active, NULL, ifs); 34867c478bd9Sstevel@tonic-gate if (fg == NULL) 34877c478bd9Sstevel@tonic-gate return -1; 34887c478bd9Sstevel@tonic-gate for (fh = fg->fg_head; fh; n++, fh = fh->fr_next) 34897c478bd9Sstevel@tonic-gate if (fh == fr) 34907c478bd9Sstevel@tonic-gate break; 34917c478bd9Sstevel@tonic-gate if (fh == NULL) 34927c478bd9Sstevel@tonic-gate return -1; 34937c478bd9Sstevel@tonic-gate return n; 34947c478bd9Sstevel@tonic-gate } 34957c478bd9Sstevel@tonic-gate 34967c478bd9Sstevel@tonic-gate 34977c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 34987c478bd9Sstevel@tonic-gate /* Function: frflushlist */ 34997c478bd9Sstevel@tonic-gate /* Returns: int - >= 0 - number of flushed rules */ 35007c478bd9Sstevel@tonic-gate /* Parameters: set(I) - which set of rules (inactive/inactive) this is */ 35017c478bd9Sstevel@tonic-gate /* unit(I) - device for which to flush rules */ 35027c478bd9Sstevel@tonic-gate /* flags(I) - which set of rules to flush */ 35037c478bd9Sstevel@tonic-gate /* nfreedp(O) - pointer to int where flush count is stored */ 35047c478bd9Sstevel@tonic-gate /* listp(I) - pointer to list to flush pointer */ 35057c478bd9Sstevel@tonic-gate /* Write Locks: ipf_mutex */ 35067c478bd9Sstevel@tonic-gate /* */ 35077c478bd9Sstevel@tonic-gate /* Recursively flush rules from the list, descending groups as they are */ 35087c478bd9Sstevel@tonic-gate /* encountered. if a rule is the head of a group and it has lost all its */ 35097c478bd9Sstevel@tonic-gate /* group members, then also delete the group reference. nfreedp is needed */ 35107c478bd9Sstevel@tonic-gate /* to store the accumulating count of rules removed, whereas the returned */ 35117c478bd9Sstevel@tonic-gate /* value is just the number removed from the current list. The latter is */ 35127c478bd9Sstevel@tonic-gate /* needed to correctly adjust reference counts on rules that define groups. */ 35137c478bd9Sstevel@tonic-gate /* */ 35147c478bd9Sstevel@tonic-gate /* NOTE: Rules not loaded from user space cannot be flushed. */ 35157c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 3516f4b3ec61Sdh static int frflushlist(set, unit, nfreedp, listp, ifs) 35177c478bd9Sstevel@tonic-gate int set; 35187c478bd9Sstevel@tonic-gate minor_t unit; 35197c478bd9Sstevel@tonic-gate int *nfreedp; 35207c478bd9Sstevel@tonic-gate frentry_t **listp; 3521f4b3ec61Sdh ipf_stack_t *ifs; 35227c478bd9Sstevel@tonic-gate { 352324109627Syx int freed = 0; 35247c478bd9Sstevel@tonic-gate frentry_t *fp; 35257c478bd9Sstevel@tonic-gate 35267c478bd9Sstevel@tonic-gate while ((fp = *listp) != NULL) { 35277c478bd9Sstevel@tonic-gate if ((fp->fr_type & FR_T_BUILTIN) || 35287c478bd9Sstevel@tonic-gate !(fp->fr_flags & FR_COPIED)) { 35297c478bd9Sstevel@tonic-gate listp = &fp->fr_next; 35307c478bd9Sstevel@tonic-gate continue; 35317c478bd9Sstevel@tonic-gate } 35327c478bd9Sstevel@tonic-gate *listp = fp->fr_next; 35337c478bd9Sstevel@tonic-gate if (fp->fr_grp != NULL) { 353424109627Syx (void) frflushlist(set, unit, nfreedp, fp->fr_grp, ifs); 35357c478bd9Sstevel@tonic-gate } 35367c478bd9Sstevel@tonic-gate 35377c478bd9Sstevel@tonic-gate if (fp->fr_grhead != NULL) { 3538f4b3ec61Sdh fr_delgroup(fp->fr_grhead, unit, set, ifs); 35397c478bd9Sstevel@tonic-gate *fp->fr_grhead = '\0'; 35407c478bd9Sstevel@tonic-gate } 35417c478bd9Sstevel@tonic-gate 35427c478bd9Sstevel@tonic-gate ASSERT(fp->fr_ref > 0); 35437c478bd9Sstevel@tonic-gate fp->fr_next = NULL; 3544f4b3ec61Sdh if (fr_derefrule(&fp, ifs) == 0) 35457c478bd9Sstevel@tonic-gate freed++; 35467c478bd9Sstevel@tonic-gate } 35477c478bd9Sstevel@tonic-gate *nfreedp += freed; 35487c478bd9Sstevel@tonic-gate return freed; 35497c478bd9Sstevel@tonic-gate } 35507c478bd9Sstevel@tonic-gate 35517c478bd9Sstevel@tonic-gate 35527c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 35537c478bd9Sstevel@tonic-gate /* Function: frflush */ 35547c478bd9Sstevel@tonic-gate /* Returns: int - >= 0 - number of flushed rules */ 35557c478bd9Sstevel@tonic-gate /* Parameters: unit(I) - device for which to flush rules */ 35567c478bd9Sstevel@tonic-gate /* flags(I) - which set of rules to flush */ 35577c478bd9Sstevel@tonic-gate /* */ 35587c478bd9Sstevel@tonic-gate /* Calls flushlist() for all filter rules (accounting, firewall - both IPv4 */ 35597c478bd9Sstevel@tonic-gate /* and IPv6) as defined by the value of flags. */ 35607c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 3561f4b3ec61Sdh int frflush(unit, proto, flags, ifs) 35627c478bd9Sstevel@tonic-gate minor_t unit; 35637663b816Sml int proto, flags; 3564f4b3ec61Sdh ipf_stack_t *ifs; 35657c478bd9Sstevel@tonic-gate { 35667c478bd9Sstevel@tonic-gate int flushed = 0, set; 35677c478bd9Sstevel@tonic-gate 3568f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_mutex); 356914d3298eSAlexandr Nedvedicky bzero((char *)ifs->ifs_frcache, sizeof (ifs->ifs_frcache)); 35707c478bd9Sstevel@tonic-gate 3571f4b3ec61Sdh set = ifs->ifs_fr_active; 35727c478bd9Sstevel@tonic-gate if ((flags & FR_INACTIVE) == FR_INACTIVE) 35737c478bd9Sstevel@tonic-gate set = 1 - set; 35747c478bd9Sstevel@tonic-gate 35757c478bd9Sstevel@tonic-gate if (flags & FR_OUTQUE) { 35767663b816Sml if (proto == 0 || proto == 6) { 35777663b816Sml (void) frflushlist(set, unit, 3578f4b3ec61Sdh &flushed, &ifs->ifs_ipfilter6[1][set], ifs); 35797663b816Sml (void) frflushlist(set, unit, 3580f4b3ec61Sdh &flushed, &ifs->ifs_ipacct6[1][set], ifs); 35817663b816Sml } 35827663b816Sml if (proto == 0 || proto == 4) { 35837663b816Sml (void) frflushlist(set, unit, 3584f4b3ec61Sdh &flushed, &ifs->ifs_ipfilter[1][set], ifs); 35857663b816Sml (void) frflushlist(set, unit, 3586f4b3ec61Sdh &flushed, &ifs->ifs_ipacct[1][set], ifs); 35877663b816Sml } 35887c478bd9Sstevel@tonic-gate } 35897c478bd9Sstevel@tonic-gate if (flags & FR_INQUE) { 35907663b816Sml if (proto == 0 || proto == 6) { 35917663b816Sml (void) frflushlist(set, unit, 3592f4b3ec61Sdh &flushed, &ifs->ifs_ipfilter6[0][set], ifs); 35937663b816Sml (void) frflushlist(set, unit, 3594f4b3ec61Sdh &flushed, &ifs->ifs_ipacct6[0][set], ifs); 35957663b816Sml } 35967663b816Sml if (proto == 0 || proto == 4) { 35977663b816Sml (void) frflushlist(set, unit, 3598f4b3ec61Sdh &flushed, &ifs->ifs_ipfilter[0][set], ifs); 35997663b816Sml (void) frflushlist(set, unit, 3600f4b3ec61Sdh &flushed, &ifs->ifs_ipacct[0][set], ifs); 36017663b816Sml } 36027c478bd9Sstevel@tonic-gate } 3603f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 36047663b816Sml 36057663b816Sml if (unit == IPL_LOGIPF) { 36067663b816Sml int tmp; 36077663b816Sml 3608f4b3ec61Sdh tmp = frflush(IPL_LOGCOUNT, proto, flags, ifs); 36097663b816Sml if (tmp >= 0) 36107663b816Sml flushed += tmp; 36117663b816Sml } 36127c478bd9Sstevel@tonic-gate return flushed; 36137c478bd9Sstevel@tonic-gate } 36147c478bd9Sstevel@tonic-gate 36157c478bd9Sstevel@tonic-gate 36167c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 36177c478bd9Sstevel@tonic-gate /* Function: memstr */ 36187c478bd9Sstevel@tonic-gate /* Returns: char * - NULL if failed, != NULL pointer to matching bytes */ 36197c478bd9Sstevel@tonic-gate /* Parameters: src(I) - pointer to byte sequence to match */ 36207c478bd9Sstevel@tonic-gate /* dst(I) - pointer to byte sequence to search */ 36217c478bd9Sstevel@tonic-gate /* slen(I) - match length */ 36227c478bd9Sstevel@tonic-gate /* dlen(I) - length available to search in */ 36237c478bd9Sstevel@tonic-gate /* */ 36247c478bd9Sstevel@tonic-gate /* Search dst for a sequence of bytes matching those at src and extend for */ 36257c478bd9Sstevel@tonic-gate /* slen bytes. */ 36267c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 36277c478bd9Sstevel@tonic-gate char *memstr(src, dst, slen, dlen) 36287c478bd9Sstevel@tonic-gate char *src, *dst; 36297c478bd9Sstevel@tonic-gate int slen, dlen; 36307c478bd9Sstevel@tonic-gate { 36317c478bd9Sstevel@tonic-gate char *s = NULL; 36327c478bd9Sstevel@tonic-gate 36337c478bd9Sstevel@tonic-gate while (dlen >= slen) { 36347c478bd9Sstevel@tonic-gate if (bcmp(src, dst, slen) == 0) { 36357c478bd9Sstevel@tonic-gate s = dst; 36367c478bd9Sstevel@tonic-gate break; 36377c478bd9Sstevel@tonic-gate } 36387c478bd9Sstevel@tonic-gate dst++; 36397c478bd9Sstevel@tonic-gate dlen--; 36407c478bd9Sstevel@tonic-gate } 36417c478bd9Sstevel@tonic-gate return s; 36427c478bd9Sstevel@tonic-gate } 36437c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 36447c478bd9Sstevel@tonic-gate /* Function: fr_fixskip */ 36457c478bd9Sstevel@tonic-gate /* Returns: Nil */ 36467c478bd9Sstevel@tonic-gate /* Parameters: listp(IO) - pointer to start of list with skip rule */ 36477c478bd9Sstevel@tonic-gate /* rp(I) - rule added/removed with skip in it. */ 36487c478bd9Sstevel@tonic-gate /* addremove(I) - adjustment (-1/+1) to make to skip count, */ 36497c478bd9Sstevel@tonic-gate /* depending on whether a rule was just added */ 36507c478bd9Sstevel@tonic-gate /* or removed. */ 36517c478bd9Sstevel@tonic-gate /* */ 36527c478bd9Sstevel@tonic-gate /* Adjust all the rules in a list which would have skip'd past the position */ 36537c478bd9Sstevel@tonic-gate /* where we are inserting to skip to the right place given the change. */ 36547c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 36557c478bd9Sstevel@tonic-gate void fr_fixskip(listp, rp, addremove) 36567c478bd9Sstevel@tonic-gate frentry_t **listp, *rp; 36577c478bd9Sstevel@tonic-gate int addremove; 36587c478bd9Sstevel@tonic-gate { 36597c478bd9Sstevel@tonic-gate int rules, rn; 36607c478bd9Sstevel@tonic-gate frentry_t *fp; 36617c478bd9Sstevel@tonic-gate 36627c478bd9Sstevel@tonic-gate rules = 0; 36637c478bd9Sstevel@tonic-gate for (fp = *listp; (fp != NULL) && (fp != rp); fp = fp->fr_next) 36647c478bd9Sstevel@tonic-gate rules++; 36657c478bd9Sstevel@tonic-gate 36667c478bd9Sstevel@tonic-gate if (!fp) 36677c478bd9Sstevel@tonic-gate return; 36687c478bd9Sstevel@tonic-gate 36697c478bd9Sstevel@tonic-gate for (rn = 0, fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++) 36707c478bd9Sstevel@tonic-gate if (FR_ISSKIP(fp->fr_flags) && (rn + fp->fr_arg >= rules)) 36717c478bd9Sstevel@tonic-gate fp->fr_arg += addremove; 36727c478bd9Sstevel@tonic-gate } 36737c478bd9Sstevel@tonic-gate 36747c478bd9Sstevel@tonic-gate 36757c478bd9Sstevel@tonic-gate #ifdef _KERNEL 36767c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 36777c478bd9Sstevel@tonic-gate /* Function: count4bits */ 36787c478bd9Sstevel@tonic-gate /* Returns: int - >= 0 - number of consecutive bits in input */ 36797c478bd9Sstevel@tonic-gate /* Parameters: ip(I) - 32bit IP address */ 36807c478bd9Sstevel@tonic-gate /* */ 36817c478bd9Sstevel@tonic-gate /* IPv4 ONLY */ 36827c478bd9Sstevel@tonic-gate /* count consecutive 1's in bit mask. If the mask generated by counting */ 36837c478bd9Sstevel@tonic-gate /* consecutive 1's is different to that passed, return -1, else return # */ 36847c478bd9Sstevel@tonic-gate /* of bits. */ 36857c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 36867c478bd9Sstevel@tonic-gate int count4bits(ip) 36877c478bd9Sstevel@tonic-gate u_32_t ip; 36887c478bd9Sstevel@tonic-gate { 36897c478bd9Sstevel@tonic-gate u_32_t ipn; 36907c478bd9Sstevel@tonic-gate int cnt = 0, i, j; 36917c478bd9Sstevel@tonic-gate 36927c478bd9Sstevel@tonic-gate ip = ipn = ntohl(ip); 36937c478bd9Sstevel@tonic-gate for (i = 32; i; i--, ipn *= 2) 36947c478bd9Sstevel@tonic-gate if (ipn & 0x80000000) 36957c478bd9Sstevel@tonic-gate cnt++; 36967c478bd9Sstevel@tonic-gate else 36977c478bd9Sstevel@tonic-gate break; 36987c478bd9Sstevel@tonic-gate ipn = 0; 36997c478bd9Sstevel@tonic-gate for (i = 32, j = cnt; i; i--, j--) { 37007c478bd9Sstevel@tonic-gate ipn *= 2; 37017c478bd9Sstevel@tonic-gate if (j > 0) 37027c478bd9Sstevel@tonic-gate ipn++; 37037c478bd9Sstevel@tonic-gate } 37047c478bd9Sstevel@tonic-gate if (ipn == ip) 37057c478bd9Sstevel@tonic-gate return cnt; 37067c478bd9Sstevel@tonic-gate return -1; 37077c478bd9Sstevel@tonic-gate } 37087c478bd9Sstevel@tonic-gate 3709ab25eeb5Syz 37107663b816Sml #ifdef USE_INET6 37117c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 37127c478bd9Sstevel@tonic-gate /* Function: count6bits */ 37137c478bd9Sstevel@tonic-gate /* Returns: int - >= 0 - number of consecutive bits in input */ 37147c478bd9Sstevel@tonic-gate /* Parameters: msk(I) - pointer to start of IPv6 bitmask */ 37157c478bd9Sstevel@tonic-gate /* */ 37167c478bd9Sstevel@tonic-gate /* IPv6 ONLY */ 37177c478bd9Sstevel@tonic-gate /* count consecutive 1's in bit mask. */ 37187c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 37197c478bd9Sstevel@tonic-gate int count6bits(msk) 37207c478bd9Sstevel@tonic-gate u_32_t *msk; 37217c478bd9Sstevel@tonic-gate { 37227c478bd9Sstevel@tonic-gate int i = 0, k; 37237c478bd9Sstevel@tonic-gate u_32_t j; 37247c478bd9Sstevel@tonic-gate 37257c478bd9Sstevel@tonic-gate for (k = 3; k >= 0; k--) 37267c478bd9Sstevel@tonic-gate if (msk[k] == 0xffffffff) 37277c478bd9Sstevel@tonic-gate i += 32; 37287c478bd9Sstevel@tonic-gate else { 37297c478bd9Sstevel@tonic-gate for (j = msk[k]; j; j <<= 1) 37307c478bd9Sstevel@tonic-gate if (j & 0x80000000) 37317c478bd9Sstevel@tonic-gate i++; 37327c478bd9Sstevel@tonic-gate } 37337c478bd9Sstevel@tonic-gate return i; 37347c478bd9Sstevel@tonic-gate } 3735ab25eeb5Syz # endif 37367c478bd9Sstevel@tonic-gate #endif /* _KERNEL */ 37377c478bd9Sstevel@tonic-gate 37387c478bd9Sstevel@tonic-gate 3739381a2a9aSdr /* ------------------------------------------------------------------------ */ 3740381a2a9aSdr /* Function: fr_ifsync */ 3741381a2a9aSdr /* Returns: void * - new interface identifier */ 3742381a2a9aSdr /* Parameters: action(I) - type of synchronisation to do */ 3743381a2a9aSdr /* v(I) - IP version being sync'd (v4 or v6) */ 3744381a2a9aSdr /* newifp(I) - interface identifier being introduced/removed */ 3745381a2a9aSdr /* oldifp(I) - interface identifier in a filter rule */ 374640cdc2e8SAlexandr Nedvedicky /* newname(I) - name associated with newifp interface */ 374740cdc2e8SAlexandr Nedvedicky /* oldname(I) - name associated with oldifp interface */ 374840cdc2e8SAlexandr Nedvedicky /* ifs - pointer to IPF stack instance */ 3749381a2a9aSdr /* */ 3750381a2a9aSdr /* This function returns what the new value for "oldifp" should be for its */ 3751381a2a9aSdr /* caller. In some cases it will not change, in some it will. */ 3752381a2a9aSdr /* action == IPFSYNC_RESYNC */ 3753381a2a9aSdr /* a new value for oldifp will always be looked up, according to oldname, */ 3754381a2a9aSdr /* the values of newname and newifp are ignored. */ 3755381a2a9aSdr /* action == IPFSYNC_NEWIFP */ 3756381a2a9aSdr /* if oldname matches newname then we are doing a sync for the matching */ 3757381a2a9aSdr /* interface, so we return newifp to be used in place of oldifp. If the */ 3758381a2a9aSdr /* the names don't match, just return oldifp. */ 3759381a2a9aSdr /* action == IPFSYNC_OLDIFP */ 3760381a2a9aSdr /* if oldifp matches newifp then we are are doing a sync to remove any */ 3761381a2a9aSdr /* references to oldifp, so we return "-1". */ 376240cdc2e8SAlexandr Nedvedicky /* ----- */ 376340cdc2e8SAlexandr Nedvedicky /* NOTE: */ 376440cdc2e8SAlexandr Nedvedicky /* This function processes NIC event from PF_HOOKS. The action parameter */ 376540cdc2e8SAlexandr Nedvedicky /* is set in ipf_nic_event_v4()/ipf_nic_event_v6() function. There is */ 376640cdc2e8SAlexandr Nedvedicky /* one single switch statement() in ipf_nic_event_vx() function, which */ 376740cdc2e8SAlexandr Nedvedicky /* translates the HOOK event type to action parameter passed to fr_ifsync. */ 376840cdc2e8SAlexandr Nedvedicky /* The translation table looks as follows: */ 376940cdc2e8SAlexandr Nedvedicky /* event | action */ 377040cdc2e8SAlexandr Nedvedicky /* ----------------+------------- */ 377140cdc2e8SAlexandr Nedvedicky /* NE_PLUMB | IPFSYNC_NEWIFP */ 377240cdc2e8SAlexandr Nedvedicky /* NE_UNPLUMB | IPFSYNC_OLDIFP */ 377340cdc2e8SAlexandr Nedvedicky /* NE_ADDRESS_CHANGE | IPFSYNC_RESYNC */ 377440cdc2e8SAlexandr Nedvedicky /* */ 377540cdc2e8SAlexandr Nedvedicky /* The oldname and oldifp parameters are taken from IPF entry (rule, state */ 377640cdc2e8SAlexandr Nedvedicky /* table entry, NAT table entry, fragment ...). The newname and newifp */ 377740cdc2e8SAlexandr Nedvedicky /* parameters come from hook event data, parameters are taken from event */ 377840cdc2e8SAlexandr Nedvedicky /* in ipf_nic_event_vx() functions. Any time NIC changes, the IPF is */ 377940cdc2e8SAlexandr Nedvedicky /* notified by hook function. */ 378040cdc2e8SAlexandr Nedvedicky /* */ 378140cdc2e8SAlexandr Nedvedicky /* We get NE_UNPLUMB event from PF_HOOKS even if someone coincidently tries */ 378240cdc2e8SAlexandr Nedvedicky /* to plumb the interface, which is already plumbed. In such case we always */ 378340cdc2e8SAlexandr Nedvedicky /* get the event from PF_HOOKS as follows: */ 378440cdc2e8SAlexandr Nedvedicky /* event: NE_PLUMB */ 378540cdc2e8SAlexandr Nedvedicky /* NIC: 0x0 */ 3786381a2a9aSdr /* ------------------------------------------------------------------------ */ 3787f4b3ec61Sdh static void *fr_ifsync(action, v, newname, oldname, newifp, oldifp, ifs) 3788381a2a9aSdr int action, v; 3789381a2a9aSdr char *newname, *oldname; 3790381a2a9aSdr void *newifp, *oldifp; 3791f4b3ec61Sdh ipf_stack_t *ifs; 3792381a2a9aSdr { 3793381a2a9aSdr void *rval = oldifp; 3794381a2a9aSdr 3795381a2a9aSdr switch (action) 3796381a2a9aSdr { 3797381a2a9aSdr case IPFSYNC_RESYNC : 3798381a2a9aSdr if (oldname[0] != '\0') { 3799f4b3ec61Sdh rval = fr_resolvenic(oldname, v, ifs); 3800381a2a9aSdr } 3801381a2a9aSdr break; 3802381a2a9aSdr case IPFSYNC_NEWIFP : 3803381a2a9aSdr if (!strncmp(newname, oldname, LIFNAMSIZ)) 3804381a2a9aSdr rval = newifp; 3805381a2a9aSdr break; 3806381a2a9aSdr case IPFSYNC_OLDIFP : 380740cdc2e8SAlexandr Nedvedicky /* 380840cdc2e8SAlexandr Nedvedicky * If interface gets unplumbed it must be invalidated, which 380940cdc2e8SAlexandr Nedvedicky * means set all existing references to the interface to -1. 381040cdc2e8SAlexandr Nedvedicky * We don't want to invalidate references for wildcard 381140cdc2e8SAlexandr Nedvedicky * (unbound) rules (entries). 381240cdc2e8SAlexandr Nedvedicky */ 3813381a2a9aSdr if (newifp == oldifp) 381424ed9a9fSan rval = (oldifp) ? (void *)-1 : NULL; 3815381a2a9aSdr break; 3816381a2a9aSdr } 3817381a2a9aSdr 3818381a2a9aSdr return rval; 3819381a2a9aSdr } 3820381a2a9aSdr 3821381a2a9aSdr 38227c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 38237c478bd9Sstevel@tonic-gate /* Function: frsynclist */ 38247c478bd9Sstevel@tonic-gate /* Returns: void */ 3825381a2a9aSdr /* Parameters: action(I) - type of synchronisation to do */ 3826381a2a9aSdr /* v(I) - IP version being sync'd (v4 or v6) */ 3827381a2a9aSdr /* ifp(I) - interface identifier associated with action */ 382840cdc2e8SAlexandr Nedvedicky /* ifname(I) - name associated with ifp parameter */ 382940cdc2e8SAlexandr Nedvedicky /* fr(I) - pointer to filter rule */ 383040cdc2e8SAlexandr Nedvedicky /* ifs - pointer to IPF stack instance */ 38317c478bd9Sstevel@tonic-gate /* Write Locks: ipf_mutex */ 38327c478bd9Sstevel@tonic-gate /* */ 38337c478bd9Sstevel@tonic-gate /* Walk through a list of filter rules and resolve any interface names into */ 38347c478bd9Sstevel@tonic-gate /* pointers. Where dynamic addresses are used, also update the IP address */ 3835ab25eeb5Syz /* used in the rule. The interface pointer is used to limit the lookups to */ 3836ab25eeb5Syz /* a specific set of matching names if it is non-NULL. */ 38377c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 3838f4b3ec61Sdh static void frsynclist(action, v, ifp, ifname, fr, ifs) 3839381a2a9aSdr int action, v; 3840ab25eeb5Syz void *ifp; 3841381a2a9aSdr char *ifname; 3842381a2a9aSdr frentry_t *fr; 3843f4b3ec61Sdh ipf_stack_t *ifs; 38447c478bd9Sstevel@tonic-gate { 38457c478bd9Sstevel@tonic-gate frdest_t *fdp; 3846381a2a9aSdr int rv, i; 38477c478bd9Sstevel@tonic-gate 38487c478bd9Sstevel@tonic-gate for (; fr; fr = fr->fr_next) { 3849381a2a9aSdr rv = fr->fr_v; 3850381a2a9aSdr if (v != 0 && v != rv) 3851381a2a9aSdr continue; 38527c478bd9Sstevel@tonic-gate 38537c478bd9Sstevel@tonic-gate /* 38547c478bd9Sstevel@tonic-gate * Lookup all the interface names that are part of the rule. 38557c478bd9Sstevel@tonic-gate */ 38567c478bd9Sstevel@tonic-gate for (i = 0; i < 4; i++) { 3857381a2a9aSdr fr->fr_ifas[i] = fr_ifsync(action, rv, ifname, 3858381a2a9aSdr fr->fr_ifnames[i], 3859f4b3ec61Sdh ifp, fr->fr_ifas[i], 3860f4b3ec61Sdh ifs); 38617c478bd9Sstevel@tonic-gate } 38627c478bd9Sstevel@tonic-gate 3863381a2a9aSdr fdp = &fr->fr_tifs[0]; 3864381a2a9aSdr fdp->fd_ifp = fr_ifsync(action, rv, ifname, fdp->fd_ifname, 3865f4b3ec61Sdh ifp, fdp->fd_ifp, ifs); 3866381a2a9aSdr 3867381a2a9aSdr fdp = &fr->fr_tifs[1]; 3868381a2a9aSdr fdp->fd_ifp = fr_ifsync(action, rv, ifname, fdp->fd_ifname, 3869f4b3ec61Sdh ifp, fdp->fd_ifp, ifs); 3870381a2a9aSdr 3871381a2a9aSdr fdp = &fr->fr_dif; 3872381a2a9aSdr fdp->fd_ifp = fr_ifsync(action, rv, ifname, fdp->fd_ifname, 3873f4b3ec61Sdh ifp, fdp->fd_ifp, ifs); 3874381a2a9aSdr 3875381a2a9aSdr if (action != IPFSYNC_RESYNC) 3876a4cf92b0Sdr continue; 3877381a2a9aSdr 38787c478bd9Sstevel@tonic-gate if (fr->fr_type == FR_T_IPF) { 38797c478bd9Sstevel@tonic-gate if (fr->fr_satype != FRI_NORMAL && 38807c478bd9Sstevel@tonic-gate fr->fr_satype != FRI_LOOKUP) { 3881381a2a9aSdr (void)fr_ifpaddr(rv, fr->fr_satype, 38827c478bd9Sstevel@tonic-gate fr->fr_ifas[fr->fr_sifpidx], 3883f4b3ec61Sdh &fr->fr_src, &fr->fr_smsk, 3884f4b3ec61Sdh ifs); 38857c478bd9Sstevel@tonic-gate } 38867c478bd9Sstevel@tonic-gate if (fr->fr_datype != FRI_NORMAL && 38877c478bd9Sstevel@tonic-gate fr->fr_datype != FRI_LOOKUP) { 3888381a2a9aSdr (void)fr_ifpaddr(rv, fr->fr_datype, 38897c478bd9Sstevel@tonic-gate fr->fr_ifas[fr->fr_difpidx], 3890f4b3ec61Sdh &fr->fr_dst, &fr->fr_dmsk, 3891f4b3ec61Sdh ifs); 38927c478bd9Sstevel@tonic-gate } 38937c478bd9Sstevel@tonic-gate } 38947c478bd9Sstevel@tonic-gate 38957c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOOKUP 38967c478bd9Sstevel@tonic-gate if (fr->fr_type == FR_T_IPF && fr->fr_satype == FRI_LOOKUP && 38977c478bd9Sstevel@tonic-gate fr->fr_srcptr == NULL) { 38987c478bd9Sstevel@tonic-gate fr->fr_srcptr = fr_resolvelookup(fr->fr_srctype, 38997c478bd9Sstevel@tonic-gate fr->fr_srcnum, 3900f4b3ec61Sdh &fr->fr_srcfunc, ifs); 39017c478bd9Sstevel@tonic-gate } 39027c478bd9Sstevel@tonic-gate if (fr->fr_type == FR_T_IPF && fr->fr_datype == FRI_LOOKUP && 39037c478bd9Sstevel@tonic-gate fr->fr_dstptr == NULL) { 39047c478bd9Sstevel@tonic-gate fr->fr_dstptr = fr_resolvelookup(fr->fr_dsttype, 39057c478bd9Sstevel@tonic-gate fr->fr_dstnum, 3906f4b3ec61Sdh &fr->fr_dstfunc, ifs); 39077c478bd9Sstevel@tonic-gate } 39087c478bd9Sstevel@tonic-gate #endif 39097c478bd9Sstevel@tonic-gate } 39107c478bd9Sstevel@tonic-gate } 39117c478bd9Sstevel@tonic-gate 39127c478bd9Sstevel@tonic-gate 39137c478bd9Sstevel@tonic-gate #ifdef _KERNEL 39147c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 39157c478bd9Sstevel@tonic-gate /* Function: frsync */ 39167c478bd9Sstevel@tonic-gate /* Returns: void */ 3917381a2a9aSdr /* Parameters: action(I) - type of synchronisation to do */ 3918381a2a9aSdr /* v(I) - IP version being sync'd (v4 or v6) */ 3919381a2a9aSdr /* ifp(I) - interface identifier associated with action */ 3920381a2a9aSdr /* name(I) - name associated with ifp parameter */ 39217c478bd9Sstevel@tonic-gate /* */ 39227c478bd9Sstevel@tonic-gate /* frsync() is called when we suspect that the interface list or */ 39237c478bd9Sstevel@tonic-gate /* information about interfaces (like IP#) has changed. Go through all */ 39247c478bd9Sstevel@tonic-gate /* filter rules, NAT entries and the state table and check if anything */ 39257c478bd9Sstevel@tonic-gate /* needs to be changed/updated. */ 3926381a2a9aSdr /* With the filtering hooks added to Solaris, we needed to change the manner*/ 3927381a2a9aSdr /* in which this was done to support three different types of sync: */ 3928381a2a9aSdr /* - complete resync of all interface name/identifiers */ 3929381a2a9aSdr /* - new interface being announced with its name and identifier */ 3930381a2a9aSdr /* - interface removal being announced by only its identifier */ 3931381a2a9aSdr /* ------------------------------------------------------------------------ */ 3932f4b3ec61Sdh void frsync(action, v, ifp, name, ifs) 3933381a2a9aSdr int action, v; 3934ab25eeb5Syz void *ifp; 3935381a2a9aSdr char *name; 3936f4b3ec61Sdh ipf_stack_t *ifs; 39377c478bd9Sstevel@tonic-gate { 39387c478bd9Sstevel@tonic-gate int i; 3939ab25eeb5Syz 3940f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_mutex); 3941f4b3ec61Sdh frsynclist(action, v, ifp, name, ifs->ifs_ipacct[0][ifs->ifs_fr_active], ifs); 3942f4b3ec61Sdh frsynclist(action, v, ifp, name, ifs->ifs_ipacct[1][ifs->ifs_fr_active], ifs); 3943f4b3ec61Sdh frsynclist(action, v, ifp, name, ifs->ifs_ipfilter[0][ifs->ifs_fr_active], ifs); 3944f4b3ec61Sdh frsynclist(action, v, ifp, name, ifs->ifs_ipfilter[1][ifs->ifs_fr_active], ifs); 3945f4b3ec61Sdh frsynclist(action, v, ifp, name, ifs->ifs_ipacct6[0][ifs->ifs_fr_active], ifs); 3946f4b3ec61Sdh frsynclist(action, v, ifp, name, ifs->ifs_ipacct6[1][ifs->ifs_fr_active], ifs); 3947f4b3ec61Sdh frsynclist(action, v, ifp, name, ifs->ifs_ipfilter6[0][ifs->ifs_fr_active], ifs); 3948f4b3ec61Sdh frsynclist(action, v, ifp, name, ifs->ifs_ipfilter6[1][ifs->ifs_fr_active], ifs); 39497c478bd9Sstevel@tonic-gate 39507c478bd9Sstevel@tonic-gate for (i = 0; i < IPL_LOGSIZE; i++) { 39517c478bd9Sstevel@tonic-gate frgroup_t *g; 39527c478bd9Sstevel@tonic-gate 3953f4b3ec61Sdh for (g = ifs->ifs_ipfgroups[i][0]; g != NULL; g = g->fg_next) 3954f4b3ec61Sdh frsynclist(action, v, ifp, name, g->fg_start, ifs); 3955f4b3ec61Sdh for (g = ifs->ifs_ipfgroups[i][1]; g != NULL; g = g->fg_next) 3956f4b3ec61Sdh frsynclist(action, v, ifp, name, g->fg_start, ifs); 39577c478bd9Sstevel@tonic-gate } 3958f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 39597c478bd9Sstevel@tonic-gate } 39607c478bd9Sstevel@tonic-gate 3961e8d569f4SAlexandr Nedvedicky #if SOLARIS2 >= 10 3962e8d569f4SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 3963e8d569f4SAlexandr Nedvedicky /* Function: fr_syncindex */ 3964e8d569f4SAlexandr Nedvedicky /* Returns: void */ 3965e8d569f4SAlexandr Nedvedicky /* Parameters: rules - list of rules to be sync'd */ 3966e8d569f4SAlexandr Nedvedicky /* ifp - interface, which is being sync'd */ 3967e8d569f4SAlexandr Nedvedicky /* newifp - new ifindex value for interface */ 3968e8d569f4SAlexandr Nedvedicky /* */ 3969e8d569f4SAlexandr Nedvedicky /* Function updates all NIC indecis, which match ifp, in every rule. Every */ 3970e8d569f4SAlexandr Nedvedicky /* NIC index matching ifp, will be updated to newifp. */ 3971e8d569f4SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 3972e8d569f4SAlexandr Nedvedicky static void fr_syncindex(rules, ifp, newifp) 3973e8d569f4SAlexandr Nedvedicky frentry_t *rules; 3974e8d569f4SAlexandr Nedvedicky void *ifp; 3975e8d569f4SAlexandr Nedvedicky void *newifp; 3976e8d569f4SAlexandr Nedvedicky { 3977e8d569f4SAlexandr Nedvedicky int i; 3978e8d569f4SAlexandr Nedvedicky frentry_t *fr; 3979e8d569f4SAlexandr Nedvedicky 3980e8d569f4SAlexandr Nedvedicky for (fr = rules; fr != NULL; fr = fr->fr_next) { 3981e8d569f4SAlexandr Nedvedicky /* 3982e8d569f4SAlexandr Nedvedicky * Lookup all the interface names that are part of the rule. 3983e8d569f4SAlexandr Nedvedicky */ 3984e8d569f4SAlexandr Nedvedicky for (i = 0; i < 4; i++) 3985e8d569f4SAlexandr Nedvedicky if (fr->fr_ifas[i] == ifp) 3986e8d569f4SAlexandr Nedvedicky fr->fr_ifas[i] = newifp; 3987e8d569f4SAlexandr Nedvedicky 3988e8d569f4SAlexandr Nedvedicky for (i = 0; i < 2; i++) { 3989e8d569f4SAlexandr Nedvedicky if (fr->fr_tifs[i].fd_ifp == ifp) 3990e8d569f4SAlexandr Nedvedicky fr->fr_tifs[i].fd_ifp = newifp; 3991e8d569f4SAlexandr Nedvedicky } 3992e8d569f4SAlexandr Nedvedicky 3993e8d569f4SAlexandr Nedvedicky if (fr->fr_dif.fd_ifp == ifp) 3994e8d569f4SAlexandr Nedvedicky fr->fr_dif.fd_ifp = newifp; 3995e8d569f4SAlexandr Nedvedicky } 3996e8d569f4SAlexandr Nedvedicky } 3997e8d569f4SAlexandr Nedvedicky 3998e8d569f4SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 3999e8d569f4SAlexandr Nedvedicky /* Function: fr_ifindexsync */ 4000e8d569f4SAlexandr Nedvedicky /* Returns: void */ 4001e8d569f4SAlexandr Nedvedicky /* Parameters: ifp - interface, which is being sync'd */ 4002e8d569f4SAlexandr Nedvedicky /* newifp - new ifindex value for interface */ 4003e8d569f4SAlexandr Nedvedicky /* ifs - IPF's stack */ 4004e8d569f4SAlexandr Nedvedicky /* */ 4005e8d569f4SAlexandr Nedvedicky /* Function assumes ipf_mutex is locked exclusively. */ 4006e8d569f4SAlexandr Nedvedicky /* */ 4007e8d569f4SAlexandr Nedvedicky /* Function updates the NIC references in rules with new interfaces index */ 4008e8d569f4SAlexandr Nedvedicky /* (newifp). Function must process active lists: */ 4009e8d569f4SAlexandr Nedvedicky /* with accounting rules (IPv6 and IPv4) */ 4010e8d569f4SAlexandr Nedvedicky /* with inbound rules (IPv6 and IPv4) */ 4011e8d569f4SAlexandr Nedvedicky /* with outbound rules (IPv6 and IPv4) */ 4012e8d569f4SAlexandr Nedvedicky /* Function also has to take care of rule groups. */ 4013e8d569f4SAlexandr Nedvedicky /* */ 4014e8d569f4SAlexandr Nedvedicky /* NOTE: The ipf_mutex is grabbed exclusively by caller (which is always */ 4015e8d569f4SAlexandr Nedvedicky /* nic_event_hook). The hook function also updates state entries, NAT rules */ 4016e8d569f4SAlexandr Nedvedicky /* and NAT entries. We want to do all these update atomically to keep the */ 4017e8d569f4SAlexandr Nedvedicky /* NIC references consistent. The ipf_mutex will synchronize event with */ 4018e8d569f4SAlexandr Nedvedicky /* fr_check(), which processes packets, so no packet will enter fr_check(), */ 4019e8d569f4SAlexandr Nedvedicky /* while NIC references will be synchronized. */ 4020e8d569f4SAlexandr Nedvedicky /* ------------------------------------------------------------------------ */ 4021e8d569f4SAlexandr Nedvedicky void fr_ifindexsync(ifp, newifp, ifs) 4022e8d569f4SAlexandr Nedvedicky void *ifp; 4023e8d569f4SAlexandr Nedvedicky void *newifp; 4024e8d569f4SAlexandr Nedvedicky ipf_stack_t *ifs; 4025e8d569f4SAlexandr Nedvedicky { 4026e8d569f4SAlexandr Nedvedicky unsigned int i; 4027e8d569f4SAlexandr Nedvedicky frentry_t *rule_lists[8]; 4028e8d569f4SAlexandr Nedvedicky unsigned int rules = sizeof (rule_lists) / sizeof (frentry_t *); 4029e8d569f4SAlexandr Nedvedicky 4030e8d569f4SAlexandr Nedvedicky rule_lists[0] = ifs->ifs_ipacct[0][ifs->ifs_fr_active]; 4031e8d569f4SAlexandr Nedvedicky rule_lists[1] = ifs->ifs_ipacct[1][ifs->ifs_fr_active]; 4032e8d569f4SAlexandr Nedvedicky rule_lists[2] = ifs->ifs_ipfilter[0][ifs->ifs_fr_active]; 4033e8d569f4SAlexandr Nedvedicky rule_lists[3] = ifs->ifs_ipfilter[1][ifs->ifs_fr_active]; 4034e8d569f4SAlexandr Nedvedicky rule_lists[4] = ifs->ifs_ipacct6[0][ifs->ifs_fr_active]; 4035e8d569f4SAlexandr Nedvedicky rule_lists[5] = ifs->ifs_ipacct6[1][ifs->ifs_fr_active]; 4036e8d569f4SAlexandr Nedvedicky rule_lists[6] = ifs->ifs_ipfilter6[0][ifs->ifs_fr_active]; 4037e8d569f4SAlexandr Nedvedicky rule_lists[7] = ifs->ifs_ipfilter6[1][ifs->ifs_fr_active]; 4038e8d569f4SAlexandr Nedvedicky 4039e8d569f4SAlexandr Nedvedicky for (i = 0; i < rules; i++) { 4040e8d569f4SAlexandr Nedvedicky fr_syncindex(rule_lists[i], ifp, newifp); 4041e8d569f4SAlexandr Nedvedicky } 4042e8d569f4SAlexandr Nedvedicky 4043e8d569f4SAlexandr Nedvedicky /* 4044e8d569f4SAlexandr Nedvedicky * Update rule groups. 4045e8d569f4SAlexandr Nedvedicky */ 4046e8d569f4SAlexandr Nedvedicky for (i = 0; i < IPL_LOGSIZE; i++) { 4047e8d569f4SAlexandr Nedvedicky frgroup_t *g; 4048e8d569f4SAlexandr Nedvedicky 4049e8d569f4SAlexandr Nedvedicky for (g = ifs->ifs_ipfgroups[i][0]; g != NULL; g = g->fg_next) 4050e8d569f4SAlexandr Nedvedicky fr_syncindex(g->fg_start, ifp, newifp); 4051e8d569f4SAlexandr Nedvedicky for (g = ifs->ifs_ipfgroups[i][1]; g != NULL; g = g->fg_next) 4052e8d569f4SAlexandr Nedvedicky fr_syncindex(g->fg_start, ifp, newifp); 4053e8d569f4SAlexandr Nedvedicky } 4054e8d569f4SAlexandr Nedvedicky } 4055e8d569f4SAlexandr Nedvedicky #endif 40567c478bd9Sstevel@tonic-gate 40577c478bd9Sstevel@tonic-gate /* 40587c478bd9Sstevel@tonic-gate * In the functions below, bcopy() is called because the pointer being 40597c478bd9Sstevel@tonic-gate * copied _from_ in this instance is a pointer to a char buf (which could 40607c478bd9Sstevel@tonic-gate * end up being unaligned) and on the kernel's local stack. 40617c478bd9Sstevel@tonic-gate */ 40627c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 40637c478bd9Sstevel@tonic-gate /* Function: copyinptr */ 40647c478bd9Sstevel@tonic-gate /* Returns: int - 0 = success, else failure */ 40657c478bd9Sstevel@tonic-gate /* Parameters: src(I) - pointer to the source address */ 40667c478bd9Sstevel@tonic-gate /* dst(I) - destination address */ 40677c478bd9Sstevel@tonic-gate /* size(I) - number of bytes to copy */ 40687c478bd9Sstevel@tonic-gate /* */ 40697c478bd9Sstevel@tonic-gate /* Copy a block of data in from user space, given a pointer to the pointer */ 40707c478bd9Sstevel@tonic-gate /* to start copying from (src) and a pointer to where to store it (dst). */ 40717c478bd9Sstevel@tonic-gate /* NB: src - pointer to user space pointer, dst - kernel space pointer */ 40727c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 40737c478bd9Sstevel@tonic-gate int copyinptr(src, dst, size) 40747c478bd9Sstevel@tonic-gate void *src, *dst; 40757c478bd9Sstevel@tonic-gate size_t size; 40767c478bd9Sstevel@tonic-gate { 40777c478bd9Sstevel@tonic-gate caddr_t ca; 40787c478bd9Sstevel@tonic-gate int err; 40797c478bd9Sstevel@tonic-gate 4080ab25eeb5Syz # if SOLARIS 4081ab25eeb5Syz err = COPYIN(src, (caddr_t)&ca, sizeof(ca)); 40827c478bd9Sstevel@tonic-gate if (err != 0) 40837c478bd9Sstevel@tonic-gate return err; 4084ab25eeb5Syz # else 40857c478bd9Sstevel@tonic-gate bcopy(src, (caddr_t)&ca, sizeof(ca)); 4086ab25eeb5Syz # endif 4087ab25eeb5Syz err = COPYIN(ca, dst, size); 40887c478bd9Sstevel@tonic-gate return err; 40897c478bd9Sstevel@tonic-gate } 40907c478bd9Sstevel@tonic-gate 40917c478bd9Sstevel@tonic-gate 40927c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 40937c478bd9Sstevel@tonic-gate /* Function: copyoutptr */ 40947c478bd9Sstevel@tonic-gate /* Returns: int - 0 = success, else failure */ 40957c478bd9Sstevel@tonic-gate /* Parameters: src(I) - pointer to the source address */ 40967c478bd9Sstevel@tonic-gate /* dst(I) - destination address */ 40977c478bd9Sstevel@tonic-gate /* size(I) - number of bytes to copy */ 40987c478bd9Sstevel@tonic-gate /* */ 40997c478bd9Sstevel@tonic-gate /* Copy a block of data out to user space, given a pointer to the pointer */ 41007c478bd9Sstevel@tonic-gate /* to start copying from (src) and a pointer to where to store it (dst). */ 41017c478bd9Sstevel@tonic-gate /* NB: src - kernel space pointer, dst - pointer to user space pointer. */ 41027c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 41037c478bd9Sstevel@tonic-gate int copyoutptr(src, dst, size) 41047c478bd9Sstevel@tonic-gate void *src, *dst; 41057c478bd9Sstevel@tonic-gate size_t size; 41067c478bd9Sstevel@tonic-gate { 41077c478bd9Sstevel@tonic-gate caddr_t ca; 41087c478bd9Sstevel@tonic-gate int err; 41097c478bd9Sstevel@tonic-gate 4110ab25eeb5Syz # if SOLARIS 4111ab25eeb5Syz err = COPYIN(dst, (caddr_t)&ca, sizeof(ca)); 41127c478bd9Sstevel@tonic-gate if (err != 0) 41137c478bd9Sstevel@tonic-gate return err; 4114ab25eeb5Syz # else 41157c478bd9Sstevel@tonic-gate bcopy(dst, (caddr_t)&ca, sizeof(ca)); 4116ab25eeb5Syz # endif 4117ab25eeb5Syz err = COPYOUT(src, ca, size); 41187c478bd9Sstevel@tonic-gate return err; 41197c478bd9Sstevel@tonic-gate } 4120ab25eeb5Syz #endif 41217c478bd9Sstevel@tonic-gate 41227c478bd9Sstevel@tonic-gate 4123ab25eeb5Syz /* ------------------------------------------------------------------------ */ 4124ab25eeb5Syz /* Function: fr_lock */ 4125bb1d9de5SJohn Ojemann /* Returns: int - 0 = success, else error */ 4126ab25eeb5Syz /* Parameters: data(I) - pointer to lock value to set */ 4127ab25eeb5Syz /* lockp(O) - pointer to location to store old lock value */ 4128ab25eeb5Syz /* */ 4129ab25eeb5Syz /* Get the new value for the lock integer, set it and return the old value */ 4130ab25eeb5Syz /* in *lockp. */ 4131ab25eeb5Syz /* ------------------------------------------------------------------------ */ 4132bb1d9de5SJohn Ojemann int fr_lock(data, lockp) 4133ab25eeb5Syz caddr_t data; 4134ab25eeb5Syz int *lockp; 41357c478bd9Sstevel@tonic-gate { 4136bb1d9de5SJohn Ojemann int arg, err; 41377c478bd9Sstevel@tonic-gate 4138bb1d9de5SJohn Ojemann err = BCOPYIN(data, (caddr_t)&arg, sizeof(arg)); 4139bb1d9de5SJohn Ojemann if (err != 0) 4140bb1d9de5SJohn Ojemann return (EFAULT); 4141bb1d9de5SJohn Ojemann err = BCOPYOUT((caddr_t)lockp, data, sizeof(*lockp)); 4142bb1d9de5SJohn Ojemann if (err != 0) 4143bb1d9de5SJohn Ojemann return (EFAULT); 4144ab25eeb5Syz *lockp = arg; 4145bb1d9de5SJohn Ojemann return (0); 41467c478bd9Sstevel@tonic-gate } 41477c478bd9Sstevel@tonic-gate 41487c478bd9Sstevel@tonic-gate 41497c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 41507c478bd9Sstevel@tonic-gate /* Function: fr_getstat */ 41517c478bd9Sstevel@tonic-gate /* Returns: Nil */ 41527c478bd9Sstevel@tonic-gate /* Parameters: fiop(I) - pointer to ipfilter stats structure */ 41537c478bd9Sstevel@tonic-gate /* */ 41547c478bd9Sstevel@tonic-gate /* Stores a copy of current pointers, counters, etc, in the friostat */ 41557c478bd9Sstevel@tonic-gate /* structure. */ 41567c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 4157f4b3ec61Sdh void fr_getstat(fiop, ifs) 41587c478bd9Sstevel@tonic-gate friostat_t *fiop; 4159f4b3ec61Sdh ipf_stack_t *ifs; 41607c478bd9Sstevel@tonic-gate { 41617c478bd9Sstevel@tonic-gate int i, j; 41627c478bd9Sstevel@tonic-gate 4163f4b3ec61Sdh bcopy((char *)&ifs->ifs_frstats, (char *)fiop->f_st, 4164f4b3ec61Sdh sizeof(filterstats_t) * 2); 4165f4b3ec61Sdh fiop->f_locks[IPL_LOGSTATE] = ifs->ifs_fr_state_lock; 4166f4b3ec61Sdh fiop->f_locks[IPL_LOGNAT] = ifs->ifs_fr_nat_lock; 4167f4b3ec61Sdh fiop->f_locks[IPL_LOGIPF] = ifs->ifs_fr_frag_lock; 4168f4b3ec61Sdh fiop->f_locks[IPL_LOGAUTH] = ifs->ifs_fr_auth_lock; 41697c478bd9Sstevel@tonic-gate 41707c478bd9Sstevel@tonic-gate for (i = 0; i < 2; i++) 41717c478bd9Sstevel@tonic-gate for (j = 0; j < 2; j++) { 4172f4b3ec61Sdh fiop->f_ipf[i][j] = ifs->ifs_ipfilter[i][j]; 4173f4b3ec61Sdh fiop->f_acct[i][j] = ifs->ifs_ipacct[i][j]; 4174f4b3ec61Sdh fiop->f_ipf6[i][j] = ifs->ifs_ipfilter6[i][j]; 4175f4b3ec61Sdh fiop->f_acct6[i][j] = ifs->ifs_ipacct6[i][j]; 41767c478bd9Sstevel@tonic-gate } 41777c478bd9Sstevel@tonic-gate 4178f4b3ec61Sdh fiop->f_ticks = ifs->ifs_fr_ticks; 4179f4b3ec61Sdh fiop->f_active = ifs->ifs_fr_active; 4180f4b3ec61Sdh fiop->f_froute[0] = ifs->ifs_fr_frouteok[0]; 4181f4b3ec61Sdh fiop->f_froute[1] = ifs->ifs_fr_frouteok[1]; 41827c478bd9Sstevel@tonic-gate 4183f4b3ec61Sdh fiop->f_running = ifs->ifs_fr_running; 41847c478bd9Sstevel@tonic-gate for (i = 0; i < IPL_LOGSIZE; i++) { 4185f4b3ec61Sdh fiop->f_groups[i][0] = ifs->ifs_ipfgroups[i][0]; 4186f4b3ec61Sdh fiop->f_groups[i][1] = ifs->ifs_ipfgroups[i][1]; 41877c478bd9Sstevel@tonic-gate } 41887c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 41897c478bd9Sstevel@tonic-gate fiop->f_logging = 1; 41907c478bd9Sstevel@tonic-gate #else 41917c478bd9Sstevel@tonic-gate fiop->f_logging = 0; 41927c478bd9Sstevel@tonic-gate #endif 4193f4b3ec61Sdh fiop->f_defpass = ifs->ifs_fr_pass; 4194ab25eeb5Syz fiop->f_features = fr_features; 4195ab25eeb5Syz (void) strncpy(fiop->f_version, ipfilter_version, 4196ab25eeb5Syz sizeof(fiop->f_version)); 41977c478bd9Sstevel@tonic-gate } 41987c478bd9Sstevel@tonic-gate 41997c478bd9Sstevel@tonic-gate 42007c478bd9Sstevel@tonic-gate #ifdef USE_INET6 42017c478bd9Sstevel@tonic-gate int icmptoicmp6types[ICMP_MAXTYPE+1] = { 42027c478bd9Sstevel@tonic-gate ICMP6_ECHO_REPLY, /* 0: ICMP_ECHOREPLY */ 42037c478bd9Sstevel@tonic-gate -1, /* 1: UNUSED */ 42047c478bd9Sstevel@tonic-gate -1, /* 2: UNUSED */ 42057c478bd9Sstevel@tonic-gate ICMP6_DST_UNREACH, /* 3: ICMP_UNREACH */ 42067c478bd9Sstevel@tonic-gate -1, /* 4: ICMP_SOURCEQUENCH */ 42077c478bd9Sstevel@tonic-gate ND_REDIRECT, /* 5: ICMP_REDIRECT */ 42087c478bd9Sstevel@tonic-gate -1, /* 6: UNUSED */ 42097c478bd9Sstevel@tonic-gate -1, /* 7: UNUSED */ 42107c478bd9Sstevel@tonic-gate ICMP6_ECHO_REQUEST, /* 8: ICMP_ECHO */ 42117c478bd9Sstevel@tonic-gate -1, /* 9: UNUSED */ 42127c478bd9Sstevel@tonic-gate -1, /* 10: UNUSED */ 42137c478bd9Sstevel@tonic-gate ICMP6_TIME_EXCEEDED, /* 11: ICMP_TIMXCEED */ 42147c478bd9Sstevel@tonic-gate ICMP6_PARAM_PROB, /* 12: ICMP_PARAMPROB */ 42157c478bd9Sstevel@tonic-gate -1, /* 13: ICMP_TSTAMP */ 42167c478bd9Sstevel@tonic-gate -1, /* 14: ICMP_TSTAMPREPLY */ 42177c478bd9Sstevel@tonic-gate -1, /* 15: ICMP_IREQ */ 42187c478bd9Sstevel@tonic-gate -1, /* 16: ICMP_IREQREPLY */ 42197c478bd9Sstevel@tonic-gate -1, /* 17: ICMP_MASKREQ */ 42207c478bd9Sstevel@tonic-gate -1, /* 18: ICMP_MASKREPLY */ 42217c478bd9Sstevel@tonic-gate }; 42227c478bd9Sstevel@tonic-gate 42237c478bd9Sstevel@tonic-gate 42247c478bd9Sstevel@tonic-gate int icmptoicmp6unreach[ICMP_MAX_UNREACH] = { 42257c478bd9Sstevel@tonic-gate ICMP6_DST_UNREACH_ADDR, /* 0: ICMP_UNREACH_NET */ 42267c478bd9Sstevel@tonic-gate ICMP6_DST_UNREACH_ADDR, /* 1: ICMP_UNREACH_HOST */ 42277c478bd9Sstevel@tonic-gate -1, /* 2: ICMP_UNREACH_PROTOCOL */ 42287c478bd9Sstevel@tonic-gate ICMP6_DST_UNREACH_NOPORT, /* 3: ICMP_UNREACH_PORT */ 42297c478bd9Sstevel@tonic-gate -1, /* 4: ICMP_UNREACH_NEEDFRAG */ 42307c478bd9Sstevel@tonic-gate ICMP6_DST_UNREACH_NOTNEIGHBOR, /* 5: ICMP_UNREACH_SRCFAIL */ 42317c478bd9Sstevel@tonic-gate ICMP6_DST_UNREACH_ADDR, /* 6: ICMP_UNREACH_NET_UNKNOWN */ 42327c478bd9Sstevel@tonic-gate ICMP6_DST_UNREACH_ADDR, /* 7: ICMP_UNREACH_HOST_UNKNOWN */ 42337c478bd9Sstevel@tonic-gate -1, /* 8: ICMP_UNREACH_ISOLATED */ 42347c478bd9Sstevel@tonic-gate ICMP6_DST_UNREACH_ADMIN, /* 9: ICMP_UNREACH_NET_PROHIB */ 42357c478bd9Sstevel@tonic-gate ICMP6_DST_UNREACH_ADMIN, /* 10: ICMP_UNREACH_HOST_PROHIB */ 42367c478bd9Sstevel@tonic-gate -1, /* 11: ICMP_UNREACH_TOSNET */ 42377c478bd9Sstevel@tonic-gate -1, /* 12: ICMP_UNREACH_TOSHOST */ 42387c478bd9Sstevel@tonic-gate ICMP6_DST_UNREACH_ADMIN, /* 13: ICMP_UNREACH_ADMIN_PROHIBIT */ 42397c478bd9Sstevel@tonic-gate }; 42407c478bd9Sstevel@tonic-gate int icmpreplytype6[ICMP6_MAXTYPE + 1]; 42417c478bd9Sstevel@tonic-gate #endif 42427c478bd9Sstevel@tonic-gate 42437c478bd9Sstevel@tonic-gate int icmpreplytype4[ICMP_MAXTYPE + 1]; 42447c478bd9Sstevel@tonic-gate 42457c478bd9Sstevel@tonic-gate 42467c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 42477c478bd9Sstevel@tonic-gate /* Function: fr_matchicmpqueryreply */ 42487c478bd9Sstevel@tonic-gate /* Returns: int - 1 if "icmp" is a valid reply to "ic" else 0. */ 42497c478bd9Sstevel@tonic-gate /* Parameters: v(I) - IP protocol version (4 or 6) */ 42507c478bd9Sstevel@tonic-gate /* ic(I) - ICMP information */ 42517c478bd9Sstevel@tonic-gate /* icmp(I) - ICMP packet header */ 42527c478bd9Sstevel@tonic-gate /* rev(I) - direction (0 = forward/1 = reverse) of packet */ 42537c478bd9Sstevel@tonic-gate /* */ 42547c478bd9Sstevel@tonic-gate /* Check if the ICMP packet defined by the header pointed to by icmp is a */ 42557c478bd9Sstevel@tonic-gate /* reply to one as described by what's in ic. If it is a match, return 1, */ 42567c478bd9Sstevel@tonic-gate /* else return 0 for no match. */ 42577c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 42587c478bd9Sstevel@tonic-gate int fr_matchicmpqueryreply(v, ic, icmp, rev) 42597c478bd9Sstevel@tonic-gate int v; 42607c478bd9Sstevel@tonic-gate icmpinfo_t *ic; 42617c478bd9Sstevel@tonic-gate icmphdr_t *icmp; 42627c478bd9Sstevel@tonic-gate int rev; 42637c478bd9Sstevel@tonic-gate { 42647c478bd9Sstevel@tonic-gate int ictype; 42657c478bd9Sstevel@tonic-gate 42667c478bd9Sstevel@tonic-gate ictype = ic->ici_type; 42677c478bd9Sstevel@tonic-gate 42687c478bd9Sstevel@tonic-gate if (v == 4) { 42697c478bd9Sstevel@tonic-gate /* 42707c478bd9Sstevel@tonic-gate * If we matched its type on the way in, then when going out 42717c478bd9Sstevel@tonic-gate * it will still be the same type. 42727c478bd9Sstevel@tonic-gate */ 42737c478bd9Sstevel@tonic-gate if ((!rev && (icmp->icmp_type == ictype)) || 42747c478bd9Sstevel@tonic-gate (rev && (icmpreplytype4[ictype] == icmp->icmp_type))) { 42757c478bd9Sstevel@tonic-gate if (icmp->icmp_type != ICMP_ECHOREPLY) 42767c478bd9Sstevel@tonic-gate return 1; 4277ab25eeb5Syz if (icmp->icmp_id == ic->ici_id) 42787c478bd9Sstevel@tonic-gate return 1; 42797c478bd9Sstevel@tonic-gate } 42807c478bd9Sstevel@tonic-gate } 42817c478bd9Sstevel@tonic-gate #ifdef USE_INET6 42827c478bd9Sstevel@tonic-gate else if (v == 6) { 42837c478bd9Sstevel@tonic-gate if ((!rev && (icmp->icmp_type == ictype)) || 42847c478bd9Sstevel@tonic-gate (rev && (icmpreplytype6[ictype] == icmp->icmp_type))) { 42857c478bd9Sstevel@tonic-gate if (icmp->icmp_type != ICMP6_ECHO_REPLY) 42867c478bd9Sstevel@tonic-gate return 1; 4287ab25eeb5Syz if (icmp->icmp_id == ic->ici_id) 42887c478bd9Sstevel@tonic-gate return 1; 42897c478bd9Sstevel@tonic-gate } 42907c478bd9Sstevel@tonic-gate } 42917c478bd9Sstevel@tonic-gate #endif 42927c478bd9Sstevel@tonic-gate return 0; 42937c478bd9Sstevel@tonic-gate } 42947c478bd9Sstevel@tonic-gate 42957c478bd9Sstevel@tonic-gate 42967c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOOKUP 42977c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 42987c478bd9Sstevel@tonic-gate /* Function: fr_resolvelookup */ 42997c478bd9Sstevel@tonic-gate /* Returns: void * - NULL = failure, else success. */ 43007c478bd9Sstevel@tonic-gate /* Parameters: type(I) - type of lookup these parameters are for. */ 43017c478bd9Sstevel@tonic-gate /* number(I) - table number to use when searching */ 43027c478bd9Sstevel@tonic-gate /* funcptr(IO) - pointer to pointer for storing IP address */ 4303de22af4eSJohn Ojemann /* searching function. */ 4304de22af4eSJohn Ojemann /* ifs - ipf stack instance */ 43057c478bd9Sstevel@tonic-gate /* */ 43067c478bd9Sstevel@tonic-gate /* Search for the "table" number passed in amongst those configured for */ 43077c478bd9Sstevel@tonic-gate /* that particular type. If the type is recognised then the function to */ 43087c478bd9Sstevel@tonic-gate /* call to do the IP address search will be change, regardless of whether */ 43097c478bd9Sstevel@tonic-gate /* or not the "table" number exists. */ 43107c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 4311f4b3ec61Sdh static void *fr_resolvelookup(type, number, funcptr, ifs) 43127c478bd9Sstevel@tonic-gate u_int type, number; 43137c478bd9Sstevel@tonic-gate lookupfunc_t *funcptr; 4314f4b3ec61Sdh ipf_stack_t *ifs; 43157c478bd9Sstevel@tonic-gate { 43167c478bd9Sstevel@tonic-gate char name[FR_GROUPLEN]; 43177c478bd9Sstevel@tonic-gate iphtable_t *iph; 43187c478bd9Sstevel@tonic-gate ip_pool_t *ipo; 43197c478bd9Sstevel@tonic-gate void *ptr; 43207c478bd9Sstevel@tonic-gate 4321ab25eeb5Syz #if defined(SNPRINTF) && defined(_KERNEL) 4322ab25eeb5Syz (void) SNPRINTF(name, sizeof(name), "%u", number); 4323ab25eeb5Syz #else 43247c478bd9Sstevel@tonic-gate (void) sprintf(name, "%u", number); 4325ab25eeb5Syz #endif 43267c478bd9Sstevel@tonic-gate 4327f4b3ec61Sdh READ_ENTER(&ifs->ifs_ip_poolrw); 43287c478bd9Sstevel@tonic-gate 43297c478bd9Sstevel@tonic-gate switch (type) 43307c478bd9Sstevel@tonic-gate { 43317c478bd9Sstevel@tonic-gate case IPLT_POOL : 43327c478bd9Sstevel@tonic-gate # if (defined(__osf__) && defined(_KERNEL)) 43337c478bd9Sstevel@tonic-gate ptr = NULL; 43347c478bd9Sstevel@tonic-gate *funcptr = NULL; 43357c478bd9Sstevel@tonic-gate # else 4336f4b3ec61Sdh ipo = ip_pool_find(IPL_LOGIPF, name, ifs); 43377c478bd9Sstevel@tonic-gate ptr = ipo; 43387c478bd9Sstevel@tonic-gate if (ipo != NULL) { 43397c478bd9Sstevel@tonic-gate ATOMIC_INC32(ipo->ipo_ref); 43407c478bd9Sstevel@tonic-gate } 43417c478bd9Sstevel@tonic-gate *funcptr = ip_pool_search; 43427c478bd9Sstevel@tonic-gate # endif 43437c478bd9Sstevel@tonic-gate break; 43447c478bd9Sstevel@tonic-gate case IPLT_HASH : 4345f4b3ec61Sdh iph = fr_findhtable(IPL_LOGIPF, name, ifs); 43467c478bd9Sstevel@tonic-gate ptr = iph; 43477c478bd9Sstevel@tonic-gate if (iph != NULL) { 43487c478bd9Sstevel@tonic-gate ATOMIC_INC32(iph->iph_ref); 43497c478bd9Sstevel@tonic-gate } 43507c478bd9Sstevel@tonic-gate *funcptr = fr_iphmfindip; 43517c478bd9Sstevel@tonic-gate break; 43527c478bd9Sstevel@tonic-gate default: 43537c478bd9Sstevel@tonic-gate ptr = NULL; 43547c478bd9Sstevel@tonic-gate *funcptr = NULL; 43557c478bd9Sstevel@tonic-gate break; 43567c478bd9Sstevel@tonic-gate } 4357f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ip_poolrw); 43587c478bd9Sstevel@tonic-gate 43597c478bd9Sstevel@tonic-gate return ptr; 43607c478bd9Sstevel@tonic-gate } 43617c478bd9Sstevel@tonic-gate #endif 43627c478bd9Sstevel@tonic-gate 43637c478bd9Sstevel@tonic-gate 43647c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 43657c478bd9Sstevel@tonic-gate /* Function: frrequest */ 43667c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, > 0 == errno value */ 43677c478bd9Sstevel@tonic-gate /* Parameters: unit(I) - device for which this is for */ 43687c478bd9Sstevel@tonic-gate /* req(I) - ioctl command (SIOC*) */ 43697c478bd9Sstevel@tonic-gate /* data(I) - pointr to ioctl data */ 43707c478bd9Sstevel@tonic-gate /* set(I) - 1 or 0 (filter set) */ 43717c478bd9Sstevel@tonic-gate /* makecopy(I) - flag indicating whether data points to a rule */ 43727c478bd9Sstevel@tonic-gate /* in kernel space & hence doesn't need copying. */ 43737c478bd9Sstevel@tonic-gate /* */ 43747c478bd9Sstevel@tonic-gate /* This function handles all the requests which operate on the list of */ 43757c478bd9Sstevel@tonic-gate /* filter rules. This includes adding, deleting, insertion. It is also */ 43767c478bd9Sstevel@tonic-gate /* responsible for creating groups when a "head" rule is loaded. Interface */ 43777c478bd9Sstevel@tonic-gate /* names are resolved here and other sanity checks are made on the content */ 43787c478bd9Sstevel@tonic-gate /* of the rule structure being loaded. If a rule has user defined timeouts */ 43797c478bd9Sstevel@tonic-gate /* then make sure they are created and initialised before exiting. */ 43807c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 4381f4b3ec61Sdh int frrequest(unit, req, data, set, makecopy, ifs) 43827c478bd9Sstevel@tonic-gate int unit; 4383ab25eeb5Syz ioctlcmd_t req; 43847c478bd9Sstevel@tonic-gate int set, makecopy; 43857c478bd9Sstevel@tonic-gate caddr_t data; 4386f4b3ec61Sdh ipf_stack_t *ifs; 43877c478bd9Sstevel@tonic-gate { 43887c478bd9Sstevel@tonic-gate frentry_t frd, *fp, *f, **fprev, **ftail; 43897c478bd9Sstevel@tonic-gate int error = 0, in, v; 4390ab25eeb5Syz void *ptr, *uptr; 43917c478bd9Sstevel@tonic-gate u_int *p, *pp; 43927c478bd9Sstevel@tonic-gate frgroup_t *fg; 43937c478bd9Sstevel@tonic-gate char *group; 43947c478bd9Sstevel@tonic-gate 43957c478bd9Sstevel@tonic-gate fg = NULL; 43967c478bd9Sstevel@tonic-gate fp = &frd; 43977c478bd9Sstevel@tonic-gate if (makecopy != 0) { 43987c478bd9Sstevel@tonic-gate error = fr_inobj(data, fp, IPFOBJ_FRENTRY); 43997c478bd9Sstevel@tonic-gate if (error) 44007c478bd9Sstevel@tonic-gate return EFAULT; 44017c478bd9Sstevel@tonic-gate if ((fp->fr_flags & FR_T_BUILTIN) != 0) 44027c478bd9Sstevel@tonic-gate return EINVAL; 44037c478bd9Sstevel@tonic-gate fp->fr_ref = 0; 44047c478bd9Sstevel@tonic-gate fp->fr_flags |= FR_COPIED; 44057c478bd9Sstevel@tonic-gate } else { 44067c478bd9Sstevel@tonic-gate fp = (frentry_t *)data; 44077c478bd9Sstevel@tonic-gate if ((fp->fr_type & FR_T_BUILTIN) == 0) 44087c478bd9Sstevel@tonic-gate return EINVAL; 44097c478bd9Sstevel@tonic-gate fp->fr_flags &= ~FR_COPIED; 44107c478bd9Sstevel@tonic-gate } 44117c478bd9Sstevel@tonic-gate 44127c478bd9Sstevel@tonic-gate if (((fp->fr_dsize == 0) && (fp->fr_data != NULL)) || 44137c478bd9Sstevel@tonic-gate ((fp->fr_dsize != 0) && (fp->fr_data == NULL))) 44147c478bd9Sstevel@tonic-gate return EINVAL; 44157c478bd9Sstevel@tonic-gate 44167c478bd9Sstevel@tonic-gate v = fp->fr_v; 4417ab25eeb5Syz uptr = fp->fr_data; 44187c478bd9Sstevel@tonic-gate 44197c478bd9Sstevel@tonic-gate /* 44207c478bd9Sstevel@tonic-gate * Only filter rules for IPv4 or IPv6 are accepted. 44217c478bd9Sstevel@tonic-gate */ 44227c478bd9Sstevel@tonic-gate if (v == 4) 44237c478bd9Sstevel@tonic-gate /*EMPTY*/; 44247c478bd9Sstevel@tonic-gate #ifdef USE_INET6 44257c478bd9Sstevel@tonic-gate else if (v == 6) 44267c478bd9Sstevel@tonic-gate /*EMPTY*/; 44277c478bd9Sstevel@tonic-gate #endif 44287c478bd9Sstevel@tonic-gate else { 44297c478bd9Sstevel@tonic-gate return EINVAL; 44307c478bd9Sstevel@tonic-gate } 44317c478bd9Sstevel@tonic-gate 44327c478bd9Sstevel@tonic-gate /* 44337c478bd9Sstevel@tonic-gate * If the rule is being loaded from user space, i.e. we had to copy it 44347c478bd9Sstevel@tonic-gate * into kernel space, then do not trust the function pointer in the 44357c478bd9Sstevel@tonic-gate * rule. 44367c478bd9Sstevel@tonic-gate */ 44377c478bd9Sstevel@tonic-gate if ((makecopy == 1) && (fp->fr_func != NULL)) { 44387c478bd9Sstevel@tonic-gate if (fr_findfunc(fp->fr_func) == NULL) 44397c478bd9Sstevel@tonic-gate return ESRCH; 4440f4b3ec61Sdh error = fr_funcinit(fp, ifs); 44417c478bd9Sstevel@tonic-gate if (error != 0) 44427c478bd9Sstevel@tonic-gate return error; 44437c478bd9Sstevel@tonic-gate } 44447c478bd9Sstevel@tonic-gate 44457c478bd9Sstevel@tonic-gate ptr = NULL; 44467c478bd9Sstevel@tonic-gate /* 44477c478bd9Sstevel@tonic-gate * Check that the group number does exist and that its use (in/out) 44487c478bd9Sstevel@tonic-gate * matches what the rule is. 44497c478bd9Sstevel@tonic-gate */ 4450ab25eeb5Syz if (!strncmp(fp->fr_grhead, "0", FR_GROUPLEN)) 4451ab25eeb5Syz *fp->fr_grhead = '\0'; 44527c478bd9Sstevel@tonic-gate group = fp->fr_group; 4453ab25eeb5Syz if (!strncmp(group, "0", FR_GROUPLEN)) 44547c478bd9Sstevel@tonic-gate *group = '\0'; 44556d512983Sdr 44566d512983Sdr if (FR_ISACCOUNT(fp->fr_flags)) 44576d512983Sdr unit = IPL_LOGCOUNT; 44586d512983Sdr 44597c478bd9Sstevel@tonic-gate if ((req != (int)SIOCZRLST) && (*group != '\0')) { 4460f4b3ec61Sdh fg = fr_findgroup(group, unit, set, NULL, ifs); 44617c478bd9Sstevel@tonic-gate if (fg == NULL) 44627c478bd9Sstevel@tonic-gate return ESRCH; 44637c478bd9Sstevel@tonic-gate if (fg->fg_flags == 0) 44647c478bd9Sstevel@tonic-gate fg->fg_flags = fp->fr_flags & FR_INOUT; 44657c478bd9Sstevel@tonic-gate else if (fg->fg_flags != (fp->fr_flags & FR_INOUT)) 44667c478bd9Sstevel@tonic-gate return ESRCH; 44677c478bd9Sstevel@tonic-gate } 44687c478bd9Sstevel@tonic-gate 44697c478bd9Sstevel@tonic-gate in = (fp->fr_flags & FR_INQUE) ? 0 : 1; 44707c478bd9Sstevel@tonic-gate 44717c478bd9Sstevel@tonic-gate /* 44727c478bd9Sstevel@tonic-gate * Work out which rule list this change is being applied to. 44737c478bd9Sstevel@tonic-gate */ 44747c478bd9Sstevel@tonic-gate ftail = NULL; 44757c478bd9Sstevel@tonic-gate fprev = NULL; 44767c478bd9Sstevel@tonic-gate if (unit == IPL_LOGAUTH) 4477f4b3ec61Sdh fprev = &ifs->ifs_ipauth; 44787c478bd9Sstevel@tonic-gate else if (v == 4) { 44797c478bd9Sstevel@tonic-gate if (FR_ISACCOUNT(fp->fr_flags)) 4480f4b3ec61Sdh fprev = &ifs->ifs_ipacct[in][set]; 44816d512983Sdr else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0) 4482f4b3ec61Sdh fprev = &ifs->ifs_ipfilter[in][set]; 44837c478bd9Sstevel@tonic-gate } else if (v == 6) { 44847c478bd9Sstevel@tonic-gate if (FR_ISACCOUNT(fp->fr_flags)) 4485f4b3ec61Sdh fprev = &ifs->ifs_ipacct6[in][set]; 44866d512983Sdr else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0) 4487f4b3ec61Sdh fprev = &ifs->ifs_ipfilter6[in][set]; 44887c478bd9Sstevel@tonic-gate } 44897c478bd9Sstevel@tonic-gate if (fprev == NULL) 44907c478bd9Sstevel@tonic-gate return ESRCH; 44917c478bd9Sstevel@tonic-gate 44927c478bd9Sstevel@tonic-gate if (*group != '\0') { 4493f4b3ec61Sdh if (!fg && !(fg = fr_findgroup(group, unit, set, NULL, ifs))) 44947c478bd9Sstevel@tonic-gate return ESRCH; 44957c478bd9Sstevel@tonic-gate fprev = &fg->fg_start; 44967c478bd9Sstevel@tonic-gate } 44977c478bd9Sstevel@tonic-gate 44987c478bd9Sstevel@tonic-gate ftail = fprev; 4499ab25eeb5Syz for (f = *ftail; (f = *ftail) != NULL; ftail = &f->fr_next) { 4500ab25eeb5Syz if (fp->fr_collect <= f->fr_collect) { 4501ab25eeb5Syz ftail = fprev; 4502ab25eeb5Syz f = NULL; 4503ab25eeb5Syz break; 4504ab25eeb5Syz } 4505ab25eeb5Syz fprev = ftail; 4506ab25eeb5Syz } 45077c478bd9Sstevel@tonic-gate 45087c478bd9Sstevel@tonic-gate /* 45097c478bd9Sstevel@tonic-gate * Copy in extra data for the rule. 45107c478bd9Sstevel@tonic-gate */ 45117c478bd9Sstevel@tonic-gate if (fp->fr_dsize != 0) { 45127c478bd9Sstevel@tonic-gate if (makecopy != 0) { 45137c478bd9Sstevel@tonic-gate KMALLOCS(ptr, void *, fp->fr_dsize); 45147c478bd9Sstevel@tonic-gate if (!ptr) 45157c478bd9Sstevel@tonic-gate return ENOMEM; 4516ab25eeb5Syz error = COPYIN(uptr, ptr, fp->fr_dsize); 45177c478bd9Sstevel@tonic-gate } else { 4518ab25eeb5Syz ptr = uptr; 45197c478bd9Sstevel@tonic-gate error = 0; 45207c478bd9Sstevel@tonic-gate } 45217c478bd9Sstevel@tonic-gate if (error != 0) { 45227c478bd9Sstevel@tonic-gate KFREES(ptr, fp->fr_dsize); 452372680cf5SDarren Reed return EFAULT; 45247c478bd9Sstevel@tonic-gate } 45257c478bd9Sstevel@tonic-gate fp->fr_data = ptr; 45267c478bd9Sstevel@tonic-gate } else 45277c478bd9Sstevel@tonic-gate fp->fr_data = NULL; 45287c478bd9Sstevel@tonic-gate 45297c478bd9Sstevel@tonic-gate /* 45307c478bd9Sstevel@tonic-gate * Perform per-rule type sanity checks of their members. 45317c478bd9Sstevel@tonic-gate */ 45327c478bd9Sstevel@tonic-gate switch (fp->fr_type & ~FR_T_BUILTIN) 45337c478bd9Sstevel@tonic-gate { 4534ab25eeb5Syz #if defined(IPFILTER_BPF) 45357c478bd9Sstevel@tonic-gate case FR_T_BPFOPC : 45367c478bd9Sstevel@tonic-gate if (fp->fr_dsize == 0) 45377c478bd9Sstevel@tonic-gate return EINVAL; 45387c478bd9Sstevel@tonic-gate if (!bpf_validate(ptr, fp->fr_dsize/sizeof(struct bpf_insn))) { 45397c478bd9Sstevel@tonic-gate if (makecopy && fp->fr_data != NULL) { 45407c478bd9Sstevel@tonic-gate KFREES(fp->fr_data, fp->fr_dsize); 45417c478bd9Sstevel@tonic-gate } 45427c478bd9Sstevel@tonic-gate return EINVAL; 45437c478bd9Sstevel@tonic-gate } 45447c478bd9Sstevel@tonic-gate break; 45457c478bd9Sstevel@tonic-gate #endif 45467c478bd9Sstevel@tonic-gate case FR_T_IPF : 454772680cf5SDarren Reed if (fp->fr_dsize != sizeof(fripf_t)) { 454872680cf5SDarren Reed if (makecopy && fp->fr_data != NULL) { 454972680cf5SDarren Reed KFREES(fp->fr_data, fp->fr_dsize); 455072680cf5SDarren Reed } 4551ab25eeb5Syz return EINVAL; 455272680cf5SDarren Reed } 4553ab25eeb5Syz 4554ab25eeb5Syz /* 4555ab25eeb5Syz * Allowing a rule with both "keep state" and "with oow" is 4556ab25eeb5Syz * pointless because adding a state entry to the table will 4557ab25eeb5Syz * fail with the out of window (oow) flag set. 4558ab25eeb5Syz */ 455972680cf5SDarren Reed if ((fp->fr_flags & FR_KEEPSTATE) && (fp->fr_flx & FI_OOW)) { 456072680cf5SDarren Reed if (makecopy && fp->fr_data != NULL) { 456172680cf5SDarren Reed KFREES(fp->fr_data, fp->fr_dsize); 456272680cf5SDarren Reed } 45637c478bd9Sstevel@tonic-gate return EINVAL; 456472680cf5SDarren Reed } 4565ab25eeb5Syz 45667c478bd9Sstevel@tonic-gate switch (fp->fr_satype) 45677c478bd9Sstevel@tonic-gate { 45687c478bd9Sstevel@tonic-gate case FRI_BROADCAST : 45697c478bd9Sstevel@tonic-gate case FRI_DYNAMIC : 45707c478bd9Sstevel@tonic-gate case FRI_NETWORK : 45717c478bd9Sstevel@tonic-gate case FRI_NETMASKED : 45727c478bd9Sstevel@tonic-gate case FRI_PEERADDR : 45737c478bd9Sstevel@tonic-gate if (fp->fr_sifpidx < 0 || fp->fr_sifpidx > 3) { 45747c478bd9Sstevel@tonic-gate if (makecopy && fp->fr_data != NULL) { 45757c478bd9Sstevel@tonic-gate KFREES(fp->fr_data, fp->fr_dsize); 45767c478bd9Sstevel@tonic-gate } 45777c478bd9Sstevel@tonic-gate return EINVAL; 45787c478bd9Sstevel@tonic-gate } 45797c478bd9Sstevel@tonic-gate break; 45807c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOOKUP 45817c478bd9Sstevel@tonic-gate case FRI_LOOKUP : 45827c478bd9Sstevel@tonic-gate fp->fr_srcptr = fr_resolvelookup(fp->fr_srctype, 45837c478bd9Sstevel@tonic-gate fp->fr_srcnum, 4584f4b3ec61Sdh &fp->fr_srcfunc, ifs); 45857c478bd9Sstevel@tonic-gate break; 45867c478bd9Sstevel@tonic-gate #endif 45877c478bd9Sstevel@tonic-gate default : 45887c478bd9Sstevel@tonic-gate break; 45897c478bd9Sstevel@tonic-gate } 45907c478bd9Sstevel@tonic-gate 45917c478bd9Sstevel@tonic-gate switch (fp->fr_datype) 45927c478bd9Sstevel@tonic-gate { 45937c478bd9Sstevel@tonic-gate case FRI_BROADCAST : 45947c478bd9Sstevel@tonic-gate case FRI_DYNAMIC : 45957c478bd9Sstevel@tonic-gate case FRI_NETWORK : 45967c478bd9Sstevel@tonic-gate case FRI_NETMASKED : 45977c478bd9Sstevel@tonic-gate case FRI_PEERADDR : 45987c478bd9Sstevel@tonic-gate if (fp->fr_difpidx < 0 || fp->fr_difpidx > 3) { 45997c478bd9Sstevel@tonic-gate if (makecopy && fp->fr_data != NULL) { 46007c478bd9Sstevel@tonic-gate KFREES(fp->fr_data, fp->fr_dsize); 46017c478bd9Sstevel@tonic-gate } 46027c478bd9Sstevel@tonic-gate return EINVAL; 46037c478bd9Sstevel@tonic-gate } 46047c478bd9Sstevel@tonic-gate break; 46057c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOOKUP 46067c478bd9Sstevel@tonic-gate case FRI_LOOKUP : 46077c478bd9Sstevel@tonic-gate fp->fr_dstptr = fr_resolvelookup(fp->fr_dsttype, 46087c478bd9Sstevel@tonic-gate fp->fr_dstnum, 4609f4b3ec61Sdh &fp->fr_dstfunc, ifs); 46107c478bd9Sstevel@tonic-gate break; 46117c478bd9Sstevel@tonic-gate #endif 46127c478bd9Sstevel@tonic-gate default : 46137c478bd9Sstevel@tonic-gate break; 46147c478bd9Sstevel@tonic-gate } 46157c478bd9Sstevel@tonic-gate break; 46167c478bd9Sstevel@tonic-gate case FR_T_NONE : 46177c478bd9Sstevel@tonic-gate break; 46187c478bd9Sstevel@tonic-gate case FR_T_CALLFUNC : 46197c478bd9Sstevel@tonic-gate break; 46207c478bd9Sstevel@tonic-gate case FR_T_COMPIPF : 46217c478bd9Sstevel@tonic-gate break; 46227c478bd9Sstevel@tonic-gate default : 46237c478bd9Sstevel@tonic-gate if (makecopy && fp->fr_data != NULL) { 46247c478bd9Sstevel@tonic-gate KFREES(fp->fr_data, fp->fr_dsize); 46257c478bd9Sstevel@tonic-gate } 46267c478bd9Sstevel@tonic-gate return EINVAL; 46277c478bd9Sstevel@tonic-gate } 46287c478bd9Sstevel@tonic-gate 46297c478bd9Sstevel@tonic-gate /* 46307c478bd9Sstevel@tonic-gate * Lookup all the interface names that are part of the rule. 46317c478bd9Sstevel@tonic-gate */ 4632f4b3ec61Sdh frsynclist(0, 0, NULL, NULL, fp, ifs); 46337c478bd9Sstevel@tonic-gate fp->fr_statecnt = 0; 46347c478bd9Sstevel@tonic-gate 46357c478bd9Sstevel@tonic-gate /* 46367c478bd9Sstevel@tonic-gate * Look for an existing matching filter rule, but don't include the 46377c478bd9Sstevel@tonic-gate * next or interface pointer in the comparison (fr_next, fr_ifa). 46387c478bd9Sstevel@tonic-gate * This elminates rules which are indentical being loaded. Checksum 46397c478bd9Sstevel@tonic-gate * the constant part of the filter rule to make comparisons quicker 46407c478bd9Sstevel@tonic-gate * (this meaning no pointers are included). 46417c478bd9Sstevel@tonic-gate */ 46427c478bd9Sstevel@tonic-gate for (fp->fr_cksum = 0, p = (u_int *)&fp->fr_func, pp = &fp->fr_cksum; 46437c478bd9Sstevel@tonic-gate p < pp; p++) 46447c478bd9Sstevel@tonic-gate fp->fr_cksum += *p; 46457c478bd9Sstevel@tonic-gate pp = (u_int *)(fp->fr_caddr + fp->fr_dsize); 46467c478bd9Sstevel@tonic-gate for (p = (u_int *)fp->fr_data; p < pp; p++) 46477c478bd9Sstevel@tonic-gate fp->fr_cksum += *p; 46487c478bd9Sstevel@tonic-gate 4649f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_mutex); 465014d3298eSAlexandr Nedvedicky bzero((char *)ifs->ifs_frcache, sizeof (ifs->ifs_frcache)); 46517c478bd9Sstevel@tonic-gate 4652ab25eeb5Syz for (; (f = *ftail) != NULL; ftail = &f->fr_next) { 4653ab25eeb5Syz if ((fp->fr_cksum != f->fr_cksum) || 4654ab25eeb5Syz (f->fr_dsize != fp->fr_dsize)) 4655ab25eeb5Syz continue; 4656ab25eeb5Syz if (bcmp((char *)&f->fr_func, (char *)&fp->fr_func, FR_CMPSIZ)) 4657ab25eeb5Syz continue; 4658ab25eeb5Syz if ((!ptr && !f->fr_data) || 4659ab25eeb5Syz (ptr && f->fr_data && 46607c478bd9Sstevel@tonic-gate !bcmp((char *)ptr, (char *)f->fr_data, f->fr_dsize))) 46617c478bd9Sstevel@tonic-gate break; 4662ab25eeb5Syz } 46637c478bd9Sstevel@tonic-gate 46647c478bd9Sstevel@tonic-gate /* 46657c478bd9Sstevel@tonic-gate * If zero'ing statistics, copy current to caller and zero. 46667c478bd9Sstevel@tonic-gate */ 4667ab25eeb5Syz if (req == (ioctlcmd_t)SIOCZRLST) { 46687c478bd9Sstevel@tonic-gate if (f == NULL) 46697c478bd9Sstevel@tonic-gate error = ESRCH; 46707c478bd9Sstevel@tonic-gate else { 4671ab25eeb5Syz /* 4672ab25eeb5Syz * Copy and reduce lock because of impending copyout. 4673ab25eeb5Syz * Well we should, but if we do then the atomicity of 4674ab25eeb5Syz * this call and the correctness of fr_hits and 4675ab25eeb5Syz * fr_bytes cannot be guaranteed. As it is, this code 4676ab25eeb5Syz * only resets them to 0 if they are successfully 4677ab25eeb5Syz * copied out into user space. 4678ab25eeb5Syz */ 4679ab25eeb5Syz bcopy((char *)f, (char *)fp, sizeof(*f)); 4680ab25eeb5Syz 4681ab25eeb5Syz /* 4682ab25eeb5Syz * When we copy this rule back out, set the data 4683ab25eeb5Syz * pointer to be what it was in user space. 4684ab25eeb5Syz */ 4685ab25eeb5Syz fp->fr_data = uptr; 4686ab25eeb5Syz error = fr_outobj(data, fp, IPFOBJ_FRENTRY); 4687ab25eeb5Syz 46887c478bd9Sstevel@tonic-gate if (error == 0) { 4689ab25eeb5Syz if ((f->fr_dsize != 0) && (uptr != NULL)) 4690ab25eeb5Syz error = COPYOUT(f->fr_data, uptr, 46917c478bd9Sstevel@tonic-gate f->fr_dsize); 46927c478bd9Sstevel@tonic-gate if (error == 0) { 46937c478bd9Sstevel@tonic-gate f->fr_hits = 0; 46947c478bd9Sstevel@tonic-gate f->fr_bytes = 0; 46957c478bd9Sstevel@tonic-gate } 46967c478bd9Sstevel@tonic-gate } 46977c478bd9Sstevel@tonic-gate } 46987c478bd9Sstevel@tonic-gate 4699ab25eeb5Syz if ((ptr != NULL) && (makecopy != 0)) { 47007c478bd9Sstevel@tonic-gate KFREES(ptr, fp->fr_dsize); 47017c478bd9Sstevel@tonic-gate } 4702f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 47037c478bd9Sstevel@tonic-gate return error; 47047c478bd9Sstevel@tonic-gate } 47057c478bd9Sstevel@tonic-gate 47067c478bd9Sstevel@tonic-gate if (!f) { 4707ab25eeb5Syz /* 4708ab25eeb5Syz * At the end of this, ftail must point to the place where the 4709ab25eeb5Syz * new rule is to be saved/inserted/added. 4710ab25eeb5Syz * For SIOCAD*FR, this should be the last rule in the group of 4711ab25eeb5Syz * rules that have equal fr_collect fields. 4712ab25eeb5Syz * For SIOCIN*FR, ... 4713ab25eeb5Syz */ 4714ab25eeb5Syz if (req == (ioctlcmd_t)SIOCADAFR || 4715ab25eeb5Syz req == (ioctlcmd_t)SIOCADIFR) { 4716ab25eeb5Syz 4717ab25eeb5Syz for (ftail = fprev; (f = *ftail) != NULL; ) { 4718ab25eeb5Syz if (f->fr_collect > fp->fr_collect) 4719ab25eeb5Syz break; 4720ab25eeb5Syz ftail = &f->fr_next; 4721ab25eeb5Syz } 4722ab25eeb5Syz f = NULL; 4723ab25eeb5Syz ptr = NULL; 4724ab25eeb5Syz error = 0; 4725ab25eeb5Syz } else if (req == (ioctlcmd_t)SIOCINAFR || 4726ab25eeb5Syz req == (ioctlcmd_t)SIOCINIFR) { 4727ab25eeb5Syz while ((f = *fprev) != NULL) { 4728ab25eeb5Syz if (f->fr_collect >= fp->fr_collect) 4729ab25eeb5Syz break; 4730ab25eeb5Syz fprev = &f->fr_next; 4731ab25eeb5Syz } 47327c478bd9Sstevel@tonic-gate ftail = fprev; 47337c478bd9Sstevel@tonic-gate if (fp->fr_hits != 0) { 4734ab25eeb5Syz while (fp->fr_hits && (f = *ftail)) { 4735ab25eeb5Syz if (f->fr_collect != fp->fr_collect) 4736ab25eeb5Syz break; 4737ab25eeb5Syz fprev = ftail; 47387c478bd9Sstevel@tonic-gate ftail = &f->fr_next; 4739ab25eeb5Syz fp->fr_hits--; 4740ab25eeb5Syz } 47417c478bd9Sstevel@tonic-gate } 47427c478bd9Sstevel@tonic-gate f = NULL; 47437c478bd9Sstevel@tonic-gate ptr = NULL; 47447c478bd9Sstevel@tonic-gate error = 0; 47457c478bd9Sstevel@tonic-gate } 47467c478bd9Sstevel@tonic-gate } 47477c478bd9Sstevel@tonic-gate 47487c478bd9Sstevel@tonic-gate /* 47497c478bd9Sstevel@tonic-gate * Request to remove a rule. 47507c478bd9Sstevel@tonic-gate */ 4751ab25eeb5Syz if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR) { 47527c478bd9Sstevel@tonic-gate if (!f) 47537c478bd9Sstevel@tonic-gate error = ESRCH; 47547c478bd9Sstevel@tonic-gate else { 47557c478bd9Sstevel@tonic-gate /* 47567c478bd9Sstevel@tonic-gate * Do not allow activity from user space to interfere 47577c478bd9Sstevel@tonic-gate * with rules not loaded that way. 47587c478bd9Sstevel@tonic-gate */ 47597c478bd9Sstevel@tonic-gate if ((makecopy == 1) && !(f->fr_flags & FR_COPIED)) { 47607c478bd9Sstevel@tonic-gate error = EPERM; 47617c478bd9Sstevel@tonic-gate goto done; 47627c478bd9Sstevel@tonic-gate } 47637c478bd9Sstevel@tonic-gate 47647c478bd9Sstevel@tonic-gate /* 47657c478bd9Sstevel@tonic-gate * Return EBUSY if the rule is being reference by 47667c478bd9Sstevel@tonic-gate * something else (eg state information. 47677c478bd9Sstevel@tonic-gate */ 47687c478bd9Sstevel@tonic-gate if (f->fr_ref > 1) { 47697c478bd9Sstevel@tonic-gate error = EBUSY; 47707c478bd9Sstevel@tonic-gate goto done; 47717c478bd9Sstevel@tonic-gate } 47727c478bd9Sstevel@tonic-gate #ifdef IPFILTER_SCAN 47737c478bd9Sstevel@tonic-gate if (f->fr_isctag[0] != '\0' && 47747c478bd9Sstevel@tonic-gate (f->fr_isc != (struct ipscan *)-1)) 4775ab25eeb5Syz ipsc_detachfr(f); 47767c478bd9Sstevel@tonic-gate #endif 47777c478bd9Sstevel@tonic-gate if (unit == IPL_LOGAUTH) { 4778f4b3ec61Sdh error = fr_preauthcmd(req, f, ftail, ifs); 47797c478bd9Sstevel@tonic-gate goto done; 47807c478bd9Sstevel@tonic-gate } 47817c478bd9Sstevel@tonic-gate if (*f->fr_grhead != '\0') 4782f4b3ec61Sdh fr_delgroup(f->fr_grhead, unit, set, ifs); 4783ab25eeb5Syz fr_fixskip(ftail, f, -1); 47847c478bd9Sstevel@tonic-gate *ftail = f->fr_next; 47857c478bd9Sstevel@tonic-gate f->fr_next = NULL; 4786f4b3ec61Sdh (void)fr_derefrule(&f, ifs); 47877c478bd9Sstevel@tonic-gate } 47887c478bd9Sstevel@tonic-gate } else { 47897c478bd9Sstevel@tonic-gate /* 47907c478bd9Sstevel@tonic-gate * Not removing, so we must be adding/inserting a rule. 47917c478bd9Sstevel@tonic-gate */ 47927c478bd9Sstevel@tonic-gate if (f) 47937c478bd9Sstevel@tonic-gate error = EEXIST; 47947c478bd9Sstevel@tonic-gate else { 47957c478bd9Sstevel@tonic-gate if (unit == IPL_LOGAUTH) { 4796f4b3ec61Sdh error = fr_preauthcmd(req, fp, ftail, ifs); 47977c478bd9Sstevel@tonic-gate goto done; 47987c478bd9Sstevel@tonic-gate } 47997c478bd9Sstevel@tonic-gate if (makecopy) { 48007c478bd9Sstevel@tonic-gate KMALLOC(f, frentry_t *); 48017c478bd9Sstevel@tonic-gate } else 48027c478bd9Sstevel@tonic-gate f = fp; 48037c478bd9Sstevel@tonic-gate if (f != NULL) { 48047c478bd9Sstevel@tonic-gate if (fp != f) 48057c478bd9Sstevel@tonic-gate bcopy((char *)fp, (char *)f, 48067c478bd9Sstevel@tonic-gate sizeof(*f)); 48077c478bd9Sstevel@tonic-gate MUTEX_NUKE(&f->fr_lock); 48087c478bd9Sstevel@tonic-gate MUTEX_INIT(&f->fr_lock, "filter rule lock"); 48097c478bd9Sstevel@tonic-gate #ifdef IPFILTER_SCAN 4810ab25eeb5Syz if (f->fr_isctag[0] != '\0' && 4811ab25eeb5Syz ipsc_attachfr(f)) 48127c478bd9Sstevel@tonic-gate f->fr_isc = (struct ipscan *)-1; 48137c478bd9Sstevel@tonic-gate #endif 48147c478bd9Sstevel@tonic-gate f->fr_hits = 0; 48157c478bd9Sstevel@tonic-gate if (makecopy != 0) 48167c478bd9Sstevel@tonic-gate f->fr_ref = 1; 48177c478bd9Sstevel@tonic-gate f->fr_next = *ftail; 48187c478bd9Sstevel@tonic-gate *ftail = f; 4819ab25eeb5Syz if (req == (ioctlcmd_t)SIOCINIFR || 4820ab25eeb5Syz req == (ioctlcmd_t)SIOCINAFR) 4821ab25eeb5Syz fr_fixskip(ftail, f, 1); 48227c478bd9Sstevel@tonic-gate f->fr_grp = NULL; 48237c478bd9Sstevel@tonic-gate group = f->fr_grhead; 48247c478bd9Sstevel@tonic-gate if (*group != '\0') { 48257c478bd9Sstevel@tonic-gate fg = fr_addgroup(group, f, f->fr_flags, 4826f4b3ec61Sdh unit, set, ifs); 48277c478bd9Sstevel@tonic-gate if (fg != NULL) 48287c478bd9Sstevel@tonic-gate f->fr_grp = &fg->fg_start; 48297c478bd9Sstevel@tonic-gate } 48307c478bd9Sstevel@tonic-gate } else 48317c478bd9Sstevel@tonic-gate error = ENOMEM; 48327c478bd9Sstevel@tonic-gate } 48337c478bd9Sstevel@tonic-gate } 48347c478bd9Sstevel@tonic-gate done: 4835f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 48367c478bd9Sstevel@tonic-gate if ((ptr != NULL) && (error != 0) && (makecopy != 0)) { 48377c478bd9Sstevel@tonic-gate KFREES(ptr, fp->fr_dsize); 48387c478bd9Sstevel@tonic-gate } 48397c478bd9Sstevel@tonic-gate return (error); 48407c478bd9Sstevel@tonic-gate } 48417c478bd9Sstevel@tonic-gate 48427c478bd9Sstevel@tonic-gate 48437c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 48447c478bd9Sstevel@tonic-gate /* Function: fr_funcinit */ 48457c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, else ESRCH: cannot resolve rule details */ 48467c478bd9Sstevel@tonic-gate /* Parameters: fr(I) - pointer to filter rule */ 48477c478bd9Sstevel@tonic-gate /* */ 48487c478bd9Sstevel@tonic-gate /* If a rule is a call rule, then check if the function it points to needs */ 48497c478bd9Sstevel@tonic-gate /* an init function to be called now the rule has been loaded. */ 48507c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 4851f4b3ec61Sdh static int fr_funcinit(fr, ifs) 48527c478bd9Sstevel@tonic-gate frentry_t *fr; 4853f4b3ec61Sdh ipf_stack_t *ifs; 48547c478bd9Sstevel@tonic-gate { 48557c478bd9Sstevel@tonic-gate ipfunc_resolve_t *ft; 48567c478bd9Sstevel@tonic-gate int err; 48577c478bd9Sstevel@tonic-gate 48587c478bd9Sstevel@tonic-gate err = ESRCH; 48597c478bd9Sstevel@tonic-gate 48607c478bd9Sstevel@tonic-gate for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++) 48617c478bd9Sstevel@tonic-gate if (ft->ipfu_addr == fr->fr_func) { 48627c478bd9Sstevel@tonic-gate err = 0; 48637c478bd9Sstevel@tonic-gate if (ft->ipfu_init != NULL) 4864f4b3ec61Sdh err = (*ft->ipfu_init)(fr, ifs); 48657c478bd9Sstevel@tonic-gate break; 48667c478bd9Sstevel@tonic-gate } 48677c478bd9Sstevel@tonic-gate return err; 48687c478bd9Sstevel@tonic-gate } 48697c478bd9Sstevel@tonic-gate 48707c478bd9Sstevel@tonic-gate 48717c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 48727c478bd9Sstevel@tonic-gate /* Function: fr_findfunc */ 48737c478bd9Sstevel@tonic-gate /* Returns: ipfunc_t - pointer to function if found, else NULL */ 48747c478bd9Sstevel@tonic-gate /* Parameters: funcptr(I) - function pointer to lookup */ 48757c478bd9Sstevel@tonic-gate /* */ 48767c478bd9Sstevel@tonic-gate /* Look for a function in the table of known functions. */ 48777c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 48787c478bd9Sstevel@tonic-gate static ipfunc_t fr_findfunc(funcptr) 48797c478bd9Sstevel@tonic-gate ipfunc_t funcptr; 48807c478bd9Sstevel@tonic-gate { 48817c478bd9Sstevel@tonic-gate ipfunc_resolve_t *ft; 48827c478bd9Sstevel@tonic-gate 48837c478bd9Sstevel@tonic-gate for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++) 48847c478bd9Sstevel@tonic-gate if (ft->ipfu_addr == funcptr) 48857c478bd9Sstevel@tonic-gate return funcptr; 48867c478bd9Sstevel@tonic-gate return NULL; 48877c478bd9Sstevel@tonic-gate } 48887c478bd9Sstevel@tonic-gate 48897c478bd9Sstevel@tonic-gate 48907c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 48917c478bd9Sstevel@tonic-gate /* Function: fr_resolvefunc */ 48927c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, else error */ 48937c478bd9Sstevel@tonic-gate /* Parameters: data(IO) - ioctl data pointer to ipfunc_resolve_t struct */ 48947c478bd9Sstevel@tonic-gate /* */ 48957c478bd9Sstevel@tonic-gate /* Copy in a ipfunc_resolve_t structure and then fill in the missing field. */ 48967c478bd9Sstevel@tonic-gate /* This will either be the function name (if the pointer is set) or the */ 4897ab25eeb5Syz /* function pointer if the name is set. When found, fill in the other one */ 4898ab25eeb5Syz /* so that the entire, complete, structure can be copied back to user space.*/ 48997c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 49007c478bd9Sstevel@tonic-gate int fr_resolvefunc(data) 49017c478bd9Sstevel@tonic-gate void *data; 49027c478bd9Sstevel@tonic-gate { 49037c478bd9Sstevel@tonic-gate ipfunc_resolve_t res, *ft; 4904bb1d9de5SJohn Ojemann int err; 49057c478bd9Sstevel@tonic-gate 4906bb1d9de5SJohn Ojemann err = BCOPYIN(data, &res, sizeof(res)); 4907bb1d9de5SJohn Ojemann if (err != 0) 4908bb1d9de5SJohn Ojemann return EFAULT; 49097c478bd9Sstevel@tonic-gate 49107c478bd9Sstevel@tonic-gate if (res.ipfu_addr == NULL && res.ipfu_name[0] != '\0') { 49117c478bd9Sstevel@tonic-gate for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++) 49127c478bd9Sstevel@tonic-gate if (strncmp(res.ipfu_name, ft->ipfu_name, 49137c478bd9Sstevel@tonic-gate sizeof(res.ipfu_name)) == 0) { 49147c478bd9Sstevel@tonic-gate res.ipfu_addr = ft->ipfu_addr; 49157c478bd9Sstevel@tonic-gate res.ipfu_init = ft->ipfu_init; 49167c478bd9Sstevel@tonic-gate if (COPYOUT(&res, data, sizeof(res)) != 0) 49177c478bd9Sstevel@tonic-gate return EFAULT; 49187c478bd9Sstevel@tonic-gate return 0; 49197c478bd9Sstevel@tonic-gate } 49207c478bd9Sstevel@tonic-gate } 49217c478bd9Sstevel@tonic-gate if (res.ipfu_addr != NULL && res.ipfu_name[0] == '\0') { 49227c478bd9Sstevel@tonic-gate for (ft = fr_availfuncs; ft->ipfu_addr != NULL; ft++) 49237c478bd9Sstevel@tonic-gate if (ft->ipfu_addr == res.ipfu_addr) { 49247c478bd9Sstevel@tonic-gate (void) strncpy(res.ipfu_name, ft->ipfu_name, 4925ab25eeb5Syz sizeof(res.ipfu_name)); 49267c478bd9Sstevel@tonic-gate res.ipfu_init = ft->ipfu_init; 49277c478bd9Sstevel@tonic-gate if (COPYOUT(&res, data, sizeof(res)) != 0) 49287c478bd9Sstevel@tonic-gate return EFAULT; 49297c478bd9Sstevel@tonic-gate return 0; 49307c478bd9Sstevel@tonic-gate } 49317c478bd9Sstevel@tonic-gate } 49327c478bd9Sstevel@tonic-gate return ESRCH; 49337c478bd9Sstevel@tonic-gate } 49347c478bd9Sstevel@tonic-gate 49357c478bd9Sstevel@tonic-gate 4936ab25eeb5Syz #if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__FreeBSD__)) || \ 4937ab25eeb5Syz (defined(__FreeBSD__) && (__FreeBSD_version < 490000)) || \ 4938ab25eeb5Syz (defined(__NetBSD__) && (__NetBSD_Version__ < 105000000)) || \ 4939ab25eeb5Syz (defined(__OpenBSD__) && (OpenBSD < 200006)) 49407c478bd9Sstevel@tonic-gate /* 49417c478bd9Sstevel@tonic-gate * From: NetBSD 49427c478bd9Sstevel@tonic-gate * ppsratecheck(): packets (or events) per second limitation. 49437c478bd9Sstevel@tonic-gate */ 49447c478bd9Sstevel@tonic-gate int 49457c478bd9Sstevel@tonic-gate ppsratecheck(lasttime, curpps, maxpps) 49467c478bd9Sstevel@tonic-gate struct timeval *lasttime; 49477c478bd9Sstevel@tonic-gate int *curpps; 49487c478bd9Sstevel@tonic-gate int maxpps; /* maximum pps allowed */ 49497c478bd9Sstevel@tonic-gate { 49507c478bd9Sstevel@tonic-gate struct timeval tv, delta; 49517c478bd9Sstevel@tonic-gate int rv; 49527c478bd9Sstevel@tonic-gate 49537c478bd9Sstevel@tonic-gate GETKTIME(&tv); 49547c478bd9Sstevel@tonic-gate 49557c478bd9Sstevel@tonic-gate delta.tv_sec = tv.tv_sec - lasttime->tv_sec; 49567c478bd9Sstevel@tonic-gate delta.tv_usec = tv.tv_usec - lasttime->tv_usec; 49577c478bd9Sstevel@tonic-gate if (delta.tv_usec < 0) { 49587c478bd9Sstevel@tonic-gate delta.tv_sec--; 49597c478bd9Sstevel@tonic-gate delta.tv_usec += 1000000; 49607c478bd9Sstevel@tonic-gate } 49617c478bd9Sstevel@tonic-gate 49627c478bd9Sstevel@tonic-gate /* 49637c478bd9Sstevel@tonic-gate * check for 0,0 is so that the message will be seen at least once. 49647c478bd9Sstevel@tonic-gate * if more than one second have passed since the last update of 49657c478bd9Sstevel@tonic-gate * lasttime, reset the counter. 49667c478bd9Sstevel@tonic-gate * 49677c478bd9Sstevel@tonic-gate * we do increment *curpps even in *curpps < maxpps case, as some may 49687c478bd9Sstevel@tonic-gate * try to use *curpps for stat purposes as well. 49697c478bd9Sstevel@tonic-gate */ 49707c478bd9Sstevel@tonic-gate if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) || 49717c478bd9Sstevel@tonic-gate delta.tv_sec >= 1) { 49727c478bd9Sstevel@tonic-gate *lasttime = tv; 49737c478bd9Sstevel@tonic-gate *curpps = 0; 49747c478bd9Sstevel@tonic-gate rv = 1; 49757c478bd9Sstevel@tonic-gate } else if (maxpps < 0) 49767c478bd9Sstevel@tonic-gate rv = 1; 49777c478bd9Sstevel@tonic-gate else if (*curpps < maxpps) 49787c478bd9Sstevel@tonic-gate rv = 1; 49797c478bd9Sstevel@tonic-gate else 49807c478bd9Sstevel@tonic-gate rv = 0; 49817c478bd9Sstevel@tonic-gate *curpps = *curpps + 1; 49827c478bd9Sstevel@tonic-gate 49837c478bd9Sstevel@tonic-gate return (rv); 49847c478bd9Sstevel@tonic-gate } 49857c478bd9Sstevel@tonic-gate #endif 49867c478bd9Sstevel@tonic-gate 49877c478bd9Sstevel@tonic-gate 49887c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 49897c478bd9Sstevel@tonic-gate /* Function: fr_derefrule */ 49907c478bd9Sstevel@tonic-gate /* Returns: int - 0 == rule freed up, else rule not freed */ 49917c478bd9Sstevel@tonic-gate /* Parameters: fr(I) - pointer to filter rule */ 49927c478bd9Sstevel@tonic-gate /* */ 49937c478bd9Sstevel@tonic-gate /* Decrement the reference counter to a rule by one. If it reaches zero, */ 49947c478bd9Sstevel@tonic-gate /* free it and any associated storage space being used by it. */ 49957c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 4996f4b3ec61Sdh int fr_derefrule(frp, ifs) 49977c478bd9Sstevel@tonic-gate frentry_t **frp; 4998f4b3ec61Sdh ipf_stack_t *ifs; 49997c478bd9Sstevel@tonic-gate { 50007c478bd9Sstevel@tonic-gate frentry_t *fr; 50017c478bd9Sstevel@tonic-gate 50027c478bd9Sstevel@tonic-gate fr = *frp; 50037c478bd9Sstevel@tonic-gate 50047c478bd9Sstevel@tonic-gate MUTEX_ENTER(&fr->fr_lock); 50057c478bd9Sstevel@tonic-gate fr->fr_ref--; 50067c478bd9Sstevel@tonic-gate if (fr->fr_ref == 0) { 50077c478bd9Sstevel@tonic-gate MUTEX_EXIT(&fr->fr_lock); 50087c478bd9Sstevel@tonic-gate MUTEX_DESTROY(&fr->fr_lock); 50097c478bd9Sstevel@tonic-gate 50107c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOOKUP 50117c478bd9Sstevel@tonic-gate if (fr->fr_type == FR_T_IPF && fr->fr_satype == FRI_LOOKUP) 5012f4b3ec61Sdh ip_lookup_deref(fr->fr_srctype, fr->fr_srcptr, ifs); 50137c478bd9Sstevel@tonic-gate if (fr->fr_type == FR_T_IPF && fr->fr_datype == FRI_LOOKUP) 5014f4b3ec61Sdh ip_lookup_deref(fr->fr_dsttype, fr->fr_dstptr, ifs); 50157c478bd9Sstevel@tonic-gate #endif 50167c478bd9Sstevel@tonic-gate 50177c478bd9Sstevel@tonic-gate if (fr->fr_dsize) { 50187c478bd9Sstevel@tonic-gate KFREES(fr->fr_data, fr->fr_dsize); 50197c478bd9Sstevel@tonic-gate } 50207c478bd9Sstevel@tonic-gate if ((fr->fr_flags & FR_COPIED) != 0) { 50217c478bd9Sstevel@tonic-gate KFREE(fr); 50227c478bd9Sstevel@tonic-gate return 0; 50237c478bd9Sstevel@tonic-gate } 50247c478bd9Sstevel@tonic-gate return 1; 50257c478bd9Sstevel@tonic-gate } else { 50267c478bd9Sstevel@tonic-gate MUTEX_EXIT(&fr->fr_lock); 50277c478bd9Sstevel@tonic-gate } 50287c478bd9Sstevel@tonic-gate *frp = NULL; 50297c478bd9Sstevel@tonic-gate return -1; 50307c478bd9Sstevel@tonic-gate } 50317c478bd9Sstevel@tonic-gate 50327c478bd9Sstevel@tonic-gate 50337c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOOKUP 50347c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 50357c478bd9Sstevel@tonic-gate /* Function: fr_grpmapinit */ 50367c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, else ESRCH because table entry not found*/ 50377c478bd9Sstevel@tonic-gate /* Parameters: fr(I) - pointer to rule to find hash table for */ 50387c478bd9Sstevel@tonic-gate /* */ 50397c478bd9Sstevel@tonic-gate /* Looks for group hash table fr_arg and stores a pointer to it in fr_ptr. */ 50407c478bd9Sstevel@tonic-gate /* fr_ptr is later used by fr_srcgrpmap and fr_dstgrpmap. */ 50417c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 5042f4b3ec61Sdh static int fr_grpmapinit(fr, ifs) 50437c478bd9Sstevel@tonic-gate frentry_t *fr; 5044f4b3ec61Sdh ipf_stack_t *ifs; 50457c478bd9Sstevel@tonic-gate { 50467c478bd9Sstevel@tonic-gate char name[FR_GROUPLEN]; 50477c478bd9Sstevel@tonic-gate iphtable_t *iph; 50487c478bd9Sstevel@tonic-gate 5049ab25eeb5Syz #if defined(SNPRINTF) && defined(_KERNEL) 5050ab25eeb5Syz (void) SNPRINTF(name, sizeof(name), "%d", fr->fr_arg); 5051ab25eeb5Syz #else 50527c478bd9Sstevel@tonic-gate (void) sprintf(name, "%d", fr->fr_arg); 5053ab25eeb5Syz #endif 5054f4b3ec61Sdh iph = fr_findhtable(IPL_LOGIPF, name, ifs); 50557c478bd9Sstevel@tonic-gate if (iph == NULL) 50567c478bd9Sstevel@tonic-gate return ESRCH; 50577c478bd9Sstevel@tonic-gate if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT)) 50587c478bd9Sstevel@tonic-gate return ESRCH; 50597c478bd9Sstevel@tonic-gate fr->fr_ptr = iph; 50607c478bd9Sstevel@tonic-gate return 0; 50617c478bd9Sstevel@tonic-gate } 50627c478bd9Sstevel@tonic-gate 50637c478bd9Sstevel@tonic-gate 50647c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 50657c478bd9Sstevel@tonic-gate /* Function: fr_srcgrpmap */ 50667c478bd9Sstevel@tonic-gate /* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ 50677c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 50687c478bd9Sstevel@tonic-gate /* passp(IO) - pointer to current/new filter decision (unused) */ 50697c478bd9Sstevel@tonic-gate /* */ 50707c478bd9Sstevel@tonic-gate /* Look for a rule group head in a hash table, using the source address as */ 50717c478bd9Sstevel@tonic-gate /* the key, and descend into that group and continue matching rules against */ 50727c478bd9Sstevel@tonic-gate /* the packet. */ 50737c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 50747c478bd9Sstevel@tonic-gate frentry_t *fr_srcgrpmap(fin, passp) 50757c478bd9Sstevel@tonic-gate fr_info_t *fin; 50767c478bd9Sstevel@tonic-gate u_32_t *passp; 50777c478bd9Sstevel@tonic-gate { 50787c478bd9Sstevel@tonic-gate frgroup_t *fg; 50797c478bd9Sstevel@tonic-gate void *rval; 5080f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 50817c478bd9Sstevel@tonic-gate 5082f4b3ec61Sdh rval = fr_iphmfindgroup(fin->fin_fr->fr_ptr, fin->fin_v, &fin->fin_src, ifs); 50837c478bd9Sstevel@tonic-gate if (rval == NULL) 50847c478bd9Sstevel@tonic-gate return NULL; 50857c478bd9Sstevel@tonic-gate 50867c478bd9Sstevel@tonic-gate fg = rval; 50877c478bd9Sstevel@tonic-gate fin->fin_fr = fg->fg_start; 5088ab25eeb5Syz (void) fr_scanlist(fin, *passp); 50897c478bd9Sstevel@tonic-gate return fin->fin_fr; 50907c478bd9Sstevel@tonic-gate } 50917c478bd9Sstevel@tonic-gate 50927c478bd9Sstevel@tonic-gate 50937c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 50947c478bd9Sstevel@tonic-gate /* Function: fr_dstgrpmap */ 50957c478bd9Sstevel@tonic-gate /* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ 50967c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 50977c478bd9Sstevel@tonic-gate /* passp(IO) - pointer to current/new filter decision (unused) */ 50987c478bd9Sstevel@tonic-gate /* */ 50997c478bd9Sstevel@tonic-gate /* Look for a rule group head in a hash table, using the destination */ 51007c478bd9Sstevel@tonic-gate /* address as the key, and descend into that group and continue matching */ 51017c478bd9Sstevel@tonic-gate /* rules against the packet. */ 51027c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 51037c478bd9Sstevel@tonic-gate frentry_t *fr_dstgrpmap(fin, passp) 51047c478bd9Sstevel@tonic-gate fr_info_t *fin; 51057c478bd9Sstevel@tonic-gate u_32_t *passp; 51067c478bd9Sstevel@tonic-gate { 51077c478bd9Sstevel@tonic-gate frgroup_t *fg; 51087c478bd9Sstevel@tonic-gate void *rval; 5109f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 51107c478bd9Sstevel@tonic-gate 5111f4b3ec61Sdh rval = fr_iphmfindgroup(fin->fin_fr->fr_ptr, fin->fin_v, &fin->fin_dst, ifs); 51127c478bd9Sstevel@tonic-gate if (rval == NULL) 51137c478bd9Sstevel@tonic-gate return NULL; 51147c478bd9Sstevel@tonic-gate 51157c478bd9Sstevel@tonic-gate fg = rval; 51167c478bd9Sstevel@tonic-gate fin->fin_fr = fg->fg_start; 5117ab25eeb5Syz (void) fr_scanlist(fin, *passp); 51187c478bd9Sstevel@tonic-gate return fin->fin_fr; 51197c478bd9Sstevel@tonic-gate } 51207c478bd9Sstevel@tonic-gate #endif /* IPFILTER_LOOKUP */ 51217c478bd9Sstevel@tonic-gate 5122ab25eeb5Syz /* 5123ab25eeb5Syz * Queue functions 5124ab25eeb5Syz * =============== 5125ab25eeb5Syz * These functions manage objects on queues for efficient timeouts. There are 5126ab25eeb5Syz * a number of system defined queues as well as user defined timeouts. It is 5127ab25eeb5Syz * expected that a lock is held in the domain in which the queue belongs 5128ab25eeb5Syz * (i.e. either state or NAT) when calling any of these functions that prevents 5129ab25eeb5Syz * fr_freetimeoutqueue() from being called at the same time as any other. 5130ab25eeb5Syz */ 5131ab25eeb5Syz 51327c478bd9Sstevel@tonic-gate 51337c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 51347c478bd9Sstevel@tonic-gate /* Function: fr_addtimeoutqueue */ 51357c478bd9Sstevel@tonic-gate /* Returns: struct ifqtq * - NULL if malloc fails, else pointer to */ 51367c478bd9Sstevel@tonic-gate /* timeout queue with given interval. */ 51377c478bd9Sstevel@tonic-gate /* Parameters: parent(I) - pointer to pointer to parent node of this list */ 51387c478bd9Sstevel@tonic-gate /* of interface queues. */ 51397c478bd9Sstevel@tonic-gate /* seconds(I) - timeout value in seconds for this queue. */ 51407c478bd9Sstevel@tonic-gate /* */ 51417c478bd9Sstevel@tonic-gate /* This routine first looks for a timeout queue that matches the interval */ 51427c478bd9Sstevel@tonic-gate /* being requested. If it finds one, increments the reference counter and */ 51437c478bd9Sstevel@tonic-gate /* returns a pointer to it. If none are found, it allocates a new one and */ 51447c478bd9Sstevel@tonic-gate /* inserts it at the top of the list. */ 5145ab25eeb5Syz /* */ 5146ab25eeb5Syz /* Locking. */ 5147ab25eeb5Syz /* It is assumed that the caller of this function has an appropriate lock */ 5148ab25eeb5Syz /* held (exclusively) in the domain that encompases 'parent'. */ 51497c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 5150f4b3ec61Sdh ipftq_t *fr_addtimeoutqueue(parent, seconds, ifs) 51517c478bd9Sstevel@tonic-gate ipftq_t **parent; 51527c478bd9Sstevel@tonic-gate u_int seconds; 5153f4b3ec61Sdh ipf_stack_t *ifs; 51547c478bd9Sstevel@tonic-gate { 51557c478bd9Sstevel@tonic-gate ipftq_t *ifq; 5156ab25eeb5Syz u_int period; 51577c478bd9Sstevel@tonic-gate 51587c478bd9Sstevel@tonic-gate period = seconds * IPF_HZ_DIVIDE; 5159ab25eeb5Syz 5160f4b3ec61Sdh MUTEX_ENTER(&ifs->ifs_ipf_timeoutlock); 5161ab25eeb5Syz for (ifq = *parent; ifq != NULL; ifq = ifq->ifq_next) { 5162ab25eeb5Syz if (ifq->ifq_ttl == period) { 5163ab25eeb5Syz /* 5164ab25eeb5Syz * Reset the delete flag, if set, so the structure 5165ab25eeb5Syz * gets reused rather than freed and reallocated. 5166ab25eeb5Syz */ 5167ab25eeb5Syz MUTEX_ENTER(&ifq->ifq_lock); 5168ab25eeb5Syz ifq->ifq_flags &= ~IFQF_DELETE; 5169ab25eeb5Syz ifq->ifq_ref++; 5170ab25eeb5Syz MUTEX_EXIT(&ifq->ifq_lock); 5171f4b3ec61Sdh MUTEX_EXIT(&ifs->ifs_ipf_timeoutlock); 51727c478bd9Sstevel@tonic-gate 5173ab25eeb5Syz return ifq; 5174ab25eeb5Syz } 51757c478bd9Sstevel@tonic-gate } 51767c478bd9Sstevel@tonic-gate 51777c478bd9Sstevel@tonic-gate KMALLOC(ifq, ipftq_t *); 51787c478bd9Sstevel@tonic-gate if (ifq != NULL) { 51797c478bd9Sstevel@tonic-gate ifq->ifq_ttl = period; 51807c478bd9Sstevel@tonic-gate ifq->ifq_head = NULL; 51817c478bd9Sstevel@tonic-gate ifq->ifq_tail = &ifq->ifq_head; 51827c478bd9Sstevel@tonic-gate ifq->ifq_next = *parent; 51837c478bd9Sstevel@tonic-gate ifq->ifq_pnext = parent; 51847c478bd9Sstevel@tonic-gate ifq->ifq_ref = 1; 51857c478bd9Sstevel@tonic-gate ifq->ifq_flags = IFQF_USER; 51867c478bd9Sstevel@tonic-gate *parent = ifq; 5187f4b3ec61Sdh ifs->ifs_fr_userifqs++; 51887c478bd9Sstevel@tonic-gate MUTEX_NUKE(&ifq->ifq_lock); 51897c478bd9Sstevel@tonic-gate MUTEX_INIT(&ifq->ifq_lock, "ipftq mutex"); 51907c478bd9Sstevel@tonic-gate } 5191f4b3ec61Sdh MUTEX_EXIT(&ifs->ifs_ipf_timeoutlock); 51927c478bd9Sstevel@tonic-gate return ifq; 51937c478bd9Sstevel@tonic-gate } 51947c478bd9Sstevel@tonic-gate 51957c478bd9Sstevel@tonic-gate 51967c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 51977c478bd9Sstevel@tonic-gate /* Function: fr_deletetimeoutqueue */ 5198ab25eeb5Syz /* Returns: int - new reference count value of the timeout queue */ 5199ab25eeb5Syz /* Parameters: ifq(I) - timeout queue which is losing a reference. */ 5200ab25eeb5Syz /* Locks: ifq->ifq_lock */ 52017c478bd9Sstevel@tonic-gate /* */ 52027c478bd9Sstevel@tonic-gate /* This routine must be called when we're discarding a pointer to a timeout */ 5203ab25eeb5Syz /* queue object, taking care of the reference counter. */ 5204ab25eeb5Syz /* */ 5205ab25eeb5Syz /* Now that this just sets a DELETE flag, it requires the expire code to */ 5206ab25eeb5Syz /* check the list of user defined timeout queues and call the free function */ 5207ab25eeb5Syz /* below (currently commented out) to stop memory leaking. It is done this */ 5208ab25eeb5Syz /* way because the locking may not be sufficient to safely do a free when */ 5209ab25eeb5Syz /* this function is called. */ 52107c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 5211ab25eeb5Syz int fr_deletetimeoutqueue(ifq) 52127c478bd9Sstevel@tonic-gate ipftq_t *ifq; 52137c478bd9Sstevel@tonic-gate { 52147c478bd9Sstevel@tonic-gate 52157c478bd9Sstevel@tonic-gate ifq->ifq_ref--; 5216ab25eeb5Syz if ((ifq->ifq_ref == 0) && ((ifq->ifq_flags & IFQF_USER) != 0)) { 5217ab25eeb5Syz ifq->ifq_flags |= IFQF_DELETE; 5218ab25eeb5Syz } 52197c478bd9Sstevel@tonic-gate 5220ab25eeb5Syz return ifq->ifq_ref; 5221ab25eeb5Syz } 5222ab25eeb5Syz 5223ab25eeb5Syz 5224ab25eeb5Syz /* ------------------------------------------------------------------------ */ 5225ab25eeb5Syz /* Function: fr_freetimeoutqueue */ 5226ab25eeb5Syz /* Parameters: ifq(I) - timeout queue which is losing a reference. */ 5227ab25eeb5Syz /* Returns: Nil */ 5228ab25eeb5Syz /* */ 5229ab25eeb5Syz /* Locking: */ 5230ab25eeb5Syz /* It is assumed that the caller of this function has an appropriate lock */ 5231ab25eeb5Syz /* held (exclusively) in the domain that encompases the callers "domain". */ 5232ab25eeb5Syz /* The ifq_lock for this structure should not be held. */ 5233ab25eeb5Syz /* */ 5234ab25eeb5Syz /* Remove a user definde timeout queue from the list of queues it is in and */ 5235ab25eeb5Syz /* tidy up after this is done. */ 5236ab25eeb5Syz /* ------------------------------------------------------------------------ */ 5237f4b3ec61Sdh void fr_freetimeoutqueue(ifq, ifs) 5238ab25eeb5Syz ipftq_t *ifq; 5239f4b3ec61Sdh ipf_stack_t *ifs; 5240ab25eeb5Syz { 5241ab25eeb5Syz 5242ab25eeb5Syz 5243ab25eeb5Syz if (((ifq->ifq_flags & IFQF_DELETE) == 0) || (ifq->ifq_ref != 0) || 5244ab25eeb5Syz ((ifq->ifq_flags & IFQF_USER) == 0)) { 5245ab25eeb5Syz printf("fr_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n", 5246ab25eeb5Syz (u_long)ifq, ifq->ifq_flags, ifq->ifq_ttl, 5247ab25eeb5Syz ifq->ifq_ref); 5248ab25eeb5Syz return; 52497c478bd9Sstevel@tonic-gate } 5250ab25eeb5Syz 5251ab25eeb5Syz /* 5252ab25eeb5Syz * Remove from its position in the list. 5253ab25eeb5Syz */ 5254ab25eeb5Syz *ifq->ifq_pnext = ifq->ifq_next; 5255ab25eeb5Syz if (ifq->ifq_next != NULL) 5256ab25eeb5Syz ifq->ifq_next->ifq_pnext = ifq->ifq_pnext; 5257ab25eeb5Syz 5258ab25eeb5Syz MUTEX_DESTROY(&ifq->ifq_lock); 5259f4b3ec61Sdh ifs->ifs_fr_userifqs--; 5260ab25eeb5Syz KFREE(ifq); 5261ab25eeb5Syz } 5262ab25eeb5Syz 5263ab25eeb5Syz 5264ab25eeb5Syz /* ------------------------------------------------------------------------ */ 5265ab25eeb5Syz /* Function: fr_deletequeueentry */ 5266ab25eeb5Syz /* Returns: Nil */ 5267ab25eeb5Syz /* Parameters: tqe(I) - timeout queue entry to delete */ 5268ab25eeb5Syz /* ifq(I) - timeout queue to remove entry from */ 5269ab25eeb5Syz /* */ 5270ab25eeb5Syz /* Remove a tail queue entry from its queue and make it an orphan. */ 5271ab25eeb5Syz /* fr_deletetimeoutqueue is called to make sure the reference count on the */ 5272ab25eeb5Syz /* queue is correct. We can't, however, call fr_freetimeoutqueue because */ 5273ab25eeb5Syz /* the correct lock(s) may not be held that would make it safe to do so. */ 5274ab25eeb5Syz /* ------------------------------------------------------------------------ */ 5275ab25eeb5Syz void fr_deletequeueentry(tqe) 5276ab25eeb5Syz ipftqent_t *tqe; 5277ab25eeb5Syz { 5278ab25eeb5Syz ipftq_t *ifq; 5279ab25eeb5Syz 5280ab25eeb5Syz ifq = tqe->tqe_ifq; 5281ab25eeb5Syz if (ifq == NULL) 5282ab25eeb5Syz return; 5283ab25eeb5Syz 5284ab25eeb5Syz MUTEX_ENTER(&ifq->ifq_lock); 5285ab25eeb5Syz 5286ab25eeb5Syz if (tqe->tqe_pnext != NULL) { 5287ab25eeb5Syz *tqe->tqe_pnext = tqe->tqe_next; 5288ab25eeb5Syz if (tqe->tqe_next != NULL) 5289ab25eeb5Syz tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5290ab25eeb5Syz else /* we must be the tail anyway */ 5291ab25eeb5Syz ifq->ifq_tail = tqe->tqe_pnext; 5292ab25eeb5Syz 5293ab25eeb5Syz tqe->tqe_pnext = NULL; 5294ab25eeb5Syz tqe->tqe_ifq = NULL; 5295ab25eeb5Syz } 5296ab25eeb5Syz 5297ab25eeb5Syz (void) fr_deletetimeoutqueue(ifq); 5298ab25eeb5Syz 5299ab25eeb5Syz MUTEX_EXIT(&ifq->ifq_lock); 53007c478bd9Sstevel@tonic-gate } 53017c478bd9Sstevel@tonic-gate 53027c478bd9Sstevel@tonic-gate 53037c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 53047c478bd9Sstevel@tonic-gate /* Function: fr_queuefront */ 53057c478bd9Sstevel@tonic-gate /* Returns: Nil */ 5306ab25eeb5Syz /* Parameters: tqe(I) - pointer to timeout queue entry */ 53077c478bd9Sstevel@tonic-gate /* */ 53087c478bd9Sstevel@tonic-gate /* Move a queue entry to the front of the queue, if it isn't already there. */ 53097c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 53107c478bd9Sstevel@tonic-gate void fr_queuefront(tqe) 53117c478bd9Sstevel@tonic-gate ipftqent_t *tqe; 53127c478bd9Sstevel@tonic-gate { 53137c478bd9Sstevel@tonic-gate ipftq_t *ifq; 53147c478bd9Sstevel@tonic-gate 53157c478bd9Sstevel@tonic-gate ifq = tqe->tqe_ifq; 5316ab25eeb5Syz if (ifq == NULL) 5317ab25eeb5Syz return; 53187c478bd9Sstevel@tonic-gate 5319ab25eeb5Syz MUTEX_ENTER(&ifq->ifq_lock); 53207c478bd9Sstevel@tonic-gate if (ifq->ifq_head != tqe) { 53217c478bd9Sstevel@tonic-gate *tqe->tqe_pnext = tqe->tqe_next; 53227c478bd9Sstevel@tonic-gate if (tqe->tqe_next) 53237c478bd9Sstevel@tonic-gate tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 53247c478bd9Sstevel@tonic-gate else 53257c478bd9Sstevel@tonic-gate ifq->ifq_tail = tqe->tqe_pnext; 53267c478bd9Sstevel@tonic-gate 53277c478bd9Sstevel@tonic-gate tqe->tqe_next = ifq->ifq_head; 53287c478bd9Sstevel@tonic-gate ifq->ifq_head->tqe_pnext = &tqe->tqe_next; 53297c478bd9Sstevel@tonic-gate ifq->ifq_head = tqe; 53307c478bd9Sstevel@tonic-gate tqe->tqe_pnext = &ifq->ifq_head; 53317c478bd9Sstevel@tonic-gate } 5332ab25eeb5Syz MUTEX_EXIT(&ifq->ifq_lock); 53337c478bd9Sstevel@tonic-gate } 53347c478bd9Sstevel@tonic-gate 53357c478bd9Sstevel@tonic-gate 53367c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 53377c478bd9Sstevel@tonic-gate /* Function: fr_queueback */ 53387c478bd9Sstevel@tonic-gate /* Returns: Nil */ 5339ab25eeb5Syz /* Parameters: tqe(I) - pointer to timeout queue entry */ 53407c478bd9Sstevel@tonic-gate /* */ 53417c478bd9Sstevel@tonic-gate /* Move a queue entry to the back of the queue, if it isn't already there. */ 53427c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 5343f4b3ec61Sdh void fr_queueback(tqe, ifs) 53447c478bd9Sstevel@tonic-gate ipftqent_t *tqe; 5345f4b3ec61Sdh ipf_stack_t *ifs; 53467c478bd9Sstevel@tonic-gate { 53477c478bd9Sstevel@tonic-gate ipftq_t *ifq; 53487c478bd9Sstevel@tonic-gate 53497c478bd9Sstevel@tonic-gate ifq = tqe->tqe_ifq; 53507663b816Sml if (ifq == NULL) 53517663b816Sml return; 5352f4b3ec61Sdh tqe->tqe_die = ifs->ifs_fr_ticks + ifq->ifq_ttl; 53537c478bd9Sstevel@tonic-gate 5354ab25eeb5Syz MUTEX_ENTER(&ifq->ifq_lock); 5355ab25eeb5Syz if (tqe->tqe_next == NULL) { /* at the end already ? */ 53567c478bd9Sstevel@tonic-gate MUTEX_EXIT(&ifq->ifq_lock); 5357ab25eeb5Syz return; 53587c478bd9Sstevel@tonic-gate } 5359ab25eeb5Syz 5360ab25eeb5Syz /* 5361ab25eeb5Syz * Remove from list 5362ab25eeb5Syz */ 5363ab25eeb5Syz *tqe->tqe_pnext = tqe->tqe_next; 5364ab25eeb5Syz tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5365ab25eeb5Syz 5366ab25eeb5Syz /* 5367ab25eeb5Syz * Make it the last entry. 5368ab25eeb5Syz */ 5369ab25eeb5Syz tqe->tqe_next = NULL; 5370ab25eeb5Syz tqe->tqe_pnext = ifq->ifq_tail; 5371ab25eeb5Syz *ifq->ifq_tail = tqe; 5372ab25eeb5Syz ifq->ifq_tail = &tqe->tqe_next; 5373ab25eeb5Syz MUTEX_EXIT(&ifq->ifq_lock); 5374ab25eeb5Syz } 5375ab25eeb5Syz 5376ab25eeb5Syz 5377ab25eeb5Syz /* ------------------------------------------------------------------------ */ 5378ab25eeb5Syz /* Function: fr_queueappend */ 5379ab25eeb5Syz /* Returns: Nil */ 5380ab25eeb5Syz /* Parameters: tqe(I) - pointer to timeout queue entry */ 5381ab25eeb5Syz /* ifq(I) - pointer to timeout queue */ 5382ab25eeb5Syz /* parent(I) - owing object pointer */ 5383ab25eeb5Syz /* */ 5384ab25eeb5Syz /* Add a new item to this queue and put it on the very end. */ 5385ab25eeb5Syz /* ------------------------------------------------------------------------ */ 5386f4b3ec61Sdh void fr_queueappend(tqe, ifq, parent, ifs) 5387ab25eeb5Syz ipftqent_t *tqe; 5388ab25eeb5Syz ipftq_t *ifq; 5389ab25eeb5Syz void *parent; 5390f4b3ec61Sdh ipf_stack_t *ifs; 5391ab25eeb5Syz { 5392ab25eeb5Syz 5393ab25eeb5Syz MUTEX_ENTER(&ifq->ifq_lock); 5394ab25eeb5Syz tqe->tqe_parent = parent; 5395ab25eeb5Syz tqe->tqe_pnext = ifq->ifq_tail; 5396ab25eeb5Syz *ifq->ifq_tail = tqe; 5397ab25eeb5Syz ifq->ifq_tail = &tqe->tqe_next; 5398ab25eeb5Syz tqe->tqe_next = NULL; 5399ab25eeb5Syz tqe->tqe_ifq = ifq; 5400f4b3ec61Sdh tqe->tqe_die = ifs->ifs_fr_ticks + ifq->ifq_ttl; 5401ab25eeb5Syz ifq->ifq_ref++; 5402ab25eeb5Syz MUTEX_EXIT(&ifq->ifq_lock); 54037c478bd9Sstevel@tonic-gate } 54047c478bd9Sstevel@tonic-gate 54057c478bd9Sstevel@tonic-gate 54067c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 54077c478bd9Sstevel@tonic-gate /* Function: fr_movequeue */ 54087c478bd9Sstevel@tonic-gate /* Returns: Nil */ 54097c478bd9Sstevel@tonic-gate /* Parameters: tq(I) - pointer to timeout queue information */ 54107c478bd9Sstevel@tonic-gate /* oifp(I) - old timeout queue entry was on */ 54117c478bd9Sstevel@tonic-gate /* nifp(I) - new timeout queue to put entry on */ 5412dc0749f3SJohn Ojemann /* ifs - ipf stack instance */ 54137c478bd9Sstevel@tonic-gate /* */ 54147c478bd9Sstevel@tonic-gate /* Move a queue entry from one timeout queue to another timeout queue. */ 54157c478bd9Sstevel@tonic-gate /* If it notices that the current entry is already last and does not need */ 54167c478bd9Sstevel@tonic-gate /* to move queue, the return. */ 54177c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 5418f4b3ec61Sdh void fr_movequeue(tqe, oifq, nifq, ifs) 54197c478bd9Sstevel@tonic-gate ipftqent_t *tqe; 54207c478bd9Sstevel@tonic-gate ipftq_t *oifq, *nifq; 5421f4b3ec61Sdh ipf_stack_t *ifs; 54227c478bd9Sstevel@tonic-gate { 54237c478bd9Sstevel@tonic-gate /* 5424dc0749f3SJohn Ojemann * If the queue isn't changing, and the clock hasn't ticked 5425dc0749f3SJohn Ojemann * since the last update, the operation will be a no-op. 54267c478bd9Sstevel@tonic-gate */ 5427dc0749f3SJohn Ojemann if (oifq == nifq && tqe->tqe_touched == ifs->ifs_fr_ticks) 5428dc0749f3SJohn Ojemann return; 5429dc0749f3SJohn Ojemann 5430dc0749f3SJohn Ojemann /* 5431dc0749f3SJohn Ojemann * Grab the lock and update the timers. 5432dc0749f3SJohn Ojemann */ 5433dc0749f3SJohn Ojemann MUTEX_ENTER(&oifq->ifq_lock); 5434dc0749f3SJohn Ojemann tqe->tqe_touched = ifs->ifs_fr_ticks; 5435cbded9aeSdr tqe->tqe_die = ifs->ifs_fr_ticks + nifq->ifq_ttl; 5436dc0749f3SJohn Ojemann 5437dc0749f3SJohn Ojemann /* 5438dc0749f3SJohn Ojemann * The remainder of the operation can still be a no-op. 5439dc0749f3SJohn Ojemann * 5440dc0749f3SJohn Ojemann * If the queue isn't changing, check to see if 5441dc0749f3SJohn Ojemann * an update would be meaningless. 5442dc0749f3SJohn Ojemann */ 5443cbded9aeSdr if (oifq == nifq) { 5444dc0749f3SJohn Ojemann if ((tqe->tqe_next == NULL) || 5445dc0749f3SJohn Ojemann (tqe->tqe_next->tqe_die == tqe->tqe_die)) { 5446dc0749f3SJohn Ojemann MUTEX_EXIT(&oifq->ifq_lock); 5447cbded9aeSdr return; 5448dc0749f3SJohn Ojemann } 5449ab25eeb5Syz } 54507c478bd9Sstevel@tonic-gate 54517c478bd9Sstevel@tonic-gate /* 54527c478bd9Sstevel@tonic-gate * Remove from the old queue 54537c478bd9Sstevel@tonic-gate */ 54547c478bd9Sstevel@tonic-gate *tqe->tqe_pnext = tqe->tqe_next; 54557c478bd9Sstevel@tonic-gate if (tqe->tqe_next) 54567c478bd9Sstevel@tonic-gate tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 54577c478bd9Sstevel@tonic-gate else 54587c478bd9Sstevel@tonic-gate oifq->ifq_tail = tqe->tqe_pnext; 54597c478bd9Sstevel@tonic-gate tqe->tqe_next = NULL; 54607c478bd9Sstevel@tonic-gate 54617c478bd9Sstevel@tonic-gate /* 54627c478bd9Sstevel@tonic-gate * If we're moving from one queue to another, release the lock on the 54637c478bd9Sstevel@tonic-gate * old queue and get a lock on the new queue. For user defined queues, 54647c478bd9Sstevel@tonic-gate * if we're moving off it, call delete in case it can now be freed. 54657c478bd9Sstevel@tonic-gate */ 54667c478bd9Sstevel@tonic-gate if (oifq != nifq) { 54677c478bd9Sstevel@tonic-gate tqe->tqe_ifq = NULL; 5468ab25eeb5Syz 5469ab25eeb5Syz (void) fr_deletetimeoutqueue(oifq); 5470ab25eeb5Syz 54717c478bd9Sstevel@tonic-gate MUTEX_EXIT(&oifq->ifq_lock); 54727c478bd9Sstevel@tonic-gate 54737c478bd9Sstevel@tonic-gate MUTEX_ENTER(&nifq->ifq_lock); 5474ab25eeb5Syz 54757c478bd9Sstevel@tonic-gate tqe->tqe_ifq = nifq; 54767c478bd9Sstevel@tonic-gate nifq->ifq_ref++; 54777c478bd9Sstevel@tonic-gate } 54787c478bd9Sstevel@tonic-gate 54797c478bd9Sstevel@tonic-gate /* 54807c478bd9Sstevel@tonic-gate * Add to the bottom of the new queue 54817c478bd9Sstevel@tonic-gate */ 54827c478bd9Sstevel@tonic-gate tqe->tqe_pnext = nifq->ifq_tail; 54837c478bd9Sstevel@tonic-gate *nifq->ifq_tail = tqe; 54847c478bd9Sstevel@tonic-gate nifq->ifq_tail = &tqe->tqe_next; 54857c478bd9Sstevel@tonic-gate MUTEX_EXIT(&nifq->ifq_lock); 54867c478bd9Sstevel@tonic-gate } 54877c478bd9Sstevel@tonic-gate 54887c478bd9Sstevel@tonic-gate 54897c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 54907c478bd9Sstevel@tonic-gate /* Function: fr_updateipid */ 54917c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 54927c478bd9Sstevel@tonic-gate /* Parameters: fin(I) - pointer to packet information */ 54937c478bd9Sstevel@tonic-gate /* */ 54947c478bd9Sstevel@tonic-gate /* When we are doing NAT, change the IP of every packet to represent a */ 54957c478bd9Sstevel@tonic-gate /* single sequence of packets coming from the host, hiding any host */ 54967c478bd9Sstevel@tonic-gate /* specific sequencing that might otherwise be revealed. If the packet is */ 54977c478bd9Sstevel@tonic-gate /* a fragment, then store the 'new' IPid in the fragment cache and look up */ 54987c478bd9Sstevel@tonic-gate /* the fragment cache for non-leading fragments. If a non-leading fragment */ 54997c478bd9Sstevel@tonic-gate /* has no match in the cache, return an error. */ 55007c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 55017c478bd9Sstevel@tonic-gate static INLINE int fr_updateipid(fin) 55027c478bd9Sstevel@tonic-gate fr_info_t *fin; 55037c478bd9Sstevel@tonic-gate { 55047c478bd9Sstevel@tonic-gate u_short id, ido, sums; 55057c478bd9Sstevel@tonic-gate u_32_t sumd, sum; 55067c478bd9Sstevel@tonic-gate ip_t *ip; 55077c478bd9Sstevel@tonic-gate 55087c478bd9Sstevel@tonic-gate if (fin->fin_off != 0) { 55097c478bd9Sstevel@tonic-gate sum = fr_ipid_knownfrag(fin); 55107c478bd9Sstevel@tonic-gate if (sum == 0xffffffff) 55117c478bd9Sstevel@tonic-gate return -1; 55127c478bd9Sstevel@tonic-gate sum &= 0xffff; 55137c478bd9Sstevel@tonic-gate id = (u_short)sum; 55147c478bd9Sstevel@tonic-gate } else { 55157c478bd9Sstevel@tonic-gate id = fr_nextipid(fin); 55167c478bd9Sstevel@tonic-gate if (fin->fin_off == 0 && (fin->fin_flx & FI_FRAG) != 0) 55177c478bd9Sstevel@tonic-gate (void) fr_ipid_newfrag(fin, (u_32_t)id); 55187c478bd9Sstevel@tonic-gate } 55197c478bd9Sstevel@tonic-gate 55207c478bd9Sstevel@tonic-gate ip = fin->fin_ip; 55217c478bd9Sstevel@tonic-gate ido = ntohs(ip->ip_id); 55227c478bd9Sstevel@tonic-gate if (id == ido) 55237c478bd9Sstevel@tonic-gate return 0; 55247c478bd9Sstevel@tonic-gate ip->ip_id = htons(id); 55257c478bd9Sstevel@tonic-gate CALC_SUMD(ido, id, sumd); /* DESTRUCTIVE MACRO! id,ido change */ 55267c478bd9Sstevel@tonic-gate sum = (~ntohs(ip->ip_sum)) & 0xffff; 55277c478bd9Sstevel@tonic-gate sum += sumd; 55287c478bd9Sstevel@tonic-gate sum = (sum >> 16) + (sum & 0xffff); 55297c478bd9Sstevel@tonic-gate sum = (sum >> 16) + (sum & 0xffff); 55307c478bd9Sstevel@tonic-gate sums = ~(u_short)sum; 55317c478bd9Sstevel@tonic-gate ip->ip_sum = htons(sums); 55327c478bd9Sstevel@tonic-gate return 0; 55337c478bd9Sstevel@tonic-gate } 55347c478bd9Sstevel@tonic-gate 55357c478bd9Sstevel@tonic-gate 55367c478bd9Sstevel@tonic-gate #ifdef NEED_FRGETIFNAME 55377c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 55387c478bd9Sstevel@tonic-gate /* Function: fr_getifname */ 5539ab25eeb5Syz /* Returns: char * - pointer to interface name */ 5540ab25eeb5Syz /* Parameters: ifp(I) - pointer to network interface */ 5541ab25eeb5Syz /* buffer(O) - pointer to where to store interface name */ 55427c478bd9Sstevel@tonic-gate /* */ 5543ab25eeb5Syz /* Constructs an interface name in the buffer passed. The buffer passed is */ 5544ab25eeb5Syz /* expected to be at least LIFNAMSIZ in bytes big. If buffer is passed in */ 5545ab25eeb5Syz /* as a NULL pointer then return a pointer to a static array. */ 55467c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 55477c478bd9Sstevel@tonic-gate char *fr_getifname(ifp, buffer) 55487c478bd9Sstevel@tonic-gate struct ifnet *ifp; 55497c478bd9Sstevel@tonic-gate char *buffer; 55507c478bd9Sstevel@tonic-gate { 5551ab25eeb5Syz static char namebuf[LIFNAMSIZ]; 5552ab25eeb5Syz # if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \ 5553ab25eeb5Syz defined(__sgi) || defined(linux) || defined(_AIX51) || \ 5554ab25eeb5Syz (defined(sun) && !defined(__SVR4) && !defined(__svr4__)) 55557c478bd9Sstevel@tonic-gate int unit, space; 55567c478bd9Sstevel@tonic-gate char temp[20]; 55577c478bd9Sstevel@tonic-gate char *s; 5558ab25eeb5Syz # endif 55597c478bd9Sstevel@tonic-gate 5560f4b3ec61Sdh ASSERT(buffer != NULL); 5561f4b3ec61Sdh #ifdef notdef 55627c478bd9Sstevel@tonic-gate if (buffer == NULL) 55637c478bd9Sstevel@tonic-gate buffer = namebuf; 5564f4b3ec61Sdh #endif 55657c478bd9Sstevel@tonic-gate (void) strncpy(buffer, ifp->if_name, LIFNAMSIZ); 5566ab25eeb5Syz buffer[LIFNAMSIZ - 1] = '\0'; 5567ab25eeb5Syz # if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \ 5568ab25eeb5Syz defined(__sgi) || defined(_AIX51) || \ 5569ab25eeb5Syz (defined(sun) && !defined(__SVR4) && !defined(__svr4__)) 55707c478bd9Sstevel@tonic-gate for (s = buffer; *s; s++) 55717c478bd9Sstevel@tonic-gate ; 55727c478bd9Sstevel@tonic-gate unit = ifp->if_unit; 55737c478bd9Sstevel@tonic-gate space = LIFNAMSIZ - (s - buffer); 55747c478bd9Sstevel@tonic-gate if (space > 0) { 5575ab25eeb5Syz # if defined(SNPRINTF) && defined(_KERNEL) 5576ab25eeb5Syz (void) SNPRINTF(temp, sizeof(temp), "%d", unit); 5577ab25eeb5Syz # else 55787c478bd9Sstevel@tonic-gate (void) sprintf(temp, "%d", unit); 5579ab25eeb5Syz # endif 55807c478bd9Sstevel@tonic-gate (void) strncpy(s, temp, space); 55817c478bd9Sstevel@tonic-gate } 5582ab25eeb5Syz # endif 55837c478bd9Sstevel@tonic-gate return buffer; 55847c478bd9Sstevel@tonic-gate } 55857c478bd9Sstevel@tonic-gate #endif 55867c478bd9Sstevel@tonic-gate 55877c478bd9Sstevel@tonic-gate 55887c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 55897c478bd9Sstevel@tonic-gate /* Function: fr_ioctlswitch */ 55907c478bd9Sstevel@tonic-gate /* Returns: int - -1 continue processing, else ioctl return value */ 55917c478bd9Sstevel@tonic-gate /* Parameters: unit(I) - device unit opened */ 55927c478bd9Sstevel@tonic-gate /* data(I) - pointer to ioctl data */ 55937c478bd9Sstevel@tonic-gate /* cmd(I) - ioctl command */ 55947c478bd9Sstevel@tonic-gate /* mode(I) - mode value */ 55957c478bd9Sstevel@tonic-gate /* */ 55967c478bd9Sstevel@tonic-gate /* Based on the value of unit, call the appropriate ioctl handler or return */ 55977c478bd9Sstevel@tonic-gate /* EIO if ipfilter is not running. Also checks if write perms are req'd */ 55987c478bd9Sstevel@tonic-gate /* for the device in order to execute the ioctl. */ 55997c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 5600f4b3ec61Sdh INLINE int fr_ioctlswitch(unit, data, cmd, mode, uid, ctx, ifs) 5601f4b3ec61Sdh int unit, mode, uid; 5602ab25eeb5Syz ioctlcmd_t cmd; 5603f4b3ec61Sdh void *data, *ctx; 5604f4b3ec61Sdh ipf_stack_t *ifs; 56057c478bd9Sstevel@tonic-gate { 56067c478bd9Sstevel@tonic-gate int error = 0; 56077c478bd9Sstevel@tonic-gate 56087c478bd9Sstevel@tonic-gate switch (unit) 56097c478bd9Sstevel@tonic-gate { 56107c478bd9Sstevel@tonic-gate case IPL_LOGIPF : 56117c478bd9Sstevel@tonic-gate error = -1; 56127c478bd9Sstevel@tonic-gate break; 56137c478bd9Sstevel@tonic-gate case IPL_LOGNAT : 5614f4b3ec61Sdh if (ifs->ifs_fr_running > 0) 5615f4b3ec61Sdh error = fr_nat_ioctl(data, cmd, mode, uid, ctx, ifs); 56167c478bd9Sstevel@tonic-gate else 56177c478bd9Sstevel@tonic-gate error = EIO; 56187c478bd9Sstevel@tonic-gate break; 56197c478bd9Sstevel@tonic-gate case IPL_LOGSTATE : 5620f4b3ec61Sdh if (ifs->ifs_fr_running > 0) 5621f4b3ec61Sdh error = fr_state_ioctl(data, cmd, mode, uid, ctx, ifs); 56227c478bd9Sstevel@tonic-gate else 56237c478bd9Sstevel@tonic-gate error = EIO; 56247c478bd9Sstevel@tonic-gate break; 56257c478bd9Sstevel@tonic-gate case IPL_LOGAUTH : 5626f4b3ec61Sdh if (ifs->ifs_fr_running > 0) { 5627ab25eeb5Syz if ((cmd == (ioctlcmd_t)SIOCADAFR) || 5628ab25eeb5Syz (cmd == (ioctlcmd_t)SIOCRMAFR)) { 56297c478bd9Sstevel@tonic-gate if (!(mode & FWRITE)) { 56307c478bd9Sstevel@tonic-gate error = EPERM; 56317c478bd9Sstevel@tonic-gate } else { 56327c478bd9Sstevel@tonic-gate error = frrequest(unit, cmd, data, 5633f4b3ec61Sdh ifs->ifs_fr_active, 1, ifs); 56347c478bd9Sstevel@tonic-gate } 56357c478bd9Sstevel@tonic-gate } else { 5636f4b3ec61Sdh error = fr_auth_ioctl(data, cmd, mode, uid, ctx, ifs); 56377c478bd9Sstevel@tonic-gate } 56387c478bd9Sstevel@tonic-gate } else 56397c478bd9Sstevel@tonic-gate error = EIO; 56407c478bd9Sstevel@tonic-gate break; 56417c478bd9Sstevel@tonic-gate case IPL_LOGSYNC : 56427c478bd9Sstevel@tonic-gate #ifdef IPFILTER_SYNC 5643f4b3ec61Sdh if (ifs->ifs_fr_running > 0) 5644f4b3ec61Sdh error = fr_sync_ioctl(data, cmd, mode, ifs); 56457c478bd9Sstevel@tonic-gate else 56467c478bd9Sstevel@tonic-gate #endif 56477c478bd9Sstevel@tonic-gate error = EIO; 56487c478bd9Sstevel@tonic-gate break; 56497c478bd9Sstevel@tonic-gate case IPL_LOGSCAN : 56507c478bd9Sstevel@tonic-gate #ifdef IPFILTER_SCAN 5651f4b3ec61Sdh if (ifs->ifs_fr_running > 0) 5652f4b3ec61Sdh error = fr_scan_ioctl(data, cmd, mode, ifs); 56537c478bd9Sstevel@tonic-gate else 56547c478bd9Sstevel@tonic-gate #endif 56557c478bd9Sstevel@tonic-gate error = EIO; 56567c478bd9Sstevel@tonic-gate break; 56577c478bd9Sstevel@tonic-gate case IPL_LOGLOOKUP : 56587c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOOKUP 5659f4b3ec61Sdh if (ifs->ifs_fr_running > 0) 5660f4b3ec61Sdh error = ip_lookup_ioctl(data, cmd, mode, uid, ctx, ifs); 56617c478bd9Sstevel@tonic-gate else 56627c478bd9Sstevel@tonic-gate #endif 56637c478bd9Sstevel@tonic-gate error = EIO; 56647c478bd9Sstevel@tonic-gate break; 56657c478bd9Sstevel@tonic-gate default : 56667c478bd9Sstevel@tonic-gate error = EIO; 56677c478bd9Sstevel@tonic-gate break; 56687c478bd9Sstevel@tonic-gate } 56697c478bd9Sstevel@tonic-gate 56707c478bd9Sstevel@tonic-gate return error; 56717c478bd9Sstevel@tonic-gate } 56727c478bd9Sstevel@tonic-gate 56737c478bd9Sstevel@tonic-gate 56747c478bd9Sstevel@tonic-gate /* 56757c478bd9Sstevel@tonic-gate * This array defines the expected size of objects coming into the kernel 56767c478bd9Sstevel@tonic-gate * for the various recognised object types. 56777c478bd9Sstevel@tonic-gate */ 5678f4b3ec61Sdh #define NUM_OBJ_TYPES 19 5679ab25eeb5Syz 5680ab25eeb5Syz static int fr_objbytes[NUM_OBJ_TYPES][2] = { 5681ab25eeb5Syz { 1, sizeof(struct frentry) }, /* frentry */ 5682ab25eeb5Syz { 0, sizeof(struct friostat) }, 5683ab25eeb5Syz { 0, sizeof(struct fr_info) }, 5684ab25eeb5Syz { 0, sizeof(struct fr_authstat) }, 5685ab25eeb5Syz { 0, sizeof(struct ipfrstat) }, 5686ab25eeb5Syz { 0, sizeof(struct ipnat) }, 5687ab25eeb5Syz { 0, sizeof(struct natstat) }, 5688ab25eeb5Syz { 0, sizeof(struct ipstate_save) }, 5689ab25eeb5Syz { 1, sizeof(struct nat_save) }, /* nat_save */ 5690ab25eeb5Syz { 0, sizeof(struct natlookup) }, 5691ab25eeb5Syz { 1, sizeof(struct ipstate) }, /* ipstate */ 5692ab25eeb5Syz { 0, sizeof(struct ips_stat) }, 5693ab25eeb5Syz { 0, sizeof(struct frauth) }, 5694f4b3ec61Sdh { 0, sizeof(struct ipftune) }, 5695f4b3ec61Sdh { 0, sizeof(struct nat) }, /* nat_t */ 5696f4b3ec61Sdh { 0, sizeof(struct ipfruleiter) }, 5697f4b3ec61Sdh { 0, sizeof(struct ipfgeniter) }, 5698f4b3ec61Sdh { 0, sizeof(struct ipftable) }, 5699f4b3ec61Sdh { 0, sizeof(struct ipflookupiter) } 57007c478bd9Sstevel@tonic-gate }; 57017c478bd9Sstevel@tonic-gate 57027c478bd9Sstevel@tonic-gate 5703*94bdecd9SRob Gulewich /* ------------------------------------------------------------------------ */ 5704*94bdecd9SRob Gulewich /* Function: fr_getzoneid */ 5705*94bdecd9SRob Gulewich /* Returns: int - 0 = success, else failure */ 5706*94bdecd9SRob Gulewich /* Parameters: idsp(I) - pointer to ipf_devstate_t */ 5707*94bdecd9SRob Gulewich /* data(I) - pointer to ioctl data */ 5708*94bdecd9SRob Gulewich /* */ 5709*94bdecd9SRob Gulewich /* Set the zone ID in idsp based on the zone name in ipfzoneobj. Further */ 5710*94bdecd9SRob Gulewich /* ioctls will act on the IPF stack for that zone ID. */ 5711*94bdecd9SRob Gulewich /* ------------------------------------------------------------------------ */ 5712*94bdecd9SRob Gulewich #if defined(_KERNEL) 5713*94bdecd9SRob Gulewich int fr_setzoneid(idsp, data) 5714*94bdecd9SRob Gulewich ipf_devstate_t *idsp; 5715*94bdecd9SRob Gulewich void *data; 5716*94bdecd9SRob Gulewich { 5717*94bdecd9SRob Gulewich int error = 0; 5718*94bdecd9SRob Gulewich ipfzoneobj_t ipfzo; 5719*94bdecd9SRob Gulewich zone_t *zone; 5720*94bdecd9SRob Gulewich 5721*94bdecd9SRob Gulewich error = BCOPYIN(data, &ipfzo, sizeof(ipfzo)); 5722*94bdecd9SRob Gulewich if (error != 0) 5723*94bdecd9SRob Gulewich return EFAULT; 5724*94bdecd9SRob Gulewich 5725*94bdecd9SRob Gulewich if (memchr(ipfzo.ipfz_zonename, '\0', ZONENAME_MAX) == NULL) 5726*94bdecd9SRob Gulewich return EFAULT; 5727*94bdecd9SRob Gulewich 5728*94bdecd9SRob Gulewich /* 5729*94bdecd9SRob Gulewich * The global zone doesn't have a GZ-controlled stack, so no 5730*94bdecd9SRob Gulewich * sense in going any further 5731*94bdecd9SRob Gulewich */ 5732*94bdecd9SRob Gulewich if (strcmp(ipfzo.ipfz_zonename, "global") == 0) 5733*94bdecd9SRob Gulewich return ENODEV; 5734*94bdecd9SRob Gulewich 5735*94bdecd9SRob Gulewich if ((zone = zone_find_by_name(ipfzo.ipfz_zonename)) == NULL) 5736*94bdecd9SRob Gulewich return ENODEV; 5737*94bdecd9SRob Gulewich 5738*94bdecd9SRob Gulewich /* 5739*94bdecd9SRob Gulewich * Store the zone ID that to control, and whether it's the 5740*94bdecd9SRob Gulewich * GZ-controlled stack that's wanted 5741*94bdecd9SRob Gulewich */ 5742*94bdecd9SRob Gulewich idsp->ipfs_zoneid = zone->zone_id; 5743*94bdecd9SRob Gulewich idsp->ipfs_gz = (ipfzo.ipfz_gz == 1) ? B_TRUE : B_FALSE; 5744*94bdecd9SRob Gulewich zone_rele(zone); 5745*94bdecd9SRob Gulewich 5746*94bdecd9SRob Gulewich return error; 5747*94bdecd9SRob Gulewich } 5748*94bdecd9SRob Gulewich #endif 5749*94bdecd9SRob Gulewich 5750*94bdecd9SRob Gulewich 57517c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 57527c478bd9Sstevel@tonic-gate /* Function: fr_inobj */ 57537c478bd9Sstevel@tonic-gate /* Returns: int - 0 = success, else failure */ 57547c478bd9Sstevel@tonic-gate /* Parameters: data(I) - pointer to ioctl data */ 57557c478bd9Sstevel@tonic-gate /* ptr(I) - pointer to store real data in */ 57567c478bd9Sstevel@tonic-gate /* type(I) - type of structure being moved */ 57577c478bd9Sstevel@tonic-gate /* */ 57587c478bd9Sstevel@tonic-gate /* Copy in the contents of what the ipfobj_t points to. In future, we */ 57597c478bd9Sstevel@tonic-gate /* add things to check for version numbers, sizes, etc, to make it backward */ 57607c478bd9Sstevel@tonic-gate /* compatible at the ABI for user land. */ 57617c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 57627c478bd9Sstevel@tonic-gate int fr_inobj(data, ptr, type) 57637c478bd9Sstevel@tonic-gate void *data; 57647c478bd9Sstevel@tonic-gate void *ptr; 57657c478bd9Sstevel@tonic-gate int type; 57667c478bd9Sstevel@tonic-gate { 57677c478bd9Sstevel@tonic-gate ipfobj_t obj; 57687c478bd9Sstevel@tonic-gate int error = 0; 57697c478bd9Sstevel@tonic-gate 5770ab25eeb5Syz if ((type < 0) || (type > NUM_OBJ_TYPES-1)) 57717c478bd9Sstevel@tonic-gate return EINVAL; 57727c478bd9Sstevel@tonic-gate 5773bb1d9de5SJohn Ojemann error = BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj)); 5774bb1d9de5SJohn Ojemann if (error != 0) 5775bb1d9de5SJohn Ojemann return EFAULT; 57767c478bd9Sstevel@tonic-gate 57777c478bd9Sstevel@tonic-gate if (obj.ipfo_type != type) 57787c478bd9Sstevel@tonic-gate return EINVAL; 57797c478bd9Sstevel@tonic-gate 57807c478bd9Sstevel@tonic-gate #ifndef IPFILTER_COMPAT 5781ab25eeb5Syz if ((fr_objbytes[type][0] & 1) != 0) { 5782ab25eeb5Syz if (obj.ipfo_size < fr_objbytes[type][1]) 5783ab25eeb5Syz return EINVAL; 5784ab25eeb5Syz } else if (obj.ipfo_size != fr_objbytes[type][1]) 57857c478bd9Sstevel@tonic-gate return EINVAL; 57867c478bd9Sstevel@tonic-gate #else 5787d6c23f6fSyx if (obj.ipfo_rev != IPFILTER_VERSION) { 5788d6c23f6fSyx error = fr_incomptrans(&obj, ptr); 5789d6c23f6fSyx return error; 5790d6c23f6fSyx } 5791d6c23f6fSyx 5792d6c23f6fSyx if ((fr_objbytes[type][0] & 1) != 0 && 5793d6c23f6fSyx obj.ipfo_size < fr_objbytes[type][1] || 5794d6c23f6fSyx obj.ipfo_size != fr_objbytes[type][1]) 57957c478bd9Sstevel@tonic-gate return EINVAL; 57967c478bd9Sstevel@tonic-gate #endif 57977c478bd9Sstevel@tonic-gate 5798ab25eeb5Syz if ((fr_objbytes[type][0] & 1) != 0) { 5799ab25eeb5Syz error = COPYIN((caddr_t)obj.ipfo_ptr, (caddr_t)ptr, 5800ab25eeb5Syz fr_objbytes[type][1]); 5801ab25eeb5Syz } else { 5802ab25eeb5Syz error = COPYIN((caddr_t)obj.ipfo_ptr, (caddr_t)ptr, 5803ab25eeb5Syz obj.ipfo_size); 5804ab25eeb5Syz } 58057c478bd9Sstevel@tonic-gate return error; 58067c478bd9Sstevel@tonic-gate } 58077c478bd9Sstevel@tonic-gate 58087c478bd9Sstevel@tonic-gate 58097c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 5810ab25eeb5Syz /* Function: fr_inobjsz */ 58117c478bd9Sstevel@tonic-gate /* Returns: int - 0 = success, else failure */ 58127c478bd9Sstevel@tonic-gate /* Parameters: data(I) - pointer to ioctl data */ 58137c478bd9Sstevel@tonic-gate /* ptr(I) - pointer to store real data in */ 58147c478bd9Sstevel@tonic-gate /* type(I) - type of structure being moved */ 5815ab25eeb5Syz /* sz(I) - size of data to copy */ 58167c478bd9Sstevel@tonic-gate /* */ 5817ab25eeb5Syz /* As per fr_inobj, except the size of the object to copy in is passed in */ 5818ab25eeb5Syz /* but it must not be smaller than the size defined for the type and the */ 5819ab25eeb5Syz /* type must allow for varied sized objects. The extra requirement here is */ 5820ab25eeb5Syz /* that sz must match the size of the object being passed in - this is not */ 5821ab25eeb5Syz /* not possible nor required in fr_inobj(). */ 58227c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 5823ab25eeb5Syz int fr_inobjsz(data, ptr, type, sz) 58247c478bd9Sstevel@tonic-gate void *data; 58257c478bd9Sstevel@tonic-gate void *ptr; 5826ab25eeb5Syz int type, sz; 58277c478bd9Sstevel@tonic-gate { 58287c478bd9Sstevel@tonic-gate ipfobj_t obj; 58297c478bd9Sstevel@tonic-gate int error; 58307c478bd9Sstevel@tonic-gate 5831ab25eeb5Syz if ((type < 0) || (type > NUM_OBJ_TYPES-1)) 5832ab25eeb5Syz return EINVAL; 5833ab25eeb5Syz if (((fr_objbytes[type][0] & 1) == 0) || (sz < fr_objbytes[type][1])) 5834ab25eeb5Syz return EINVAL; 5835ab25eeb5Syz 5836bb1d9de5SJohn Ojemann error = BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj)); 5837bb1d9de5SJohn Ojemann if (error != 0) 5838bb1d9de5SJohn Ojemann return EFAULT; 58397c478bd9Sstevel@tonic-gate 58407c478bd9Sstevel@tonic-gate if (obj.ipfo_type != type) 58417c478bd9Sstevel@tonic-gate return EINVAL; 58427c478bd9Sstevel@tonic-gate 58437c478bd9Sstevel@tonic-gate #ifndef IPFILTER_COMPAT 5844ab25eeb5Syz if (obj.ipfo_size != sz) 58457c478bd9Sstevel@tonic-gate return EINVAL; 58467c478bd9Sstevel@tonic-gate #else 58477c478bd9Sstevel@tonic-gate if (obj.ipfo_rev != IPFILTER_VERSION) 5848d6c23f6fSyx /*XXX compatibility hook here */ 5849d6c23f6fSyx /*EMPTY*/; 5850ab25eeb5Syz if (obj.ipfo_size != sz) 58517c478bd9Sstevel@tonic-gate /* XXX compatibility hook here */ 58527c478bd9Sstevel@tonic-gate return EINVAL; 58537c478bd9Sstevel@tonic-gate #endif 58547c478bd9Sstevel@tonic-gate 5855ab25eeb5Syz error = COPYIN((caddr_t)obj.ipfo_ptr, (caddr_t)ptr, sz); 58567c478bd9Sstevel@tonic-gate return error; 58577c478bd9Sstevel@tonic-gate } 58587c478bd9Sstevel@tonic-gate 58597c478bd9Sstevel@tonic-gate 58607c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 5861ab25eeb5Syz /* Function: fr_outobjsz */ 5862ab25eeb5Syz /* Returns: int - 0 = success, else failure */ 5863ab25eeb5Syz /* Parameters: data(I) - pointer to ioctl data */ 5864ab25eeb5Syz /* ptr(I) - pointer to store real data in */ 5865ab25eeb5Syz /* type(I) - type of structure being moved */ 5866ab25eeb5Syz /* sz(I) - size of data to copy */ 58677c478bd9Sstevel@tonic-gate /* */ 5868ab25eeb5Syz /* As per fr_outobj, except the size of the object to copy out is passed in */ 5869ab25eeb5Syz /* but it must not be smaller than the size defined for the type and the */ 5870ab25eeb5Syz /* type must allow for varied sized objects. The extra requirement here is */ 5871ab25eeb5Syz /* that sz must match the size of the object being passed in - this is not */ 5872ab25eeb5Syz /* not possible nor required in fr_outobj(). */ 58737c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 5874ab25eeb5Syz int fr_outobjsz(data, ptr, type, sz) 5875ab25eeb5Syz void *data; 5876ab25eeb5Syz void *ptr; 5877ab25eeb5Syz int type, sz; 58787c478bd9Sstevel@tonic-gate { 5879ab25eeb5Syz ipfobj_t obj; 5880ab25eeb5Syz int error; 58817c478bd9Sstevel@tonic-gate 5882ab25eeb5Syz if ((type < 0) || (type > NUM_OBJ_TYPES-1) || 5883ab25eeb5Syz ((fr_objbytes[type][0] & 1) == 0) || 5884ab25eeb5Syz (sz < fr_objbytes[type][1])) 5885ab25eeb5Syz return EINVAL; 58867c478bd9Sstevel@tonic-gate 5887bb1d9de5SJohn Ojemann error = BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj)); 5888bb1d9de5SJohn Ojemann if (error != 0) 5889bb1d9de5SJohn Ojemann return EFAULT; 58907c478bd9Sstevel@tonic-gate 5891ab25eeb5Syz if (obj.ipfo_type != type) 5892ab25eeb5Syz return EINVAL; 58937c478bd9Sstevel@tonic-gate 5894ab25eeb5Syz #ifndef IPFILTER_COMPAT 5895ab25eeb5Syz if (obj.ipfo_size != sz) 5896ab25eeb5Syz return EINVAL; 5897ab25eeb5Syz #else 5898ab25eeb5Syz if (obj.ipfo_rev != IPFILTER_VERSION) 5899ab25eeb5Syz /* XXX compatibility hook here */ 5900d6c23f6fSyx /*EMPTY*/; 5901ab25eeb5Syz if (obj.ipfo_size != sz) 5902ab25eeb5Syz /* XXX compatibility hook here */ 5903ab25eeb5Syz return EINVAL; 59047c478bd9Sstevel@tonic-gate #endif 5905ab25eeb5Syz 5906ab25eeb5Syz error = COPYOUT((caddr_t)ptr, (caddr_t)obj.ipfo_ptr, sz); 5907ab25eeb5Syz return error; 5908ab25eeb5Syz } 5909ab25eeb5Syz 5910ab25eeb5Syz 5911ab25eeb5Syz /* ------------------------------------------------------------------------ */ 5912ab25eeb5Syz /* Function: fr_outobj */ 5913ab25eeb5Syz /* Returns: int - 0 = success, else failure */ 5914ab25eeb5Syz /* Parameters: data(I) - pointer to ioctl data */ 5915ab25eeb5Syz /* ptr(I) - pointer to store real data in */ 5916ab25eeb5Syz /* type(I) - type of structure being moved */ 5917ab25eeb5Syz /* */ 5918ab25eeb5Syz /* Copy out the contents of what ptr is to where ipfobj points to. In */ 5919ab25eeb5Syz /* future, we add things to check for version numbers, sizes, etc, to make */ 5920ab25eeb5Syz /* it backward compatible at the ABI for user land. */ 5921ab25eeb5Syz /* ------------------------------------------------------------------------ */ 5922ab25eeb5Syz int fr_outobj(data, ptr, type) 5923ab25eeb5Syz void *data; 5924ab25eeb5Syz void *ptr; 5925ab25eeb5Syz int type; 5926ab25eeb5Syz { 5927ab25eeb5Syz ipfobj_t obj; 5928ab25eeb5Syz int error; 5929ab25eeb5Syz 5930ab25eeb5Syz if ((type < 0) || (type > NUM_OBJ_TYPES-1)) 5931ab25eeb5Syz return EINVAL; 5932ab25eeb5Syz 5933bb1d9de5SJohn Ojemann error = BCOPYIN((caddr_t)data, (caddr_t)&obj, sizeof(obj)); 5934bb1d9de5SJohn Ojemann if (error != 0) 5935bb1d9de5SJohn Ojemann return EFAULT; 5936ab25eeb5Syz 5937ab25eeb5Syz if (obj.ipfo_type != type) 5938ab25eeb5Syz return EINVAL; 5939ab25eeb5Syz 5940ab25eeb5Syz #ifndef IPFILTER_COMPAT 5941ab25eeb5Syz if ((fr_objbytes[type][0] & 1) != 0) { 5942ab25eeb5Syz if (obj.ipfo_size < fr_objbytes[type][1]) 5943ab25eeb5Syz return EINVAL; 5944ab25eeb5Syz } else if (obj.ipfo_size != fr_objbytes[type][1]) 5945ab25eeb5Syz return EINVAL; 5946ab25eeb5Syz #else 5947d6c23f6fSyx if (obj.ipfo_rev != IPFILTER_VERSION) { 5948d6c23f6fSyx error = fr_outcomptrans(&obj, ptr); 5949d6c23f6fSyx return error; 5950d6c23f6fSyx } 5951d6c23f6fSyx 5952d6c23f6fSyx if ((fr_objbytes[type][0] & 1) != 0 && 5953d6c23f6fSyx obj.ipfo_size < fr_objbytes[type][1] || 5954d6c23f6fSyx obj.ipfo_size != fr_objbytes[type][1]) 5955ab25eeb5Syz return EINVAL; 5956ab25eeb5Syz #endif 5957ab25eeb5Syz 5958ab25eeb5Syz error = COPYOUT((caddr_t)ptr, (caddr_t)obj.ipfo_ptr, obj.ipfo_size); 5959ab25eeb5Syz return error; 5960ab25eeb5Syz } 5961ab25eeb5Syz 5962ab25eeb5Syz 5963ab25eeb5Syz /* ------------------------------------------------------------------------ */ 5964ab25eeb5Syz /* Function: fr_checkl4sum */ 5965ab25eeb5Syz /* Returns: int - 0 = good, -1 = bad, 1 = cannot check */ 5966ab25eeb5Syz /* Parameters: fin(I) - pointer to packet information */ 5967ab25eeb5Syz /* */ 5968ab25eeb5Syz /* If possible, calculate the layer 4 checksum for the packet. If this is */ 5969ab25eeb5Syz /* not possible, return without indicating a failure or success but in a */ 5970ab25eeb5Syz /* way that is ditinguishable. */ 5971ab25eeb5Syz /* ------------------------------------------------------------------------ */ 5972ab25eeb5Syz int fr_checkl4sum(fin) 5973ab25eeb5Syz fr_info_t *fin; 5974ab25eeb5Syz { 5975ab25eeb5Syz u_short sum, hdrsum, *csump; 5976ab25eeb5Syz udphdr_t *udp; 5977ab25eeb5Syz int dosum; 5978f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 5979ab25eeb5Syz 5980381a2a9aSdr #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) 59817ddc9b1aSDarren Reed net_handle_t net_data_p; 5982381a2a9aSdr if (fin->fin_v == 4) 5983f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv4; 5984381a2a9aSdr else 5985f4b3ec61Sdh net_data_p = ifs->ifs_ipf_ipv6; 5986381a2a9aSdr #endif 5987381a2a9aSdr 5988ab25eeb5Syz if ((fin->fin_flx & FI_NOCKSUM) != 0) 5989ab25eeb5Syz return 0; 5990ab25eeb5Syz 5991ab25eeb5Syz /* 5992ab25eeb5Syz * If the TCP packet isn't a fragment, isn't too short and otherwise 5993ab25eeb5Syz * isn't already considered "bad", then validate the checksum. If 5994ab25eeb5Syz * this check fails then considered the packet to be "bad". 5995ab25eeb5Syz */ 5996ab25eeb5Syz if ((fin->fin_flx & (FI_FRAG|FI_SHORT|FI_BAD)) != 0) 5997ab25eeb5Syz return 1; 5998ab25eeb5Syz 5999ab25eeb5Syz csump = NULL; 6000ab25eeb5Syz hdrsum = 0; 6001ab25eeb5Syz dosum = 0; 6002ab25eeb5Syz sum = 0; 6003ab25eeb5Syz 6004381a2a9aSdr #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) 6005381a2a9aSdr ASSERT(fin->fin_m != NULL); 6006381a2a9aSdr if (NET_IS_HCK_L4_FULL(net_data_p, fin->fin_m) || 6007381a2a9aSdr NET_IS_HCK_L4_PART(net_data_p, fin->fin_m)) { 6008381a2a9aSdr hdrsum = 0; 6009381a2a9aSdr sum = 0; 6010ab25eeb5Syz } else { 6011ab25eeb5Syz #endif 6012ab25eeb5Syz switch (fin->fin_p) 6013ab25eeb5Syz { 60147c478bd9Sstevel@tonic-gate case IPPROTO_TCP : 60157c478bd9Sstevel@tonic-gate csump = &((tcphdr_t *)fin->fin_dp)->th_sum; 60167c478bd9Sstevel@tonic-gate dosum = 1; 60177c478bd9Sstevel@tonic-gate break; 60187c478bd9Sstevel@tonic-gate 60197c478bd9Sstevel@tonic-gate case IPPROTO_UDP : 60207c478bd9Sstevel@tonic-gate udp = fin->fin_dp; 60217c478bd9Sstevel@tonic-gate if (udp->uh_sum != 0) { 60227c478bd9Sstevel@tonic-gate csump = &udp->uh_sum; 60237c478bd9Sstevel@tonic-gate dosum = 1; 60247c478bd9Sstevel@tonic-gate } 60257c478bd9Sstevel@tonic-gate break; 60267c478bd9Sstevel@tonic-gate 60277c478bd9Sstevel@tonic-gate case IPPROTO_ICMP : 60287c478bd9Sstevel@tonic-gate csump = &((struct icmp *)fin->fin_dp)->icmp_cksum; 60297c478bd9Sstevel@tonic-gate dosum = 1; 60307c478bd9Sstevel@tonic-gate break; 60317c478bd9Sstevel@tonic-gate 60327c478bd9Sstevel@tonic-gate default : 60337c478bd9Sstevel@tonic-gate return 1; 60347c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 60357c478bd9Sstevel@tonic-gate } 60367c478bd9Sstevel@tonic-gate 60377c478bd9Sstevel@tonic-gate if (csump != NULL) 60387c478bd9Sstevel@tonic-gate hdrsum = *csump; 60397c478bd9Sstevel@tonic-gate 60407c478bd9Sstevel@tonic-gate if (dosum) 60417c478bd9Sstevel@tonic-gate sum = fr_cksum(fin->fin_m, fin->fin_ip, 60427c478bd9Sstevel@tonic-gate fin->fin_p, fin->fin_dp); 6043381a2a9aSdr #if SOLARIS && defined(_KERNEL) && (SOLARIS2 >= 6) 60447c478bd9Sstevel@tonic-gate } 60457c478bd9Sstevel@tonic-gate #endif 60467c478bd9Sstevel@tonic-gate #if !defined(_KERNEL) 6047ab25eeb5Syz if (sum == hdrsum) { 6048ab25eeb5Syz FR_DEBUG(("checkl4sum: %hx == %hx\n", sum, hdrsum)); 6049ab25eeb5Syz } else { 6050ab25eeb5Syz FR_DEBUG(("checkl4sum: %hx != %hx\n", sum, hdrsum)); 6051ab25eeb5Syz } 60527c478bd9Sstevel@tonic-gate #endif 60537c478bd9Sstevel@tonic-gate if (hdrsum == sum) 60547c478bd9Sstevel@tonic-gate return 0; 60557c478bd9Sstevel@tonic-gate return -1; 60567c478bd9Sstevel@tonic-gate } 60577c478bd9Sstevel@tonic-gate 60587c478bd9Sstevel@tonic-gate 60597c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 60607c478bd9Sstevel@tonic-gate /* Function: fr_ifpfillv4addr */ 60617c478bd9Sstevel@tonic-gate /* Returns: int - 0 = address update, -1 = address not updated */ 60627c478bd9Sstevel@tonic-gate /* Parameters: atype(I) - type of network address update to perform */ 60637c478bd9Sstevel@tonic-gate /* sin(I) - pointer to source of address information */ 60647c478bd9Sstevel@tonic-gate /* mask(I) - pointer to source of netmask information */ 60657c478bd9Sstevel@tonic-gate /* inp(I) - pointer to destination address store */ 60667c478bd9Sstevel@tonic-gate /* inpmask(I) - pointer to destination netmask store */ 60677c478bd9Sstevel@tonic-gate /* */ 60687c478bd9Sstevel@tonic-gate /* Given a type of network address update (atype) to perform, copy */ 60697c478bd9Sstevel@tonic-gate /* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ 60707c478bd9Sstevel@tonic-gate /* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ 60717c478bd9Sstevel@tonic-gate /* which case the operation fails. For all values of atype other than */ 60727c478bd9Sstevel@tonic-gate /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ 60737c478bd9Sstevel@tonic-gate /* value. */ 60747c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 60757c478bd9Sstevel@tonic-gate int fr_ifpfillv4addr(atype, sin, mask, inp, inpmask) 60767c478bd9Sstevel@tonic-gate int atype; 60777c478bd9Sstevel@tonic-gate struct sockaddr_in *sin, *mask; 60787c478bd9Sstevel@tonic-gate struct in_addr *inp, *inpmask; 60797c478bd9Sstevel@tonic-gate { 60807c478bd9Sstevel@tonic-gate if (inpmask != NULL && atype != FRI_NETMASKED) 60817c478bd9Sstevel@tonic-gate inpmask->s_addr = 0xffffffff; 60827c478bd9Sstevel@tonic-gate 60837c478bd9Sstevel@tonic-gate if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { 60847c478bd9Sstevel@tonic-gate if (atype == FRI_NETMASKED) { 60857c478bd9Sstevel@tonic-gate if (inpmask == NULL) 60867c478bd9Sstevel@tonic-gate return -1; 60877c478bd9Sstevel@tonic-gate inpmask->s_addr = mask->sin_addr.s_addr; 60887c478bd9Sstevel@tonic-gate } 60897c478bd9Sstevel@tonic-gate inp->s_addr = sin->sin_addr.s_addr & mask->sin_addr.s_addr; 60907c478bd9Sstevel@tonic-gate } else { 60917c478bd9Sstevel@tonic-gate inp->s_addr = sin->sin_addr.s_addr; 60927c478bd9Sstevel@tonic-gate } 60937c478bd9Sstevel@tonic-gate return 0; 60947c478bd9Sstevel@tonic-gate } 60957c478bd9Sstevel@tonic-gate 60967c478bd9Sstevel@tonic-gate 60977c478bd9Sstevel@tonic-gate #ifdef USE_INET6 60987c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 60997c478bd9Sstevel@tonic-gate /* Function: fr_ifpfillv6addr */ 61007c478bd9Sstevel@tonic-gate /* Returns: int - 0 = address update, -1 = address not updated */ 61017c478bd9Sstevel@tonic-gate /* Parameters: atype(I) - type of network address update to perform */ 61027c478bd9Sstevel@tonic-gate /* sin(I) - pointer to source of address information */ 61037c478bd9Sstevel@tonic-gate /* mask(I) - pointer to source of netmask information */ 61047c478bd9Sstevel@tonic-gate /* inp(I) - pointer to destination address store */ 61057c478bd9Sstevel@tonic-gate /* inpmask(I) - pointer to destination netmask store */ 61067c478bd9Sstevel@tonic-gate /* */ 61077c478bd9Sstevel@tonic-gate /* Given a type of network address update (atype) to perform, copy */ 61087c478bd9Sstevel@tonic-gate /* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ 61097c478bd9Sstevel@tonic-gate /* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ 61107c478bd9Sstevel@tonic-gate /* which case the operation fails. For all values of atype other than */ 61117c478bd9Sstevel@tonic-gate /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ 61127c478bd9Sstevel@tonic-gate /* value. */ 61137c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 61147c478bd9Sstevel@tonic-gate int fr_ifpfillv6addr(atype, sin, mask, inp, inpmask) 61157c478bd9Sstevel@tonic-gate int atype; 61167c478bd9Sstevel@tonic-gate struct sockaddr_in6 *sin, *mask; 61177c478bd9Sstevel@tonic-gate struct in_addr *inp, *inpmask; 61187c478bd9Sstevel@tonic-gate { 61197c478bd9Sstevel@tonic-gate i6addr_t *src, *dst, *and, *dmask; 61207c478bd9Sstevel@tonic-gate 61217c478bd9Sstevel@tonic-gate src = (i6addr_t *)&sin->sin6_addr; 61227c478bd9Sstevel@tonic-gate and = (i6addr_t *)&mask->sin6_addr; 61237c478bd9Sstevel@tonic-gate dst = (i6addr_t *)inp; 61247c478bd9Sstevel@tonic-gate dmask = (i6addr_t *)inpmask; 61257c478bd9Sstevel@tonic-gate 61267c478bd9Sstevel@tonic-gate if (inpmask != NULL && atype != FRI_NETMASKED) { 61277c478bd9Sstevel@tonic-gate dmask->i6[0] = 0xffffffff; 61287c478bd9Sstevel@tonic-gate dmask->i6[1] = 0xffffffff; 61297c478bd9Sstevel@tonic-gate dmask->i6[2] = 0xffffffff; 61307c478bd9Sstevel@tonic-gate dmask->i6[3] = 0xffffffff; 61317c478bd9Sstevel@tonic-gate } 61327c478bd9Sstevel@tonic-gate 61337c478bd9Sstevel@tonic-gate if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { 61347c478bd9Sstevel@tonic-gate if (atype == FRI_NETMASKED) { 61357c478bd9Sstevel@tonic-gate if (inpmask == NULL) 61367c478bd9Sstevel@tonic-gate return -1; 61377c478bd9Sstevel@tonic-gate dmask->i6[0] = and->i6[0]; 61387c478bd9Sstevel@tonic-gate dmask->i6[1] = and->i6[1]; 61397c478bd9Sstevel@tonic-gate dmask->i6[2] = and->i6[2]; 61407c478bd9Sstevel@tonic-gate dmask->i6[3] = and->i6[3]; 61417c478bd9Sstevel@tonic-gate } 61427c478bd9Sstevel@tonic-gate 61437c478bd9Sstevel@tonic-gate dst->i6[0] = src->i6[0] & and->i6[0]; 61447c478bd9Sstevel@tonic-gate dst->i6[1] = src->i6[1] & and->i6[1]; 61457c478bd9Sstevel@tonic-gate dst->i6[2] = src->i6[2] & and->i6[2]; 61467c478bd9Sstevel@tonic-gate dst->i6[3] = src->i6[3] & and->i6[3]; 61477c478bd9Sstevel@tonic-gate } else { 61487c478bd9Sstevel@tonic-gate dst->i6[0] = src->i6[0]; 61497c478bd9Sstevel@tonic-gate dst->i6[1] = src->i6[1]; 61507c478bd9Sstevel@tonic-gate dst->i6[2] = src->i6[2]; 61517c478bd9Sstevel@tonic-gate dst->i6[3] = src->i6[3]; 61527c478bd9Sstevel@tonic-gate } 61537c478bd9Sstevel@tonic-gate return 0; 61547c478bd9Sstevel@tonic-gate } 61557c478bd9Sstevel@tonic-gate #endif 61567c478bd9Sstevel@tonic-gate 61577c478bd9Sstevel@tonic-gate 61587c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 61597c478bd9Sstevel@tonic-gate /* Function: fr_matchtag */ 61607c478bd9Sstevel@tonic-gate /* Returns: 0 == mismatch, 1 == match. */ 61617c478bd9Sstevel@tonic-gate /* Parameters: tag1(I) - pointer to first tag to compare */ 61627c478bd9Sstevel@tonic-gate /* tag2(I) - pointer to second tag to compare */ 61637c478bd9Sstevel@tonic-gate /* */ 61647c478bd9Sstevel@tonic-gate /* Returns true (non-zero) or false(0) if the two tag structures can be */ 61657c478bd9Sstevel@tonic-gate /* considered to be a match or not match, respectively. The tag is 16 */ 61667c478bd9Sstevel@tonic-gate /* bytes long (16 characters) but that is overlayed with 4 32bit ints so */ 61677c478bd9Sstevel@tonic-gate /* compare the ints instead, for speed. tag1 is the master of the */ 61687c478bd9Sstevel@tonic-gate /* comparison. This function should only be called with both tag1 and tag2 */ 61697c478bd9Sstevel@tonic-gate /* as non-NULL pointers. */ 61707c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 61717c478bd9Sstevel@tonic-gate int fr_matchtag(tag1, tag2) 61727c478bd9Sstevel@tonic-gate ipftag_t *tag1, *tag2; 61737c478bd9Sstevel@tonic-gate { 61747c478bd9Sstevel@tonic-gate if (tag1 == tag2) 61757c478bd9Sstevel@tonic-gate return 1; 61767c478bd9Sstevel@tonic-gate 61777c478bd9Sstevel@tonic-gate if ((tag1->ipt_num[0] == 0) && (tag2->ipt_num[0] == 0)) 61787c478bd9Sstevel@tonic-gate return 1; 61797c478bd9Sstevel@tonic-gate 61807c478bd9Sstevel@tonic-gate if ((tag1->ipt_num[0] == tag2->ipt_num[0]) && 61817c478bd9Sstevel@tonic-gate (tag1->ipt_num[1] == tag2->ipt_num[1]) && 61827c478bd9Sstevel@tonic-gate (tag1->ipt_num[2] == tag2->ipt_num[2]) && 61837c478bd9Sstevel@tonic-gate (tag1->ipt_num[3] == tag2->ipt_num[3])) 61847c478bd9Sstevel@tonic-gate return 1; 61857c478bd9Sstevel@tonic-gate return 0; 61867c478bd9Sstevel@tonic-gate } 61877c478bd9Sstevel@tonic-gate 61887c478bd9Sstevel@tonic-gate 61897c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 6190ab25eeb5Syz /* Function: fr_coalesce */ 6191ab25eeb5Syz /* Returns: 1 == success, -1 == failure, 0 == no change */ 6192ab25eeb5Syz /* Parameters: fin(I) - pointer to packet information */ 61937c478bd9Sstevel@tonic-gate /* */ 6194ab25eeb5Syz /* Attempt to get all of the packet data into a single, contiguous buffer. */ 6195ab25eeb5Syz /* If this call returns a failure then the buffers have also been freed. */ 6196ab25eeb5Syz /* ------------------------------------------------------------------------ */ 6197ab25eeb5Syz int fr_coalesce(fin) 61987c478bd9Sstevel@tonic-gate fr_info_t *fin; 61997c478bd9Sstevel@tonic-gate { 6200f4b3ec61Sdh ipf_stack_t *ifs = fin->fin_ifs; 62017c478bd9Sstevel@tonic-gate if ((fin->fin_flx & FI_COALESCE) != 0) 6202ab25eeb5Syz return 1; 62037c478bd9Sstevel@tonic-gate 6204ab25eeb5Syz /* 6205ab25eeb5Syz * If the mbuf pointers indicate that there is no mbuf to work with, 6206ab25eeb5Syz * return but do not indicate success or failure. 6207ab25eeb5Syz */ 6208ab25eeb5Syz if (fin->fin_m == NULL || fin->fin_mp == NULL) 6209ab25eeb5Syz return 0; 62107c478bd9Sstevel@tonic-gate 6211ab25eeb5Syz #if defined(_KERNEL) 6212ab25eeb5Syz if (fr_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) { 6213cbded9aeSdr IPF_BUMP(ifs->ifs_fr_badcoalesces[fin->fin_out]); 62147c478bd9Sstevel@tonic-gate # ifdef MENTAT 6215ab25eeb5Syz FREE_MB_T(*fin->fin_mp); 6216ab25eeb5Syz # endif 6217ab25eeb5Syz *fin->fin_mp = NULL; 6218ab25eeb5Syz fin->fin_m = NULL; 6219ab25eeb5Syz return -1; 62207c478bd9Sstevel@tonic-gate } 6221ab25eeb5Syz #else 6222ab25eeb5Syz fin = fin; /* LINT */ 6223ab25eeb5Syz #endif 6224ab25eeb5Syz return 1; 62257c478bd9Sstevel@tonic-gate } 62267c478bd9Sstevel@tonic-gate 62277c478bd9Sstevel@tonic-gate 62287c478bd9Sstevel@tonic-gate /* 62297c478bd9Sstevel@tonic-gate * The following table lists all of the tunable variables that can be 6230f4b3ec61Sdh * accessed via SIOCIPFGET/SIOCIPFSET/SIOCIPFGETNEXT. The format of each row 62317c478bd9Sstevel@tonic-gate * in the table below is as follows: 62327c478bd9Sstevel@tonic-gate * 62337c478bd9Sstevel@tonic-gate * pointer to value, name of value, minimum, maximum, size of the value's 62347c478bd9Sstevel@tonic-gate * container, value attribute flags 62357c478bd9Sstevel@tonic-gate * 62367c478bd9Sstevel@tonic-gate * For convienience, IPFT_RDONLY means the value is read-only, IPFT_WRDISABLED 62377c478bd9Sstevel@tonic-gate * means the value can only be written to when IPFilter is loaded but disabled. 62387c478bd9Sstevel@tonic-gate * The obvious implication is if neither of these are set then the value can be 62397c478bd9Sstevel@tonic-gate * changed at any time without harm. 62407c478bd9Sstevel@tonic-gate */ 6241f4b3ec61Sdh ipftuneable_t lcl_ipf_tuneables[] = { 62427c478bd9Sstevel@tonic-gate /* filtering */ 6243f4b3ec61Sdh { { NULL }, "fr_flags", 0, 0xffffffff, 6244f4b3ec61Sdh 0, 0 }, 6245f4b3ec61Sdh { { NULL }, "fr_active", 0, 0, 6246f4b3ec61Sdh 0, IPFT_RDONLY }, 6247f4b3ec61Sdh { { NULL }, "fr_control_forwarding", 0, 1, 6248f4b3ec61Sdh 0, 0 }, 6249f4b3ec61Sdh { { NULL }, "fr_update_ipid", 0, 1, 6250f4b3ec61Sdh 0, 0 }, 6251f4b3ec61Sdh { { NULL }, "fr_chksrc", 0, 1, 6252f4b3ec61Sdh 0, 0 }, 6253f4b3ec61Sdh { { NULL }, "fr_minttl", 0, 1, 6254f4b3ec61Sdh 0, 0 }, 6255f4b3ec61Sdh { { NULL }, "fr_icmpminfragmtu", 0, 1, 6256f4b3ec61Sdh 0, 0 }, 6257f4b3ec61Sdh { { NULL }, "fr_pass", 0, 0xffffffff, 6258f4b3ec61Sdh 0, 0 }, 6259381a2a9aSdr #if SOLARIS2 >= 10 6260f4b3ec61Sdh { { NULL }, "ipf_loopback", 0, 1, 6261f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6262381a2a9aSdr #endif 62637c478bd9Sstevel@tonic-gate /* state */ 6264f4b3ec61Sdh { { NULL }, "fr_tcpidletimeout", 1, 0x7fffffff, 6265f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6266f4b3ec61Sdh { { NULL }, "fr_tcpclosewait", 1, 0x7fffffff, 6267f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6268f4b3ec61Sdh { { NULL }, "fr_tcplastack", 1, 0x7fffffff, 6269f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6270f4b3ec61Sdh { { NULL }, "fr_tcptimeout", 1, 0x7fffffff, 6271f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6272f4b3ec61Sdh { { NULL }, "fr_tcpclosed", 1, 0x7fffffff, 6273f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6274f4b3ec61Sdh { { NULL }, "fr_tcphalfclosed", 1, 0x7fffffff, 6275f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6276f4b3ec61Sdh { { NULL }, "fr_udptimeout", 1, 0x7fffffff, 6277f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6278f4b3ec61Sdh { { NULL }, "fr_udpacktimeout", 1, 0x7fffffff, 6279f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6280f4b3ec61Sdh { { NULL }, "fr_icmptimeout", 1, 0x7fffffff, 6281f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6282f4b3ec61Sdh { { NULL }, "fr_icmpacktimeout", 1, 0x7fffffff, 6283f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6284f4b3ec61Sdh { { NULL }, "fr_iptimeout", 1, 0x7fffffff, 6285f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6286f4b3ec61Sdh { { NULL }, "fr_statemax", 1, 0x7fffffff, 6287f4b3ec61Sdh 0, 0 }, 6288f4b3ec61Sdh { { NULL }, "fr_statesize", 1, 0x7fffffff, 6289f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6290f4b3ec61Sdh { { NULL }, "fr_state_lock", 0, 1, 6291f4b3ec61Sdh 0, IPFT_RDONLY }, 6292f4b3ec61Sdh { { NULL }, "fr_state_maxbucket", 1, 0x7fffffff, 6293f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6294f4b3ec61Sdh { { NULL }, "fr_state_maxbucket_reset", 0, 1, 6295f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6296f4b3ec61Sdh { { NULL }, "ipstate_logging", 0, 1, 6297f4b3ec61Sdh 0, 0 }, 6298ea8244dcSJohn Ojemann { { NULL }, "state_flush_level_hi", 1, 100, 6299ea8244dcSJohn Ojemann 0, 0 }, 6300ea8244dcSJohn Ojemann { { NULL }, "state_flush_level_lo", 1, 100, 6301ea8244dcSJohn Ojemann 0, 0 }, 63027c478bd9Sstevel@tonic-gate /* nat */ 6303f4b3ec61Sdh { { NULL }, "fr_nat_lock", 0, 1, 6304f4b3ec61Sdh 0, IPFT_RDONLY }, 6305f4b3ec61Sdh { { NULL }, "ipf_nattable_sz", 1, 0x7fffffff, 6306f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6307f4b3ec61Sdh { { NULL }, "ipf_nattable_max", 1, 0x7fffffff, 6308f4b3ec61Sdh 0, 0 }, 6309f4b3ec61Sdh { { NULL }, "ipf_natrules_sz", 1, 0x7fffffff, 6310f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6311f4b3ec61Sdh { { NULL }, "ipf_rdrrules_sz", 1, 0x7fffffff, 6312f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6313f4b3ec61Sdh { { NULL }, "ipf_hostmap_sz", 1, 0x7fffffff, 6314f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6315f4b3ec61Sdh { { NULL }, "fr_nat_maxbucket", 1, 0x7fffffff, 6316f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6317f4b3ec61Sdh { { NULL }, "fr_nat_maxbucket_reset", 0, 1, 6318f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6319f4b3ec61Sdh { { NULL }, "nat_logging", 0, 1, 6320f4b3ec61Sdh 0, 0 }, 6321f4b3ec61Sdh { { NULL }, "fr_defnatage", 1, 0x7fffffff, 6322f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6323f4b3ec61Sdh { { NULL }, "fr_defnatipage", 1, 0x7fffffff, 6324f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6325f4b3ec61Sdh { { NULL }, "fr_defnaticmpage", 1, 0x7fffffff, 6326f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6327ea8244dcSJohn Ojemann { { NULL }, "nat_flush_level_hi", 1, 100, 63283805c50fSan 0, 0 }, 6329ea8244dcSJohn Ojemann { { NULL }, "nat_flush_level_lo", 1, 100, 63303805c50fSan 0, 0 }, 63317c478bd9Sstevel@tonic-gate /* frag */ 6332f4b3ec61Sdh { { NULL }, "ipfr_size", 1, 0x7fffffff, 6333f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6334f4b3ec61Sdh { { NULL }, "fr_ipfrttl", 1, 0x7fffffff, 6335f4b3ec61Sdh 0, IPFT_WRDISABLED }, 63367c478bd9Sstevel@tonic-gate #ifdef IPFILTER_LOG 63377c478bd9Sstevel@tonic-gate /* log */ 6338f4b3ec61Sdh { { NULL }, "ipl_suppress", 0, 1, 6339f4b3ec61Sdh 0, 0 }, 6340f4b3ec61Sdh { { NULL }, "ipl_buffer_sz", 0, 0, 6341f4b3ec61Sdh 0, IPFT_RDONLY }, 6342f4b3ec61Sdh { { NULL }, "ipl_logmax", 0, 0x7fffffff, 6343f4b3ec61Sdh 0, IPFT_WRDISABLED }, 6344f4b3ec61Sdh { { NULL }, "ipl_logall", 0, 1, 6345f4b3ec61Sdh 0, 0 }, 6346f4b3ec61Sdh { { NULL }, "ipl_logsize", 0, 0x80000, 6347f4b3ec61Sdh 0, 0 }, 63487c478bd9Sstevel@tonic-gate #endif 63497c478bd9Sstevel@tonic-gate { { NULL }, NULL, 0, 0 } 63507c478bd9Sstevel@tonic-gate }; 63517c478bd9Sstevel@tonic-gate 6352f4b3ec61Sdh static ipftuneable_t * 6353f4b3ec61Sdh tune_lookup(ipf_stack_t *ifs, char *name) 6354f4b3ec61Sdh { 6355f4b3ec61Sdh int i; 6356ab25eeb5Syz 6357f4b3ec61Sdh for (i = 0; ifs->ifs_ipf_tuneables[i].ipft_name != NULL; i++) { 6358f4b3ec61Sdh if (strcmp(ifs->ifs_ipf_tuneables[i].ipft_name, name) == 0) 6359f4b3ec61Sdh return (&ifs->ifs_ipf_tuneables[i]); 6360f4b3ec61Sdh } 6361f4b3ec61Sdh return (NULL); 6362f4b3ec61Sdh } 6363f4b3ec61Sdh 6364f4b3ec61Sdh #ifdef _KERNEL 6365f4b3ec61Sdh extern dev_info_t *ipf_dev_info; 6366f4b3ec61Sdh extern int ipf_property_update __P((dev_info_t *, ipf_stack_t *)); 6367f4b3ec61Sdh #endif 63688128a42dSan 63698128a42dSan /* -------------------------------------------------------------------- */ 63708128a42dSan /* Function: ipftuneable_setdefs() */ 63718128a42dSan /* Returns: void */ 63728128a42dSan /* Parameters: ifs - pointer to newly allocated IPF instance */ 63738128a42dSan /* assigned to IP instance */ 63748128a42dSan /* */ 63758128a42dSan /* Function initializes IPF instance variables. Function is invoked */ 63768128a42dSan /* from ipftuneable_alloc(). ipftuneable_alloc() is called only one */ 63778128a42dSan /* time during IP instance lifetime - at the time of IP instance */ 63788128a42dSan /* creation. Anytime IP instance is being created new private IPF */ 63798128a42dSan /* instance is allocated and assigned to it. The moment of IP */ 63808128a42dSan /* instance creation is the right time to initialize those IPF */ 63818128a42dSan /* variables. */ 63828128a42dSan /* */ 63838128a42dSan /* -------------------------------------------------------------------- */ 63848128a42dSan static void ipftuneable_setdefs(ipf_stack_t *ifs) 63858128a42dSan { 63868128a42dSan ifs->ifs_ipfr_size = IPFT_SIZE; 63878128a42dSan ifs->ifs_fr_ipfrttl = 120; /* 60 seconds */ 63888128a42dSan 63898128a42dSan /* it comes from fr_authinit() in IPF auth */ 63908128a42dSan ifs->ifs_fr_authsize = FR_NUMAUTH; 63918128a42dSan ifs->ifs_fr_defaultauthage = 600; 63928128a42dSan 63938128a42dSan /* it comes from fr_stateinit() in IPF state */ 63948128a42dSan ifs->ifs_fr_tcpidletimeout = IPF_TTLVAL(3600 * 24 * 5); /* five days */ 63958128a42dSan ifs->ifs_fr_tcpclosewait = IPF_TTLVAL(TCP_MSL); 63968128a42dSan ifs->ifs_fr_tcplastack = IPF_TTLVAL(TCP_MSL); 63978128a42dSan ifs->ifs_fr_tcptimeout = IPF_TTLVAL(TCP_MSL); 63988128a42dSan ifs->ifs_fr_tcpclosed = IPF_TTLVAL(60); 63998128a42dSan ifs->ifs_fr_tcphalfclosed = IPF_TTLVAL(2 * 3600); /* 2 hours */ 64008128a42dSan ifs->ifs_fr_udptimeout = IPF_TTLVAL(120); 64018128a42dSan ifs->ifs_fr_udpacktimeout = IPF_TTLVAL(12); 64028128a42dSan ifs->ifs_fr_icmptimeout = IPF_TTLVAL(60); 64038128a42dSan ifs->ifs_fr_icmpacktimeout = IPF_TTLVAL(6); 64048128a42dSan ifs->ifs_fr_iptimeout = IPF_TTLVAL(60); 64058128a42dSan ifs->ifs_fr_statemax = IPSTATE_MAX; 64068128a42dSan ifs->ifs_fr_statesize = IPSTATE_SIZE; 64078128a42dSan ifs->ifs_fr_state_maxbucket_reset = 1; 6408ea8244dcSJohn Ojemann ifs->ifs_state_flush_level_hi = ST_FLUSH_HI; 6409ea8244dcSJohn Ojemann ifs->ifs_state_flush_level_lo = ST_FLUSH_LO; 64108128a42dSan 64118128a42dSan /* it comes from fr_natinit() in ipnat */ 64128128a42dSan ifs->ifs_ipf_nattable_sz = NAT_TABLE_SZ; 64138128a42dSan ifs->ifs_ipf_nattable_max = NAT_TABLE_MAX; 64148128a42dSan ifs->ifs_ipf_natrules_sz = NAT_SIZE; 64158128a42dSan ifs->ifs_ipf_rdrrules_sz = RDR_SIZE; 64168128a42dSan ifs->ifs_ipf_hostmap_sz = HOSTMAP_SIZE; 64178128a42dSan ifs->ifs_fr_nat_maxbucket_reset = 1; 64188128a42dSan ifs->ifs_fr_defnatage = DEF_NAT_AGE; 64198128a42dSan ifs->ifs_fr_defnatipage = 120; /* 60 seconds */ 64208128a42dSan ifs->ifs_fr_defnaticmpage = 6; /* 3 seconds */ 6421ea8244dcSJohn Ojemann ifs->ifs_nat_flush_level_hi = NAT_FLUSH_HI; 6422ea8244dcSJohn Ojemann ifs->ifs_nat_flush_level_lo = NAT_FLUSH_LO; 64238128a42dSan 64248128a42dSan #ifdef IPFILTER_LOG 64258128a42dSan /* it comes from fr_loginit() in IPF log */ 64268128a42dSan ifs->ifs_ipl_suppress = 1; 64278128a42dSan ifs->ifs_ipl_logmax = IPL_LOGMAX; 64288128a42dSan ifs->ifs_ipl_logsize = IPFILTER_LOGSIZE; 64298128a42dSan 64308128a42dSan /* from fr_natinit() */ 64318128a42dSan ifs->ifs_nat_logging = 1; 64328128a42dSan 64338128a42dSan /* from fr_stateinit() */ 64348128a42dSan ifs->ifs_ipstate_logging = 1; 64358128a42dSan #else 64368128a42dSan /* from fr_natinit() */ 64378128a42dSan ifs->ifs_nat_logging = 0; 64388128a42dSan 64398128a42dSan /* from fr_stateinit() */ 64408128a42dSan ifs->ifs_ipstate_logging = 0; 64418128a42dSan #endif 6442fd636508Szf ifs->ifs_ipf_loopback = 0; 64438128a42dSan 64448128a42dSan } 6445f4b3ec61Sdh /* 6446f4b3ec61Sdh * Allocate a per-stack tuneable and copy in the names. Then 6447f4b3ec61Sdh * set it to point to each of the per-stack tunables. 6448f4b3ec61Sdh */ 6449f4b3ec61Sdh void 6450f4b3ec61Sdh ipftuneable_alloc(ipf_stack_t *ifs) 6451f4b3ec61Sdh { 6452f4b3ec61Sdh ipftuneable_t *item; 6453f4b3ec61Sdh 6454f4b3ec61Sdh KMALLOCS(ifs->ifs_ipf_tuneables, ipftuneable_t *, 6455f4b3ec61Sdh sizeof (lcl_ipf_tuneables)); 6456f4b3ec61Sdh bcopy(lcl_ipf_tuneables, ifs->ifs_ipf_tuneables, 6457f4b3ec61Sdh sizeof (lcl_ipf_tuneables)); 6458f4b3ec61Sdh 6459f4b3ec61Sdh #define TUNE_SET(_ifs, _name, _field) \ 6460f4b3ec61Sdh item = tune_lookup((_ifs), (_name)); \ 6461f4b3ec61Sdh if (item != NULL) { \ 6462f4b3ec61Sdh item->ipft_una.ipftp_int = (unsigned int *)&((_ifs)->_field); \ 6463f4b3ec61Sdh item->ipft_sz = sizeof ((_ifs)->_field); \ 6464f4b3ec61Sdh } 6465f4b3ec61Sdh 6466f4b3ec61Sdh TUNE_SET(ifs, "fr_flags", ifs_fr_flags); 6467f4b3ec61Sdh TUNE_SET(ifs, "fr_active", ifs_fr_active); 6468f4b3ec61Sdh TUNE_SET(ifs, "fr_control_forwarding", ifs_fr_control_forwarding); 6469f4b3ec61Sdh TUNE_SET(ifs, "fr_update_ipid", ifs_fr_update_ipid); 6470f4b3ec61Sdh TUNE_SET(ifs, "fr_chksrc", ifs_fr_chksrc); 6471f4b3ec61Sdh TUNE_SET(ifs, "fr_minttl", ifs_fr_minttl); 6472f4b3ec61Sdh TUNE_SET(ifs, "fr_icmpminfragmtu", ifs_fr_icmpminfragmtu); 6473f4b3ec61Sdh TUNE_SET(ifs, "fr_pass", ifs_fr_pass); 6474f4b3ec61Sdh TUNE_SET(ifs, "fr_tcpidletimeout", ifs_fr_tcpidletimeout); 6475f4b3ec61Sdh TUNE_SET(ifs, "fr_tcpclosewait", ifs_fr_tcpclosewait); 6476f4b3ec61Sdh TUNE_SET(ifs, "fr_tcplastack", ifs_fr_tcplastack); 6477f4b3ec61Sdh TUNE_SET(ifs, "fr_tcptimeout", ifs_fr_tcptimeout); 6478f4b3ec61Sdh TUNE_SET(ifs, "fr_tcpclosed", ifs_fr_tcpclosed); 6479f4b3ec61Sdh TUNE_SET(ifs, "fr_tcphalfclosed", ifs_fr_tcphalfclosed); 6480f4b3ec61Sdh TUNE_SET(ifs, "fr_udptimeout", ifs_fr_udptimeout); 6481f4b3ec61Sdh TUNE_SET(ifs, "fr_udpacktimeout", ifs_fr_udpacktimeout); 6482f4b3ec61Sdh TUNE_SET(ifs, "fr_icmptimeout", ifs_fr_icmptimeout); 6483f4b3ec61Sdh TUNE_SET(ifs, "fr_icmpacktimeout", ifs_fr_icmpacktimeout); 6484f4b3ec61Sdh TUNE_SET(ifs, "fr_iptimeout", ifs_fr_iptimeout); 6485f4b3ec61Sdh TUNE_SET(ifs, "fr_statemax", ifs_fr_statemax); 6486f4b3ec61Sdh TUNE_SET(ifs, "fr_statesize", ifs_fr_statesize); 6487f4b3ec61Sdh TUNE_SET(ifs, "fr_state_lock", ifs_fr_state_lock); 6488f4b3ec61Sdh TUNE_SET(ifs, "fr_state_maxbucket", ifs_fr_state_maxbucket); 6489f4b3ec61Sdh TUNE_SET(ifs, "fr_state_maxbucket_reset", ifs_fr_state_maxbucket_reset); 6490f4b3ec61Sdh TUNE_SET(ifs, "ipstate_logging", ifs_ipstate_logging); 6491f4b3ec61Sdh TUNE_SET(ifs, "fr_nat_lock", ifs_fr_nat_lock); 6492f4b3ec61Sdh TUNE_SET(ifs, "ipf_nattable_sz", ifs_ipf_nattable_sz); 6493f4b3ec61Sdh TUNE_SET(ifs, "ipf_nattable_max", ifs_ipf_nattable_max); 6494f4b3ec61Sdh TUNE_SET(ifs, "ipf_natrules_sz", ifs_ipf_natrules_sz); 6495f4b3ec61Sdh TUNE_SET(ifs, "ipf_rdrrules_sz", ifs_ipf_rdrrules_sz); 6496f4b3ec61Sdh TUNE_SET(ifs, "ipf_hostmap_sz", ifs_ipf_hostmap_sz); 6497f4b3ec61Sdh TUNE_SET(ifs, "fr_nat_maxbucket", ifs_fr_nat_maxbucket); 6498f4b3ec61Sdh TUNE_SET(ifs, "fr_nat_maxbucket_reset", ifs_fr_nat_maxbucket_reset); 6499f4b3ec61Sdh TUNE_SET(ifs, "nat_logging", ifs_nat_logging); 6500f4b3ec61Sdh TUNE_SET(ifs, "fr_defnatage", ifs_fr_defnatage); 6501fd636508Szf TUNE_SET(ifs, "fr_defnatipage", ifs_fr_defnatipage); 6502f4b3ec61Sdh TUNE_SET(ifs, "fr_defnaticmpage", ifs_fr_defnaticmpage); 6503ea8244dcSJohn Ojemann TUNE_SET(ifs, "nat_flush_level_hi", ifs_nat_flush_level_hi); 6504ea8244dcSJohn Ojemann TUNE_SET(ifs, "nat_flush_level_lo", ifs_nat_flush_level_lo); 6505ea8244dcSJohn Ojemann TUNE_SET(ifs, "state_flush_level_hi", ifs_state_flush_level_hi); 6506ea8244dcSJohn Ojemann TUNE_SET(ifs, "state_flush_level_lo", ifs_state_flush_level_lo); 6507f4b3ec61Sdh TUNE_SET(ifs, "ipfr_size", ifs_ipfr_size); 6508f4b3ec61Sdh TUNE_SET(ifs, "fr_ipfrttl", ifs_fr_ipfrttl); 6509fd636508Szf TUNE_SET(ifs, "ipf_loopback", ifs_ipf_loopback); 6510f4b3ec61Sdh #ifdef IPFILTER_LOG 6511f4b3ec61Sdh TUNE_SET(ifs, "ipl_suppress", ifs_ipl_suppress); 6512f4b3ec61Sdh TUNE_SET(ifs, "ipl_buffer_sz", ifs_ipl_buffer_sz); 6513f4b3ec61Sdh TUNE_SET(ifs, "ipl_logmax", ifs_ipl_logmax); 6514f4b3ec61Sdh TUNE_SET(ifs, "ipl_logall", ifs_ipl_logall); 6515f4b3ec61Sdh TUNE_SET(ifs, "ipl_logsize", ifs_ipl_logsize); 6516f4b3ec61Sdh #endif 6517f4b3ec61Sdh #undef TUNE_SET 6518f4b3ec61Sdh 65198128a42dSan ipftuneable_setdefs(ifs); 65208128a42dSan 6521f4b3ec61Sdh #ifdef _KERNEL 6522f4b3ec61Sdh (void) ipf_property_update(ipf_dev_info, ifs); 6523f4b3ec61Sdh #endif 6524f4b3ec61Sdh } 6525f4b3ec61Sdh 6526f4b3ec61Sdh void 6527f4b3ec61Sdh ipftuneable_free(ipf_stack_t *ifs) 6528f4b3ec61Sdh { 6529f4b3ec61Sdh KFREES(ifs->ifs_ipf_tuneables, sizeof (lcl_ipf_tuneables)); 6530f4b3ec61Sdh ifs->ifs_ipf_tuneables = NULL; 6531f4b3ec61Sdh } 6532ab25eeb5Syz 6533ab25eeb5Syz /* ------------------------------------------------------------------------ */ 6534ab25eeb5Syz /* Function: fr_findtunebycookie */ 6535ab25eeb5Syz /* Returns: NULL = search failed, else pointer to tune struct */ 6536ab25eeb5Syz /* Parameters: cookie(I) - cookie value to search for amongst tuneables */ 6537ab25eeb5Syz /* next(O) - pointer to place to store the cookie for the */ 6538ab25eeb5Syz /* "next" tuneable, if it is desired. */ 6539ab25eeb5Syz /* */ 6540ab25eeb5Syz /* This function is used to walk through all of the existing tunables with */ 6541ab25eeb5Syz /* successive calls. It searches the known tunables for the one which has */ 6542ab25eeb5Syz /* a matching value for "cookie" - ie its address. When returning a match, */ 6543ab25eeb5Syz /* the next one to be found may be returned inside next. */ 6544ab25eeb5Syz /* ------------------------------------------------------------------------ */ 6545f4b3ec61Sdh static ipftuneable_t *fr_findtunebycookie(cookie, next, ifs) 6546ab25eeb5Syz void *cookie, **next; 6547f4b3ec61Sdh ipf_stack_t * ifs; 6548ab25eeb5Syz { 6549ab25eeb5Syz ipftuneable_t *ta, **tap; 6550ab25eeb5Syz 6551f4b3ec61Sdh for (ta = ifs->ifs_ipf_tuneables; ta->ipft_name != NULL; ta++) 6552ab25eeb5Syz if (ta == cookie) { 6553ab25eeb5Syz if (next != NULL) { 6554ab25eeb5Syz /* 6555ab25eeb5Syz * If the next entry in the array has a name 6556ab25eeb5Syz * present, then return a pointer to it for 6557ab25eeb5Syz * where to go next, else return a pointer to 6558ab25eeb5Syz * the dynaminc list as a key to search there 6559ab25eeb5Syz * next. This facilitates a weak linking of 6560ab25eeb5Syz * the two "lists" together. 6561ab25eeb5Syz */ 6562ab25eeb5Syz if ((ta + 1)->ipft_name != NULL) 6563ab25eeb5Syz *next = ta + 1; 6564ab25eeb5Syz else 6565f4b3ec61Sdh *next = &ifs->ifs_ipf_tunelist; 6566ab25eeb5Syz } 6567ab25eeb5Syz return ta; 6568ab25eeb5Syz } 6569ab25eeb5Syz 6570f4b3ec61Sdh for (tap = &ifs->ifs_ipf_tunelist; (ta = *tap) != NULL; tap = &ta->ipft_next) 6571ab25eeb5Syz if (tap == cookie) { 6572ab25eeb5Syz if (next != NULL) 6573ab25eeb5Syz *next = &ta->ipft_next; 6574ab25eeb5Syz return ta; 6575ab25eeb5Syz } 6576ab25eeb5Syz 6577ab25eeb5Syz if (next != NULL) 6578ab25eeb5Syz *next = NULL; 6579ab25eeb5Syz return NULL; 6580ab25eeb5Syz } 6581ab25eeb5Syz 6582ab25eeb5Syz 6583ab25eeb5Syz /* ------------------------------------------------------------------------ */ 6584ab25eeb5Syz /* Function: fr_findtunebyname */ 6585ab25eeb5Syz /* Returns: NULL = search failed, else pointer to tune struct */ 6586ab25eeb5Syz /* Parameters: name(I) - name of the tuneable entry to find. */ 6587ab25eeb5Syz /* */ 6588ab25eeb5Syz /* Search the static array of tuneables and the list of dynamic tuneables */ 6589ab25eeb5Syz /* for an entry with a matching name. If we can find one, return a pointer */ 6590ab25eeb5Syz /* to the matching structure. */ 6591ab25eeb5Syz /* ------------------------------------------------------------------------ */ 6592f4b3ec61Sdh static ipftuneable_t *fr_findtunebyname(name, ifs) 6593ab25eeb5Syz const char *name; 6594f4b3ec61Sdh ipf_stack_t *ifs; 6595ab25eeb5Syz { 6596ab25eeb5Syz ipftuneable_t *ta; 6597ab25eeb5Syz 6598f4b3ec61Sdh for (ta = ifs->ifs_ipf_tuneables; ta->ipft_name != NULL; ta++) 6599ab25eeb5Syz if (!strcmp(ta->ipft_name, name)) { 6600ab25eeb5Syz return ta; 6601ab25eeb5Syz } 6602ab25eeb5Syz 6603f4b3ec61Sdh for (ta = ifs->ifs_ipf_tunelist; ta != NULL; ta = ta->ipft_next) 6604ab25eeb5Syz if (!strcmp(ta->ipft_name, name)) { 6605ab25eeb5Syz return ta; 6606ab25eeb5Syz } 6607ab25eeb5Syz 6608ab25eeb5Syz return NULL; 6609ab25eeb5Syz } 6610ab25eeb5Syz 6611ab25eeb5Syz 6612ab25eeb5Syz /* ------------------------------------------------------------------------ */ 6613ab25eeb5Syz /* Function: fr_addipftune */ 6614ab25eeb5Syz /* Returns: int - 0 == success, else failure */ 6615ab25eeb5Syz /* Parameters: newtune - pointer to new tune struct to add to tuneables */ 6616ab25eeb5Syz /* */ 6617ab25eeb5Syz /* Appends the tune structure pointer to by "newtune" to the end of the */ 6618ab25eeb5Syz /* current list of "dynamic" tuneable parameters. Once added, the owner */ 6619ab25eeb5Syz /* of the object is not expected to ever change "ipft_next". */ 6620ab25eeb5Syz /* ------------------------------------------------------------------------ */ 6621f4b3ec61Sdh int fr_addipftune(newtune, ifs) 6622ab25eeb5Syz ipftuneable_t *newtune; 6623f4b3ec61Sdh ipf_stack_t *ifs; 6624ab25eeb5Syz { 6625ab25eeb5Syz ipftuneable_t *ta, **tap; 6626ab25eeb5Syz 6627f4b3ec61Sdh ta = fr_findtunebyname(newtune->ipft_name, ifs); 6628ab25eeb5Syz if (ta != NULL) 6629ab25eeb5Syz return EEXIST; 6630ab25eeb5Syz 6631f4b3ec61Sdh for (tap = &ifs->ifs_ipf_tunelist; *tap != NULL; tap = &(*tap)->ipft_next) 6632ab25eeb5Syz ; 6633ab25eeb5Syz 6634ab25eeb5Syz newtune->ipft_next = NULL; 6635ab25eeb5Syz *tap = newtune; 6636ab25eeb5Syz return 0; 6637ab25eeb5Syz } 6638ab25eeb5Syz 6639ab25eeb5Syz 6640ab25eeb5Syz /* ------------------------------------------------------------------------ */ 6641ab25eeb5Syz /* Function: fr_delipftune */ 6642ab25eeb5Syz /* Returns: int - 0 == success, else failure */ 6643ab25eeb5Syz /* Parameters: oldtune - pointer to tune struct to remove from the list of */ 6644ab25eeb5Syz /* current dynamic tuneables */ 6645ab25eeb5Syz /* */ 6646ab25eeb5Syz /* Search for the tune structure, by pointer, in the list of those that are */ 6647ab25eeb5Syz /* dynamically added at run time. If found, adjust the list so that this */ 6648ab25eeb5Syz /* structure is no longer part of it. */ 6649ab25eeb5Syz /* ------------------------------------------------------------------------ */ 6650f4b3ec61Sdh int fr_delipftune(oldtune, ifs) 6651ab25eeb5Syz ipftuneable_t *oldtune; 6652f4b3ec61Sdh ipf_stack_t *ifs; 6653ab25eeb5Syz { 6654ab25eeb5Syz ipftuneable_t *ta, **tap; 6655ab25eeb5Syz 6656f4b3ec61Sdh for (tap = &ifs->ifs_ipf_tunelist; (ta = *tap) != NULL; tap = &ta->ipft_next) 6657ab25eeb5Syz if (ta == oldtune) { 6658ab25eeb5Syz *tap = oldtune->ipft_next; 6659ab25eeb5Syz oldtune->ipft_next = NULL; 6660ab25eeb5Syz return 0; 6661ab25eeb5Syz } 6662ab25eeb5Syz 6663ab25eeb5Syz return ESRCH; 6664ab25eeb5Syz } 6665ab25eeb5Syz 66667c478bd9Sstevel@tonic-gate 66677c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 66687c478bd9Sstevel@tonic-gate /* Function: fr_ipftune */ 66697c478bd9Sstevel@tonic-gate /* Returns: int - 0 == success, else failure */ 66707c478bd9Sstevel@tonic-gate /* Parameters: cmd(I) - ioctl command number */ 66717c478bd9Sstevel@tonic-gate /* data(I) - pointer to ioctl data structure */ 66727c478bd9Sstevel@tonic-gate /* */ 66737c478bd9Sstevel@tonic-gate /* Implement handling of SIOCIPFGETNEXT, SIOCIPFGET and SIOCIPFSET. These */ 66747c478bd9Sstevel@tonic-gate /* three ioctls provide the means to access and control global variables */ 66757c478bd9Sstevel@tonic-gate /* within IPFilter, allowing (for example) timeouts and table sizes to be */ 66767c478bd9Sstevel@tonic-gate /* changed without rebooting, reloading or recompiling. The initialisation */ 66777c478bd9Sstevel@tonic-gate /* and 'destruction' routines of the various components of ipfilter are all */ 66787c478bd9Sstevel@tonic-gate /* each responsible for handling their own values being too big. */ 66797c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------ */ 6680f4b3ec61Sdh int fr_ipftune(cmd, data, ifs) 6681ab25eeb5Syz ioctlcmd_t cmd; 6682ab25eeb5Syz void *data; 6683f4b3ec61Sdh ipf_stack_t *ifs; 66847c478bd9Sstevel@tonic-gate { 66857c478bd9Sstevel@tonic-gate ipftuneable_t *ta; 66867c478bd9Sstevel@tonic-gate ipftune_t tu; 66877c478bd9Sstevel@tonic-gate void *cookie; 66887c478bd9Sstevel@tonic-gate int error; 66897c478bd9Sstevel@tonic-gate 66907c478bd9Sstevel@tonic-gate error = fr_inobj(data, &tu, IPFOBJ_TUNEABLE); 66917c478bd9Sstevel@tonic-gate if (error != 0) 66927c478bd9Sstevel@tonic-gate return error; 66937c478bd9Sstevel@tonic-gate 66947c478bd9Sstevel@tonic-gate tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0'; 66957c478bd9Sstevel@tonic-gate cookie = tu.ipft_cookie; 6696ab25eeb5Syz ta = NULL; 66977c478bd9Sstevel@tonic-gate 66987c478bd9Sstevel@tonic-gate switch (cmd) 66997c478bd9Sstevel@tonic-gate { 67007c478bd9Sstevel@tonic-gate case SIOCIPFGETNEXT : 67017c478bd9Sstevel@tonic-gate /* 67027c478bd9Sstevel@tonic-gate * If cookie is non-NULL, assume it to be a pointer to the last 67037c478bd9Sstevel@tonic-gate * entry we looked at, so find it (if possible) and return a 67047c478bd9Sstevel@tonic-gate * pointer to the next one after it. The last entry in the 67057c478bd9Sstevel@tonic-gate * the table is a NULL entry, so when we get to it, set cookie 67067c478bd9Sstevel@tonic-gate * to NULL and return that, indicating end of list, erstwhile 67077c478bd9Sstevel@tonic-gate * if we come in with cookie set to NULL, we are starting anew 67087c478bd9Sstevel@tonic-gate * at the front of the list. 67097c478bd9Sstevel@tonic-gate */ 67107c478bd9Sstevel@tonic-gate if (cookie != NULL) { 6711f4b3ec61Sdh ta = fr_findtunebycookie(cookie, &tu.ipft_cookie, ifs); 6712ab25eeb5Syz } else { 6713f4b3ec61Sdh ta = ifs->ifs_ipf_tuneables; 6714ab25eeb5Syz tu.ipft_cookie = ta + 1; 67157c478bd9Sstevel@tonic-gate } 67167c478bd9Sstevel@tonic-gate if (ta != NULL) { 67177c478bd9Sstevel@tonic-gate /* 67187c478bd9Sstevel@tonic-gate * Entry found, but does the data pointed to by that 67197c478bd9Sstevel@tonic-gate * row fit in what we can return? 67207c478bd9Sstevel@tonic-gate */ 67217c478bd9Sstevel@tonic-gate if (ta->ipft_sz > sizeof(tu.ipft_un)) 67227c478bd9Sstevel@tonic-gate return EINVAL; 67237c478bd9Sstevel@tonic-gate 67247c478bd9Sstevel@tonic-gate tu.ipft_vlong = 0; 67257c478bd9Sstevel@tonic-gate if (ta->ipft_sz == sizeof(u_long)) 67267c478bd9Sstevel@tonic-gate tu.ipft_vlong = *ta->ipft_plong; 67277c478bd9Sstevel@tonic-gate else if (ta->ipft_sz == sizeof(u_int)) 67287c478bd9Sstevel@tonic-gate tu.ipft_vint = *ta->ipft_pint; 67297c478bd9Sstevel@tonic-gate else if (ta->ipft_sz == sizeof(u_short)) 67307c478bd9Sstevel@tonic-gate tu.ipft_vshort = *ta->ipft_pshort; 67317c478bd9Sstevel@tonic-gate else if (ta->ipft_sz == sizeof(u_char)) 67327c478bd9Sstevel@tonic-gate tu.ipft_vchar = *ta->ipft_pchar; 67337c478bd9Sstevel@tonic-gate 67347c478bd9Sstevel@tonic-gate tu.ipft_sz = ta->ipft_sz; 67357c478bd9Sstevel@tonic-gate tu.ipft_min = ta->ipft_min; 67367c478bd9Sstevel@tonic-gate tu.ipft_max = ta->ipft_max; 67377c478bd9Sstevel@tonic-gate tu.ipft_flags = ta->ipft_flags; 67387c478bd9Sstevel@tonic-gate bcopy(ta->ipft_name, tu.ipft_name, 67397c478bd9Sstevel@tonic-gate MIN(sizeof(tu.ipft_name), 67407c478bd9Sstevel@tonic-gate strlen(ta->ipft_name) + 1)); 67417c478bd9Sstevel@tonic-gate } 67427c478bd9Sstevel@tonic-gate error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE); 6743ab25eeb5Syz break; 67447c478bd9Sstevel@tonic-gate 67457c478bd9Sstevel@tonic-gate case SIOCIPFGET : 67467c478bd9Sstevel@tonic-gate case SIOCIPFSET : 67477c478bd9Sstevel@tonic-gate /* 67487c478bd9Sstevel@tonic-gate * Search by name or by cookie value for a particular entry 67497c478bd9Sstevel@tonic-gate * in the tuning paramter table. 67507c478bd9Sstevel@tonic-gate */ 6751ab25eeb5Syz error = ESRCH; 67527c478bd9Sstevel@tonic-gate if (cookie != NULL) { 6753f4b3ec61Sdh ta = fr_findtunebycookie(cookie, NULL, ifs); 6754ab25eeb5Syz if (ta != NULL) 6755ab25eeb5Syz error = 0; 67567c478bd9Sstevel@tonic-gate } else if (tu.ipft_name[0] != '\0') { 6757f4b3ec61Sdh ta = fr_findtunebyname(tu.ipft_name, ifs); 6758ab25eeb5Syz if (ta != NULL) 6759ab25eeb5Syz error = 0; 6760ab25eeb5Syz } 6761ab25eeb5Syz if (error != 0) 6762ab25eeb5Syz break; 67637c478bd9Sstevel@tonic-gate 6764ab25eeb5Syz if (cmd == (ioctlcmd_t)SIOCIPFGET) { 67657c478bd9Sstevel@tonic-gate /* 67667c478bd9Sstevel@tonic-gate * Fetch the tuning parameters for a particular value 67677c478bd9Sstevel@tonic-gate */ 67687c478bd9Sstevel@tonic-gate tu.ipft_vlong = 0; 67697c478bd9Sstevel@tonic-gate if (ta->ipft_sz == sizeof(u_long)) 67707c478bd9Sstevel@tonic-gate tu.ipft_vlong = *ta->ipft_plong; 67717c478bd9Sstevel@tonic-gate else if (ta->ipft_sz == sizeof(u_int)) 67727c478bd9Sstevel@tonic-gate tu.ipft_vint = *ta->ipft_pint; 67737c478bd9Sstevel@tonic-gate else if (ta->ipft_sz == sizeof(u_short)) 67747c478bd9Sstevel@tonic-gate tu.ipft_vshort = *ta->ipft_pshort; 67757c478bd9Sstevel@tonic-gate else if (ta->ipft_sz == sizeof(u_char)) 67767c478bd9Sstevel@tonic-gate tu.ipft_vchar = *ta->ipft_pchar; 6777ab25eeb5Syz tu.ipft_cookie = ta; 67787c478bd9Sstevel@tonic-gate tu.ipft_sz = ta->ipft_sz; 67797c478bd9Sstevel@tonic-gate tu.ipft_min = ta->ipft_min; 67807c478bd9Sstevel@tonic-gate tu.ipft_max = ta->ipft_max; 67817c478bd9Sstevel@tonic-gate tu.ipft_flags = ta->ipft_flags; 67827c478bd9Sstevel@tonic-gate error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE); 6783ab25eeb5Syz 6784ab25eeb5Syz } else if (cmd == (ioctlcmd_t)SIOCIPFSET) { 67857c478bd9Sstevel@tonic-gate /* 67867c478bd9Sstevel@tonic-gate * Set an internal parameter. The hard part here is 67877c478bd9Sstevel@tonic-gate * getting the new value safely and correctly out of 67887c478bd9Sstevel@tonic-gate * the kernel (given we only know its size, not type.) 67897c478bd9Sstevel@tonic-gate */ 67907c478bd9Sstevel@tonic-gate u_long in; 67917c478bd9Sstevel@tonic-gate 67927c478bd9Sstevel@tonic-gate if (((ta->ipft_flags & IPFT_WRDISABLED) != 0) && 6793f4b3ec61Sdh (ifs->ifs_fr_running > 0)) { 6794ab25eeb5Syz error = EBUSY; 6795ab25eeb5Syz break; 6796ab25eeb5Syz } 67977c478bd9Sstevel@tonic-gate 67987c478bd9Sstevel@tonic-gate in = tu.ipft_vlong; 6799ab25eeb5Syz if (in < ta->ipft_min || in > ta->ipft_max) { 6800ab25eeb5Syz error = EINVAL; 6801ab25eeb5Syz break; 6802ab25eeb5Syz } 68037c478bd9Sstevel@tonic-gate 68047c478bd9Sstevel@tonic-gate if (ta->ipft_sz == sizeof(u_long)) { 68057c478bd9Sstevel@tonic-gate tu.ipft_vlong = *ta->ipft_plong; 68067c478bd9Sstevel@tonic-gate *ta->ipft_plong = in; 68077c478bd9Sstevel@tonic-gate } else if (ta->ipft_sz == sizeof(u_int)) { 68087c478bd9Sstevel@tonic-gate tu.ipft_vint = *ta->ipft_pint; 68097c478bd9Sstevel@tonic-gate *ta->ipft_pint = (u_int)(in & 0xffffffff); 68107c478bd9Sstevel@tonic-gate } else if (ta->ipft_sz == sizeof(u_short)) { 68117c478bd9Sstevel@tonic-gate tu.ipft_vshort = *ta->ipft_pshort; 68127c478bd9Sstevel@tonic-gate *ta->ipft_pshort = (u_short)(in & 0xffff); 68137c478bd9Sstevel@tonic-gate } else if (ta->ipft_sz == sizeof(u_char)) { 68147c478bd9Sstevel@tonic-gate tu.ipft_vchar = *ta->ipft_pchar; 68157c478bd9Sstevel@tonic-gate *ta->ipft_pchar = (u_char)(in & 0xff); 68167c478bd9Sstevel@tonic-gate } 68177c478bd9Sstevel@tonic-gate error = fr_outobj(data, &tu, IPFOBJ_TUNEABLE); 68187c478bd9Sstevel@tonic-gate } 6819ab25eeb5Syz break; 6820ab25eeb5Syz 68217c478bd9Sstevel@tonic-gate default : 6822ab25eeb5Syz error = EINVAL; 68237c478bd9Sstevel@tonic-gate break; 68247c478bd9Sstevel@tonic-gate } 68257c478bd9Sstevel@tonic-gate 6826ab25eeb5Syz return error; 6827ab25eeb5Syz } 6828ab25eeb5Syz 6829ab25eeb5Syz 6830ab25eeb5Syz /* ------------------------------------------------------------------------ */ 6831ab25eeb5Syz /* Function: fr_initialise */ 6832ab25eeb5Syz /* Returns: int - 0 == success, < 0 == failure */ 6833ab25eeb5Syz /* Parameters: None. */ 6834ab25eeb5Syz /* */ 6835ab25eeb5Syz /* Call of the initialise functions for all the various subsystems inside */ 6836ab25eeb5Syz /* of IPFilter. If any of them should fail, return immeadiately a failure */ 6837ab25eeb5Syz /* BUT do not try to recover from the error here. */ 6838ab25eeb5Syz /* ------------------------------------------------------------------------ */ 6839f4b3ec61Sdh int fr_initialise(ifs) 6840f4b3ec61Sdh ipf_stack_t *ifs; 6841ab25eeb5Syz { 6842ab25eeb5Syz int i; 6843ab25eeb5Syz 6844ab25eeb5Syz #ifdef IPFILTER_LOG 6845f4b3ec61Sdh i = fr_loginit(ifs); 6846ab25eeb5Syz if (i < 0) 6847ab25eeb5Syz return -10 + i; 6848ab25eeb5Syz #endif 6849f4b3ec61Sdh i = fr_natinit(ifs); 6850ab25eeb5Syz if (i < 0) 6851ab25eeb5Syz return -20 + i; 6852ab25eeb5Syz 6853f4b3ec61Sdh i = fr_stateinit(ifs); 6854ab25eeb5Syz if (i < 0) 6855ab25eeb5Syz return -30 + i; 6856ab25eeb5Syz 6857f4b3ec61Sdh i = fr_authinit(ifs); 6858ab25eeb5Syz if (i < 0) 6859ab25eeb5Syz return -40 + i; 6860ab25eeb5Syz 6861f4b3ec61Sdh i = fr_fraginit(ifs); 6862ab25eeb5Syz if (i < 0) 6863ab25eeb5Syz return -50 + i; 6864ab25eeb5Syz 6865f4b3ec61Sdh i = appr_init(ifs); 6866ab25eeb5Syz if (i < 0) 6867ab25eeb5Syz return -60 + i; 6868ab25eeb5Syz 6869ab25eeb5Syz #ifdef IPFILTER_SYNC 6870f4b3ec61Sdh i = ipfsync_init(ifs); 6871ab25eeb5Syz if (i < 0) 6872ab25eeb5Syz return -70 + i; 6873ab25eeb5Syz #endif 6874ab25eeb5Syz #ifdef IPFILTER_SCAN 6875f4b3ec61Sdh i = ipsc_init(ifs); 6876ab25eeb5Syz if (i < 0) 6877ab25eeb5Syz return -80 + i; 6878ab25eeb5Syz #endif 6879ab25eeb5Syz #ifdef IPFILTER_LOOKUP 6880f4b3ec61Sdh i = ip_lookup_init(ifs); 6881ab25eeb5Syz if (i < 0) 6882ab25eeb5Syz return -90 + i; 6883ab25eeb5Syz #endif 6884ab25eeb5Syz #ifdef IPFILTER_COMPILED 6885f4b3ec61Sdh ipfrule_add(ifs); 6886ab25eeb5Syz #endif 6887ab25eeb5Syz return 0; 6888ab25eeb5Syz } 6889ab25eeb5Syz 6890ab25eeb5Syz 6891ab25eeb5Syz /* ------------------------------------------------------------------------ */ 6892ab25eeb5Syz /* Function: fr_deinitialise */ 6893ab25eeb5Syz /* Returns: None. */ 6894ab25eeb5Syz /* Parameters: None. */ 6895ab25eeb5Syz /* */ 6896ab25eeb5Syz /* Call all the various subsystem cleanup routines to deallocate memory or */ 6897ab25eeb5Syz /* destroy locks or whatever they've done that they need to now undo. */ 6898ab25eeb5Syz /* The order here IS important as there are some cross references of */ 6899ab25eeb5Syz /* internal data structures. */ 6900ab25eeb5Syz /* ------------------------------------------------------------------------ */ 6901f4b3ec61Sdh void fr_deinitialise(ifs) 6902f4b3ec61Sdh ipf_stack_t *ifs; 6903ab25eeb5Syz { 6904f4b3ec61Sdh fr_fragunload(ifs); 6905f4b3ec61Sdh fr_authunload(ifs); 6906f4b3ec61Sdh fr_natunload(ifs); 6907f4b3ec61Sdh fr_stateunload(ifs); 6908ab25eeb5Syz #ifdef IPFILTER_SCAN 6909f4b3ec61Sdh fr_scanunload(ifs); 6910ab25eeb5Syz #endif 6911f4b3ec61Sdh appr_unload(ifs); 6912ab25eeb5Syz 6913ab25eeb5Syz #ifdef IPFILTER_COMPILED 6914f4b3ec61Sdh ipfrule_remove(ifs); 6915ab25eeb5Syz #endif 6916ab25eeb5Syz 6917f4b3ec61Sdh (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE, ifs); 6918f4b3ec61Sdh (void) frflush(IPL_LOGIPF, 0, FR_INQUE|FR_OUTQUE, ifs); 6919f4b3ec61Sdh (void) frflush(IPL_LOGCOUNT, 0, FR_INQUE|FR_OUTQUE|FR_INACTIVE, ifs); 6920f4b3ec61Sdh (void) frflush(IPL_LOGCOUNT, 0, FR_INQUE|FR_OUTQUE, ifs); 6921ab25eeb5Syz 6922ab25eeb5Syz #ifdef IPFILTER_LOOKUP 6923f4b3ec61Sdh ip_lookup_unload(ifs); 6924ab25eeb5Syz #endif 6925ab25eeb5Syz 6926ab25eeb5Syz #ifdef IPFILTER_LOG 6927f4b3ec61Sdh fr_logunload(ifs); 6928ab25eeb5Syz #endif 6929ab25eeb5Syz } 6930ab25eeb5Syz 6931ab25eeb5Syz 6932ab25eeb5Syz /* ------------------------------------------------------------------------ */ 6933ab25eeb5Syz /* Function: fr_zerostats */ 6934ab25eeb5Syz /* Returns: int - 0 = success, else failure */ 6935ab25eeb5Syz /* Parameters: data(O) - pointer to pointer for copying data back to */ 6936ab25eeb5Syz /* */ 6937ab25eeb5Syz /* Copies the current statistics out to userspace and then zero's the */ 6938ab25eeb5Syz /* current ones in the kernel. The lock is only held across the bzero() as */ 6939ab25eeb5Syz /* the copyout may result in paging (ie network activity.) */ 6940ab25eeb5Syz /* ------------------------------------------------------------------------ */ 6941f4b3ec61Sdh int fr_zerostats(data, ifs) 6942ab25eeb5Syz caddr_t data; 6943f4b3ec61Sdh ipf_stack_t *ifs; 6944ab25eeb5Syz { 6945ab25eeb5Syz friostat_t fio; 6946ab25eeb5Syz int error; 6947ab25eeb5Syz 6948f4b3ec61Sdh fr_getstat(&fio, ifs); 6949ab25eeb5Syz error = copyoutptr(&fio, data, sizeof(fio)); 6950ab25eeb5Syz if (error) 6951ab25eeb5Syz return EFAULT; 6952ab25eeb5Syz 6953f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_mutex); 6954f4b3ec61Sdh bzero((char *)ifs->ifs_frstats, sizeof(*ifs->ifs_frstats) * 2); 6955f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 6956ab25eeb5Syz 6957ab25eeb5Syz return 0; 6958ab25eeb5Syz } 6959ab25eeb5Syz 6960ab25eeb5Syz 6961ab25eeb5Syz #ifdef _KERNEL 6962ab25eeb5Syz /* ------------------------------------------------------------------------ */ 6963ab25eeb5Syz /* Function: fr_resolvedest */ 6964ab25eeb5Syz /* Returns: Nil */ 6965ab25eeb5Syz /* Parameters: fdp(IO) - pointer to destination information to resolve */ 6966ab25eeb5Syz /* v(I) - IP protocol version to match */ 6967ab25eeb5Syz /* */ 6968ab25eeb5Syz /* Looks up an interface name in the frdest structure pointed to by fdp and */ 6969ab25eeb5Syz /* if a matching name can be found for the particular IP protocol version */ 6970ab25eeb5Syz /* then store the interface pointer in the frdest struct. If no match is */ 6971ab25eeb5Syz /* found, then set the interface pointer to be -1 as NULL is considered to */ 6972ab25eeb5Syz /* indicate there is no information at all in the structure. */ 6973ab25eeb5Syz /* ------------------------------------------------------------------------ */ 6974f4b3ec61Sdh void fr_resolvedest(fdp, v, ifs) 6975ab25eeb5Syz frdest_t *fdp; 6976ab25eeb5Syz int v; 6977f4b3ec61Sdh ipf_stack_t *ifs; 6978ab25eeb5Syz { 6979381a2a9aSdr fdp->fd_ifp = NULL; 6980ab25eeb5Syz 6981381a2a9aSdr if (*fdp->fd_ifname != '\0') { 6982f4b3ec61Sdh fdp->fd_ifp = GETIFP(fdp->fd_ifname, v, ifs); 6983381a2a9aSdr if (fdp->fd_ifp == NULL) 6984381a2a9aSdr fdp->fd_ifp = (void *)-1; 6985ab25eeb5Syz } 6986ab25eeb5Syz } 6987ab25eeb5Syz #endif /* _KERNEL */ 6988ab25eeb5Syz 6989ab25eeb5Syz 6990ab25eeb5Syz /* ------------------------------------------------------------------------ */ 6991ab25eeb5Syz /* Function: fr_resolvenic */ 6992ab25eeb5Syz /* Returns: void* - NULL = wildcard name, -1 = failed to find NIC, else */ 6993ab25eeb5Syz /* pointer to interface structure for NIC */ 6994ab25eeb5Syz /* Parameters: name(I) - complete interface name */ 6995ab25eeb5Syz /* v(I) - IP protocol version */ 6996ab25eeb5Syz /* */ 6997ab25eeb5Syz /* Look for a network interface structure that firstly has a matching name */ 6998ab25eeb5Syz /* to that passed in and that is also being used for that IP protocol */ 6999ab25eeb5Syz /* version (necessary on some platforms where there are separate listings */ 7000ab25eeb5Syz /* for both IPv4 and IPv6 on the same physical NIC. */ 7001ab25eeb5Syz /* */ 7002ab25eeb5Syz /* One might wonder why name gets terminated with a \0 byte in here. The */ 7003ab25eeb5Syz /* reason is an interface name could get into the kernel structures of ipf */ 7004ab25eeb5Syz /* in any number of ways and so long as they all use the same sized array */ 7005ab25eeb5Syz /* to put the name in, it makes sense to ensure it gets null terminated */ 7006ab25eeb5Syz /* before it is used for its intended purpose - finding its match in the */ 7007ab25eeb5Syz /* kernel's list of configured interfaces. */ 7008ab25eeb5Syz /* */ 7009ab25eeb5Syz /* NOTE: This SHOULD ONLY be used with IPFilter structures that have an */ 7010ab25eeb5Syz /* array for the name that is LIFNAMSIZ bytes (at least) in length. */ 7011ab25eeb5Syz /* ------------------------------------------------------------------------ */ 7012f4b3ec61Sdh void *fr_resolvenic(name, v, ifs) 7013ab25eeb5Syz char *name; 7014ab25eeb5Syz int v; 7015f4b3ec61Sdh ipf_stack_t *ifs; 7016ab25eeb5Syz { 7017ab25eeb5Syz void *nic; 7018ab25eeb5Syz 7019ab25eeb5Syz if (name[0] == '\0') 7020ab25eeb5Syz return NULL; 7021ab25eeb5Syz 7022ab25eeb5Syz if ((name[1] == '\0') && ((name[0] == '-') || (name[0] == '*'))) { 7023ab25eeb5Syz return NULL; 7024ab25eeb5Syz } 7025ab25eeb5Syz 7026ab25eeb5Syz name[LIFNAMSIZ - 1] = '\0'; 7027ab25eeb5Syz 7028f4b3ec61Sdh nic = GETIFP(name, v, ifs); 7029ab25eeb5Syz if (nic == NULL) 7030ab25eeb5Syz nic = (void *)-1; 7031ab25eeb5Syz return nic; 70327c478bd9Sstevel@tonic-gate } 7033f4b3ec61Sdh 703490b0a856Sjojemann 703590b0a856Sjojemann /* ------------------------------------------------------------------------ */ 703690b0a856Sjojemann /* Function: ipf_expiretokens */ 703790b0a856Sjojemann /* Returns: None. */ 703890b0a856Sjojemann /* Parameters: ifs - ipf stack instance */ 703990b0a856Sjojemann /* */ 704090b0a856Sjojemann /* This function is run every ipf tick to see if there are any tokens that */ 704190b0a856Sjojemann /* have been held for too long and need to be freed up. */ 704290b0a856Sjojemann /* ------------------------------------------------------------------------ */ 7043f4b3ec61Sdh void ipf_expiretokens(ifs) 7044f4b3ec61Sdh ipf_stack_t *ifs; 7045f4b3ec61Sdh { 7046f4b3ec61Sdh ipftoken_t *it; 7047f4b3ec61Sdh 7048f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_tokens); 7049f4b3ec61Sdh while ((it = ifs->ifs_ipftokenhead) != NULL) { 7050f4b3ec61Sdh if (it->ipt_die > ifs->ifs_fr_ticks) 7051f4b3ec61Sdh break; 7052f4b3ec61Sdh 7053f4b3ec61Sdh ipf_freetoken(it, ifs); 7054f4b3ec61Sdh } 7055f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_tokens); 7056f4b3ec61Sdh } 7057f4b3ec61Sdh 7058f4b3ec61Sdh 705990b0a856Sjojemann /* ------------------------------------------------------------------------ */ 706090b0a856Sjojemann /* Function: ipf_deltoken */ 706190b0a856Sjojemann /* Returns: int - 0 = success, else error */ 706290b0a856Sjojemann /* Parameters: type(I) - the token type to match */ 706390b0a856Sjojemann /* uid(I) - uid owning the token */ 706490b0a856Sjojemann /* ptr(I) - context pointer for the token */ 706590b0a856Sjojemann /* ifs - ipf stack instance */ 706690b0a856Sjojemann /* */ 706790b0a856Sjojemann /* This function looks for a a token in the current list that matches up */ 706890b0a856Sjojemann /* the fields (type, uid, ptr). If none is found, ESRCH is returned, else */ 706990b0a856Sjojemann /* call ipf_freetoken() to remove it from the list. */ 707090b0a856Sjojemann /* ------------------------------------------------------------------------ */ 7071f4b3ec61Sdh int ipf_deltoken(type, uid, ptr, ifs) 7072f4b3ec61Sdh int type, uid; 7073f4b3ec61Sdh void *ptr; 7074f4b3ec61Sdh ipf_stack_t *ifs; 7075f4b3ec61Sdh { 7076f4b3ec61Sdh ipftoken_t *it; 7077f4b3ec61Sdh int error = ESRCH; 7078f4b3ec61Sdh 7079f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_tokens); 7080f4b3ec61Sdh for (it = ifs->ifs_ipftokenhead; it != NULL; it = it->ipt_next) 7081f4b3ec61Sdh if (ptr == it->ipt_ctx && type == it->ipt_type && 7082f4b3ec61Sdh uid == it->ipt_uid) { 7083f4b3ec61Sdh ipf_freetoken(it, ifs); 7084f4b3ec61Sdh error = 0; 7085f4b3ec61Sdh break; 7086f4b3ec61Sdh } 7087f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_tokens); 7088f4b3ec61Sdh 7089f4b3ec61Sdh return error; 7090f4b3ec61Sdh } 7091f4b3ec61Sdh 709290b0a856Sjojemann 709390b0a856Sjojemann /* ------------------------------------------------------------------------ */ 709490b0a856Sjojemann /* Function: ipf_unlinktoken */ 709590b0a856Sjojemann /* Returns: None. */ 709690b0a856Sjojemann /* Parameters: token(I) - pointer to token structure */ 709790b0a856Sjojemann /* ifs - ipf stack instance */ 709890b0a856Sjojemann /* */ 709990b0a856Sjojemann /* This function unlinks a token structure from the linked list of tokens */ 710090b0a856Sjojemann /* that it belongs to. The head pointer never needs to be explicitly */ 710190b0a856Sjojemann /* adjusted, but the tail does due to the linked list implementation. */ 710290b0a856Sjojemann /* ------------------------------------------------------------------------ */ 7103786c7074Sjojemann static void ipf_unlinktoken(token, ifs) 7104f4b3ec61Sdh ipftoken_t *token; 7105f4b3ec61Sdh ipf_stack_t *ifs; 7106f4b3ec61Sdh { 7107f4b3ec61Sdh 7108f4b3ec61Sdh if (ifs->ifs_ipftokentail == &token->ipt_next) 7109f4b3ec61Sdh ifs->ifs_ipftokentail = token->ipt_pnext; 7110f4b3ec61Sdh 7111f4b3ec61Sdh *token->ipt_pnext = token->ipt_next; 7112f4b3ec61Sdh if (token->ipt_next != NULL) 7113f4b3ec61Sdh token->ipt_next->ipt_pnext = token->ipt_pnext; 7114f4b3ec61Sdh } 7115f4b3ec61Sdh 7116f4b3ec61Sdh 711790b0a856Sjojemann /* ------------------------------------------------------------------------ */ 711890b0a856Sjojemann /* Function: ipf_findtoken */ 711990b0a856Sjojemann /* Returns: ipftoken_t * - NULL if no memory, else pointer to token */ 712090b0a856Sjojemann /* Parameters: type(I) - the token type to match */ 712190b0a856Sjojemann /* uid(I) - uid owning the token */ 712290b0a856Sjojemann /* ptr(I) - context pointer for the token */ 712390b0a856Sjojemann /* ifs - ipf stack instance */ 712490b0a856Sjojemann /* */ 712590b0a856Sjojemann /* This function looks for a live token in the list of current tokens that */ 712690b0a856Sjojemann /* matches the tuple (type, uid, ptr). If one cannot be found then one is */ 712790b0a856Sjojemann /* allocated. If one is found then it is moved to the top of the list of */ 712890b0a856Sjojemann /* currently active tokens. */ 712990b0a856Sjojemann /* */ 713090b0a856Sjojemann /* NOTE: It is by design that this function returns holding a read lock on */ 713190b0a856Sjojemann /* ipf_tokens. Callers must make sure they release it! */ 713290b0a856Sjojemann /* ------------------------------------------------------------------------ */ 7133f4b3ec61Sdh ipftoken_t *ipf_findtoken(type, uid, ptr, ifs) 7134f4b3ec61Sdh int type, uid; 7135f4b3ec61Sdh void *ptr; 7136f4b3ec61Sdh ipf_stack_t *ifs; 7137f4b3ec61Sdh { 7138f4b3ec61Sdh ipftoken_t *it, *new; 7139f4b3ec61Sdh 7140f4b3ec61Sdh KMALLOC(new, ipftoken_t *); 7141f4b3ec61Sdh 7142f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_tokens); 7143f4b3ec61Sdh for (it = ifs->ifs_ipftokenhead; it != NULL; it = it->ipt_next) { 7144f4b3ec61Sdh if (it->ipt_alive == 0) 7145f4b3ec61Sdh continue; 7146f4b3ec61Sdh if (ptr == it->ipt_ctx && type == it->ipt_type && 7147f4b3ec61Sdh uid == it->ipt_uid) 7148f4b3ec61Sdh break; 7149f4b3ec61Sdh } 7150f4b3ec61Sdh 7151f4b3ec61Sdh if (it == NULL) { 7152f4b3ec61Sdh it = new; 7153f4b3ec61Sdh new = NULL; 7154f4b3ec61Sdh if (it == NULL) 7155f4b3ec61Sdh return NULL; 7156f4b3ec61Sdh it->ipt_data = NULL; 7157f4b3ec61Sdh it->ipt_ctx = ptr; 7158f4b3ec61Sdh it->ipt_uid = uid; 7159f4b3ec61Sdh it->ipt_type = type; 7160f4b3ec61Sdh it->ipt_next = NULL; 7161f4b3ec61Sdh it->ipt_alive = 1; 7162f4b3ec61Sdh } else { 7163f4b3ec61Sdh if (new != NULL) { 7164f4b3ec61Sdh KFREE(new); 7165f4b3ec61Sdh new = NULL; 7166f4b3ec61Sdh } 7167f4b3ec61Sdh 7168f4b3ec61Sdh ipf_unlinktoken(it, ifs); 7169f4b3ec61Sdh } 7170f4b3ec61Sdh it->ipt_pnext = ifs->ifs_ipftokentail; 7171f4b3ec61Sdh *ifs->ifs_ipftokentail = it; 7172f4b3ec61Sdh ifs->ifs_ipftokentail = &it->ipt_next; 7173f4b3ec61Sdh it->ipt_next = NULL; 7174f4b3ec61Sdh 7175f4b3ec61Sdh it->ipt_die = ifs->ifs_fr_ticks + 2; 7176f4b3ec61Sdh 7177f4b3ec61Sdh MUTEX_DOWNGRADE(&ifs->ifs_ipf_tokens); 7178f4b3ec61Sdh 7179f4b3ec61Sdh return it; 7180f4b3ec61Sdh } 7181f4b3ec61Sdh 7182f4b3ec61Sdh 718390b0a856Sjojemann /* ------------------------------------------------------------------------ */ 718490b0a856Sjojemann /* Function: ipf_freetoken */ 718590b0a856Sjojemann /* Returns: None. */ 718690b0a856Sjojemann /* Parameters: token(I) - pointer to token structure */ 718790b0a856Sjojemann /* ifs - ipf stack instance */ 718890b0a856Sjojemann /* */ 718990b0a856Sjojemann /* This function unlinks a token from the linked list and on the path to */ 719090b0a856Sjojemann /* free'ing the data, it calls the dereference function that is associated */ 719190b0a856Sjojemann /* with the type of data pointed to by the token as it is considered to */ 719290b0a856Sjojemann /* hold a reference to it. */ 719390b0a856Sjojemann /* ------------------------------------------------------------------------ */ 7194f4b3ec61Sdh void ipf_freetoken(token, ifs) 7195f4b3ec61Sdh ipftoken_t *token; 7196f4b3ec61Sdh ipf_stack_t *ifs; 7197f4b3ec61Sdh { 719890b0a856Sjojemann void *data, **datap; 7199f4b3ec61Sdh 7200f4b3ec61Sdh ipf_unlinktoken(token, ifs); 7201f4b3ec61Sdh 7202f4b3ec61Sdh data = token->ipt_data; 720390b0a856Sjojemann datap = &data; 7204f4b3ec61Sdh 7205f4b3ec61Sdh if ((data != NULL) && (data != (void *)-1)) { 7206f4b3ec61Sdh switch (token->ipt_type) 7207f4b3ec61Sdh { 7208f4b3ec61Sdh case IPFGENITER_IPF : 720990b0a856Sjojemann (void)fr_derefrule((frentry_t **)datap, ifs); 7210f4b3ec61Sdh break; 7211f4b3ec61Sdh case IPFGENITER_IPNAT : 7212f4b3ec61Sdh WRITE_ENTER(&ifs->ifs_ipf_nat); 721390b0a856Sjojemann fr_ipnatderef((ipnat_t **)datap, ifs); 7214f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_nat); 7215f4b3ec61Sdh break; 7216f4b3ec61Sdh case IPFGENITER_NAT : 721790b0a856Sjojemann fr_natderef((nat_t **)datap, ifs); 7218f4b3ec61Sdh break; 7219f4b3ec61Sdh case IPFGENITER_STATE : 722090b0a856Sjojemann fr_statederef((ipstate_t **)datap, ifs); 7221f4b3ec61Sdh break; 7222f4b3ec61Sdh case IPFGENITER_FRAG : 722390b0a856Sjojemann fr_fragderef((ipfr_t **)datap, &ifs->ifs_ipf_frag, ifs); 7224f4b3ec61Sdh break; 7225f4b3ec61Sdh case IPFGENITER_NATFRAG : 722690b0a856Sjojemann fr_fragderef((ipfr_t **)datap, 722790b0a856Sjojemann &ifs->ifs_ipf_natfrag, ifs); 7228f4b3ec61Sdh break; 7229f4b3ec61Sdh case IPFGENITER_HOSTMAP : 723090b0a856Sjojemann WRITE_ENTER(&ifs->ifs_ipf_nat); 723190b0a856Sjojemann fr_hostmapdel((hostmap_t **)datap); 723290b0a856Sjojemann RWLOCK_EXIT(&ifs->ifs_ipf_nat); 7233f4b3ec61Sdh break; 7234f4b3ec61Sdh default : 7235f4b3ec61Sdh (void) ip_lookup_iterderef(token->ipt_type, data, ifs); 7236f4b3ec61Sdh break; 7237f4b3ec61Sdh } 7238f4b3ec61Sdh } 7239f4b3ec61Sdh 7240f4b3ec61Sdh KFREE(token); 7241f4b3ec61Sdh } 7242f4b3ec61Sdh 724390b0a856Sjojemann 724490b0a856Sjojemann /* ------------------------------------------------------------------------ */ 724590b0a856Sjojemann /* Function: ipf_getnextrule */ 724690b0a856Sjojemann /* Returns: int - 0 = success, else error */ 724790b0a856Sjojemann /* Parameters: t(I) - pointer to destination information to resolve */ 724890b0a856Sjojemann /* ptr(I) - pointer to ipfobj_t to copyin from user space */ 724990b0a856Sjojemann /* ifs - ipf stack instance */ 725090b0a856Sjojemann /* */ 725190b0a856Sjojemann /* This function's first job is to bring in the ipfruleiter_t structure via */ 725290b0a856Sjojemann /* the ipfobj_t structure to determine what should be the next rule to */ 725390b0a856Sjojemann /* return. Once the ipfruleiter_t has been brought in, it then tries to */ 725490b0a856Sjojemann /* find the 'next rule'. This may include searching rule group lists or */ 725590b0a856Sjojemann /* just be as simple as looking at the 'next' field in the rule structure. */ 725690b0a856Sjojemann /* When we have found the rule to return, increase its reference count and */ 725790b0a856Sjojemann /* if we used an existing rule to get here, decrease its reference count. */ 725890b0a856Sjojemann /* ------------------------------------------------------------------------ */ 725990b0a856Sjojemann int ipf_getnextrule(t, ptr, ifs) 726090b0a856Sjojemann ipftoken_t *t; 726190b0a856Sjojemann void *ptr; 726290b0a856Sjojemann ipf_stack_t *ifs; 7263f4b3ec61Sdh { 7264f4b3ec61Sdh frentry_t *fr, *next, zero; 726590b0a856Sjojemann int error, out, count; 7266f4b3ec61Sdh ipfruleiter_t it; 7267f4b3ec61Sdh frgroup_t *fg; 726890b0a856Sjojemann char *dst; 7269f4b3ec61Sdh 7270f4b3ec61Sdh if (t == NULL || ptr == NULL) 7271f4b3ec61Sdh return EFAULT; 7272f4b3ec61Sdh error = fr_inobj(ptr, &it, IPFOBJ_IPFITER); 7273f4b3ec61Sdh if (error != 0) 7274f4b3ec61Sdh return error; 7275f4b3ec61Sdh if ((it.iri_ver != AF_INET) && (it.iri_ver != AF_INET6)) 7276f4b3ec61Sdh return EINVAL; 727790b0a856Sjojemann if ((it.iri_inout < 0) || (it.iri_inout > 3)) 727890b0a856Sjojemann return EINVAL; 727990b0a856Sjojemann if (it.iri_nrules == 0) 7280f4b3ec61Sdh return EINVAL; 7281f4b3ec61Sdh if ((it.iri_active != 0) && (it.iri_active != 1)) 7282f4b3ec61Sdh return EINVAL; 7283f4b3ec61Sdh if (it.iri_rule == NULL) 7284f4b3ec61Sdh return EFAULT; 7285f4b3ec61Sdh 728690b0a856Sjojemann /* 728790b0a856Sjojemann * Use bitmask on it.iri_inout to determine direction. 728890b0a856Sjojemann * F_OUT (1) and F_ACOUT (3) mask to out = 1, while 728990b0a856Sjojemann * F_IN (0) and F_ACIN (2) mask to out = 0. 729090b0a856Sjojemann */ 729190b0a856Sjojemann out = it.iri_inout & F_OUT; 7292f4b3ec61Sdh READ_ENTER(&ifs->ifs_ipf_mutex); 7293786c7074Sjojemann 7294786c7074Sjojemann /* 7295786c7074Sjojemann * Retrieve "previous" entry from token and find the next entry. 7296786c7074Sjojemann */ 7297786c7074Sjojemann fr = t->ipt_data; 7298f4b3ec61Sdh if (fr == NULL) { 7299f4b3ec61Sdh if (*it.iri_group == '\0') { 730090b0a856Sjojemann /* 730190b0a856Sjojemann * Use bitmask again to determine accounting or not. 730290b0a856Sjojemann * F_ACIN will mask to accounting cases F_ACIN (2) 730390b0a856Sjojemann * or F_ACOUT (3), but not F_IN or F_OUT. 730490b0a856Sjojemann */ 730590b0a856Sjojemann if ((it.iri_inout & F_ACIN) != 0) { 730690b0a856Sjojemann if (it.iri_ver == AF_INET) 730790b0a856Sjojemann next = ifs->ifs_ipacct 730890b0a856Sjojemann [out][it.iri_active]; 730990b0a856Sjojemann else 731090b0a856Sjojemann next = ifs->ifs_ipacct6 731190b0a856Sjojemann [out][it.iri_active]; 731290b0a856Sjojemann } else { 731390b0a856Sjojemann if (it.iri_ver == AF_INET) 731490b0a856Sjojemann next = ifs->ifs_ipfilter 731590b0a856Sjojemann [out][it.iri_active]; 731690b0a856Sjojemann else 731790b0a856Sjojemann next = ifs->ifs_ipfilter6 731890b0a856Sjojemann [out][it.iri_active]; 731990b0a856Sjojemann } 7320f4b3ec61Sdh } else { 7321f4b3ec61Sdh fg = fr_findgroup(it.iri_group, IPL_LOGIPF, 7322f4b3ec61Sdh it.iri_active, NULL, ifs); 7323f4b3ec61Sdh if (fg != NULL) 7324f4b3ec61Sdh next = fg->fg_start; 7325f4b3ec61Sdh else 7326f4b3ec61Sdh next = NULL; 7327f4b3ec61Sdh } 7328f4b3ec61Sdh } else { 7329f4b3ec61Sdh next = fr->fr_next; 7330f4b3ec61Sdh } 7331f4b3ec61Sdh 733290b0a856Sjojemann dst = (char *)it.iri_rule; 733390b0a856Sjojemann /* 733490b0a856Sjojemann * The ipfruleiter may ask for more than 1 rule at a time to be 733590b0a856Sjojemann * copied out, so long as that many exist in the list to start with! 733690b0a856Sjojemann */ 733790b0a856Sjojemann for (count = it.iri_nrules; count > 0; count--) { 7338786c7074Sjojemann /* 7339786c7074Sjojemann * If we found an entry, add reference to it and update token. 7340786c7074Sjojemann * Otherwise, zero out data to be returned and NULL out token. 7341786c7074Sjojemann */ 734290b0a856Sjojemann if (next != NULL) { 7343f4b3ec61Sdh MUTEX_ENTER(&next->fr_lock); 7344f4b3ec61Sdh next->fr_ref++; 7345f4b3ec61Sdh MUTEX_EXIT(&next->fr_lock); 7346966f126dSzf t->ipt_data = next; 734790b0a856Sjojemann } else { 734890b0a856Sjojemann bzero(&zero, sizeof(zero)); 734990b0a856Sjojemann next = &zero; 735090b0a856Sjojemann t->ipt_data = NULL; 735190b0a856Sjojemann } 7352786c7074Sjojemann 7353786c7074Sjojemann /* 7354786c7074Sjojemann * Now that we have ref, it's save to give up lock. 7355786c7074Sjojemann */ 735690b0a856Sjojemann RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 735790b0a856Sjojemann 7358786c7074Sjojemann /* 7359786c7074Sjojemann * Copy out data and clean up references and token as needed. 7360786c7074Sjojemann */ 736190b0a856Sjojemann error = COPYOUT(next, dst, sizeof(*next)); 7362f4b3ec61Sdh if (error != 0) 7363786c7074Sjojemann error = EFAULT; 7364786c7074Sjojemann if (t->ipt_data == NULL) { 7365786c7074Sjojemann ipf_freetoken(t, ifs); 7366786c7074Sjojemann break; 7367786c7074Sjojemann } else { 7368786c7074Sjojemann if (fr != NULL) 7369786c7074Sjojemann (void) fr_derefrule(&fr, ifs); 7370786c7074Sjojemann if (next->fr_data != NULL) { 7371786c7074Sjojemann dst += sizeof(*next); 7372786c7074Sjojemann error = COPYOUT(next->fr_data, dst, 7373786c7074Sjojemann next->fr_dsize); 7374786c7074Sjojemann if (error != 0) 7375786c7074Sjojemann error = EFAULT; 7376786c7074Sjojemann else 7377786c7074Sjojemann dst += next->fr_dsize; 7378786c7074Sjojemann } 7379786c7074Sjojemann if (next->fr_next == NULL) { 7380786c7074Sjojemann ipf_freetoken(t, ifs); 7381786c7074Sjojemann break; 7382786c7074Sjojemann } 738390b0a856Sjojemann } 738490b0a856Sjojemann 738590b0a856Sjojemann if ((count == 1) || (error != 0)) 738690b0a856Sjojemann break; 7387f4b3ec61Sdh 738890b0a856Sjojemann READ_ENTER(&ifs->ifs_ipf_mutex); 738990b0a856Sjojemann fr = next; 739090b0a856Sjojemann next = fr->fr_next; 739190b0a856Sjojemann } 7392786c7074Sjojemann 7393f4b3ec61Sdh return error; 7394f4b3ec61Sdh } 7395f4b3ec61Sdh 7396f4b3ec61Sdh 739790b0a856Sjojemann /* ------------------------------------------------------------------------ */ 739890b0a856Sjojemann /* Function: fr_frruleiter */ 739990b0a856Sjojemann /* Returns: int - 0 = success, else error */ 740090b0a856Sjojemann /* Parameters: data(I) - the token type to match */ 740190b0a856Sjojemann /* uid(I) - uid owning the token */ 740290b0a856Sjojemann /* ptr(I) - context pointer for the token */ 740390b0a856Sjojemann /* ifs - ipf stack instance */ 740490b0a856Sjojemann /* */ 740590b0a856Sjojemann /* This function serves as a stepping stone between fr_ipf_ioctl and */ 740690b0a856Sjojemann /* ipf_getnextrule. It's role is to find the right token in the kernel for */ 740790b0a856Sjojemann /* the process doing the ioctl and use that to ask for the next rule. */ 740890b0a856Sjojemann /* ------------------------------------------------------------------------ */ 7409f4b3ec61Sdh int ipf_frruleiter(data, uid, ctx, ifs) 7410f4b3ec61Sdh void *data, *ctx; 7411f4b3ec61Sdh int uid; 7412f4b3ec61Sdh ipf_stack_t *ifs; 7413f4b3ec61Sdh { 7414f4b3ec61Sdh ipftoken_t *token; 7415f4b3ec61Sdh int error; 7416f4b3ec61Sdh 7417f4b3ec61Sdh token = ipf_findtoken(IPFGENITER_IPF, uid, ctx, ifs); 7418f4b3ec61Sdh if (token != NULL) 7419f4b3ec61Sdh error = ipf_getnextrule(token, data, ifs); 7420f4b3ec61Sdh else 7421f4b3ec61Sdh error = EFAULT; 7422f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_tokens); 7423f4b3ec61Sdh 7424f4b3ec61Sdh return error; 7425f4b3ec61Sdh } 7426f4b3ec61Sdh 7427f4b3ec61Sdh 742890b0a856Sjojemann /* ------------------------------------------------------------------------ */ 742990b0a856Sjojemann /* Function: ipf_geniter */ 743090b0a856Sjojemann /* Returns: int - 0 = success, else error */ 743190b0a856Sjojemann /* Parameters: token(I) - pointer to ipftoken structure */ 743290b0a856Sjojemann /* itp(I) - pointer to ipfgeniter structure */ 743390b0a856Sjojemann /* ifs - ipf stack instance */ 743490b0a856Sjojemann /* */ 743590b0a856Sjojemann /* Generic iterator called from ipf_genericiter. Currently only used for */ 743690b0a856Sjojemann /* walking through list of fragments. */ 743790b0a856Sjojemann /* ------------------------------------------------------------------------ */ 7438f4b3ec61Sdh int ipf_geniter(token, itp, ifs) 7439f4b3ec61Sdh ipftoken_t *token; 7440f4b3ec61Sdh ipfgeniter_t *itp; 7441f4b3ec61Sdh ipf_stack_t *ifs; 7442f4b3ec61Sdh { 7443f4b3ec61Sdh int error; 7444f4b3ec61Sdh 7445f4b3ec61Sdh switch (itp->igi_type) 7446f4b3ec61Sdh { 7447f4b3ec61Sdh case IPFGENITER_FRAG : 7448f4b3ec61Sdh error = fr_nextfrag(token, itp, &ifs->ifs_ipfr_list, 744990b0a856Sjojemann &ifs->ifs_ipfr_tail, &ifs->ifs_ipf_frag, 745090b0a856Sjojemann ifs); 7451f4b3ec61Sdh break; 7452f4b3ec61Sdh default : 7453f4b3ec61Sdh error = EINVAL; 7454f4b3ec61Sdh break; 7455f4b3ec61Sdh } 7456f4b3ec61Sdh 7457f4b3ec61Sdh return error; 7458f4b3ec61Sdh } 7459f4b3ec61Sdh 7460f4b3ec61Sdh 746190b0a856Sjojemann /* ------------------------------------------------------------------------ */ 746290b0a856Sjojemann /* Function: ipf_genericiter */ 746390b0a856Sjojemann /* Returns: int - 0 = success, else error */ 746490b0a856Sjojemann /* Parameters: data(I) - the token type to match */ 746590b0a856Sjojemann /* uid(I) - uid owning the token */ 746690b0a856Sjojemann /* ptr(I) - context pointer for the token */ 746790b0a856Sjojemann /* ifs - ipf stack instance */ 746890b0a856Sjojemann /* */ 746990b0a856Sjojemann /* This function serves as a stepping stone between fr_ipf_ioctl and */ 747090b0a856Sjojemann /* ipf_geniter when handling SIOCGENITER. It's role is to find the right */ 747190b0a856Sjojemann /* token in the kernel for the process using the ioctl, and to use that */ 747290b0a856Sjojemann /* token when calling ipf_geniter. */ 747390b0a856Sjojemann /* ------------------------------------------------------------------------ */ 7474f4b3ec61Sdh int ipf_genericiter(data, uid, ctx, ifs) 7475f4b3ec61Sdh void *data, *ctx; 7476f4b3ec61Sdh int uid; 7477f4b3ec61Sdh ipf_stack_t *ifs; 7478f4b3ec61Sdh { 7479f4b3ec61Sdh ipftoken_t *token; 7480f4b3ec61Sdh ipfgeniter_t iter; 7481f4b3ec61Sdh int error; 7482f4b3ec61Sdh 7483f4b3ec61Sdh error = fr_inobj(data, &iter, IPFOBJ_GENITER); 7484f4b3ec61Sdh if (error != 0) 7485f4b3ec61Sdh return error; 7486f4b3ec61Sdh 7487f4b3ec61Sdh token = ipf_findtoken(iter.igi_type, uid, ctx, ifs); 7488f4b3ec61Sdh if (token != NULL) { 7489f4b3ec61Sdh token->ipt_subtype = iter.igi_type; 7490f4b3ec61Sdh error = ipf_geniter(token, &iter, ifs); 7491f4b3ec61Sdh } else 7492f4b3ec61Sdh error = EFAULT; 7493f4b3ec61Sdh RWLOCK_EXIT(&ifs->ifs_ipf_tokens); 7494f4b3ec61Sdh 7495f4b3ec61Sdh return error; 7496f4b3ec61Sdh } 7497ea8244dcSJohn Ojemann 7498ea8244dcSJohn Ojemann 7499ea8244dcSJohn Ojemann /* --------------------------------------------------------------------- */ 7500ea8244dcSJohn Ojemann /* Function: ipf_earlydrop */ 7501ea8244dcSJohn Ojemann /* Returns: number of dropped/removed entries from the queue */ 7502ea8244dcSJohn Ojemann /* Parameters: flushtype - which table we're cleaning (NAT or State) */ 7503ea8244dcSJohn Ojemann /* ifq - pointer to queue with entries to be deleted */ 7504ea8244dcSJohn Ojemann /* idletime - entry must be idle this long to be deleted */ 7505ea8244dcSJohn Ojemann /* ifs - ipf stack instance */ 7506ea8244dcSJohn Ojemann /* */ 7507ea8244dcSJohn Ojemann /* Function is invoked from state/NAT flush routines to remove entries */ 7508ea8244dcSJohn Ojemann /* from specified timeout queue, based on how long they've sat idle, */ 7509ea8244dcSJohn Ojemann /* without waiting for it to happen on its own. */ 7510ea8244dcSJohn Ojemann /* --------------------------------------------------------------------- */ 7511ea8244dcSJohn Ojemann int ipf_earlydrop(flushtype, ifq, idletime, ifs) 7512ea8244dcSJohn Ojemann int flushtype; 7513ea8244dcSJohn Ojemann ipftq_t *ifq; 7514ea8244dcSJohn Ojemann int idletime; 7515ea8244dcSJohn Ojemann ipf_stack_t *ifs; 7516ea8244dcSJohn Ojemann { 7517ea8244dcSJohn Ojemann ipftqent_t *tqe, *tqn; 7518ea8244dcSJohn Ojemann unsigned int dropped; 7519ea8244dcSJohn Ojemann int droptick; 7520ea8244dcSJohn Ojemann void *ent; 7521ea8244dcSJohn Ojemann 7522ea8244dcSJohn Ojemann if (ifq == NULL) 7523ea8244dcSJohn Ojemann return (0); 7524ea8244dcSJohn Ojemann 7525ea8244dcSJohn Ojemann dropped = 0; 7526ea8244dcSJohn Ojemann 7527ea8244dcSJohn Ojemann /* 7528ea8244dcSJohn Ojemann * Determine the tick representing the idle time we're interested 7529ea8244dcSJohn Ojemann * in. If an entry exists in the queue, and it was touched before 7530ea8244dcSJohn Ojemann * that tick, then it's been idle longer than idletime, so it should 7531ea8244dcSJohn Ojemann * be deleted. 7532ea8244dcSJohn Ojemann */ 7533ea8244dcSJohn Ojemann droptick = ifs->ifs_fr_ticks - idletime; 7534ea8244dcSJohn Ojemann tqn = ifq->ifq_head; 7535ea8244dcSJohn Ojemann while ((tqe = tqn) != NULL && tqe->tqe_touched < droptick) { 7536ea8244dcSJohn Ojemann tqn = tqe->tqe_next; 7537ea8244dcSJohn Ojemann ent = tqe->tqe_parent; 7538ea8244dcSJohn Ojemann switch (flushtype) 7539ea8244dcSJohn Ojemann { 7540ea8244dcSJohn Ojemann case NAT_FLUSH: 7541ea8244dcSJohn Ojemann if (nat_delete((nat_t *)ent, NL_FLUSH, ifs) == 0) 7542ea8244dcSJohn Ojemann dropped++; 7543ea8244dcSJohn Ojemann break; 7544ea8244dcSJohn Ojemann case STATE_FLUSH: 7545ea8244dcSJohn Ojemann if (fr_delstate((ipstate_t *)ent, ISL_FLUSH, ifs) == 0) 7546ea8244dcSJohn Ojemann dropped++; 7547ea8244dcSJohn Ojemann break; 7548ea8244dcSJohn Ojemann default: 7549ea8244dcSJohn Ojemann return (0); 7550ea8244dcSJohn Ojemann } 7551ea8244dcSJohn Ojemann } 7552ea8244dcSJohn Ojemann return (dropped); 7553ea8244dcSJohn Ojemann } 7554ea8244dcSJohn Ojemann 7555ea8244dcSJohn Ojemann 7556ea8244dcSJohn Ojemann /* --------------------------------------------------------------------- */ 7557ea8244dcSJohn Ojemann /* Function: ipf_flushclosing */ 7558ea8244dcSJohn Ojemann /* Returns: int - number of entries deleted */ 7559ea8244dcSJohn Ojemann /* Parameters: flushtype - which table we're cleaning (NAT or State) */ 7560ea8244dcSJohn Ojemann /* stateval - TCP state at which to start removing entries */ 7561ea8244dcSJohn Ojemann /* ipfqs - pointer to timeout queues */ 7562ea8244dcSJohn Ojemann /* userqs - pointer to user defined queues */ 7563ea8244dcSJohn Ojemann /* ifs - ipf stack instance */ 7564ea8244dcSJohn Ojemann /* */ 7565ea8244dcSJohn Ojemann /* Remove state/NAT table entries for TCP connections which are in the */ 7566ea8244dcSJohn Ojemann /* process of closing, and have at least reached the state specified by */ 7567ea8244dcSJohn Ojemann /* the 'stateval' parameter. */ 7568ea8244dcSJohn Ojemann /* --------------------------------------------------------------------- */ 7569ea8244dcSJohn Ojemann int ipf_flushclosing(flushtype, stateval, ipfqs, userqs, ifs) 7570ea8244dcSJohn Ojemann int flushtype, stateval; 7571ea8244dcSJohn Ojemann ipftq_t *ipfqs, *userqs; 7572ea8244dcSJohn Ojemann ipf_stack_t *ifs; 7573ea8244dcSJohn Ojemann { 7574ea8244dcSJohn Ojemann ipftq_t *ifq, *ifqn; 7575ea8244dcSJohn Ojemann ipftqent_t *tqe, *tqn; 7576ea8244dcSJohn Ojemann int dropped; 7577ea8244dcSJohn Ojemann void *ent; 7578ea8244dcSJohn Ojemann nat_t *nat; 7579ea8244dcSJohn Ojemann ipstate_t *is; 7580ea8244dcSJohn Ojemann 7581ea8244dcSJohn Ojemann dropped = 0; 7582ea8244dcSJohn Ojemann 7583ea8244dcSJohn Ojemann /* 7584ea8244dcSJohn Ojemann * Start by deleting any entries in specific timeout queues. 7585ea8244dcSJohn Ojemann */ 7586ea8244dcSJohn Ojemann ifqn = &ipfqs[stateval]; 7587ea8244dcSJohn Ojemann while ((ifq = ifqn) != NULL) { 7588ea8244dcSJohn Ojemann ifqn = ifq->ifq_next; 7589ea8244dcSJohn Ojemann dropped += ipf_earlydrop(flushtype, ifq, (int)0, ifs); 7590ea8244dcSJohn Ojemann } 7591ea8244dcSJohn Ojemann 7592ea8244dcSJohn Ojemann /* 7593ea8244dcSJohn Ojemann * Next, look through user defined queues for closing entries. 7594ea8244dcSJohn Ojemann */ 7595ea8244dcSJohn Ojemann ifqn = userqs; 7596ea8244dcSJohn Ojemann while ((ifq = ifqn) != NULL) { 7597ea8244dcSJohn Ojemann ifqn = ifq->ifq_next; 7598ea8244dcSJohn Ojemann tqn = ifq->ifq_head; 7599ea8244dcSJohn Ojemann while ((tqe = tqn) != NULL) { 7600ea8244dcSJohn Ojemann tqn = tqe->tqe_next; 7601ea8244dcSJohn Ojemann ent = tqe->tqe_parent; 7602ea8244dcSJohn Ojemann switch (flushtype) 7603ea8244dcSJohn Ojemann { 7604ea8244dcSJohn Ojemann case NAT_FLUSH: 7605ea8244dcSJohn Ojemann nat = (nat_t *)ent; 7606ea8244dcSJohn Ojemann if ((nat->nat_p == IPPROTO_TCP) && 7607ea8244dcSJohn Ojemann (nat->nat_tcpstate[0] >= stateval) && 7608ea8244dcSJohn Ojemann (nat->nat_tcpstate[1] >= stateval) && 7609ea8244dcSJohn Ojemann (nat_delete(nat, NL_EXPIRE, ifs) == 0)) 7610ea8244dcSJohn Ojemann dropped++; 7611ea8244dcSJohn Ojemann break; 7612ea8244dcSJohn Ojemann case STATE_FLUSH: 7613ea8244dcSJohn Ojemann is = (ipstate_t *)ent; 7614ea8244dcSJohn Ojemann if ((is->is_p == IPPROTO_TCP) && 7615ea8244dcSJohn Ojemann (is->is_state[0] >= stateval) && 7616ea8244dcSJohn Ojemann (is->is_state[1] >= stateval) && 7617ea8244dcSJohn Ojemann (fr_delstate(is, ISL_EXPIRE, ifs) == 0)) 7618ea8244dcSJohn Ojemann dropped++; 7619ea8244dcSJohn Ojemann break; 7620ea8244dcSJohn Ojemann default: 7621ea8244dcSJohn Ojemann return (0); 7622ea8244dcSJohn Ojemann } 7623ea8244dcSJohn Ojemann } 7624ea8244dcSJohn Ojemann } 7625ea8244dcSJohn Ojemann return (dropped); 7626ea8244dcSJohn Ojemann } 7627ea8244dcSJohn Ojemann 7628ea8244dcSJohn Ojemann 7629ea8244dcSJohn Ojemann /* --------------------------------------------------------------------- */ 7630ea8244dcSJohn Ojemann /* Function: ipf_extraflush */ 7631ea8244dcSJohn Ojemann /* Returns: int - number of entries flushed (0 = none) */ 7632ea8244dcSJohn Ojemann /* Parameters: flushtype - which table we're cleaning (NAT or State) */ 7633ea8244dcSJohn Ojemann /* ipfqs - pointer to 'established' timeout queue */ 7634ea8244dcSJohn Ojemann /* userqs - pointer to user defined queues */ 7635ea8244dcSJohn Ojemann /* ifs - ipf stack instance */ 7636ea8244dcSJohn Ojemann /* */ 7637ea8244dcSJohn Ojemann /* This function gets called when either NAT or state tables fill up. */ 7638ea8244dcSJohn Ojemann /* We need to try a bit harder to free up some space. The function will */ 7639ea8244dcSJohn Ojemann /* flush entries for TCP connections which have been idle a long time. */ 7640ea8244dcSJohn Ojemann /* */ 7641ea8244dcSJohn Ojemann /* Currently, the idle time is checked using values from ideltime_tab[] */ 7642ea8244dcSJohn Ojemann /* --------------------------------------------------------------------- */ 7643ea8244dcSJohn Ojemann int ipf_extraflush(flushtype, ipfqs, userqs, ifs) 7644ea8244dcSJohn Ojemann int flushtype; 7645ea8244dcSJohn Ojemann ipftq_t *ipfqs, *userqs; 7646ea8244dcSJohn Ojemann ipf_stack_t *ifs; 7647ea8244dcSJohn Ojemann { 7648ea8244dcSJohn Ojemann ipftq_t *ifq, *ifqn; 7649ea8244dcSJohn Ojemann int idletime, removed, idle_idx; 7650ea8244dcSJohn Ojemann 7651ea8244dcSJohn Ojemann removed = 0; 7652ea8244dcSJohn Ojemann 7653ea8244dcSJohn Ojemann /* 7654ea8244dcSJohn Ojemann * Determine initial threshold for minimum idle time based on 7655ea8244dcSJohn Ojemann * how long ipfilter has been running. Ipfilter needs to have 7656ea8244dcSJohn Ojemann * been up as long as the smallest interval to continue on. 7657ea8244dcSJohn Ojemann * 7658ea8244dcSJohn Ojemann * Minimum idle times stored in idletime_tab and indexed by 7659ea8244dcSJohn Ojemann * idle_idx. Start at upper end of array and work backwards. 7660ea8244dcSJohn Ojemann * 7661ea8244dcSJohn Ojemann * Once the index is found, set the initial idle time to the 7662ea8244dcSJohn Ojemann * first interval before the current ipfilter run time. 7663ea8244dcSJohn Ojemann */ 7664ea8244dcSJohn Ojemann if (ifs->ifs_fr_ticks < idletime_tab[0]) 7665ea8244dcSJohn Ojemann return (0); 7666ea8244dcSJohn Ojemann idle_idx = (sizeof (idletime_tab) / sizeof (int)) - 1; 7667ea8244dcSJohn Ojemann if (ifs->ifs_fr_ticks > idletime_tab[idle_idx]) { 7668ea8244dcSJohn Ojemann idletime = idletime_tab[idle_idx]; 7669ea8244dcSJohn Ojemann } else { 7670ea8244dcSJohn Ojemann while ((idle_idx > 0) && 7671ea8244dcSJohn Ojemann (ifs->ifs_fr_ticks < idletime_tab[idle_idx])) 7672ea8244dcSJohn Ojemann idle_idx--; 7673ea8244dcSJohn Ojemann 7674ea8244dcSJohn Ojemann idletime = (ifs->ifs_fr_ticks / 7675ea8244dcSJohn Ojemann idletime_tab[idle_idx]) * 7676ea8244dcSJohn Ojemann idletime_tab[idle_idx]; 7677ea8244dcSJohn Ojemann } 7678ea8244dcSJohn Ojemann 7679ea8244dcSJohn Ojemann while (idle_idx >= 0) { 7680ea8244dcSJohn Ojemann /* 7681ea8244dcSJohn Ojemann * Check to see if we need to delete more entries. 7682ea8244dcSJohn Ojemann * If we do, start with appropriate timeout queue. 7683ea8244dcSJohn Ojemann */ 7684ea8244dcSJohn Ojemann if (flushtype == NAT_FLUSH) { 7685ea8244dcSJohn Ojemann if (NAT_TAB_WATER_LEVEL(ifs) <= 7686ea8244dcSJohn Ojemann ifs->ifs_nat_flush_level_lo) 7687ea8244dcSJohn Ojemann break; 7688ea8244dcSJohn Ojemann } else if (flushtype == STATE_FLUSH) { 7689ea8244dcSJohn Ojemann if (ST_TAB_WATER_LEVEL(ifs) <= 7690ea8244dcSJohn Ojemann ifs->ifs_state_flush_level_lo) 7691ea8244dcSJohn Ojemann break; 7692ea8244dcSJohn Ojemann } else { 7693ea8244dcSJohn Ojemann break; 7694ea8244dcSJohn Ojemann } 7695ea8244dcSJohn Ojemann 7696ea8244dcSJohn Ojemann removed += ipf_earlydrop(flushtype, ipfqs, idletime, ifs); 7697ea8244dcSJohn Ojemann 7698ea8244dcSJohn Ojemann /* 7699ea8244dcSJohn Ojemann * Next, check the user defined queues. But first, make 7700ea8244dcSJohn Ojemann * certain that timeout queue deletions didn't do enough. 7701ea8244dcSJohn Ojemann */ 7702ea8244dcSJohn Ojemann if (flushtype == NAT_FLUSH) { 7703ea8244dcSJohn Ojemann if (NAT_TAB_WATER_LEVEL(ifs) <= 7704ea8244dcSJohn Ojemann ifs->ifs_nat_flush_level_lo) 7705ea8244dcSJohn Ojemann break; 7706ea8244dcSJohn Ojemann } else { 7707ea8244dcSJohn Ojemann if (ST_TAB_WATER_LEVEL(ifs) <= 7708ea8244dcSJohn Ojemann ifs->ifs_state_flush_level_lo) 7709ea8244dcSJohn Ojemann break; 7710ea8244dcSJohn Ojemann } 7711ea8244dcSJohn Ojemann ifqn = userqs; 7712ea8244dcSJohn Ojemann while ((ifq = ifqn) != NULL) { 7713ea8244dcSJohn Ojemann ifqn = ifq->ifq_next; 7714ea8244dcSJohn Ojemann removed += ipf_earlydrop(flushtype, ifq, idletime, ifs); 7715ea8244dcSJohn Ojemann } 7716ea8244dcSJohn Ojemann 7717ea8244dcSJohn Ojemann /* 7718ea8244dcSJohn Ojemann * Adjust the granularity of idle time. 7719ea8244dcSJohn Ojemann * 7720ea8244dcSJohn Ojemann * If we reach an interval boundary, we need to 7721ea8244dcSJohn Ojemann * either adjust the idle time accordingly or exit 7722ea8244dcSJohn Ojemann * the loop altogether (if this is very last check). 7723ea8244dcSJohn Ojemann */ 7724ea8244dcSJohn Ojemann idletime -= idletime_tab[idle_idx]; 7725ea8244dcSJohn Ojemann if (idletime < idletime_tab[idle_idx]) { 7726ea8244dcSJohn Ojemann if (idle_idx != 0) { 7727ea8244dcSJohn Ojemann idletime = idletime_tab[idle_idx] - 7728ea8244dcSJohn Ojemann idletime_tab[idle_idx - 1]; 7729ea8244dcSJohn Ojemann idle_idx--; 7730ea8244dcSJohn Ojemann } else { 7731ea8244dcSJohn Ojemann break; 7732ea8244dcSJohn Ojemann } 7733ea8244dcSJohn Ojemann } 7734ea8244dcSJohn Ojemann } 7735ea8244dcSJohn Ojemann 7736ea8244dcSJohn Ojemann return (removed); 7737ea8244dcSJohn Ojemann } 7738