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