1 0 stevel /* 2 0 stevel * Copyright (C) 1993-2003 by Darren Reed. 3 0 stevel * 4 0 stevel * See the IPFILTER.LICENCE file for details on licencing. 5 2393 yz155240 * 6 8624 Darren * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 7 0 stevel * Use is subject to license terms. 8 0 stevel */ 9 0 stevel 10 0 stevel #if defined(KERNEL) || defined(_KERNEL) 11 0 stevel # undef KERNEL 12 0 stevel # undef _KERNEL 13 0 stevel # define KERNEL 1 14 0 stevel # define _KERNEL 1 15 0 stevel #endif 16 0 stevel #include <sys/errno.h> 17 0 stevel #include <sys/types.h> 18 0 stevel #include <sys/param.h> 19 0 stevel #include <sys/time.h> 20 0 stevel #if defined(__NetBSD__) 21 0 stevel # if (NetBSD >= 199905) && !defined(IPFILTER_LKM) && defined(_KERNEL) 22 0 stevel # include "opt_ipfilter_log.h" 23 0 stevel # endif 24 0 stevel #endif 25 0 stevel #if defined(_KERNEL) && defined(__FreeBSD_version) && \ 26 0 stevel (__FreeBSD_version >= 220000) 27 0 stevel # if (__FreeBSD_version >= 400000) 28 0 stevel # if !defined(IPFILTER_LKM) 29 0 stevel # include "opt_inet6.h" 30 0 stevel # endif 31 0 stevel # if (__FreeBSD_version == 400019) 32 0 stevel # define CSUM_DELAY_DATA 33 0 stevel # endif 34 0 stevel # endif 35 0 stevel # include <sys/filio.h> 36 0 stevel #else 37 0 stevel # include <sys/ioctl.h> 38 0 stevel #endif 39 2393 yz155240 #if !defined(_AIX51) 40 2393 yz155240 # include <sys/fcntl.h> 41 2393 yz155240 #endif 42 0 stevel #if defined(_KERNEL) 43 0 stevel # include <sys/systm.h> 44 0 stevel # include <sys/file.h> 45 0 stevel #else 46 0 stevel # include <stdio.h> 47 0 stevel # include <string.h> 48 0 stevel # include <stdlib.h> 49 2393 yz155240 # include <stddef.h> 50 0 stevel # include <sys/file.h> 51 0 stevel # define _KERNEL 52 0 stevel # ifdef __OpenBSD__ 53 0 stevel struct file; 54 0 stevel # endif 55 0 stevel # include <sys/uio.h> 56 0 stevel # undef _KERNEL 57 0 stevel #endif 58 2393 yz155240 #if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux) && \ 59 2393 yz155240 !defined(linux) 60 0 stevel # include <sys/mbuf.h> 61 0 stevel #else 62 2393 yz155240 # if !defined(linux) 63 2393 yz155240 # include <sys/byteorder.h> 64 2393 yz155240 # endif 65 0 stevel # if (SOLARIS2 < 5) && defined(sun) 66 0 stevel # include <sys/dditypes.h> 67 0 stevel # endif 68 0 stevel #endif 69 0 stevel #ifdef __hpux 70 0 stevel # define _NET_ROUTE_INCLUDED 71 0 stevel #endif 72 2393 yz155240 #if !defined(linux) 73 2393 yz155240 # include <sys/protosw.h> 74 2393 yz155240 #endif 75 0 stevel #include <sys/socket.h> 76 0 stevel #include <net/if.h> 77 0 stevel #ifdef sun 78 0 stevel # include <net/af.h> 79 0 stevel #endif 80 2393 yz155240 #if !defined(_KERNEL) && defined(__FreeBSD__) 81 2393 yz155240 # include "radix_ipf.h" 82 2393 yz155240 #endif 83 0 stevel #include <net/route.h> 84 0 stevel #include <netinet/in.h> 85 0 stevel #include <netinet/in_systm.h> 86 0 stevel #include <netinet/ip.h> 87 2393 yz155240 #if !defined(linux) 88 2393 yz155240 # include <netinet/ip_var.h> 89 2393 yz155240 #endif 90 0 stevel #if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */ 91 0 stevel # include <sys/hashing.h> 92 0 stevel # include <netinet/in_var.h> 93 0 stevel #endif 94 0 stevel #include <netinet/tcp.h> 95 2393 yz155240 #if (!defined(__sgi) && !defined(AIX)) || defined(_KERNEL) 96 2393 yz155240 # include <netinet/udp.h> 97 2393 yz155240 # include <netinet/ip_icmp.h> 98 2393 yz155240 #endif 99 0 stevel #ifdef __hpux 100 0 stevel # undef _NET_ROUTE_INCLUDED 101 0 stevel #endif 102 2393 yz155240 #include "netinet/ip_compat.h" 103 0 stevel #ifdef USE_INET6 104 0 stevel # include <netinet/icmp6.h> 105 2393 yz155240 # if !SOLARIS && defined(_KERNEL) && !defined(__osf__) && !defined(__hpux) 106 0 stevel # include <netinet6/in6_var.h> 107 0 stevel # endif 108 0 stevel #endif 109 0 stevel #include <netinet/tcpip.h> 110 0 stevel #include "netinet/ip_fil.h" 111 0 stevel #include "netinet/ip_nat.h" 112 0 stevel #include "netinet/ip_frag.h" 113 0 stevel #include "netinet/ip_state.h" 114 0 stevel #include "netinet/ip_proxy.h" 115 0 stevel #include "netinet/ip_auth.h" 116 3448 dh155122 #include "netinet/ipf_stack.h" 117 0 stevel #ifdef IPFILTER_SCAN 118 0 stevel # include "netinet/ip_scan.h" 119 0 stevel #endif 120 2393 yz155240 #ifdef IPFILTER_SYNC 121 2393 yz155240 # include "netinet/ip_sync.h" 122 2393 yz155240 #endif 123 0 stevel #include "netinet/ip_pool.h" 124 0 stevel #include "netinet/ip_htable.h" 125 2393 yz155240 #ifdef IPFILTER_COMPILED 126 2393 yz155240 # include "netinet/ip_rules.h" 127 2393 yz155240 #endif 128 2393 yz155240 #if defined(IPFILTER_BPF) && defined(_KERNEL) 129 0 stevel # include <net/bpf.h> 130 0 stevel #endif 131 0 stevel #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 132 0 stevel # include <sys/malloc.h> 133 0 stevel # if defined(_KERNEL) && !defined(IPFILTER_LKM) 134 0 stevel # include "opt_ipfilter.h" 135 0 stevel # endif 136 0 stevel #endif 137 0 stevel #include "netinet/ipl.h" 138 2393 yz155240 /* END OF INCLUDES */ 139 0 stevel 140 0 stevel #if !defined(lint) 141 0 stevel static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed"; 142 2393 yz155240 static const char rcsid[] = "@(#)$Id: fil.c,v 2.243.2.64 2005/08/13 05:19:59 darrenr Exp $"; 143 0 stevel #endif 144 0 stevel 145 0 stevel #ifndef _KERNEL 146 0 stevel # include "ipf.h" 147 0 stevel # include "ipt.h" 148 2393 yz155240 # include "bpf-ipf.h" 149 0 stevel extern int opts; 150 0 stevel 151 0 stevel # define FR_VERBOSE(verb_pr) verbose verb_pr 152 0 stevel # define FR_DEBUG(verb_pr) debug verb_pr 153 0 stevel #else /* #ifndef _KERNEL */ 154 0 stevel # define FR_VERBOSE(verb_pr) 155 0 stevel # define FR_DEBUG(verb_pr) 156 0 stevel #endif /* _KERNEL */ 157 0 stevel 158 0 stevel 159 2393 yz155240 char ipfilter_version[] = IPL_VERSION; 160 2393 yz155240 int fr_features = 0 161 2393 yz155240 #ifdef IPFILTER_LKM 162 2393 yz155240 | IPF_FEAT_LKM 163 2393 yz155240 #endif 164 2393 yz155240 #ifdef IPFILTER_LOG 165 2393 yz155240 | IPF_FEAT_LOG 166 2393 yz155240 #endif 167 2393 yz155240 #ifdef IPFILTER_LOOKUP 168 2393 yz155240 | IPF_FEAT_LOOKUP 169 2393 yz155240 #endif 170 2393 yz155240 #ifdef IPFILTER_BPF 171 2393 yz155240 | IPF_FEAT_BPF 172 2393 yz155240 #endif 173 2393 yz155240 #ifdef IPFILTER_COMPILED 174 2393 yz155240 | IPF_FEAT_COMPILED 175 2393 yz155240 #endif 176 2393 yz155240 #ifdef IPFILTER_CKSUM 177 2393 yz155240 | IPF_FEAT_CKSUM 178 2393 yz155240 #endif 179 2393 yz155240 #ifdef IPFILTER_SYNC 180 2393 yz155240 | IPF_FEAT_SYNC 181 2393 yz155240 #endif 182 2393 yz155240 #ifdef IPFILTER_SCAN 183 2393 yz155240 | IPF_FEAT_SCAN 184 2393 yz155240 #endif 185 2393 yz155240 #ifdef USE_INET6 186 2393 yz155240 | IPF_FEAT_IPV6 187 2393 yz155240 #endif 188 2393 yz155240 ; 189 0 stevel 190 7131 dr146992 #define IPF_BUMP(x) (x)++ 191 7131 dr146992 192 7131 dr146992 static INLINE int fr_ipfcheck __P((fr_info_t *, frentry_t *, int)); 193 0 stevel static INLINE int fr_ipfcheck __P((fr_info_t *, frentry_t *, int)); 194 0 stevel static int fr_portcheck __P((frpcmp_t *, u_short *)); 195 3448 dh155122 static int frflushlist __P((int, minor_t, int *, frentry_t **, 196 3448 dh155122 ipf_stack_t *)); 197 0 stevel static ipfunc_t fr_findfunc __P((ipfunc_t)); 198 0 stevel static frentry_t *fr_firewall __P((fr_info_t *, u_32_t *)); 199 3448 dh155122 static int fr_funcinit __P((frentry_t *fr, ipf_stack_t *)); 200 2393 yz155240 static INLINE void frpr_ah __P((fr_info_t *)); 201 637 ml37995 static INLINE void frpr_esp __P((fr_info_t *)); 202 637 ml37995 static INLINE void frpr_gre __P((fr_info_t *)); 203 0 stevel static INLINE void frpr_udp __P((fr_info_t *)); 204 0 stevel static INLINE void frpr_tcp __P((fr_info_t *)); 205 0 stevel static INLINE void frpr_icmp __P((fr_info_t *)); 206 0 stevel static INLINE void frpr_ipv4hdr __P((fr_info_t *)); 207 637 ml37995 static INLINE int frpr_pullup __P((fr_info_t *, int)); 208 637 ml37995 static INLINE void frpr_short __P((fr_info_t *, int)); 209 0 stevel static INLINE void frpr_tcpcommon __P((fr_info_t *)); 210 0 stevel static INLINE void frpr_udpcommon __P((fr_info_t *)); 211 0 stevel static INLINE int fr_updateipid __P((fr_info_t *)); 212 0 stevel #ifdef IPFILTER_LOOKUP 213 3448 dh155122 static int fr_grpmapinit __P((frentry_t *fr, ipf_stack_t *)); 214 3448 dh155122 static INLINE void *fr_resolvelookup __P((u_int, u_int, lookupfunc_t *, 215 3448 dh155122 ipf_stack_t *)); 216 3448 dh155122 #endif 217 3448 dh155122 static void frsynclist __P((int, int, void *, char *, frentry_t *, 218 3448 dh155122 ipf_stack_t *)); 219 2958 dr146992 static void *fr_ifsync __P((int, int, char *, char *, 220 3448 dh155122 void *, void *, ipf_stack_t *)); 221 3448 dh155122 static ipftuneable_t *fr_findtunebyname __P((const char *, ipf_stack_t *)); 222 3448 dh155122 static ipftuneable_t *fr_findtunebycookie __P((void *, void **, ipf_stack_t *)); 223 0 stevel 224 0 stevel /* 225 0 stevel * bit values for identifying presence of individual IP options 226 2393 yz155240 * All of these tables should be ordered by increasing key value on the left 227 2393 yz155240 * hand side to allow for binary searching of the array and include a trailer 228 2393 yz155240 * with a 0 for the bitmask for linear searches to easily find the end with. 229 2393 yz155240 */ 230 2393 yz155240 const struct optlist ipopts[20] = { 231 0 stevel { IPOPT_NOP, 0x000001 }, 232 0 stevel { IPOPT_RR, 0x000002 }, 233 0 stevel { IPOPT_ZSU, 0x000004 }, 234 0 stevel { IPOPT_MTUP, 0x000008 }, 235 0 stevel { IPOPT_MTUR, 0x000010 }, 236 0 stevel { IPOPT_ENCODE, 0x000020 }, 237 0 stevel { IPOPT_TS, 0x000040 }, 238 0 stevel { IPOPT_TR, 0x000080 }, 239 0 stevel { IPOPT_SECURITY, 0x000100 }, 240 0 stevel { IPOPT_LSRR, 0x000200 }, 241 0 stevel { IPOPT_E_SEC, 0x000400 }, 242 0 stevel { IPOPT_CIPSO, 0x000800 }, 243 0 stevel { IPOPT_SATID, 0x001000 }, 244 0 stevel { IPOPT_SSRR, 0x002000 }, 245 0 stevel { IPOPT_ADDEXT, 0x004000 }, 246 0 stevel { IPOPT_VISA, 0x008000 }, 247 0 stevel { IPOPT_IMITD, 0x010000 }, 248 0 stevel { IPOPT_EIP, 0x020000 }, 249 0 stevel { IPOPT_FINN, 0x040000 }, 250 0 stevel { 0, 0x000000 } 251 0 stevel }; 252 0 stevel 253 0 stevel #ifdef USE_INET6 254 0 stevel struct optlist ip6exthdr[] = { 255 0 stevel { IPPROTO_HOPOPTS, 0x000001 }, 256 637 ml37995 { IPPROTO_IPV6, 0x000002 }, 257 637 ml37995 { IPPROTO_ROUTING, 0x000004 }, 258 637 ml37995 { IPPROTO_FRAGMENT, 0x000008 }, 259 637 ml37995 { IPPROTO_ESP, 0x000010 }, 260 637 ml37995 { IPPROTO_AH, 0x000020 }, 261 637 ml37995 { IPPROTO_NONE, 0x000040 }, 262 637 ml37995 { IPPROTO_DSTOPTS, 0x000080 }, 263 637 ml37995 { 0, 0 } 264 0 stevel }; 265 0 stevel #endif 266 0 stevel 267 0 stevel struct optlist tcpopts[] = { 268 0 stevel { TCPOPT_NOP, 0x000001 }, 269 0 stevel { TCPOPT_MAXSEG, 0x000002 }, 270 0 stevel { TCPOPT_WINDOW, 0x000004 }, 271 0 stevel { TCPOPT_SACK_PERMITTED, 0x000008 }, 272 0 stevel { TCPOPT_SACK, 0x000010 }, 273 0 stevel { TCPOPT_TIMESTAMP, 0x000020 }, 274 0 stevel { 0, 0x000000 } 275 0 stevel }; 276 0 stevel 277 0 stevel /* 278 0 stevel * bit values for identifying presence of individual IP security options 279 0 stevel */ 280 2393 yz155240 const struct optlist secopt[8] = { 281 0 stevel { IPSO_CLASS_RES4, 0x01 }, 282 0 stevel { IPSO_CLASS_TOPS, 0x02 }, 283 0 stevel { IPSO_CLASS_SECR, 0x04 }, 284 0 stevel { IPSO_CLASS_RES3, 0x08 }, 285 0 stevel { IPSO_CLASS_CONF, 0x10 }, 286 0 stevel { IPSO_CLASS_UNCL, 0x20 }, 287 0 stevel { IPSO_CLASS_RES2, 0x40 }, 288 0 stevel { IPSO_CLASS_RES1, 0x80 } 289 0 stevel }; 290 0 stevel 291 0 stevel 292 0 stevel /* 293 0 stevel * Table of functions available for use with call rules. 294 0 stevel */ 295 0 stevel static ipfunc_resolve_t fr_availfuncs[] = { 296 0 stevel #ifdef IPFILTER_LOOKUP 297 0 stevel { "fr_srcgrpmap", fr_srcgrpmap, fr_grpmapinit }, 298 0 stevel { "fr_dstgrpmap", fr_dstgrpmap, fr_grpmapinit }, 299 0 stevel #endif 300 0 stevel { "", NULL } 301 0 stevel }; 302 0 stevel 303 0 stevel 304 0 stevel /* 305 8170 John * Below we declare a list of constants used only by the ipf_extraflush() 306 8170 John * routine. We are placing it here, instead of in ipf_extraflush() itself, 307 8170 John * because we want to make it visible to tools such as mdb, nm etc., so the 308 8170 John * values can easily be altered during debugging. 309 8170 John */ 310 8170 John static const int idletime_tab[] = { 311 8170 John IPF_TTLVAL(30), /* 30 seconds */ 312 8170 John IPF_TTLVAL(1800), /* 30 minutes */ 313 8170 John IPF_TTLVAL(43200), /* 12 hours */ 314 8170 John IPF_TTLVAL(345600), /* 4 days */ 315 8170 John }; 316 8170 John 317 8170 John 318 8170 John /* 319 0 stevel * The next section of code is a a collection of small routines that set 320 0 stevel * fields in the fr_info_t structure passed based on properties of the 321 0 stevel * current packet. There are different routines for the same protocol 322 0 stevel * for each of IPv4 and IPv6. Adding a new protocol, for which there 323 0 stevel * will "special" inspection for setup, is now more easily done by adding 324 0 stevel * a new routine and expanding the frpr_ipinit*() function rather than by 325 0 stevel * adding more code to a growing switch statement. 326 0 stevel */ 327 0 stevel #ifdef USE_INET6 328 2393 yz155240 static INLINE int frpr_ah6 __P((fr_info_t *)); 329 2393 yz155240 static INLINE void frpr_esp6 __P((fr_info_t *)); 330 2393 yz155240 static INLINE void frpr_gre6 __P((fr_info_t *)); 331 0 stevel static INLINE void frpr_udp6 __P((fr_info_t *)); 332 0 stevel static INLINE void frpr_tcp6 __P((fr_info_t *)); 333 0 stevel static INLINE void frpr_icmp6 __P((fr_info_t *)); 334 8624 Darren static INLINE void frpr_ipv6hdr __P((fr_info_t *)); 335 0 stevel static INLINE void frpr_short6 __P((fr_info_t *, int)); 336 637 ml37995 static INLINE int frpr_hopopts6 __P((fr_info_t *)); 337 637 ml37995 static INLINE int frpr_routing6 __P((fr_info_t *)); 338 637 ml37995 static INLINE int frpr_dstopts6 __P((fr_info_t *)); 339 637 ml37995 static INLINE int frpr_fragment6 __P((fr_info_t *)); 340 2393 yz155240 static INLINE int frpr_ipv6exthdr __P((fr_info_t *, int, int)); 341 0 stevel 342 0 stevel 343 0 stevel /* ------------------------------------------------------------------------ */ 344 0 stevel /* Function: frpr_short6 */ 345 0 stevel /* Returns: void */ 346 0 stevel /* Parameters: fin(I) - pointer to packet information */ 347 0 stevel /* */ 348 0 stevel /* IPv6 Only */ 349 0 stevel /* This is function enforces the 'is a packet too short to be legit' rule */ 350 2393 yz155240 /* for IPv6 and marks the packet with FI_SHORT if so. See function comment */ 351 2393 yz155240 /* for frpr_short() for more details. */ 352 2393 yz155240 /* ------------------------------------------------------------------------ */ 353 2393 yz155240 static INLINE void frpr_short6(fin, xmin) 354 2393 yz155240 fr_info_t *fin; 355 2393 yz155240 int xmin; 356 2393 yz155240 { 357 2393 yz155240 358 2393 yz155240 if (fin->fin_dlen < xmin) 359 2393 yz155240 fin->fin_flx |= FI_SHORT; 360 0 stevel } 361 0 stevel 362 0 stevel 363 0 stevel /* ------------------------------------------------------------------------ */ 364 0 stevel /* Function: frpr_ipv6hdr */ 365 8624 Darren /* Returns: Nil */ 366 0 stevel /* Parameters: fin(I) - pointer to packet information */ 367 0 stevel /* */ 368 0 stevel /* IPv6 Only */ 369 0 stevel /* Copy values from the IPv6 header into the fr_info_t struct and call the */ 370 0 stevel /* per-protocol analyzer if it exists. */ 371 0 stevel /* ------------------------------------------------------------------------ */ 372 8624 Darren static INLINE void frpr_ipv6hdr(fin) 373 0 stevel fr_info_t *fin; 374 0 stevel { 375 0 stevel ip6_t *ip6 = (ip6_t *)fin->fin_ip; 376 2393 yz155240 int p, go = 1, i, hdrcount; 377 0 stevel fr_ip_t *fi = &fin->fin_fi; 378 0 stevel 379 0 stevel fin->fin_off = 0; 380 0 stevel 381 0 stevel fi->fi_tos = 0; 382 0 stevel fi->fi_optmsk = 0; 383 0 stevel fi->fi_secmsk = 0; 384 0 stevel fi->fi_auth = 0; 385 0 stevel 386 0 stevel p = ip6->ip6_nxt; 387 0 stevel fi->fi_ttl = ip6->ip6_hlim; 388 0 stevel fi->fi_src.in6 = ip6->ip6_src; 389 0 stevel fi->fi_dst.in6 = ip6->ip6_dst; 390 637 ml37995 fin->fin_id = 0; 391 0 stevel 392 0 stevel hdrcount = 0; 393 637 ml37995 while (go && !(fin->fin_flx & (FI_BAD|FI_SHORT))) { 394 0 stevel switch (p) 395 0 stevel { 396 0 stevel case IPPROTO_UDP : 397 0 stevel frpr_udp6(fin); 398 0 stevel go = 0; 399 0 stevel break; 400 637 ml37995 401 0 stevel case IPPROTO_TCP : 402 0 stevel frpr_tcp6(fin); 403 0 stevel go = 0; 404 0 stevel break; 405 637 ml37995 406 0 stevel case IPPROTO_ICMPV6 : 407 0 stevel frpr_icmp6(fin); 408 0 stevel go = 0; 409 0 stevel break; 410 637 ml37995 411 637 ml37995 case IPPROTO_GRE : 412 2393 yz155240 frpr_gre6(fin); 413 637 ml37995 go = 0; 414 637 ml37995 break; 415 637 ml37995 416 0 stevel case IPPROTO_HOPOPTS : 417 0 stevel /* 418 2393 yz155240 * hop by hop ext header is only allowed 419 2393 yz155240 * right after IPv6 header. 420 2393 yz155240 */ 421 2393 yz155240 if (hdrcount != 0) { 422 637 ml37995 fin->fin_flx |= FI_BAD; 423 2393 yz155240 p = IPPROTO_NONE; 424 2393 yz155240 } else { 425 2393 yz155240 p = frpr_hopopts6(fin); 426 2393 yz155240 } 427 637 ml37995 break; 428 637 ml37995 429 0 stevel case IPPROTO_DSTOPTS : 430 637 ml37995 p = frpr_dstopts6(fin); 431 637 ml37995 break; 432 637 ml37995 433 0 stevel case IPPROTO_ROUTING : 434 637 ml37995 p = frpr_routing6(fin); 435 637 ml37995 break; 436 637 ml37995 437 2393 yz155240 case IPPROTO_AH : 438 2393 yz155240 p = frpr_ah6(fin); 439 2393 yz155240 break; 440 2393 yz155240 441 0 stevel case IPPROTO_ESP : 442 2393 yz155240 frpr_esp6(fin); 443 2393 yz155240 go = 0; 444 2393 yz155240 break; 445 2393 yz155240 446 2393 yz155240 case IPPROTO_IPV6 : 447 637 ml37995 for (i = 0; ip6exthdr[i].ol_bit != 0; i++) 448 637 ml37995 if (ip6exthdr[i].ol_val == p) { 449 2393 yz155240 fin->fin_flx |= ip6exthdr[i].ol_bit; 450 637 ml37995 break; 451 637 ml37995 } 452 637 ml37995 go = 0; 453 637 ml37995 break; 454 637 ml37995 455 2393 yz155240 case IPPROTO_NONE : 456 637 ml37995 go = 0; 457 637 ml37995 break; 458 637 ml37995 459 637 ml37995 case IPPROTO_FRAGMENT : 460 2393 yz155240 p = frpr_fragment6(fin); 461 2393 yz155240 if (fin->fin_off != 0) /* Not the first frag */ 462 637 ml37995 go = 0; 463 637 ml37995 break; 464 637 ml37995 465 637 ml37995 default : 466 637 ml37995 go = 0; 467 637 ml37995 break; 468 637 ml37995 } 469 0 stevel hdrcount++; 470 2393 yz155240 471 2393 yz155240 /* 472 2393 yz155240 * It is important to note that at this point, for the 473 2393 yz155240 * extension headers (go != 0), the entire header may not have 474 2393 yz155240 * been pulled up when the code gets to this point. This is 475 2393 yz155240 * only done for "go != 0" because the other header handlers 476 2393 yz155240 * will all pullup their complete header. The other indicator 477 2393 yz155240 * of an incomplete packet is that this was just an extension 478 2393 yz155240 * header. 479 2393 yz155240 */ 480 2393 yz155240 if ((go != 0) && (p != IPPROTO_NONE) && 481 2393 yz155240 (frpr_pullup(fin, 0) == -1)) { 482 2393 yz155240 p = IPPROTO_NONE; 483 2393 yz155240 go = 0; 484 2393 yz155240 } 485 2393 yz155240 } 486 637 ml37995 fi->fi_p = p; 487 2393 yz155240 } 488 2393 yz155240 489 2393 yz155240 490 2393 yz155240 /* ------------------------------------------------------------------------ */ 491 2393 yz155240 /* Function: frpr_ipv6exthdr */ 492 637 ml37995 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 493 2393 yz155240 /* Parameters: fin(I) - pointer to packet information */ 494 2393 yz155240 /* multiple(I) - flag indicating yes/no if multiple occurances */ 495 2393 yz155240 /* of this extension header are allowed. */ 496 2393 yz155240 /* proto(I) - protocol number for this extension header */ 497 2393 yz155240 /* */ 498 2393 yz155240 /* IPv6 Only */ 499 9876 Darren /* This function expects to find an IPv6 extension header at fin_dp. */ 500 9876 Darren /* There must be at least 8 bytes of data at fin_dp for there to be a valid */ 501 9876 Darren /* extension header present. If a good one is found, fin_dp is advanced to */ 502 9876 Darren /* point at the first piece of data after the extension header, fin_exthdr */ 503 9876 Darren /* points to the start of the extension header and the "protocol" of the */ 504 9876 Darren /* *NEXT* header is returned. */ 505 2393 yz155240 /* ------------------------------------------------------------------------ */ 506 2393 yz155240 static INLINE int frpr_ipv6exthdr(fin, multiple, proto) 507 2393 yz155240 fr_info_t *fin; 508 2393 yz155240 int multiple, proto; 509 0 stevel { 510 0 stevel struct ip6_ext *hdr; 511 0 stevel u_short shift; 512 0 stevel int i; 513 0 stevel 514 0 stevel fin->fin_flx |= FI_V6EXTHDR; 515 0 stevel 516 2393 yz155240 /* 8 is default length of extension hdr */ 517 2393 yz155240 if ((fin->fin_dlen - 8) < 0) { 518 2393 yz155240 fin->fin_flx |= FI_SHORT; 519 2393 yz155240 return IPPROTO_NONE; 520 2393 yz155240 } 521 637 ml37995 522 637 ml37995 if (frpr_pullup(fin, 8) == -1) 523 637 ml37995 return IPPROTO_NONE; 524 0 stevel 525 0 stevel hdr = fin->fin_dp; 526 0 stevel shift = 8 + (hdr->ip6e_len << 3); 527 0 stevel if (shift > fin->fin_dlen) { /* Nasty extension header length? */ 528 0 stevel fin->fin_flx |= FI_BAD; 529 637 ml37995 return IPPROTO_NONE; 530 637 ml37995 } 531 637 ml37995 532 637 ml37995 for (i = 0; ip6exthdr[i].ol_bit != 0; i++) 533 2393 yz155240 if (ip6exthdr[i].ol_val == proto) { 534 2393 yz155240 /* 535 2393 yz155240 * Most IPv6 extension headers are only allowed once. 536 2393 yz155240 */ 537 2393 yz155240 if ((multiple == 0) && 538 2393 yz155240 ((fin->fin_optmsk & ip6exthdr[i].ol_bit) != 0)) 539 2393 yz155240 fin->fin_flx |= FI_BAD; 540 2393 yz155240 else 541 2393 yz155240 fin->fin_optmsk |= ip6exthdr[i].ol_bit; 542 637 ml37995 break; 543 637 ml37995 } 544 637 ml37995 545 637 ml37995 fin->fin_dp = (char *)fin->fin_dp + shift; 546 637 ml37995 fin->fin_dlen -= shift; 547 637 ml37995 548 637 ml37995 return hdr->ip6e_nxt; 549 637 ml37995 } 550 637 ml37995 551 637 ml37995 552 637 ml37995 /* ------------------------------------------------------------------------ */ 553 2393 yz155240 /* Function: frpr_hopopts6 */ 554 2393 yz155240 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 555 2393 yz155240 /* Parameters: fin(I) - pointer to packet information */ 556 2393 yz155240 /* */ 557 2393 yz155240 /* IPv6 Only */ 558 2393 yz155240 /* This is function checks pending hop by hop options extension header */ 559 2393 yz155240 /* ------------------------------------------------------------------------ */ 560 2393 yz155240 static INLINE int frpr_hopopts6(fin) 561 2393 yz155240 fr_info_t *fin; 562 2393 yz155240 { 563 2393 yz155240 return frpr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS); 564 2393 yz155240 } 565 2393 yz155240 566 2393 yz155240 567 2393 yz155240 /* ------------------------------------------------------------------------ */ 568 637 ml37995 /* Function: frpr_routing6 */ 569 637 ml37995 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 570 637 ml37995 /* Parameters: fin(I) - pointer to packet information */ 571 637 ml37995 /* */ 572 637 ml37995 /* IPv6 Only */ 573 637 ml37995 /* This is function checks pending routing extension header */ 574 637 ml37995 /* ------------------------------------------------------------------------ */ 575 637 ml37995 static INLINE int frpr_routing6(fin) 576 637 ml37995 fr_info_t *fin; 577 637 ml37995 { 578 637 ml37995 struct ip6_ext *hdr; 579 2393 yz155240 int shift; 580 2393 yz155240 581 637 ml37995 hdr = fin->fin_dp; 582 2393 yz155240 if (frpr_ipv6exthdr(fin, 0, IPPROTO_ROUTING) == IPPROTO_NONE) 583 2393 yz155240 return IPPROTO_NONE; 584 637 ml37995 585 637 ml37995 shift = 8 + (hdr->ip6e_len << 3); 586 637 ml37995 /* 587 637 ml37995 * Nasty extension header length? 588 637 ml37995 */ 589 2393 yz155240 if ((hdr->ip6e_len << 3) & 15) { 590 2393 yz155240 fin->fin_flx |= FI_BAD; 591 2393 yz155240 /* 592 2393 yz155240 * Compensate for the changes made in frpr_ipv6exthdr() 593 2393 yz155240 */ 594 2393 yz155240 fin->fin_dlen += shift; 595 2393 yz155240 fin->fin_dp = (char *)fin->fin_dp - shift; 596 2393 yz155240 return IPPROTO_NONE; 597 2393 yz155240 } 598 637 ml37995 599 637 ml37995 return hdr->ip6e_nxt; 600 637 ml37995 } 601 637 ml37995 602 637 ml37995 603 637 ml37995 /* ------------------------------------------------------------------------ */ 604 637 ml37995 /* Function: frpr_fragment6 */ 605 637 ml37995 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 606 637 ml37995 /* Parameters: fin(I) - pointer to packet information */ 607 637 ml37995 /* */ 608 637 ml37995 /* IPv6 Only */ 609 637 ml37995 /* Examine the IPv6 fragment header and extract fragment offset information.*/ 610 2393 yz155240 /* */ 611 2393 yz155240 /* We don't know where the transport layer header (or whatever is next is), */ 612 2393 yz155240 /* as it could be behind destination options (amongst others). Because */ 613 2393 yz155240 /* there is no fragment cache, there is no knowledge about whether or not an*/ 614 2393 yz155240 /* upper layer header has been seen (or where it ends) and thus we are not */ 615 2393 yz155240 /* able to continue processing beyond this header with any confidence. */ 616 637 ml37995 /* ------------------------------------------------------------------------ */ 617 637 ml37995 static INLINE int frpr_fragment6(fin) 618 637 ml37995 fr_info_t *fin; 619 637 ml37995 { 620 637 ml37995 struct ip6_frag *frag; 621 2393 yz155240 622 2393 yz155240 fin->fin_flx |= FI_FRAG; 623 2393 yz155240 624 9876 Darren /* 625 9876 Darren * A fragmented IPv6 packet implies that there must be something 626 9876 Darren * else after the fragment. 627 9876 Darren */ 628 2393 yz155240 if (frpr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT) == IPPROTO_NONE) 629 11043 Darren return IPPROTO_NONE; 630 2393 yz155240 631 2393 yz155240 frag = (struct ip6_frag *)((char *)fin->fin_dp - sizeof(*frag)); 632 11043 Darren 633 11043 Darren /* 634 11043 Darren * If this fragment isn't the last then the packet length must 635 11043 Darren * be a multiple of 8. 636 11043 Darren */ 637 11043 Darren if ((frag->ip6f_offlg & IP6F_MORE_FRAG) != 0) { 638 11043 Darren fin->fin_flx |= FI_MOREFRAG; 639 11043 Darren 640 11043 Darren if ((fin->fin_plen & 0x7) != 0) 641 11043 Darren fin->fin_flx |= FI_BAD; 642 11043 Darren } 643 9876 Darren 644 9876 Darren fin->fin_id = frag->ip6f_ident; 645 9876 Darren fin->fin_off = ntohs(frag->ip6f_offlg & IP6F_OFF_MASK); 646 2393 yz155240 if (fin->fin_off != 0) 647 2393 yz155240 fin->fin_flx |= FI_FRAGBODY; 648 2393 yz155240 649 637 ml37995 return frag->ip6f_nxt; 650 637 ml37995 } 651 637 ml37995 652 637 ml37995 653 637 ml37995 /* ------------------------------------------------------------------------ */ 654 637 ml37995 /* Function: frpr_dstopts6 */ 655 637 ml37995 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 656 637 ml37995 /* Parameters: fin(I) - pointer to packet information */ 657 637 ml37995 /* nextheader(I) - stores next header value */ 658 637 ml37995 /* */ 659 637 ml37995 /* IPv6 Only */ 660 637 ml37995 /* This is function checks pending destination options extension header */ 661 637 ml37995 /* ------------------------------------------------------------------------ */ 662 637 ml37995 static INLINE int frpr_dstopts6(fin) 663 637 ml37995 fr_info_t *fin; 664 637 ml37995 { 665 2393 yz155240 return frpr_ipv6exthdr(fin, 1, IPPROTO_DSTOPTS); 666 0 stevel } 667 0 stevel 668 0 stevel 669 0 stevel /* ------------------------------------------------------------------------ */ 670 0 stevel /* Function: frpr_icmp6 */ 671 0 stevel /* Returns: void */ 672 0 stevel /* Parameters: fin(I) - pointer to packet information */ 673 0 stevel /* */ 674 0 stevel /* IPv6 Only */ 675 0 stevel /* This routine is mainly concerned with determining the minimum valid size */ 676 0 stevel /* for an ICMPv6 packet. */ 677 0 stevel /* ------------------------------------------------------------------------ */ 678 0 stevel static INLINE void frpr_icmp6(fin) 679 0 stevel fr_info_t *fin; 680 0 stevel { 681 0 stevel int minicmpsz = sizeof(struct icmp6_hdr); 682 0 stevel struct icmp6_hdr *icmp6; 683 637 ml37995 684 2393 yz155240 if (frpr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1) 685 637 ml37995 return; 686 0 stevel 687 0 stevel if (fin->fin_dlen > 1) { 688 0 stevel icmp6 = fin->fin_dp; 689 0 stevel 690 0 stevel fin->fin_data[0] = *(u_short *)icmp6; 691 0 stevel 692 7176 yx160601 if ((icmp6->icmp6_type & ICMP6_INFOMSG_MASK) != 0) 693 7176 yx160601 fin->fin_flx |= FI_ICMPQUERY; 694 7176 yx160601 695 0 stevel switch (icmp6->icmp6_type) 696 0 stevel { 697 0 stevel case ICMP6_ECHO_REPLY : 698 0 stevel case ICMP6_ECHO_REQUEST : 699 7176 yx160601 if (fin->fin_dlen >= 6) 700 7176 yx160601 fin->fin_data[1] = icmp6->icmp6_id; 701 0 stevel minicmpsz = ICMP6ERR_MINPKTLEN - sizeof(ip6_t); 702 0 stevel break; 703 0 stevel case ICMP6_DST_UNREACH : 704 0 stevel case ICMP6_PACKET_TOO_BIG : 705 0 stevel case ICMP6_TIME_EXCEEDED : 706 0 stevel case ICMP6_PARAM_PROB : 707 0 stevel if ((fin->fin_m != NULL) && 708 0 stevel (M_LEN(fin->fin_m) < fin->fin_plen)) { 709 637 ml37995 if (fr_coalesce(fin) != 1) 710 0 stevel return; 711 0 stevel } 712 0 stevel fin->fin_flx |= FI_ICMPERR; 713 0 stevel minicmpsz = ICMP6ERR_IPICMPHLEN - sizeof(ip6_t); 714 0 stevel break; 715 0 stevel default : 716 0 stevel break; 717 0 stevel } 718 0 stevel } 719 0 stevel 720 0 stevel frpr_short6(fin, minicmpsz); 721 0 stevel } 722 0 stevel 723 0 stevel 724 0 stevel /* ------------------------------------------------------------------------ */ 725 0 stevel /* Function: frpr_udp6 */ 726 0 stevel /* Returns: void */ 727 0 stevel /* Parameters: fin(I) - pointer to packet information */ 728 0 stevel /* */ 729 0 stevel /* IPv6 Only */ 730 0 stevel /* Analyse the packet for IPv6/UDP properties. */ 731 2393 yz155240 /* Is not expected to be called for fragmented packets. */ 732 0 stevel /* ------------------------------------------------------------------------ */ 733 0 stevel static INLINE void frpr_udp6(fin) 734 0 stevel fr_info_t *fin; 735 0 stevel { 736 0 stevel 737 0 stevel fr_checkv6sum(fin); 738 0 stevel 739 0 stevel frpr_short6(fin, sizeof(struct udphdr)); 740 674 yz155240 if (frpr_pullup(fin, sizeof(struct udphdr)) == -1) 741 674 yz155240 return; 742 0 stevel 743 0 stevel frpr_udpcommon(fin); 744 0 stevel } 745 0 stevel 746 0 stevel 747 0 stevel /* ------------------------------------------------------------------------ */ 748 0 stevel /* Function: frpr_tcp6 */ 749 0 stevel /* Returns: void */ 750 0 stevel /* Parameters: fin(I) - pointer to packet information */ 751 0 stevel /* */ 752 0 stevel /* IPv6 Only */ 753 0 stevel /* Analyse the packet for IPv6/TCP properties. */ 754 2393 yz155240 /* Is not expected to be called for fragmented packets. */ 755 0 stevel /* ------------------------------------------------------------------------ */ 756 0 stevel static INLINE void frpr_tcp6(fin) 757 0 stevel fr_info_t *fin; 758 0 stevel { 759 0 stevel 760 0 stevel fr_checkv6sum(fin); 761 0 stevel 762 0 stevel frpr_short6(fin, sizeof(struct tcphdr)); 763 674 yz155240 if (frpr_pullup(fin, sizeof(struct tcphdr)) == -1) 764 674 yz155240 return; 765 637 ml37995 766 0 stevel frpr_tcpcommon(fin); 767 2393 yz155240 } 768 2393 yz155240 769 2393 yz155240 770 2393 yz155240 /* ------------------------------------------------------------------------ */ 771 2393 yz155240 /* Function: frpr_esp6 */ 772 2393 yz155240 /* Returns: void */ 773 2393 yz155240 /* Parameters: fin(I) - pointer to packet information */ 774 2393 yz155240 /* */ 775 2393 yz155240 /* IPv6 Only */ 776 2393 yz155240 /* Analyse the packet for ESP properties. */ 777 2393 yz155240 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ 778 2393 yz155240 /* even though the newer ESP packets must also have a sequence number that */ 779 2393 yz155240 /* is 32bits as well, it is not possible(?) to determine the version from a */ 780 2393 yz155240 /* simple packet header. */ 781 2393 yz155240 /* ------------------------------------------------------------------------ */ 782 2393 yz155240 static INLINE void frpr_esp6(fin) 783 2393 yz155240 fr_info_t *fin; 784 2393 yz155240 { 785 2393 yz155240 int i; 786 2393 yz155240 frpr_short6(fin, sizeof(grehdr_t)); 787 2393 yz155240 788 2393 yz155240 (void) frpr_pullup(fin, 8); 789 2393 yz155240 790 2393 yz155240 for (i = 0; ip6exthdr[i].ol_bit != 0; i++) 791 2393 yz155240 if (ip6exthdr[i].ol_val == IPPROTO_ESP) { 792 2393 yz155240 fin->fin_optmsk |= ip6exthdr[i].ol_bit; 793 2393 yz155240 break; 794 2393 yz155240 } 795 2393 yz155240 } 796 2393 yz155240 797 2393 yz155240 798 2393 yz155240 /* ------------------------------------------------------------------------ */ 799 2393 yz155240 /* Function: frpr_ah6 */ 800 2393 yz155240 /* Returns: void */ 801 2393 yz155240 /* Parameters: fin(I) - pointer to packet information */ 802 2393 yz155240 /* */ 803 2393 yz155240 /* IPv6 Only */ 804 2393 yz155240 /* Analyse the packet for AH properties. */ 805 2393 yz155240 /* The minimum length is taken to be the combination of all fields in the */ 806 2393 yz155240 /* header being present and no authentication data (null algorithm used.) */ 807 2393 yz155240 /* ------------------------------------------------------------------------ */ 808 2393 yz155240 static INLINE int frpr_ah6(fin) 809 2393 yz155240 fr_info_t *fin; 810 2393 yz155240 { 811 2393 yz155240 authhdr_t *ah; 812 2393 yz155240 int i, shift; 813 2393 yz155240 814 2393 yz155240 frpr_short6(fin, 12); 815 2393 yz155240 816 2393 yz155240 if (frpr_pullup(fin, sizeof(*ah)) == -1) 817 2393 yz155240 return IPPROTO_NONE; 818 2393 yz155240 819 2393 yz155240 for (i = 0; ip6exthdr[i].ol_bit != 0; i++) 820 2393 yz155240 if (ip6exthdr[i].ol_val == IPPROTO_AH) { 821 2393 yz155240 fin->fin_optmsk |= ip6exthdr[i].ol_bit; 822 2393 yz155240 break; 823 2393 yz155240 } 824 2393 yz155240 825 2393 yz155240 ah = (authhdr_t *)fin->fin_dp; 826 2393 yz155240 827 2393 yz155240 shift = (ah->ah_plen + 2) * 4; 828 2393 yz155240 fin->fin_dlen -= shift; 829 2393 yz155240 fin->fin_dp = (char*)fin->fin_dp + shift; 830 2393 yz155240 831 2393 yz155240 return ah->ah_next; 832 2393 yz155240 } 833 2393 yz155240 834 2393 yz155240 835 2393 yz155240 /* ------------------------------------------------------------------------ */ 836 2393 yz155240 /* Function: frpr_gre6 */ 837 2393 yz155240 /* Returns: void */ 838 2393 yz155240 /* Parameters: fin(I) - pointer to packet information */ 839 2393 yz155240 /* */ 840 2393 yz155240 /* Analyse the packet for GRE properties. */ 841 2393 yz155240 /* ------------------------------------------------------------------------ */ 842 2393 yz155240 static INLINE void frpr_gre6(fin) 843 2393 yz155240 fr_info_t *fin; 844 2393 yz155240 { 845 2393 yz155240 grehdr_t *gre; 846 2393 yz155240 847 2393 yz155240 frpr_short6(fin, sizeof(grehdr_t)); 848 2393 yz155240 849 2393 yz155240 if (frpr_pullup(fin, sizeof(grehdr_t)) == -1) 850 2393 yz155240 return; 851 2393 yz155240 852 2393 yz155240 gre = fin->fin_dp; 853 2393 yz155240 if (GRE_REV(gre->gr_flags) == 1) 854 2393 yz155240 fin->fin_data[0] = gre->gr_call; 855 0 stevel } 856 0 stevel #endif /* USE_INET6 */ 857 637 ml37995 858 637 ml37995 859 637 ml37995 /* ------------------------------------------------------------------------ */ 860 637 ml37995 /* Function: frpr_pullup */ 861 637 ml37995 /* Returns: int - 0 == pullup succeeded, -1 == failure */ 862 637 ml37995 /* Parameters: fin(I) - pointer to packet information */ 863 637 ml37995 /* plen(I) - length (excluding L3 header) to pullup */ 864 637 ml37995 /* */ 865 637 ml37995 /* Short inline function to cut down on code duplication to perform a call */ 866 637 ml37995 /* to fr_pullup to ensure there is the required amount of data, */ 867 637 ml37995 /* consecutively in the packet buffer. */ 868 637 ml37995 /* ------------------------------------------------------------------------ */ 869 637 ml37995 static INLINE int frpr_pullup(fin, plen) 870 637 ml37995 fr_info_t *fin; 871 637 ml37995 int plen; 872 637 ml37995 { 873 2393 yz155240 #if defined(_KERNEL) 874 637 ml37995 if (fin->fin_m != NULL) { 875 7704 Alexandr int ipoff; 876 7704 Alexandr 877 7704 Alexandr ipoff = (char *)fin->fin_ip - MTOD(fin->fin_m, char *); 878 7704 Alexandr 879 637 ml37995 if (fin->fin_dp != NULL) 880 637 ml37995 plen += (char *)fin->fin_dp - 881 637 ml37995 ((char *)fin->fin_ip + fin->fin_hlen); 882 7704 Alexandr plen += fin->fin_hlen; 883 7704 Alexandr /* 884 7704 Alexandr * We don't do 'plen += ipoff;' here. The fr_pullup() will 885 7704 Alexandr * do it for us. 886 7704 Alexandr */ 887 7704 Alexandr if (M_LEN(fin->fin_m) < plen + ipoff) { 888 637 ml37995 if (fr_pullup(fin->fin_m, fin, plen) == NULL) 889 637 ml37995 return -1; 890 637 ml37995 } 891 637 ml37995 } 892 637 ml37995 #endif 893 637 ml37995 return 0; 894 637 ml37995 } 895 0 stevel 896 0 stevel 897 0 stevel /* ------------------------------------------------------------------------ */ 898 0 stevel /* Function: frpr_short */ 899 0 stevel /* Returns: void */ 900 2393 yz155240 /* Parameters: fin(I) - pointer to packet information */ 901 2393 yz155240 /* xmin(I) - minimum header size */ 902 2393 yz155240 /* */ 903 2393 yz155240 /* Check if a packet is "short" as defined by xmin. The rule we are */ 904 2393 yz155240 /* applying here is that the packet must not be fragmented within the layer */ 905 2393 yz155240 /* 4 header. That is, it must not be a fragment that has its offset set to */ 906 2393 yz155240 /* start within the layer 4 header (hdrmin) or if it is at offset 0, the */ 907 2393 yz155240 /* entire layer 4 header must be present (min). */ 908 2393 yz155240 /* ------------------------------------------------------------------------ */ 909 2393 yz155240 static INLINE void frpr_short(fin, xmin) 910 2393 yz155240 fr_info_t *fin; 911 2393 yz155240 int xmin; 912 2393 yz155240 { 913 2393 yz155240 914 2393 yz155240 if (fin->fin_off == 0) { 915 2393 yz155240 if (fin->fin_dlen < xmin) 916 2393 yz155240 fin->fin_flx |= FI_SHORT; 917 2393 yz155240 } else if (fin->fin_off < xmin) { 918 2393 yz155240 fin->fin_flx |= FI_SHORT; 919 0 stevel } 920 0 stevel } 921 0 stevel 922 0 stevel 923 0 stevel /* ------------------------------------------------------------------------ */ 924 0 stevel /* Function: frpr_icmp */ 925 0 stevel /* Returns: void */ 926 0 stevel /* Parameters: fin(I) - pointer to packet information */ 927 0 stevel /* */ 928 0 stevel /* IPv4 Only */ 929 0 stevel /* Do a sanity check on the packet for ICMP (v4). In nearly all cases, */ 930 0 stevel /* except extrememly bad packets, both type and code will be present. */ 931 2393 yz155240 /* The expected minimum size of an ICMP packet is very much dependent on */ 932 0 stevel /* the type of it. */ 933 0 stevel /* */ 934 0 stevel /* XXX - other ICMP sanity checks? */ 935 0 stevel /* ------------------------------------------------------------------------ */ 936 0 stevel static INLINE void frpr_icmp(fin) 937 0 stevel fr_info_t *fin; 938 0 stevel { 939 0 stevel int minicmpsz = sizeof(struct icmp); 940 0 stevel icmphdr_t *icmp; 941 2393 yz155240 ip_t *oip; 942 3448 dh155122 ipf_stack_t *ifs = fin->fin_ifs; 943 0 stevel 944 780 ml37995 if (fin->fin_off != 0) { 945 780 ml37995 frpr_short(fin, ICMPERR_ICMPHLEN); 946 780 ml37995 return; 947 780 ml37995 } 948 2393 yz155240 949 2393 yz155240 if (frpr_pullup(fin, ICMPERR_ICMPHLEN) == -1) 950 2393 yz155240 return; 951 780 ml37995 952 0 stevel fr_checkv4sum(fin); 953 0 stevel 954 9029 Alexandr /* 955 9029 Alexandr * This is a right place to set icmp pointer, since the memory 956 9029 Alexandr * referenced by fin_dp could get reallocated. The code down below can 957 9029 Alexandr * rely on fact icmp variable always points to ICMP header. 958 9029 Alexandr */ 959 9029 Alexandr icmp = fin->fin_dp; 960 9029 Alexandr fin->fin_data[0] = *(u_short *)icmp; 961 9029 Alexandr fin->fin_data[1] = icmp->icmp_id; 962 9029 Alexandr 963 9029 Alexandr switch (icmp->icmp_type) 964 9029 Alexandr { 965 9029 Alexandr case ICMP_ECHOREPLY : 966 9029 Alexandr case ICMP_ECHO : 967 9029 Alexandr /* Router discovery messaes - RFC 1256 */ 968 9029 Alexandr case ICMP_ROUTERADVERT : 969 9029 Alexandr case ICMP_ROUTERSOLICIT : 970 9029 Alexandr minicmpsz = ICMP_MINLEN; 971 9029 Alexandr break; 972 9029 Alexandr /* 973 9029 Alexandr * type(1) + code(1) + cksum(2) + id(2) seq(2) + 974 9029 Alexandr * 3 * timestamp(3 * 4) 975 9029 Alexandr */ 976 9029 Alexandr case ICMP_TSTAMP : 977 9029 Alexandr case ICMP_TSTAMPREPLY : 978 9029 Alexandr minicmpsz = 20; 979 9029 Alexandr break; 980 9029 Alexandr /* 981 9029 Alexandr * type(1) + code(1) + cksum(2) + id(2) seq(2) + 982 9029 Alexandr * mask(4) 983 9029 Alexandr */ 984 9029 Alexandr case ICMP_MASKREQ : 985 9029 Alexandr case ICMP_MASKREPLY : 986 0 stevel minicmpsz = 12; 987 0 stevel break; 988 9029 Alexandr /* 989 9029 Alexandr * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+) 990 9029 Alexandr */ 991 9029 Alexandr case ICMP_UNREACH : 992 9029 Alexandr if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG) { 993 9029 Alexandr if (icmp->icmp_nextmtu < ifs->ifs_fr_icmpminfragmtu) 994 2393 yz155240 fin->fin_flx |= FI_BAD; 995 9029 Alexandr } 996 9029 Alexandr /* FALLTHRU */ 997 9029 Alexandr case ICMP_SOURCEQUENCH : 998 9029 Alexandr case ICMP_REDIRECT : 999 9029 Alexandr case ICMP_TIMXCEED : 1000 9029 Alexandr case ICMP_PARAMPROB : 1001 9029 Alexandr fin->fin_flx |= FI_ICMPERR; 1002 9029 Alexandr if (fr_coalesce(fin) != 1) 1003 9029 Alexandr return; 1004 9029 Alexandr /* 1005 9029 Alexandr * ICMP error packets should not be generated for IP 1006 9029 Alexandr * packets that are a fragment that isn't the first 1007 9029 Alexandr * fragment. 1008 9029 Alexandr */ 1009 9029 Alexandr oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN); 1010 9029 Alexandr if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0) 1011 9029 Alexandr fin->fin_flx |= FI_BAD; 1012 9029 Alexandr break; 1013 9029 Alexandr default : 1014 9029 Alexandr break; 1015 0 stevel } 1016 0 stevel 1017 637 ml37995 frpr_short(fin, minicmpsz); 1018 0 stevel } 1019 0 stevel 1020 0 stevel 1021 0 stevel /* ------------------------------------------------------------------------ */ 1022 0 stevel /* Function: frpr_tcpcommon */ 1023 0 stevel /* Returns: void */ 1024 0 stevel /* Parameters: fin(I) - pointer to packet information */ 1025 0 stevel /* */ 1026 0 stevel /* TCP header sanity checking. Look for bad combinations of TCP flags, */ 1027 0 stevel /* and make some checks with how they interact with other fields. */ 1028 0 stevel /* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is */ 1029 0 stevel /* valid and mark the packet as bad if not. */ 1030 0 stevel /* ------------------------------------------------------------------------ */ 1031 0 stevel static INLINE void frpr_tcpcommon(fin) 1032 0 stevel fr_info_t *fin; 1033 0 stevel { 1034 0 stevel int flags, tlen; 1035 0 stevel tcphdr_t *tcp; 1036 780 ml37995 1037 780 ml37995 fin->fin_flx |= FI_TCPUDP; 1038 780 ml37995 if (fin->fin_off != 0) 1039 780 ml37995 return; 1040 780 ml37995 1041 2393 yz155240 if (frpr_pullup(fin, sizeof(*tcp)) == -1) 1042 2393 yz155240 return; 1043 0 stevel tcp = fin->fin_dp; 1044 0 stevel 1045 780 ml37995 if (fin->fin_dlen > 3) { 1046 0 stevel fin->fin_sport = ntohs(tcp->th_sport); 1047 0 stevel fin->fin_dport = ntohs(tcp->th_dport); 1048 0 stevel } 1049 0 stevel 1050 2393 yz155240 if ((fin->fin_flx & FI_SHORT) != 0) 1051 2393 yz155240 return; 1052 2393 yz155240 1053 2393 yz155240 /* 1054 2393 yz155240 * Use of the TCP data offset *must* result in a value that is at 1055 2393 yz155240 * least the same size as the TCP header. 1056 2393 yz155240 */ 1057 2393 yz155240 tlen = TCP_OFF(tcp) << 2; 1058 2393 yz155240 if (tlen < sizeof(tcphdr_t)) { 1059 2393 yz155240 fin->fin_flx |= FI_BAD; 1060 2393 yz155240 return; 1061 2393 yz155240 } 1062 2393 yz155240 1063 2393 yz155240 flags = tcp->th_flags; 1064 2393 yz155240 fin->fin_tcpf = tcp->th_flags; 1065 2393 yz155240 1066 2393 yz155240 /* 1067 2393 yz155240 * If the urgent flag is set, then the urgent pointer must 1068 2393 yz155240 * also be set and vice versa. Good TCP packets do not have 1069 2393 yz155240 * just one of these set. 1070 2393 yz155240 */ 1071 2393 yz155240 if ((flags & TH_URG) != 0 && (tcp->th_urp == 0)) { 1072 2393 yz155240 fin->fin_flx |= FI_BAD; 1073 2393 yz155240 } else if ((flags & TH_URG) == 0 && (tcp->th_urp != 0)) { 1074 2393 yz155240 /* Ignore this case, it shows up in "real" traffic with */ 1075 2393 yz155240 /* bogus values in the urgent pointer field. */ 1076 2393 yz155240 flags = flags; /* LINT */ 1077 2393 yz155240 } else if (((flags & (TH_SYN|TH_FIN)) != 0) && 1078 2393 yz155240 ((flags & (TH_RST|TH_ACK)) == TH_RST)) { 1079 2393 yz155240 /* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */ 1080 2393 yz155240 fin->fin_flx |= FI_BAD; 1081 2393 yz155240 } else if (!(flags & TH_ACK)) { 1082 2393 yz155240 /* 1083 2393 yz155240 * If the ack bit isn't set, then either the SYN or 1084 2393 yz155240 * RST bit must be set. If the SYN bit is set, then 1085 2393 yz155240 * we expect the ACK field to be 0. If the ACK is 1086 2393 yz155240 * not set and if URG, PSH or FIN are set, consdier 1087 2393 yz155240 * that to indicate a bad TCP packet. 1088 2393 yz155240 */ 1089 2393 yz155240 if ((flags == TH_SYN) && (tcp->th_ack != 0)) { 1090 2393 yz155240 /* 1091 2393 yz155240 * Cisco PIX sets the ACK field to a random value. 1092 2393 yz155240 * In light of this, do not set FI_BAD until a patch 1093 2393 yz155240 * is available from Cisco to ensure that 1094 2393 yz155240 * interoperability between existing systems is 1095 2393 yz155240 * achieved. 1096 2393 yz155240 */ 1097 2393 yz155240 /*fin->fin_flx |= FI_BAD*/; 1098 2393 yz155240 flags = flags; /* LINT */ 1099 2393 yz155240 } else if (!(flags & (TH_RST|TH_SYN))) { 1100 2393 yz155240 fin->fin_flx |= FI_BAD; 1101 2393 yz155240 } else if ((flags & (TH_URG|TH_PUSH|TH_FIN)) != 0) { 1102 2393 yz155240 fin->fin_flx |= FI_BAD; 1103 2393 yz155240 } 1104 2393 yz155240 } 1105 2393 yz155240 1106 0 stevel /* 1107 0 stevel * At this point, it's not exactly clear what is to be gained by 1108 0 stevel * marking up which TCP options are and are not present. The one we 1109 0 stevel * are most interested in is the TCP window scale. This is only in 1110 0 stevel * a SYN packet [RFC1323] so we don't need this here...? 1111 0 stevel * Now if we were to analyse the header for passive fingerprinting, 1112 0 stevel * then that might add some weight to adding this... 1113 0 stevel */ 1114 2393 yz155240 if (tlen == sizeof(tcphdr_t)) 1115 2393 yz155240 return; 1116 2393 yz155240 1117 2393 yz155240 if (frpr_pullup(fin, tlen) == -1) 1118 2393 yz155240 return; 1119 2393 yz155240 1120 2393 yz155240 #if 0 1121 2393 yz155240 ip = fin->fin_ip; 1122 0 stevel s = (u_char *)(tcp + 1); 1123 0 stevel off = IP_HL(ip) << 2; 1124 0 stevel # ifdef _KERNEL 1125 0 stevel if (fin->fin_mp != NULL) { 1126 0 stevel mb_t *m = *fin->fin_mp; 1127 0 stevel 1128 2393 yz155240 if (off + tlen > M_LEN(m)) 1129 0 stevel return; 1130 0 stevel } 1131 0 stevel # endif 1132 2393 yz155240 for (tlen -= (int)sizeof(*tcp); tlen > 0; ) { 1133 0 stevel opt = *s; 1134 0 stevel if (opt == '\0') 1135 0 stevel break; 1136 0 stevel else if (opt == TCPOPT_NOP) 1137 0 stevel ol = 1; 1138 0 stevel else { 1139 2393 yz155240 if (tlen < 2) 1140 0 stevel break; 1141 0 stevel ol = (int)*(s + 1); 1142 2393 yz155240 if (ol < 2 || ol > tlen) 1143 0 stevel break; 1144 0 stevel } 1145 0 stevel 1146 0 stevel for (i = 9, mv = 4; mv >= 0; ) { 1147 0 stevel op = ipopts + i; 1148 0 stevel if (opt == (u_char)op->ol_val) { 1149 0 stevel optmsk |= op->ol_bit; 1150 0 stevel break; 1151 0 stevel } 1152 0 stevel } 1153 2393 yz155240 tlen -= ol; 1154 0 stevel s += ol; 1155 0 stevel } 1156 0 stevel #endif /* 0 */ 1157 0 stevel } 1158 0 stevel 1159 0 stevel 1160 0 stevel 1161 0 stevel /* ------------------------------------------------------------------------ */ 1162 0 stevel /* Function: frpr_udpcommon */ 1163 0 stevel /* Returns: void */ 1164 0 stevel /* Parameters: fin(I) - pointer to packet information */ 1165 0 stevel /* */ 1166 0 stevel /* Extract the UDP source and destination ports, if present. If compiled */ 1167 0 stevel /* with IPFILTER_CKSUM, check to see if the UDP checksum is valid. */ 1168 0 stevel /* ------------------------------------------------------------------------ */ 1169 0 stevel static INLINE void frpr_udpcommon(fin) 1170 0 stevel fr_info_t *fin; 1171 0 stevel { 1172 0 stevel udphdr_t *udp; 1173 780 ml37995 1174 780 ml37995 fin->fin_flx |= FI_TCPUDP; 1175 0 stevel 1176 0 stevel if (!fin->fin_off && (fin->fin_dlen > 3)) { 1177 2393 yz155240 if (frpr_pullup(fin, sizeof(*udp)) == -1) { 1178 2393 yz155240 fin->fin_flx |= FI_SHORT; 1179 2393 yz155240 return; 1180 2393 yz155240 } 1181 2393 yz155240 1182 780 ml37995 udp = fin->fin_dp; 1183 780 ml37995 1184 0 stevel fin->fin_sport = ntohs(udp->uh_sport); 1185 0 stevel fin->fin_dport = ntohs(udp->uh_dport); 1186 0 stevel } 1187 0 stevel } 1188 0 stevel 1189 0 stevel 1190 0 stevel /* ------------------------------------------------------------------------ */ 1191 0 stevel /* Function: frpr_tcp */ 1192 0 stevel /* Returns: void */ 1193 0 stevel /* Parameters: fin(I) - pointer to packet information */ 1194 0 stevel /* */ 1195 0 stevel /* IPv4 Only */ 1196 0 stevel /* Analyse the packet for IPv4/TCP properties. */ 1197 0 stevel /* ------------------------------------------------------------------------ */ 1198 0 stevel static INLINE void frpr_tcp(fin) 1199 0 stevel fr_info_t *fin; 1200 0 stevel { 1201 0 stevel 1202 0 stevel fr_checkv4sum(fin); 1203 0 stevel 1204 2393 yz155240 frpr_short(fin, sizeof(tcphdr_t)); 1205 0 stevel 1206 0 stevel frpr_tcpcommon(fin); 1207 0 stevel } 1208 0 stevel 1209 0 stevel 1210 0 stevel /* ------------------------------------------------------------------------ */ 1211 0 stevel /* Function: frpr_udp */ 1212 0 stevel /* Returns: void */ 1213 0 stevel /* Parameters: fin(I) - pointer to packet information */ 1214 0 stevel /* */ 1215 0 stevel /* IPv4 Only */ 1216 0 stevel /* Analyse the packet for IPv4/UDP properties. */ 1217 0 stevel /* ------------------------------------------------------------------------ */ 1218 0 stevel static INLINE void frpr_udp(fin) 1219 0 stevel fr_info_t *fin; 1220 0 stevel { 1221 0 stevel 1222 0 stevel fr_checkv4sum(fin); 1223 0 stevel 1224 2393 yz155240 frpr_short(fin, sizeof(udphdr_t)); 1225 0 stevel 1226 0 stevel frpr_udpcommon(fin); 1227 637 ml37995 } 1228 637 ml37995 1229 637 ml37995 1230 637 ml37995 /* ------------------------------------------------------------------------ */ 1231 637 ml37995 /* Function: frpr_esp */ 1232 637 ml37995 /* Returns: void */ 1233 637 ml37995 /* Parameters: fin(I) - pointer to packet information */ 1234 637 ml37995 /* */ 1235 637 ml37995 /* Analyse the packet for ESP properties. */ 1236 637 ml37995 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ 1237 637 ml37995 /* even though the newer ESP packets must also have a sequence number that */ 1238 637 ml37995 /* is 32bits as well, it is not possible(?) to determine the version from a */ 1239 637 ml37995 /* simple packet header. */ 1240 637 ml37995 /* ------------------------------------------------------------------------ */ 1241 637 ml37995 static INLINE void frpr_esp(fin) 1242 637 ml37995 fr_info_t *fin; 1243 637 ml37995 { 1244 2393 yz155240 if ((fin->fin_off == 0) && (frpr_pullup(fin, 8) == -1)) 1245 2393 yz155240 return; 1246 2393 yz155240 1247 2393 yz155240 frpr_short(fin, 8); 1248 2393 yz155240 } 1249 2393 yz155240 1250 2393 yz155240 1251 2393 yz155240 /* ------------------------------------------------------------------------ */ 1252 2393 yz155240 /* Function: frpr_ah */ 1253 2393 yz155240 /* Returns: void */ 1254 2393 yz155240 /* Parameters: fin(I) - pointer to packet information */ 1255 2393 yz155240 /* */ 1256 2393 yz155240 /* Analyse the packet for AH properties. */ 1257 2393 yz155240 /* The minimum length is taken to be the combination of all fields in the */ 1258 2393 yz155240 /* header being present and no authentication data (null algorithm used.) */ 1259 2393 yz155240 /* ------------------------------------------------------------------------ */ 1260 2393 yz155240 static INLINE void frpr_ah(fin) 1261 2393 yz155240 fr_info_t *fin; 1262 2393 yz155240 { 1263 2393 yz155240 authhdr_t *ah; 1264 2393 yz155240 int len; 1265 2393 yz155240 1266 2393 yz155240 if ((fin->fin_off == 0) && (frpr_pullup(fin, sizeof(*ah)) == -1)) 1267 2393 yz155240 return; 1268 2393 yz155240 1269 2393 yz155240 ah = (authhdr_t *)fin->fin_dp; 1270 2393 yz155240 1271 2393 yz155240 len = (ah->ah_plen + 2) << 2; 1272 2393 yz155240 frpr_short(fin, len); 1273 637 ml37995 } 1274 637 ml37995 1275 637 ml37995 1276 637 ml37995 /* ------------------------------------------------------------------------ */ 1277 637 ml37995 /* Function: frpr_gre */ 1278 637 ml37995 /* Returns: void */ 1279 637 ml37995 /* Parameters: fin(I) - pointer to packet information */ 1280 637 ml37995 /* */ 1281 637 ml37995 /* Analyse the packet for GRE properties. */ 1282 637 ml37995 /* ------------------------------------------------------------------------ */ 1283 637 ml37995 static INLINE void frpr_gre(fin) 1284 637 ml37995 fr_info_t *fin; 1285 637 ml37995 { 1286 2393 yz155240 grehdr_t *gre; 1287 2393 yz155240 1288 2393 yz155240 if ((fin->fin_off == 0) && (frpr_pullup(fin, sizeof(grehdr_t)) == -1)) 1289 2393 yz155240 return; 1290 2393 yz155240 1291 2393 yz155240 frpr_short(fin, sizeof(grehdr_t)); 1292 2393 yz155240 1293 2393 yz155240 if (fin->fin_off == 0) { 1294 2393 yz155240 gre = fin->fin_dp; 1295 2393 yz155240 if (GRE_REV(gre->gr_flags) == 1) 1296 2393 yz155240 fin->fin_data[0] = gre->gr_call; 1297 2393 yz155240 } 1298 0 stevel } 1299 0 stevel 1300 0 stevel 1301 0 stevel /* ------------------------------------------------------------------------ */ 1302 0 stevel /* Function: frpr_ipv4hdr */ 1303 0 stevel /* Returns: void */ 1304 0 stevel /* Parameters: fin(I) - pointer to packet information */ 1305 0 stevel /* */ 1306 0 stevel /* IPv4 Only */ 1307 0 stevel /* Analyze the IPv4 header and set fields in the fr_info_t structure. */ 1308 0 stevel /* Check all options present and flag their presence if any exist. */ 1309 0 stevel /* ------------------------------------------------------------------------ */ 1310 0 stevel static INLINE void frpr_ipv4hdr(fin) 1311 0 stevel fr_info_t *fin; 1312 0 stevel { 1313 0 stevel u_short optmsk = 0, secmsk = 0, auth = 0; 1314 0 stevel int hlen, ol, mv, p, i; 1315 2393 yz155240 const struct optlist *op; 1316 0 stevel u_char *s, opt; 1317 0 stevel u_short off; 1318 0 stevel fr_ip_t *fi; 1319 0 stevel ip_t *ip; 1320 0 stevel 1321 0 stevel fi = &fin->fin_fi; 1322 0 stevel hlen = fin->fin_hlen; 1323 0 stevel 1324 0 stevel ip = fin->fin_ip; 1325 0 stevel p = ip->ip_p; 1326 0 stevel fi->fi_p = p; 1327 0 stevel fi->fi_tos = ip->ip_tos; 1328 0 stevel fin->fin_id = ip->ip_id; 1329 0 stevel off = ip->ip_off; 1330 0 stevel 1331 0 stevel /* Get both TTL and protocol */ 1332 0 stevel fi->fi_p = ip->ip_p; 1333 0 stevel fi->fi_ttl = ip->ip_ttl; 1334 0 stevel #if 0 1335 0 stevel (*(((u_short *)fi) + 1)) = (*(((u_short *)ip) + 4)); 1336 0 stevel #endif 1337 0 stevel 1338 0 stevel /* Zero out bits not used in IPv6 address */ 1339 0 stevel fi->fi_src.i6[1] = 0; 1340 0 stevel fi->fi_src.i6[2] = 0; 1341 0 stevel fi->fi_src.i6[3] = 0; 1342 0 stevel fi->fi_dst.i6[1] = 0; 1343 0 stevel fi->fi_dst.i6[2] = 0; 1344 0 stevel fi->fi_dst.i6[3] = 0; 1345 0 stevel 1346 0 stevel fi->fi_saddr = ip->ip_src.s_addr; 1347 0 stevel fi->fi_daddr = ip->ip_dst.s_addr; 1348 0 stevel 1349 0 stevel /* 1350 0 stevel * set packet attribute flags based on the offset and 1351 0 stevel * calculate the byte offset that it represents. 1352 0 stevel */ 1353 0 stevel off &= IP_MF|IP_OFFMASK; 1354 0 stevel if (off != 0) { 1355 9876 Darren int morefrag = off & IP_MF; 1356 9876 Darren 1357 0 stevel fi->fi_flx |= FI_FRAG; 1358 9876 Darren if (morefrag) 1359 9876 Darren fi->fi_flx |= FI_MOREFRAG; 1360 0 stevel off &= IP_OFFMASK; 1361 0 stevel if (off != 0) { 1362 2393 yz155240 fin->fin_flx |= FI_FRAGBODY; 1363 0 stevel off <<= 3; 1364 2393 yz155240 if ((off + fin->fin_dlen > 65535) || 1365 2393 yz155240 (fin->fin_dlen == 0) || 1366 9876 Darren ((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) { 1367 2393 yz155240 /* 1368 2393 yz155240 * The length of the packet, starting at its 1369 2393 yz155240 * offset cannot exceed 65535 (0xffff) as the 1370 2393 yz155240 * length of an IP packet is only 16 bits. 1371 2393 yz155240 * 1372 2393 yz155240 * Any fragment that isn't the last fragment 1373 2393 yz155240 * must have a length greater than 0 and it 1374 2393 yz155240 * must be an even multiple of 8. 1375 2393 yz155240 */ 1376 0 stevel fi->fi_flx |= FI_BAD; 1377 2393 yz155240 } 1378 0 stevel } 1379 0 stevel } 1380 0 stevel fin->fin_off = off; 1381 0 stevel 1382 0 stevel /* 1383 0 stevel * Call per-protocol setup and checking 1384 0 stevel */ 1385 0 stevel switch (p) 1386 0 stevel { 1387 0 stevel case IPPROTO_UDP : 1388 0 stevel frpr_udp(fin); 1389 0 stevel break; 1390 0 stevel case IPPROTO_TCP : 1391 0 stevel frpr_tcp(fin); 1392 0 stevel break; 1393 0 stevel case IPPROTO_ICMP : 1394 0 stevel frpr_icmp(fin); 1395 2393 yz155240 break; 1396 2393 yz155240 case IPPROTO_AH : 1397 2393 yz155240 frpr_ah(fin); 1398 2393 yz155240 break; 1399 2393 yz155240 case IPPROTO_ESP : 1400 2393 yz155240 frpr_esp(fin); 1401 2393 yz155240 break; 1402 2393 yz155240 case IPPROTO_GRE : 1403 2393 yz155240 frpr_gre(fin); 1404 0 stevel break; 1405 0 stevel } 1406 0 stevel 1407 0 stevel ip = fin->fin_ip; 1408 0 stevel if (ip == NULL) 1409 0 stevel return; 1410 0 stevel 1411 0 stevel /* 1412 0 stevel * If it is a standard IP header (no options), set the flag fields 1413 0 stevel * which relate to options to 0. 1414 0 stevel */ 1415 0 stevel if (hlen == sizeof(*ip)) { 1416 0 stevel fi->fi_optmsk = 0; 1417 0 stevel fi->fi_secmsk = 0; 1418 0 stevel fi->fi_auth = 0; 1419 0 stevel return; 1420 0 stevel } 1421 0 stevel 1422 0 stevel /* 1423 0 stevel * So the IP header has some IP options attached. Walk the entire 1424 0 stevel * list of options present with this packet and set flags to indicate 1425 0 stevel * which ones are here and which ones are not. For the somewhat out 1426 0 stevel * of date and obscure security classification options, set a flag to 1427 0 stevel * represent which classification is present. 1428 0 stevel */ 1429 0 stevel fi->fi_flx |= FI_OPTIONS; 1430 0 stevel 1431 0 stevel for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) { 1432 0 stevel opt = *s; 1433 0 stevel if (opt == '\0') 1434 0 stevel break; 1435 0 stevel else if (opt == IPOPT_NOP) 1436 0 stevel ol = 1; 1437 0 stevel else { 1438 0 stevel if (hlen < 2) 1439 0 stevel break; 1440 0 stevel ol = (int)*(s + 1); 1441 0 stevel if (ol < 2 || ol > hlen) 1442 0 stevel break; 1443 0 stevel } 1444 0 stevel for (i = 9, mv = 4; mv >= 0; ) { 1445 0 stevel op = ipopts + i; 1446 0 stevel if ((opt == (u_char)op->ol_val) && (ol > 4)) { 1447 0 stevel optmsk |= op->ol_bit; 1448 0 stevel if (opt == IPOPT_SECURITY) { 1449 2393 yz155240 const struct optlist *sp; 1450 0 stevel u_char sec; 1451 0 stevel int j, m; 1452 0 stevel 1453 0 stevel sec = *(s + 2); /* classification */ 1454 0 stevel for (j = 3, m = 2; m >= 0; ) { 1455 0 stevel sp = secopt + j; 1456 0 stevel if (sec == sp->ol_val) { 1457 0 stevel secmsk |= sp->ol_bit; 1458 0 stevel auth = *(s + 3); 1459 0 stevel auth *= 256; 1460 0 stevel auth += *(s + 4); 1461 0 stevel break; 1462 0 stevel } 1463 0 stevel if (sec < sp->ol_val) 1464 0 stevel j -= m; 1465 0 stevel else 1466 0 stevel j += m; 1467 0 stevel m--; 1468 0 stevel } 1469 0 stevel } 1470 0 stevel break; 1471 0 stevel } 1472 0 stevel if (opt < op->ol_val) 1473 0 stevel i -= mv; 1474 0 stevel else 1475 0 stevel i += mv; 1476 0 stevel mv--; 1477 0 stevel } 1478 0 stevel hlen -= ol; 1479 0 stevel s += ol; 1480 0 stevel } 1481 0 stevel 1482 0 stevel /* 1483 2393 yz155240 * 1484 0 stevel */ 1485 0 stevel if (auth && !(auth & 0x0100)) 1486 0 stevel auth &= 0xff00; 1487 0 stevel fi->fi_optmsk = optmsk; 1488 0 stevel fi->fi_secmsk = secmsk; 1489 0 stevel fi->fi_auth = auth; 1490 0 stevel } 1491 0 stevel 1492 0 stevel 1493 0 stevel /* ------------------------------------------------------------------------ */ 1494 0 stevel /* Function: fr_makefrip */ 1495 674 yz155240 /* Returns: int - 1 == hdr checking error, 0 == OK */ 1496 0 stevel /* Parameters: hlen(I) - length of IP packet header */ 1497 0 stevel /* ip(I) - pointer to the IP header */ 1498 2393 yz155240 /* fin(IO) - pointer to packet information */ 1499 0 stevel /* */ 1500 0 stevel /* Compact the IP header into a structure which contains just the info. */ 1501 0 stevel /* which is useful for comparing IP headers with and store this information */ 1502 0 stevel /* in the fr_info_t structure pointer to by fin. At present, it is assumed */ 1503 0 stevel /* this function will be called with either an IPv4 or IPv6 packet. */ 1504 0 stevel /* ------------------------------------------------------------------------ */ 1505 0 stevel int fr_makefrip(hlen, ip, fin) 1506 0 stevel int hlen; 1507 0 stevel ip_t *ip; 1508 0 stevel fr_info_t *fin; 1509 0 stevel { 1510 0 stevel int v; 1511 0 stevel 1512 0 stevel fin->fin_depth = 0; 1513 0 stevel fin->fin_hlen = (u_short)hlen; 1514 0 stevel fin->fin_ip = ip; 1515 0 stevel fin->fin_rule = 0xffffffff; 1516 0 stevel fin->fin_group[0] = -1; 1517 0 stevel fin->fin_group[1] = '\0'; 1518 0 stevel fin->fin_dlen = fin->fin_plen - hlen; 1519 0 stevel fin->fin_dp = (char *)ip + hlen; 1520 0 stevel 1521 0 stevel v = fin->fin_v; 1522 0 stevel if (v == 4) 1523 0 stevel frpr_ipv4hdr(fin); 1524 0 stevel #ifdef USE_INET6 1525 8624 Darren else if (v == 6) 1526 8624 Darren frpr_ipv6hdr(fin); 1527 0 stevel #endif 1528 0 stevel if (fin->fin_ip == NULL) 1529 0 stevel return -1; 1530 0 stevel return 0; 1531 0 stevel } 1532 0 stevel 1533 0 stevel 1534 0 stevel /* ------------------------------------------------------------------------ */ 1535 0 stevel /* Function: fr_portcheck */ 1536 0 stevel /* Returns: int - 1 == port matched, 0 == port match failed */ 1537 0 stevel /* Parameters: frp(I) - pointer to port check `expression' */ 1538 0 stevel /* pop(I) - pointer to port number to evaluate */ 1539 0 stevel /* */ 1540 0 stevel /* Perform a comparison of a port number against some other(s), using a */ 1541 0 stevel /* structure with compare information stored in it. */ 1542 0 stevel /* ------------------------------------------------------------------------ */ 1543 0 stevel static INLINE int fr_portcheck(frp, pop) 1544 0 stevel frpcmp_t *frp; 1545 0 stevel u_short *pop; 1546 0 stevel { 1547 0 stevel u_short tup, po; 1548 0 stevel int err = 1; 1549 0 stevel 1550 0 stevel tup = *pop; 1551 0 stevel po = frp->frp_port; 1552 0 stevel 1553 0 stevel /* 1554 0 stevel * Do opposite test to that required and continue if that succeeds. 1555 0 stevel */ 1556 0 stevel switch (frp->frp_cmp) 1557 0 stevel { 1558 0 stevel case FR_EQUAL : 1559 0 stevel if (tup != po) /* EQUAL */ 1560 0 stevel err = 0; 1561 0 stevel break; 1562 0 stevel case FR_NEQUAL : 1563 0 stevel if (tup == po) /* NOTEQUAL */ 1564 0 stevel err = 0; 1565 0 stevel break; 1566 0 stevel case FR_LESST : 1567 0 stevel if (tup >= po) /* LESSTHAN */ 1568 0 stevel err = 0; 1569 0 stevel break; 1570 0 stevel case FR_GREATERT : 1571 0 stevel if (tup <= po) /* GREATERTHAN */ 1572 0 stevel err = 0; 1573 0 stevel break; 1574 0 stevel case FR_LESSTE : 1575 0 stevel if (tup > po) /* LT or EQ */ 1576 0 stevel err = 0; 1577 0 stevel break; 1578 0 stevel case FR_GREATERTE : 1579 0 stevel if (tup < po) /* GT or EQ */ 1580 0 stevel err = 0; 1581 0 stevel break; 1582 0 stevel case FR_OUTRANGE : 1583 0 stevel if (tup >= po && tup <= frp->frp_top) /* Out of range */ 1584 0 stevel err = 0; 1585 0 stevel break; 1586 0 stevel case FR_INRANGE : 1587 0 stevel if (tup <= po || tup >= frp->frp_top) /* In range */ 1588 0 stevel err = 0; 1589 0 stevel break; 1590 0 stevel case FR_INCRANGE : 1591 0 stevel if (tup < po || tup > frp->frp_top) /* Inclusive range */ 1592 0 stevel err = 0; 1593 0 stevel break; 1594 0 stevel default : 1595 0 stevel break; 1596 0 stevel } 1597 0 stevel return err; 1598 0 stevel } 1599 0 stevel 1600 0 stevel 1601 0 stevel /* ------------------------------------------------------------------------ */ 1602 0 stevel /* Function: fr_tcpudpchk */ 1603 0 stevel /* Returns: int - 1 == protocol matched, 0 == check failed */ 1604 0 stevel /* Parameters: fin(I) - pointer to packet information */ 1605 0 stevel /* ft(I) - pointer to structure with comparison data */ 1606 0 stevel /* */ 1607 0 stevel /* Compares the current pcket (assuming it is TCP/UDP) information with a */ 1608 0 stevel /* structure containing information that we want to match against. */ 1609 0 stevel /* ------------------------------------------------------------------------ */ 1610 0 stevel int fr_tcpudpchk(fin, ft) 1611 0 stevel fr_info_t *fin; 1612 0 stevel frtuc_t *ft; 1613 0 stevel { 1614 0 stevel int err = 1; 1615 0 stevel 1616 0 stevel /* 1617 0 stevel * Both ports should *always* be in the first fragment. 1618 0 stevel * So far, I cannot find any cases where they can not be. 1619 0 stevel * 1620 0 stevel * compare destination ports 1621 0 stevel */ 1622 0 stevel if (ft->ftu_dcmp) 1623 0 stevel err = fr_portcheck(&ft->ftu_dst, &fin->fin_dport); 1624 0 stevel 1625 0 stevel /* 1626 0 stevel * compare source ports 1627 0 stevel */ 1628 0 stevel if (err && ft->ftu_scmp) 1629 0 stevel err = fr_portcheck(&ft->ftu_src, &fin->fin_sport); 1630 0 stevel 1631 0 stevel /* 1632 0 stevel * If we don't have all the TCP/UDP header, then how can we 1633 0 stevel * expect to do any sort of match on it ? If we were looking for 1634 0 stevel * TCP flags, then NO match. If not, then match (which should 1635 0 stevel * satisfy the "short" class too). 1636 0 stevel */ 1637 0 stevel if (err && (fin->fin_p == IPPROTO_TCP)) { 1638 0 stevel if (fin->fin_flx & FI_SHORT) 1639 0 stevel return !(ft->ftu_tcpf | ft->ftu_tcpfm); 1640 0 stevel /* 1641 0 stevel * Match the flags ? If not, abort this match. 1642 0 stevel */ 1643 0 stevel if (ft->ftu_tcpfm && 1644 0 stevel ft->ftu_tcpf != (fin->fin_tcpf & ft->ftu_tcpfm)) { 1645 0 stevel FR_DEBUG(("f. %#x & %#x != %#x\n", fin->fin_tcpf, 1646 0 stevel ft->ftu_tcpfm, ft->ftu_tcpf)); 1647 0 stevel err = 0; 1648 0 stevel } 1649 0 stevel } 1650 0 stevel return err; 1651 0 stevel } 1652 0 stevel 1653 0 stevel 1654 0 stevel /* ------------------------------------------------------------------------ */ 1655 0 stevel /* Function: fr_ipfcheck */ 1656 0 stevel /* Returns: int - 0 == match, 1 == no match */ 1657 0 stevel /* Parameters: fin(I) - pointer to packet information */ 1658 0 stevel /* fr(I) - pointer to filter rule */ 1659 0 stevel /* portcmp(I) - flag indicating whether to attempt matching on */ 1660 0 stevel /* TCP/UDP port data. */ 1661 0 stevel /* */ 1662 0 stevel /* Check to see if a packet matches an IPFilter rule. Checks of addresses, */ 1663 0 stevel /* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */ 1664 0 stevel /* this function. */ 1665 0 stevel /* ------------------------------------------------------------------------ */ 1666 0 stevel static INLINE int fr_ipfcheck(fin, fr, portcmp) 1667 0 stevel fr_info_t *fin; 1668 0 stevel frentry_t *fr; 1669 0 stevel int portcmp; 1670 0 stevel { 1671 0 stevel u_32_t *ld, *lm, *lip; 1672 0 stevel fripf_t *fri; 1673 0 stevel fr_ip_t *fi; 1674 0 stevel int i; 1675 3448 dh155122 ipf_stack_t *ifs = fin->fin_ifs; 1676 0 stevel 1677 0 stevel fi = &fin->fin_fi; 1678 0 stevel fri = fr->fr_ipf; 1679 0 stevel lip = (u_32_t *)fi; 1680 0 stevel lm = (u_32_t *)&fri->fri_mip; 1681 0 stevel ld = (u_32_t *)&fri->fri_ip; 1682 0 stevel 1683 0 stevel /* 1684 0 stevel * first 32 bits to check coversion: 1685 0 stevel * IP version, TOS, TTL, protocol 1686 0 stevel */ 1687 0 stevel i = ((*lip & *lm) != *ld); 1688 0 stevel FR_DEBUG(("0. %#08x & %#08x != %#08x\n", 1689 0 stevel *lip, *lm, *ld)); 1690 0 stevel if (i) 1691 0 stevel return 1; 1692 0 stevel 1693 0 stevel /* 1694 0 stevel * Next 32 bits is a constructed bitmask indicating which IP options 1695 0 stevel * are present (if any) in this packet. 1696 0 stevel */ 1697 0 stevel lip++, lm++, ld++; 1698 0 stevel i |= ((*lip & *lm) != *ld); 1699 0 stevel FR_DEBUG(("1. %#08x & %#08x != %#08x\n", 1700 0 stevel *lip, *lm, *ld)); 1701 0 stevel if (i) 1702 0 stevel return 1; 1703 0 stevel 1704 0 stevel lip++, lm++, ld++; 1705 0 stevel /* 1706 0 stevel * Unrolled loops (4 each, for 32 bits) for address checks. 1707 0 stevel */ 1708 0 stevel /* 1709 0 stevel * Check the source address. 1710 0 stevel */ 1711 0 stevel #ifdef IPFILTER_LOOKUP 1712 0 stevel if (fr->fr_satype == FRI_LOOKUP) { 1713 3448 dh155122 i = (*fr->fr_srcfunc)(fr->fr_srcptr, fi->fi_v, lip, ifs); 1714 0 stevel if (i == -1) 1715 0 stevel return 1; 1716 0 stevel lip += 3; 1717 0 stevel lm += 3; 1718 0 stevel ld += 3; 1719 0 stevel } else { 1720 0 stevel #endif 1721 0 stevel i = ((*lip & *lm) != *ld); 1722 0 stevel FR_DEBUG(("2a. %#08x & %#08x != %#08x\n", 1723 0 stevel *lip, *lm, *ld)); 1724 0 stevel if (fi->fi_v == 6) { 1725 0 stevel lip++, lm++, ld++; 1726 0 stevel i |= ((*lip & *lm) != *ld); 1727 0 stevel FR_DEBUG(("2b. %#08x & %#08x != %#08x\n", 1728 0 stevel *lip, *lm, *ld)); 1729 0 stevel lip++, lm++, ld++; 1730 0 stevel i |= ((*lip & *lm) != *ld); 1731 0 stevel FR_DEBUG(("2c. %#08x & %#08x != %#08x\n", 1732 0 stevel *lip, *lm, *ld)); 1733 0 stevel lip++, lm++, ld++; 1734 0 stevel i |= ((*lip & *lm) != *ld); 1735 0 stevel FR_DEBUG(("2d. %#08x & %#08x != %#08x\n", 1736 0 stevel *lip, *lm, *ld)); 1737 0 stevel } else { 1738 0 stevel lip += 3; 1739 0 stevel lm += 3; 1740 0 stevel ld += 3; 1741 0 stevel } 1742 0 stevel #ifdef IPFILTER_LOOKUP 1743 0 stevel } 1744 0 stevel #endif 1745 0 stevel i ^= (fr->fr_flags & FR_NOTSRCIP) >> 6; 1746 0 stevel if (i) 1747 0 stevel return 1; 1748 0 stevel 1749 0 stevel /* 1750 0 stevel * Check the destination address. 1751 0 stevel */ 1752 0 stevel lip++, lm++, ld++; 1753 0 stevel #ifdef IPFILTER_LOOKUP 1754 0 stevel if (fr->fr_datype == FRI_LOOKUP) { 1755 3448 dh155122 i = (*fr->fr_dstfunc)(fr->fr_dstptr, fi->fi_v, lip, ifs); 1756 0 stevel if (i == -1) 1757 0 stevel return 1; 1758 0 stevel lip += 3; 1759 0 stevel lm += 3; 1760 0 stevel ld += 3; 1761 0 stevel } else { 1762 0 stevel #endif 1763 0 stevel i = ((*lip & *lm) != *ld); 1764 0 stevel FR_DEBUG(("3a. %#08x & %#08x != %#08x\n", 1765 0 stevel *lip, *lm, *ld)); 1766 0 stevel if (fi->fi_v == 6) { 1767 0 stevel lip++, lm++, ld++; 1768 0 stevel i |= ((*lip & *lm) != *ld); 1769 0 stevel FR_DEBUG(("3b. %#08x & %#08x != %#08x\n", 1770 0 stevel *lip, *lm, *ld)); 1771 0 stevel lip++, lm++, ld++; 1772 0 stevel i |= ((*lip & *lm) != *ld); 1773 0 stevel FR_DEBUG(("3c. %#08x & %#08x != %#08x\n", 1774 0 stevel *lip, *lm, *ld)); 1775 0 stevel lip++, lm++, ld++; 1776 0 stevel i |= ((*lip & *lm) != *ld); 1777 0 stevel FR_DEBUG(("3d. %#08x & %#08x != %#08x\n", 1778 0 stevel *lip, *lm, *ld)); 1779 0 stevel } else { 1780 0 stevel lip += 3; 1781 0 stevel lm += 3; 1782 0 stevel ld += 3; 1783 0 stevel } 1784 0 stevel #ifdef IPFILTER_LOOKUP 1785 0 stevel } 1786 0 stevel #endif 1787 0 stevel i ^= (fr->fr_flags & FR_NOTDSTIP) >> 7; 1788 0 stevel if (i) 1789 0 stevel return 1; 1790 0 stevel /* 1791 0 stevel * IP addresses matched. The next 32bits contains: 1792 0 stevel * mast of old IP header security & authentication bits. 1793 0 stevel */ 1794 0 stevel lip++, lm++, ld++; 1795 0 stevel i |= ((*lip & *lm) != *ld); 1796 0 stevel FR_DEBUG(("4. %#08x & %#08x != %#08x\n", 1797 0 stevel *lip, *lm, *ld)); 1798 0 stevel 1799 0 stevel /* 1800 0 stevel * Next we have 32 bits of packet flags. 1801 0 stevel */ 1802 0 stevel lip++, lm++, ld++; 1803 0 stevel i |= ((*lip & *lm) != *ld); 1804 0 stevel FR_DEBUG(("5. %#08x & %#08x != %#08x\n", 1805 0 stevel *lip, *lm, *ld)); 1806 0 stevel 1807 0 stevel if (i == 0) { 1808 0 stevel /* 1809 0 stevel * If a fragment, then only the first has what we're 1810 0 stevel * looking for here... 1811 0 stevel */ 1812 0 stevel if (portcmp) { 1813 0 stevel if (!fr_tcpudpchk(fin, &fr->fr_tuc)) 1814 0 stevel i = 1; 1815 0 stevel } else { 1816 0 stevel if (fr->fr_dcmp || fr->fr_scmp || 1817 0 stevel fr->fr_tcpf || fr->fr_tcpfm) 1818 0 stevel i = 1; 1819 0 stevel if (fr->fr_icmpm || fr->fr_icmp) { 1820 0 stevel if (((fi->fi_p != IPPROTO_ICMP) && 1821 0 stevel (fi->fi_p != IPPROTO_ICMPV6)) || 1822 0 stevel fin->fin_off || (fin->fin_dlen < 2)) 1823 0 stevel i = 1; 1824 0 stevel else if ((fin->fin_data[0] & fr->fr_icmpm) != 1825 0 stevel fr->fr_icmp) { 1826 0 stevel FR_DEBUG(("i. %#x & %#x != %#x\n", 1827 0 stevel fin->fin_data[0], 1828 0 stevel fr->fr_icmpm, fr->fr_icmp)); 1829 0 stevel i = 1; 1830 0 stevel } 1831 0 stevel } 1832 0 stevel } 1833 0 stevel } 1834 0 stevel return i; 1835 0 stevel } 1836 0 stevel 1837 0 stevel 1838 0 stevel /* ------------------------------------------------------------------------ */ 1839 0 stevel /* Function: fr_scanlist */ 1840 0 stevel /* Returns: int - result flags of scanning filter list */ 1841 0 stevel /* Parameters: fin(I) - pointer to packet information */ 1842 0 stevel /* pass(I) - default result to return for filtering */ 1843 0 stevel /* */ 1844 0 stevel /* Check the input/output list of rules for a match to the current packet. */ 1845 0 stevel /* If a match is found, the value of fr_flags from the rule becomes the */ 1846 0 stevel /* return value and fin->fin_fr points to the matched rule. */ 1847 0 stevel /* */ 1848 0 stevel /* This function may be called recusively upto 16 times (limit inbuilt.) */ 1849 0 stevel /* When unwinding, it should finish up with fin_depth as 0. */ 1850 0 stevel /* */ 1851 0 stevel /* Could be per interface, but this gets real nasty when you don't have, */ 1852 0 stevel /* or can't easily change, the kernel source code to . */ 1853 0 stevel /* ------------------------------------------------------------------------ */ 1854 0 stevel int fr_scanlist(fin, pass) 1855 0 stevel fr_info_t *fin; 1856 0 stevel u_32_t pass; 1857 0 stevel { 1858 0 stevel int rulen, portcmp, off, logged, skip; 1859 0 stevel struct frentry *fr, *fnext; 1860 2393 yz155240 u_32_t passt, passo; 1861 3448 dh155122 ipf_stack_t *ifs = fin->fin_ifs; 1862 0 stevel 1863 0 stevel /* 1864 0 stevel * Do not allow nesting deeper than 16 levels. 1865 0 stevel */ 1866 0 stevel if (fin->fin_depth >= 16) 1867 0 stevel return pass; 1868 0 stevel 1869 0 stevel fr = fin->fin_fr; 1870 0 stevel 1871 0 stevel /* 1872 0 stevel * If there are no rules in this list, return now. 1873 0 stevel */ 1874 0 stevel if (fr == NULL) 1875 0 stevel return pass; 1876 0 stevel 1877 0 stevel skip = 0; 1878 0 stevel logged = 0; 1879 0 stevel portcmp = 0; 1880 0 stevel fin->fin_depth++; 1881 0 stevel fin->fin_fr = NULL; 1882 0 stevel off = fin->fin_off; 1883 0 stevel 1884 0 stevel if ((fin->fin_flx & FI_TCPUDP) && (fin->fin_dlen > 3) && !off) 1885 0 stevel portcmp = 1; 1886 0 stevel 1887 0 stevel for (rulen = 0; fr; fr = fnext, rulen++) { 1888 0 stevel fnext = fr->fr_next; 1889 0 stevel if (skip != 0) { 1890 0 stevel FR_VERBOSE(("%d (%#x)\n", skip, fr->fr_flags)); 1891 0 stevel skip--; 1892 0 stevel continue; 1893 0 stevel } 1894 0 stevel 1895 0 stevel /* 1896 0 stevel * In all checks below, a null (zero) value in the 1897 0 stevel * filter struture is taken to mean a wildcard. 1898 0 stevel * 1899 0 stevel * check that we are working for the right interface 1900 0 stevel */ 1901 0 stevel #ifdef _KERNEL 1902 0 stevel if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) 1903 0 stevel continue; 1904 0 stevel #else 1905 0 stevel if (opts & (OPT_VERBOSE|OPT_DEBUG)) 1906 0 stevel printf("\n"); 1907 0 stevel FR_VERBOSE(("%c", FR_ISSKIP(pass) ? 's' : 1908 2393 yz155240 FR_ISPASS(pass) ? 'p' : 1909 0 stevel FR_ISACCOUNT(pass) ? 'A' : 1910 0 stevel FR_ISAUTH(pass) ? 'a' : 1911 0 stevel (pass & FR_NOMATCH) ? 'n' :'b')); 1912 0 stevel if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) 1913 0 stevel continue; 1914 0 stevel FR_VERBOSE((":i")); 1915 0 stevel #endif 1916 0 stevel 1917 0 stevel switch (fr->fr_type) 1918 0 stevel { 1919 0 stevel case FR_T_IPF : 1920 0 stevel case FR_T_IPF|FR_T_BUILTIN : 1921 0 stevel if (fr_ipfcheck(fin, fr, portcmp)) 1922 0 stevel continue; 1923 0 stevel break; 1924 2393 yz155240 #if defined(IPFILTER_BPF) 1925 0 stevel case FR_T_BPFOPC : 1926 0 stevel case FR_T_BPFOPC|FR_T_BUILTIN : 1927 0 stevel { 1928 0 stevel u_char *mc; 1929 0 stevel 1930 0 stevel if (*fin->fin_mp == NULL) 1931 0 stevel continue; 1932 0 stevel if (fin->fin_v != fr->fr_v) 1933 0 stevel continue; 1934 0 stevel mc = (u_char *)fin->fin_m; 1935 2393 yz155240 if (!bpf_filter(fr->fr_data, mc, fin->fin_plen, 0)) 1936 0 stevel continue; 1937 0 stevel break; 1938 0 stevel } 1939 0 stevel #endif 1940 0 stevel case FR_T_CALLFUNC|FR_T_BUILTIN : 1941 0 stevel { 1942 0 stevel frentry_t *f; 1943 0 stevel 1944 0 stevel f = (*fr->fr_func)(fin, &pass); 1945 0 stevel if (f != NULL) 1946 0 stevel fr = f; 1947 0 stevel else 1948 0 stevel continue; 1949 0 stevel break; 1950 0 stevel } 1951 0 stevel default : 1952 0 stevel break; 1953 0 stevel } 1954 0 stevel 1955 0 stevel if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) { 1956 0 stevel if (fin->fin_nattag == NULL) 1957 0 stevel continue; 1958 0 stevel if (fr_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0) 1959 0 stevel continue; 1960 0 stevel } 1961 0 stevel FR_VERBOSE(("=%s.%d *", fr->fr_group, rulen)); 1962 0 stevel 1963 0 stevel passt = fr->fr_flags; 1964 0 stevel 1965 0 stevel /* 1966 2393 yz155240 * Allowing a rule with the "keep state" flag set to match 1967 2393 yz155240 * packets that have been tagged "out of window" by the TCP 1968 2393 yz155240 * state tracking is foolish as the attempt to add a new 1969 2393 yz155240 * state entry to the table will fail. 1970 2393 yz155240 */ 1971 2393 yz155240 if ((passt & FR_KEEPSTATE) && (fin->fin_flx & FI_OOW)) 1972 2393 yz155240 continue; 1973 2393 yz155240 1974 2393 yz155240 /* 1975 0 stevel * If the rule is a "call now" rule, then call the function 1976 0 stevel * in the rule, if it exists and use the results from that. 1977 0 stevel * If the function pointer is bad, just make like we ignore 1978 0 stevel * it, except for increasing the hit counter. 1979 0 stevel */ 1980 0 stevel if ((passt & FR_CALLNOW) != 0) { 1981 7131 dr146992 IPF_BUMP(fr->fr_hits); 1982 0 stevel if ((fr->fr_func != NULL) && 1983 0 stevel (fr->fr_func != (ipfunc_t)-1)) { 1984 0 stevel frentry_t *frs; 1985 0 stevel 1986 0 stevel frs = fin->fin_fr; 1987 0 stevel fin->fin_fr = fr; 1988 0 stevel fr = (*fr->fr_func)(fin, &passt); 1989 0 stevel if (fr == NULL) { 1990 0 stevel fin->fin_fr = frs; 1991 0 stevel continue; 1992 0 stevel } 1993 0 stevel passt = fr->fr_flags; 1994 0 stevel fin->fin_fr = fr; 1995 0 stevel } 1996 0 stevel } else { 1997 0 stevel fin->fin_fr = fr; 1998 0 stevel } 1999 0 stevel 2000 0 stevel #ifdef IPFILTER_LOG 2001 0 stevel /* 2002 0 stevel * Just log this packet... 2003 0 stevel */ 2004 0 stevel if ((passt & FR_LOGMASK) == FR_LOG) { 2005 0 stevel if (ipflog(fin, passt) == -1) { 2006 0 stevel if (passt & FR_LOGORBLOCK) { 2007 0 stevel passt &= ~FR_CMDMASK; 2008 0 stevel passt |= FR_BLOCK|FR_QUICK; 2009 0 stevel } 2010 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[fin->fin_out].fr_skip); 2011 7131 dr146992 } 2012 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[fin->fin_out].fr_pkl); 2013 0 stevel logged = 1; 2014 0 stevel } 2015 0 stevel #endif /* IPFILTER_LOG */ 2016 0 stevel fr->fr_bytes += (U_QUAD_T)fin->fin_plen; 2017 2393 yz155240 passo = pass; 2018 0 stevel if (FR_ISSKIP(passt)) 2019 0 stevel skip = fr->fr_arg; 2020 0 stevel else if ((passt & FR_LOGMASK) != FR_LOG) 2021 0 stevel pass = passt; 2022 0 stevel if (passt & (FR_RETICMP|FR_FAKEICMP)) 2023 0 stevel fin->fin_icode = fr->fr_icode; 2024 0 stevel FR_DEBUG(("pass %#x\n", pass)); 2025 7131 dr146992 IPF_BUMP(fr->fr_hits); 2026 0 stevel fin->fin_rule = rulen; 2027 0 stevel (void) strncpy(fin->fin_group, fr->fr_group, FR_GROUPLEN); 2028 0 stevel if (fr->fr_grp != NULL) { 2029 0 stevel fin->fin_fr = *fr->fr_grp; 2030 0 stevel pass = fr_scanlist(fin, pass); 2031 0 stevel if (fin->fin_fr == NULL) { 2032 0 stevel fin->fin_rule = rulen; 2033 0 stevel (void) strncpy(fin->fin_group, fr->fr_group, 2034 0 stevel FR_GROUPLEN); 2035 0 stevel fin->fin_fr = fr; 2036 0 stevel } 2037 0 stevel if (fin->fin_flx & FI_DONTCACHE) 2038 0 stevel logged = 1; 2039 0 stevel } 2040 2393 yz155240 2041 2393 yz155240 if (pass & FR_QUICK) { 2042 2393 yz155240 /* 2043 2393 yz155240 * Finally, if we've asked to track state for this 2044 2393 yz155240 * packet, set it up. Add state for "quick" rules 2045 2393 yz155240 * here so that if the action fails we can consider 2046 2393 yz155240 * the rule to "not match" and keep on processing 2047 2393 yz155240 * filter rules. 2048 2393 yz155240 */ 2049 2393 yz155240 if ((pass & FR_KEEPSTATE) && 2050 2393 yz155240 !(fin->fin_flx & FI_STATE)) { 2051 2393 yz155240 int out = fin->fin_out; 2052 2393 yz155240 2053 2393 yz155240 if (fr_addstate(fin, NULL, 0) != NULL) { 2054 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[out].fr_ads); 2055 2393 yz155240 } else { 2056 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[out].fr_bads); 2057 2393 yz155240 pass = passo; 2058 2393 yz155240 continue; 2059 2393 yz155240 } 2060 2393 yz155240 } 2061 2393 yz155240 break; 2062 2393 yz155240 } 2063 0 stevel } 2064 0 stevel if (logged) 2065 0 stevel fin->fin_flx |= FI_DONTCACHE; 2066 0 stevel fin->fin_depth--; 2067 0 stevel return pass; 2068 0 stevel } 2069 0 stevel 2070 0 stevel 2071 0 stevel /* ------------------------------------------------------------------------ */ 2072 0 stevel /* Function: fr_acctpkt */ 2073 0 stevel /* Returns: frentry_t* - always returns NULL */ 2074 0 stevel /* Parameters: fin(I) - pointer to packet information */ 2075 0 stevel /* passp(IO) - pointer to current/new filter decision (unused) */ 2076 0 stevel /* */ 2077 0 stevel /* Checks a packet against accounting rules, if there are any for the given */ 2078 0 stevel /* IP protocol version. */ 2079 0 stevel /* */ 2080 0 stevel /* N.B.: this function returns NULL to match the prototype used by other */ 2081 0 stevel /* functions called from the IPFilter "mainline" in fr_check(). */ 2082 0 stevel /* ------------------------------------------------------------------------ */ 2083 0 stevel frentry_t *fr_acctpkt(fin, passp) 2084 0 stevel fr_info_t *fin; 2085 0 stevel u_32_t *passp; 2086 0 stevel { 2087 0 stevel char group[FR_GROUPLEN]; 2088 0 stevel frentry_t *fr, *frsave; 2089 0 stevel u_32_t pass, rulen; 2090 3448 dh155122 ipf_stack_t *ifs = fin->fin_ifs; 2091 0 stevel 2092 0 stevel passp = passp; 2093 0 stevel #ifdef USE_INET6 2094 0 stevel if (fin->fin_v == 6) 2095 3448 dh155122 fr = ifs->ifs_ipacct6[fin->fin_out][ifs->ifs_fr_active]; 2096 0 stevel else 2097 0 stevel #endif 2098 3448 dh155122 fr = ifs->ifs_ipacct[fin->fin_out][ifs->ifs_fr_active]; 2099 0 stevel 2100 0 stevel if (fr != NULL) { 2101 0 stevel frsave = fin->fin_fr; 2102 0 stevel bcopy(fin->fin_group, group, FR_GROUPLEN); 2103 0 stevel rulen = fin->fin_rule; 2104 0 stevel fin->fin_fr = fr; 2105 0 stevel pass = fr_scanlist(fin, FR_NOMATCH); 2106 0 stevel if (FR_ISACCOUNT(pass)) { 2107 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[0].fr_acct); 2108 0 stevel } 2109 0 stevel fin->fin_fr = frsave; 2110 0 stevel bcopy(group, fin->fin_group, FR_GROUPLEN); 2111 0 stevel fin->fin_rule = rulen; 2112 0 stevel } 2113 0 stevel return NULL; 2114 0 stevel } 2115 0 stevel 2116 0 stevel 2117 0 stevel /* ------------------------------------------------------------------------ */ 2118 0 stevel /* Function: fr_firewall */ 2119 0 stevel /* Returns: frentry_t* - returns pointer to matched rule, if no matches */ 2120 0 stevel /* were found, returns NULL. */ 2121 0 stevel /* Parameters: fin(I) - pointer to packet information */ 2122 0 stevel /* passp(IO) - pointer to current/new filter decision (unused) */ 2123 0 stevel /* */ 2124 0 stevel /* Applies an appropriate set of firewall rules to the packet, to see if */ 2125 0 stevel /* there are any matches. The first check is to see if a match can be seen */ 2126 0 stevel /* in the cache. If not, then search an appropriate list of rules. Once a */ 2127 0 stevel /* matching rule is found, take any appropriate actions as defined by the */ 2128 0 stevel /* rule - except logging. */ 2129 0 stevel /* ------------------------------------------------------------------------ */ 2130 0 stevel static frentry_t *fr_firewall(fin, passp) 2131 0 stevel fr_info_t *fin; 2132 0 stevel u_32_t *passp; 2133 0 stevel { 2134 0 stevel frentry_t *fr; 2135 10587 Alexandr fr_info_t *fc; 2136 0 stevel u_32_t pass; 2137 0 stevel int out; 2138 3448 dh155122 ipf_stack_t *ifs = fin->fin_ifs; 2139 0 stevel 2140 0 stevel out = fin->fin_out; 2141 0 stevel pass = *passp; 2142 0 stevel 2143 7131 dr146992 #ifdef USE_INET6 2144 7131 dr146992 if (fin->fin_v == 6) 2145 7131 dr146992 fin->fin_fr = ifs->ifs_ipfilter6[out][ifs->ifs_fr_active]; 2146 7131 dr146992 else 2147 7131 dr146992 #endif 2148 7131 dr146992 fin->fin_fr = ifs->ifs_ipfilter[out][ifs->ifs_fr_active]; 2149 10587 Alexandr 2150 10587 Alexandr /* 2151 10587 Alexandr * If there are no rules loaded skip all checks and return. 2152 10587 Alexandr */ 2153 10587 Alexandr if (fin->fin_fr == NULL) { 2154 10587 Alexandr 2155 10587 Alexandr if ((pass & FR_NOMATCH)) { 2156 10587 Alexandr IPF_BUMP(ifs->ifs_frstats[out].fr_nom); 2157 10587 Alexandr } 2158 10587 Alexandr 2159 10587 Alexandr return (NULL); 2160 10587 Alexandr } 2161 10587 Alexandr 2162 10587 Alexandr fc = &ifs->ifs_frcache[out][CACHE_HASH(fin)]; 2163 10587 Alexandr READ_ENTER(&ifs->ifs_ipf_frcache); 2164 10587 Alexandr if (!bcmp((char *)fin, (char *)fc, FI_CSIZE)) { 2165 10587 Alexandr /* 2166 10587 Alexandr * copy cached data so we can unlock the mutexes earlier. 2167 10587 Alexandr */ 2168 10587 Alexandr bcopy((char *)fc, (char *)fin, FI_COPYSIZE); 2169 10587 Alexandr RWLOCK_EXIT(&ifs->ifs_ipf_frcache); 2170 10587 Alexandr IPF_BUMP(ifs->ifs_frstats[out].fr_chit); 2171 10587 Alexandr 2172 10587 Alexandr if ((fr = fin->fin_fr) != NULL) { 2173 10587 Alexandr IPF_BUMP(fr->fr_hits); 2174 10587 Alexandr pass = fr->fr_flags; 2175 10587 Alexandr } 2176 10587 Alexandr } else { 2177 10587 Alexandr RWLOCK_EXIT(&ifs->ifs_ipf_frcache); 2178 10587 Alexandr 2179 7131 dr146992 pass = fr_scanlist(fin, ifs->ifs_fr_pass); 2180 10587 Alexandr 2181 10587 Alexandr if (((pass & FR_KEEPSTATE) == 0) && 2182 10587 Alexandr ((fin->fin_flx & FI_DONTCACHE) == 0)) { 2183 10587 Alexandr WRITE_ENTER(&ifs->ifs_ipf_frcache); 2184 10587 Alexandr bcopy((char *)fin, (char *)fc, FI_COPYSIZE); 2185 10587 Alexandr RWLOCK_EXIT(&ifs->ifs_ipf_frcache); 2186 10587 Alexandr } 2187 10587 Alexandr 2188 10587 Alexandr fr = fin->fin_fr; 2189 10587 Alexandr } 2190 7131 dr146992 2191 7131 dr146992 if ((pass & FR_NOMATCH)) { 2192 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[out].fr_nom); 2193 7131 dr146992 } 2194 0 stevel 2195 0 stevel /* 2196 0 stevel * Apply packets per second rate-limiting to a rule as required. 2197 0 stevel */ 2198 0 stevel if ((fr != NULL) && (fr->fr_pps != 0) && 2199 0 stevel !ppsratecheck(&fr->fr_lastpkt, &fr->fr_curpps, fr->fr_pps)) { 2200 0 stevel pass &= ~(FR_CMDMASK|FR_DUP|FR_RETICMP|FR_RETRST); 2201 0 stevel pass |= FR_BLOCK; 2202 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[out].fr_ppshit); 2203 0 stevel } 2204 0 stevel 2205 0 stevel /* 2206 0 stevel * If we fail to add a packet to the authorization queue, then we 2207 0 stevel * drop the packet later. However, if it was added then pretend 2208 0 stevel * we've dropped it already. 2209 0 stevel */ 2210 0 stevel if (FR_ISAUTH(pass)) { 2211 0 stevel if (fr_newauth(fin->fin_m, fin) != 0) { 2212 0 stevel #ifdef _KERNEL 2213 0 stevel fin->fin_m = *fin->fin_mp = NULL; 2214 0 stevel #else 2215 0 stevel ; 2216 0 stevel #endif 2217 0 stevel fin->fin_error = 0; 2218 0 stevel } else 2219 0 stevel fin->fin_error = ENOSPC; 2220 0 stevel } 2221 0 stevel 2222 0 stevel if ((fr != NULL) && (fr->fr_func != NULL) && 2223 0 stevel (fr->fr_func != (ipfunc_t)-1) && !(pass & FR_CALLNOW)) 2224 0 stevel (void) (*fr->fr_func)(fin, &pass); 2225 0 stevel 2226 0 stevel /* 2227 0 stevel * If a rule is a pre-auth rule, check again in the list of rules 2228 0 stevel * loaded for authenticated use. It does not particulary matter 2229 0 stevel * if this search fails because a "preauth" result, from a rule, 2230 0 stevel * is treated as "not a pass", hence the packet is blocked. 2231 0 stevel */ 2232 0 stevel if (FR_ISPREAUTH(pass)) { 2233 3448 dh155122 if ((fin->fin_fr = ifs->ifs_ipauth) != NULL) 2234 3448 dh155122 pass = fr_scanlist(fin, ifs->ifs_fr_pass); 2235 0 stevel } 2236 0 stevel 2237 0 stevel /* 2238 0 stevel * If the rule has "keep frag" and the packet is actually a fragment, 2239 0 stevel * then create a fragment state entry. 2240 0 stevel */ 2241 0 stevel if ((pass & (FR_KEEPFRAG|FR_KEEPSTATE)) == FR_KEEPFRAG) { 2242 0 stevel if (fin->fin_flx & FI_FRAG) { 2243 0 stevel if (fr_newfrag(fin, pass) == -1) { 2244 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[out].fr_bnfr); 2245 0 stevel } else { 2246 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[out].fr_nfr); 2247 7131 dr146992 } 2248 7131 dr146992 } else { 2249 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[out].fr_cfr); 2250 0 stevel } 2251 0 stevel } 2252 0 stevel 2253 0 stevel /* 2254 0 stevel * Finally, if we've asked to track state for this packet, set it up. 2255 0 stevel */ 2256 2393 yz155240 if ((pass & FR_KEEPSTATE) && !(fin->fin_flx & FI_STATE)) { 2257 0 stevel if (fr_addstate(fin, NULL, 0) != NULL) { 2258 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[out].fr_ads); 2259 7131 dr146992 } else { 2260 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[out].fr_bads); 2261 2393 yz155240 if (FR_ISPASS(pass)) { 2262 2393 yz155240 pass &= ~FR_CMDMASK; 2263 2393 yz155240 pass |= FR_BLOCK; 2264 2393 yz155240 } 2265 0 stevel } 2266 0 stevel } 2267 0 stevel 2268 0 stevel fr = fin->fin_fr; 2269 0 stevel 2270 0 stevel if (passp != NULL) 2271 0 stevel *passp = pass; 2272 0 stevel 2273 0 stevel return fr; 2274 0 stevel } 2275 0 stevel 2276 0 stevel /* ------------------------------------------------------------------------ */ 2277 0 stevel /* Function: fr_check */ 2278 0 stevel /* Returns: int - 0 == packet allowed through, */ 2279 0 stevel /* User space: */ 2280 0 stevel /* -1 == packet blocked */ 2281 0 stevel /* 1 == packet not matched */ 2282 2393 yz155240 /* -2 == requires authentication */ 2283 0 stevel /* Kernel: */ 2284 0 stevel /* > 0 == filter error # for packet */ 2285 0 stevel /* Parameters: ip(I) - pointer to start of IPv4/6 packet */ 2286 0 stevel /* hlen(I) - length of header */ 2287 0 stevel /* ifp(I) - pointer to interface this packet is on */ 2288 0 stevel /* out(I) - 0 == packet going in, 1 == packet going out */ 2289 0 stevel /* mp(IO) - pointer to caller's buffer pointer that holds this */ 2290 0 stevel /* IP packet. */ 2291 0 stevel /* Solaris & HP-UX ONLY : */ 2292 2393 yz155240 /* qpi(I) - pointer to STREAMS queue information for this */ 2293 0 stevel /* interface & direction. */ 2294 0 stevel /* */ 2295 0 stevel /* fr_check() is the master function for all IPFilter packet processing. */ 2296 0 stevel /* It orchestrates: Network Address Translation (NAT), checking for packet */ 2297 0 stevel /* authorisation (or pre-authorisation), presence of related state info., */ 2298 0 stevel /* generating log entries, IP packet accounting, routing of packets as */ 2299 0 stevel /* directed by firewall rules and of course whether or not to allow the */ 2300 0 stevel /* packet to be further processed by the kernel. */ 2301 0 stevel /* */ 2302 0 stevel /* For packets blocked, the contents of "mp" will be NULL'd and the buffer */ 2303 0 stevel /* freed. Packets passed may be returned with the pointer pointed to by */ 2304 0 stevel /* by "mp" changed to a new buffer. */ 2305 0 stevel /* ------------------------------------------------------------------------ */ 2306 0 stevel int fr_check(ip, hlen, ifp, out 2307 0 stevel #if defined(_KERNEL) && defined(MENTAT) 2308 3448 dh155122 , qif, mp, ifs) 2309 2393 yz155240 void *qif; 2310 0 stevel #else 2311 3448 dh155122 , mp, ifs) 2312 0 stevel #endif 2313 0 stevel mb_t **mp; 2314 0 stevel ip_t *ip; 2315 0 stevel int hlen; 2316 0 stevel void *ifp; 2317 0 stevel int out; 2318 3448 dh155122 ipf_stack_t *ifs; 2319 0 stevel { 2320 0 stevel /* 2321 0 stevel * The above really sucks, but short of writing a diff 2322 0 stevel */ 2323 0 stevel fr_info_t frinfo; 2324 0 stevel fr_info_t *fin = &frinfo; 2325 3448 dh155122 u_32_t pass; 2326 0 stevel frentry_t *fr = NULL; 2327 2393 yz155240 int v = IP_V(ip); 2328 0 stevel mb_t *mc = NULL; 2329 0 stevel mb_t *m; 2330 637 ml37995 #ifdef USE_INET6 2331 637 ml37995 ip6_t *ip6; 2332 637 ml37995 #endif 2333 2393 yz155240 #ifdef _KERNEL 2334 2393 yz155240 # ifdef MENTAT 2335 2393 yz155240 qpktinfo_t *qpi = qif; 2336 2393 yz155240 #endif 2337 2393 yz155240 #endif 2338 3448 dh155122 2339 2393 yz155240 SPL_INT(s); 2340 3448 dh155122 pass = ifs->ifs_fr_pass; 2341 0 stevel 2342 0 stevel /* 2343 0 stevel * The first part of fr_check() deals with making sure that what goes 2344 0 stevel * into the filtering engine makes some sense. Information about the 2345 0 stevel * the packet is distilled, collected into a fr_info_t structure and 2346 0 stevel * the an attempt to ensure the buffer the packet is in is big enough 2347 0 stevel * to hold all the required packet headers. 2348 0 stevel */ 2349 0 stevel #ifdef _KERNEL 2350 0 stevel # ifdef MENTAT 2351 2393 yz155240 if (!OK_32PTR(ip)) 2352 0 stevel return 2; 2353 0 stevel # endif 2354 2393 yz155240 2355 3448 dh155122 2356 3448 dh155122 if (ifs->ifs_fr_running <= 0) { 2357 0 stevel return 0; 2358 0 stevel } 2359 0 stevel 2360 0 stevel bzero((char *)fin, sizeof(*fin)); 2361 0 stevel 2362 0 stevel # ifdef MENTAT 2363 5868 dr146992 fin->fin_flx = qpi->qpi_flags & (FI_NOCKSUM|FI_MBCAST|FI_MULTICAST| 2364 5868 dr146992 FI_BROADCAST); 2365 2393 yz155240 m = qpi->qpi_m; 2366 0 stevel fin->fin_qfm = m; 2367 2393 yz155240 fin->fin_qpi = qpi; 2368 0 stevel # else /* MENTAT */ 2369 0 stevel 2370 0 stevel m = *mp; 2371 2393 yz155240 2372 0 stevel # if defined(M_MCAST) 2373 0 stevel if ((m->m_flags & M_MCAST) != 0) 2374 2393 yz155240 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2375 2393 yz155240 # endif 2376 2393 yz155240 # if defined(M_MLOOP) 2377 2393 yz155240 if ((m->m_flags & M_MLOOP) != 0) 2378 0 stevel fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2379 0 stevel # endif 2380 0 stevel # if defined(M_BCAST) 2381 0 stevel if ((m->m_flags & M_BCAST) != 0) 2382 0 stevel fin->fin_flx |= FI_MBCAST|FI_BROADCAST; 2383 0 stevel # endif 2384 0 stevel # ifdef M_CANFASTFWD 2385 0 stevel /* 2386 0 stevel * XXX For now, IP Filter and fast-forwarding of cached flows 2387 0 stevel * XXX are mutually exclusive. Eventually, IP Filter should 2388 0 stevel * XXX get a "can-fast-forward" filter rule. 2389 0 stevel */ 2390 0 stevel m->m_flags &= ~M_CANFASTFWD; 2391 0 stevel # endif /* M_CANFASTFWD */ 2392 0 stevel # ifdef CSUM_DELAY_DATA 2393 0 stevel /* 2394 0 stevel * disable delayed checksums. 2395 0 stevel */ 2396 0 stevel if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 2397 0 stevel in_delayed_cksum(m); 2398 0 stevel m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 2399 0 stevel } 2400 0 stevel # endif /* CSUM_DELAY_DATA */ 2401 0 stevel # endif /* MENTAT */ 2402 2393 yz155240 #else 2403 0 stevel 2404 0 stevel bzero((char *)fin, sizeof(*fin)); 2405 0 stevel m = *mp; 2406 0 stevel #endif /* _KERNEL */ 2407 0 stevel 2408 0 stevel fin->fin_v = v; 2409 0 stevel fin->fin_m = m; 2410 2393 yz155240 fin->fin_ip = ip; 2411 0 stevel fin->fin_mp = mp; 2412 0 stevel fin->fin_out = out; 2413 0 stevel fin->fin_ifp = ifp; 2414 2393 yz155240 fin->fin_error = ENETUNREACH; 2415 2393 yz155240 fin->fin_hlen = (u_short)hlen; 2416 0 stevel fin->fin_dp = (char *)ip + hlen; 2417 2393 yz155240 fin->fin_ipoff = (char *)ip - MTOD(m, char *); 2418 3448 dh155122 fin->fin_ifs = ifs; 2419 2393 yz155240 2420 2393 yz155240 SPL_NET(s); 2421 2393 yz155240 2422 2393 yz155240 #ifdef USE_INET6 2423 2393 yz155240 if (v == 6) { 2424 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[out].fr_ipv6); 2425 2393 yz155240 /* 2426 2393 yz155240 * Jumbo grams are quite likely too big for internal buffer 2427 2393 yz155240 * structures to handle comfortably, for now, so just drop 2428 2393 yz155240 * them. 2429 2393 yz155240 */ 2430 2393 yz155240 ip6 = (ip6_t *)ip; 2431 2393 yz155240 fin->fin_plen = ntohs(ip6->ip6_plen); 2432 2393 yz155240 if (fin->fin_plen == 0) { 2433 3448 dh155122 READ_ENTER(&ifs->ifs_ipf_mutex); 2434 2393 yz155240 pass = FR_BLOCK|FR_NOMATCH; 2435 2393 yz155240 goto filtered; 2436 2393 yz155240 } 2437 2393 yz155240 fin->fin_plen += sizeof(ip6_t); 2438 2393 yz155240 } else 2439 2393 yz155240 #endif 2440 2393 yz155240 { 2441 2393 yz155240 #if (OpenBSD >= 200311) && defined(_KERNEL) 2442 2393 yz155240 ip->ip_len = ntohs(ip->ip_len); 2443 2393 yz155240 ip->ip_off = ntohs(ip->ip_off); 2444 2393 yz155240 #endif 2445 2393 yz155240 fin->fin_plen = ip->ip_len; 2446 2393 yz155240 } 2447 2393 yz155240 2448 637 ml37995 if (fr_makefrip(hlen, ip, fin) == -1) { 2449 3448 dh155122 READ_ENTER(&ifs->ifs_ipf_mutex); 2450 637 ml37995 pass = FR_BLOCK; 2451 637 ml37995 goto filtered; 2452 0 stevel } 2453 0 stevel 2454 0 stevel /* 2455 0 stevel * For at least IPv6 packets, if a m_pullup() fails then this pointer 2456 0 stevel * becomes NULL and so we have no packet to free. 2457 0 stevel */ 2458 0 stevel if (*fin->fin_mp == NULL) 2459 0 stevel goto finished; 2460 0 stevel 2461 0 stevel if (!out) { 2462 0 stevel if (v == 4) { 2463 0 stevel #ifdef _KERNEL 2464 3448 dh155122 if (ifs->ifs_fr_chksrc && !fr_verifysrc(fin)) { 2465 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[0].fr_badsrc); 2466 0 stevel fin->fin_flx |= FI_BADSRC; 2467 0 stevel } 2468 0 stevel #endif 2469 3448 dh155122 if (fin->fin_ip->ip_ttl < ifs->ifs_fr_minttl) { 2470 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[0].fr_badttl); 2471 0 stevel fin->fin_flx |= FI_LOWTTL; 2472 0 stevel } 2473 0 stevel } 2474 0 stevel #ifdef USE_INET6 2475 0 stevel else if (v == 6) { 2476 637 ml37995 ip6 = (ip6_t *)ip; 2477 637 ml37995 #ifdef _KERNEL 2478 3448 dh155122 if (ifs->ifs_fr_chksrc && !fr_verifysrc(fin)) { 2479 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[0].fr_badsrc); 2480 637 ml37995 fin->fin_flx |= FI_BADSRC; 2481 637 ml37995 } 2482 637 ml37995 #endif 2483 3448 dh155122 if (ip6->ip6_hlim < ifs->ifs_fr_minttl) { 2484 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[0].fr_badttl); 2485 0 stevel fin->fin_flx |= FI_LOWTTL; 2486 0 stevel } 2487 0 stevel } 2488 0 stevel #endif 2489 0 stevel } 2490 0 stevel 2491 0 stevel if (fin->fin_flx & FI_SHORT) { 2492 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[out].fr_short); 2493 3448 dh155122 } 2494 3448 dh155122 2495 3448 dh155122 READ_ENTER(&ifs->ifs_ipf_mutex); 2496 0 stevel 2497 0 stevel /* 2498 0 stevel * Check auth now. This, combined with the check below to see if apass 2499 0 stevel * is 0 is to ensure that we don't count the packet twice, which can 2500 0 stevel * otherwise occur when we reprocess it. As it is, we only count it 2501 0 stevel * after it has no auth. table matchup. This also stops NAT from 2502 0 stevel * occuring until after the packet has been auth'd. 2503 0 stevel */ 2504 0 stevel fr = fr_checkauth(fin, &pass); 2505 2393 yz155240 if (!out) { 2506 7176 yx160601 switch (fin->fin_v) 2507 7176 yx160601 { 2508 7176 yx160601 case 4 : 2509 7176 yx160601 if (fr_checknatin(fin, &pass) == -1) { 2510 7176 yx160601 RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2511 7176 yx160601 goto finished; 2512 7176 yx160601 } 2513 7176 yx160601 break; 2514 7176 yx160601 #ifdef USE_INET6 2515 7176 yx160601 case 6 : 2516 7176 yx160601 if (fr_checknat6in(fin, &pass) == -1) { 2517 7176 yx160601 RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2518 7176 yx160601 goto finished; 2519 7176 yx160601 } 2520 7176 yx160601 break; 2521 7176 yx160601 #endif 2522 7176 yx160601 default : 2523 7176 yx160601 break; 2524 2393 yz155240 } 2525 2393 yz155240 } 2526 0 stevel if (!out) 2527 0 stevel (void) fr_acctpkt(fin, NULL); 2528 0 stevel 2529 0 stevel if (fr == NULL) 2530 0 stevel if ((fin->fin_flx & (FI_FRAG|FI_BAD)) == FI_FRAG) 2531 0 stevel fr = fr_knownfrag(fin, &pass); 2532 0 stevel if (fr == NULL) 2533 0 stevel fr = fr_checkstate(fin, &pass); 2534 0 stevel 2535 0 stevel if ((pass & FR_NOMATCH) || (fr == NULL)) 2536 0 stevel fr = fr_firewall(fin, &pass); 2537 0 stevel 2538 0 stevel fin->fin_fr = fr; 2539 0 stevel 2540 0 stevel /* 2541 0 stevel * Only count/translate packets which will be passed on, out the 2542 0 stevel * interface. 2543 0 stevel */ 2544 0 stevel if (out && FR_ISPASS(pass)) { 2545 0 stevel (void) fr_acctpkt(fin, NULL); 2546 2393 yz155240 2547 7176 yx160601 switch (fin->fin_v) 2548 7176 yx160601 { 2549 7176 yx160601 case 4 : 2550 7176 yx160601 if (fr_checknatout(fin, &pass) == -1) { 2551 7176 yx160601 RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2552 7176 yx160601 goto finished; 2553 7176 yx160601 } 2554 7176 yx160601 break; 2555 7176 yx160601 #ifdef USE_INET6 2556 7176 yx160601 case 6 : 2557 7176 yx160601 if (fr_checknat6out(fin, &pass) == -1) { 2558 7176 yx160601 RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2559 7176 yx160601 goto finished; 2560 7176 yx160601 } 2561 7176 yx160601 break; 2562 7176 yx160601 #endif 2563 7176 yx160601 default : 2564 7176 yx160601 break; 2565 7176 yx160601 } 2566 7176 yx160601 2567 7176 yx160601 if ((ifs->ifs_fr_update_ipid != 0) && (v == 4)) { 2568 0 stevel if (fr_updateipid(fin) == -1) { 2569 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[1].fr_ipud); 2570 0 stevel pass &= ~FR_CMDMASK; 2571 0 stevel pass |= FR_BLOCK; 2572 0 stevel } else { 2573 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[0].fr_ipud); 2574 0 stevel } 2575 0 stevel } 2576 0 stevel } 2577 0 stevel 2578 0 stevel #ifdef IPFILTER_LOG 2579 3448 dh155122 if ((ifs->ifs_fr_flags & FF_LOGGING) || (pass & FR_LOGMASK)) { 2580 0 stevel (void) fr_dolog(fin, &pass); 2581 2393 yz155240 } 2582 0 stevel #endif 2583 0 stevel 2584 8624 Darren /* 2585 8624 Darren * The FI_STATE flag is cleared here so that calling fr_checkstate 2586 8624 Darren * will work when called from inside of fr_fastroute. Although 2587 8624 Darren * there is a similar flag, FI_NATED, for NAT, it does have the same 2588 8624 Darren * impact on code execution. 2589 8624 Darren */ 2590 8624 Darren fin->fin_flx &= ~FI_STATE; 2591 0 stevel 2592 0 stevel /* 2593 0 stevel * Only allow FR_DUP to work if a rule matched - it makes no sense to 2594 0 stevel * set FR_DUP as a "default" as there are no instructions about where 2595 2393 yz155240 * to send the packet. Use fin_m here because it may have changed 2596 2393 yz155240 * (without an update of 'm') in prior processing. 2597 0 stevel */ 2598 0 stevel if ((fr != NULL) && (pass & FR_DUP)) { 2599 2393 yz155240 mc = M_DUPLICATE(fin->fin_m); 2600 10838 Alexandr #ifdef _KERNEL 2601 10838 Alexandr mc->b_rptr += fin->fin_ipoff; 2602 10838 Alexandr #endif 2603 0 stevel } 2604 0 stevel 2605 0 stevel if (pass & (FR_RETRST|FR_RETICMP)) { 2606 0 stevel /* 2607 0 stevel * Should we return an ICMP packet to indicate error 2608 0 stevel * status passing through the packet filter ? 2609 0 stevel * WARNING: ICMP error packets AND TCP RST packets should 2610 0 stevel * ONLY be sent in repsonse to incoming packets. Sending them 2611 0 stevel * in response to outbound packets can result in a panic on 2612 0 stevel * some operating systems. 2613 0 stevel */ 2614 0 stevel if (!out) { 2615 0 stevel if (pass & FR_RETICMP) { 2616 0 stevel int dst; 2617 0 stevel 2618 0 stevel if ((pass & FR_RETMASK) == FR_FAKEICMP) 2619 0 stevel dst = 1; 2620 0 stevel else 2621 0 stevel dst = 0; 2622 9695 Alexandr #if defined(_KERNEL) && (SOLARIS2 >= 10) 2623 9695 Alexandr /* 2624 9695 Alexandr * Assume it's possible to enter insane rule: 2625 9695 Alexandr * pass return-icmp in proto udp ... 2626 9695 Alexandr * then we have no other option than to forward 2627 9695 Alexandr * packet on loopback and give up any attempt 2628 9695 Alexandr * to create a fake response. 2629 9695 Alexandr */ 2630 9695 Alexandr if (IPF_IS_LOOPBACK(qpi->qpi_flags) && 2631 9695 Alexandr FR_ISBLOCK(pass)) { 2632 9695 Alexandr 2633 9695 Alexandr if (fr_make_icmp(fin) == 0) { 2634 9695 Alexandr IPF_BUMP( 2635 9695 Alexandr ifs->ifs_frstats[out].fr_ret); 2636 9695 Alexandr } 2637 9695 Alexandr /* 2638 9695 Alexandr * we drop packet silently in case we 2639 9695 Alexandr * failed assemble fake response for it 2640 9695 Alexandr */ 2641 9695 Alexandr else if (*mp != NULL) { 2642 9695 Alexandr FREE_MB_T(*mp); 2643 9695 Alexandr m = *mp = NULL; 2644 9695 Alexandr } 2645 9695 Alexandr 2646 9695 Alexandr IPF_BUMP( 2647 9695 Alexandr ifs->ifs_frstats[out].fr_block); 2648 9695 Alexandr RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2649 9695 Alexandr 2650 9695 Alexandr return (0); 2651 9695 Alexandr } 2652 9695 Alexandr #endif /* _KERNEL && SOLARIS2 >= 10 */ 2653 9695 Alexandr 2654 0 stevel (void) fr_send_icmp_err(ICMP_UNREACH, fin, dst); 2655 9695 Alexandr IPF_BUMP(ifs->ifs_frstats[out].fr_ret); 2656 9695 Alexandr 2657 0 stevel } else if (((pass & FR_RETMASK) == FR_RETRST) && 2658 0 stevel !(fin->fin_flx & FI_SHORT)) { 2659 9695 Alexandr 2660 9695 Alexandr #if defined(_KERNEL) && (SOLARIS2 >= 10) 2661 9695 Alexandr /* 2662 9695 Alexandr * Assume it's possible to enter insane rule: 2663 9695 Alexandr * pass return-rst in proto tcp ... 2664 9695 Alexandr * then we have no other option than to forward 2665 9695 Alexandr * packet on loopback and give up any attempt 2666 9695 Alexandr * to create a fake response. 2667 9695 Alexandr */ 2668 9695 Alexandr if (IPF_IS_LOOPBACK(qpi->qpi_flags) && 2669 9695 Alexandr FR_ISBLOCK(pass)) { 2670 9695 Alexandr if (fr_make_rst(fin) == 0) { 2671 9695 Alexandr IPF_BUMP( 2672 9695 Alexandr ifs->ifs_frstats[out].fr_ret); 2673 9695 Alexandr } 2674 9695 Alexandr else if (mp != NULL) { 2675 9695 Alexandr /* 2676 9695 Alexandr * we drop packet silently in case we 2677 9695 Alexandr * failed assemble fake response for it 2678 9695 Alexandr */ 2679 9695 Alexandr FREE_MB_T(*mp); 2680 9695 Alexandr m = *mp = NULL; 2681 9695 Alexandr } 2682 9695 Alexandr 2683 9695 Alexandr IPF_BUMP( 2684 9695 Alexandr ifs->ifs_frstats[out].fr_block); 2685 9695 Alexandr RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2686 9695 Alexandr 2687 9695 Alexandr return (0); 2688 9695 Alexandr } 2689 9695 Alexandr #endif /* _KERNEL && _SOLARIS2 >= 10 */ 2690 0 stevel if (fr_send_reset(fin) == 0) { 2691 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[1].fr_ret); 2692 0 stevel } 2693 0 stevel } 2694 0 stevel } else { 2695 0 stevel if (pass & FR_RETRST) 2696 0 stevel fin->fin_error = ECONNRESET; 2697 0 stevel } 2698 0 stevel } 2699 0 stevel 2700 0 stevel /* 2701 0 stevel * If we didn't drop off the bottom of the list of rules (and thus 2702 0 stevel * the 'current' rule fr is not NULL), then we may have some extra 2703 0 stevel * instructions about what to do with a packet. 2704 0 stevel * Once we're finished return to our caller, freeing the packet if 2705 0 stevel * we are dropping it (* BSD ONLY *). 2706 2393 yz155240 * Reassign m from fin_m as we may have a new buffer, now. 2707 2393 yz155240 */ 2708 0 stevel filtered: 2709 2393 yz155240 m = fin->fin_m; 2710 0 stevel 2711 0 stevel if (fr != NULL) { 2712 0 stevel frdest_t *fdp; 2713 0 stevel 2714 0 stevel fdp = &fr->fr_tifs[fin->fin_rev]; 2715 0 stevel 2716 0 stevel if (!out && (pass & FR_FASTROUTE)) { 2717 0 stevel /* 2718 0 stevel * For fastroute rule, no destioation interface defined 2719 0 stevel * so pass NULL as the frdest_t parameter 2720 0 stevel */ 2721 0 stevel (void) fr_fastroute(m, mp, fin, NULL); 2722 0 stevel m = *mp = NULL; 2723 0 stevel } else if ((fdp->fd_ifp != NULL) && 2724 0 stevel (fdp->fd_ifp != (struct ifnet *)-1)) { 2725 0 stevel /* this is for to rules: */ 2726 0 stevel (void) fr_fastroute(m, mp, fin, fdp); 2727 0 stevel m = *mp = NULL; 2728 0 stevel } 2729 0 stevel 2730 0 stevel /* 2731 0 stevel * Generate a duplicated packet. 2732 0 stevel */ 2733 0 stevel if (mc != NULL) 2734 0 stevel (void) fr_fastroute(mc, &mc, fin, &fr->fr_dif); 2735 0 stevel } 2736 8624 Darren 2737 8624 Darren if (FR_ISBLOCK(pass) && (fin->fin_flx & FI_NEWNAT)) 2738 8624 Darren nat_uncreate(fin); 2739 0 stevel 2740 0 stevel /* 2741 0 stevel * This late because the likes of fr_fastroute() use fin_fr. 2742 0 stevel */ 2743 3448 dh155122 RWLOCK_EXIT(&ifs->ifs_ipf_mutex); 2744 0 stevel 2745 2393 yz155240 finished: 2746 0 stevel if (!FR_ISPASS(pass)) { 2747 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[out].fr_block); 2748 2393 yz155240 if (*mp != NULL) { 2749 0 stevel FREE_MB_T(*mp); 2750 0 stevel m = *mp = NULL; 2751 0 stevel } 2752 2393 yz155240 } else { 2753 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[out].fr_pass); 2754 0 stevel #if defined(_KERNEL) && defined(__sgi) 2755 2393 yz155240 if ((fin->fin_hbuf != NULL) && 2756 2393 yz155240 (mtod(fin->fin_m, struct ip *) != fin->fin_ip)) { 2757 2393 yz155240 COPYBACK(m, 0, fin->fin_plen, fin->fin_hbuf); 2758 2393 yz155240 } 2759 2393 yz155240 #endif 2760 2393 yz155240 } 2761 2393 yz155240 2762 2393 yz155240 SPL_X(s); 2763 2393 yz155240 2764 0 stevel #ifdef _KERNEL 2765 2393 yz155240 # if OpenBSD >= 200311 2766 2393 yz155240 if (FR_ISPASS(pass) && (v == 4)) { 2767 2393 yz155240 ip = fin->fin_ip; 2768 2393 yz155240 ip->ip_len = ntohs(ip->ip_len); 2769 2393 yz155240 ip->ip_off = ntohs(ip->ip_off); 2770 2393 yz155240 } 2771 2393 yz155240 # endif 2772 0 stevel return (FR_ISPASS(pass)) ? 0 : fin->fin_error; 2773 0 stevel #else /* _KERNEL */ 2774 2393 yz155240 FR_VERBOSE(("fin_flx %#x pass %#x ", fin->fin_flx, pass)); 2775 0 stevel if ((pass & FR_NOMATCH) != 0) 2776 0 stevel return 1; 2777 0 stevel 2778 0 stevel if ((pass & FR_RETMASK) != 0) 2779 0 stevel switch (pass & FR_RETMASK) 2780 0 stevel { 2781 0 stevel case FR_RETRST : 2782 0 stevel return 3; 2783 0 stevel case FR_RETICMP : 2784 0 stevel return 4; 2785 0 stevel case FR_FAKEICMP : 2786 0 stevel return 5; 2787 0 stevel } 2788 0 stevel 2789 0 stevel switch (pass & FR_CMDMASK) 2790 0 stevel { 2791 0 stevel case FR_PASS : 2792 0 stevel return 0; 2793 0 stevel case FR_BLOCK : 2794 0 stevel return -1; 2795 0 stevel case FR_AUTH : 2796 0 stevel return -2; 2797 0 stevel case FR_ACCOUNT : 2798 0 stevel return -3; 2799 0 stevel case FR_PREAUTH : 2800 0 stevel return -4; 2801 0 stevel } 2802 0 stevel return 2; 2803 0 stevel #endif /* _KERNEL */ 2804 0 stevel } 2805 0 stevel 2806 0 stevel 2807 0 stevel #ifdef IPFILTER_LOG 2808 0 stevel /* ------------------------------------------------------------------------ */ 2809 0 stevel /* Function: fr_dolog */ 2810 0 stevel /* Returns: frentry_t* - returns contents of fin_fr (no change made) */ 2811 0 stevel /* Parameters: fin(I) - pointer to packet information */ 2812 0 stevel /* passp(IO) - pointer to current/new filter decision (unused) */ 2813 0 stevel /* */ 2814 0 stevel /* Checks flags set to see how a packet should be logged, if it is to be */ 2815 0 stevel /* logged. Adjust statistics based on its success or not. */ 2816 0 stevel /* ------------------------------------------------------------------------ */ 2817 0 stevel frentry_t *fr_dolog(fin, passp) 2818 0 stevel fr_info_t *fin; 2819 0 stevel u_32_t *passp; 2820 0 stevel { 2821 0 stevel u_32_t pass; 2822 0 stevel int out; 2823 3448 dh155122 ipf_stack_t *ifs = fin->fin_ifs; 2824 0 stevel 2825 0 stevel out = fin->fin_out; 2826 0 stevel pass = *passp; 2827 0 stevel 2828 3448 dh155122 if ((ifs->ifs_fr_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) { 2829 0 stevel pass |= FF_LOGNOMATCH; 2830 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[out].fr_npkl); 2831 0 stevel goto logit; 2832 0 stevel } else if (((pass & FR_LOGMASK) == FR_LOGP) || 2833 3448 dh155122 (FR_ISPASS(pass) && (ifs->ifs_fr_flags & FF_LOGPASS))) { 2834 0 stevel if ((pass & FR_LOGMASK) != FR_LOGP) 2835 0 stevel pass |= FF_LOGPASS; 2836 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[out].fr_ppkl); 2837 0 stevel goto logit; 2838 0 stevel } else if (((pass & FR_LOGMASK) == FR_LOGB) || 2839 3448 dh155122 (FR_ISBLOCK(pass) && (ifs->ifs_fr_flags & FF_LOGBLOCK))) { 2840 0 stevel if ((pass & FR_LOGMASK) != FR_LOGB) 2841 0 stevel pass |= FF_LOGBLOCK; 2842 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[out].fr_bpkl); 2843 0 stevel logit: 2844 0 stevel if (ipflog(fin, pass) == -1) { 2845 7131 dr146992 IPF_BUMP(ifs->ifs_frstats[out].fr_skip); 2846 0 stevel 2847 0 stevel /* 2848 0 stevel * If the "or-block" option has been used then 2849 0 stevel * block the packet if we failed to log it. 2850 0 stevel */ 2851 0 stevel if ((pass & FR_LOGORBLOCK) && 2852 0 stevel FR_ISPASS(pass)) { 2853 0 stevel pass &= ~FR_CMDMASK; 2854 0 stevel pass |= FR_BLOCK; 2855 0 stevel } 2856 0 stevel } 2857 0 stevel *passp = pass; 2858 0 stevel } 2859 0 stevel 2860 0 stevel return fin->fin_fr; 2861 0 stevel } 2862 0 stevel #endif /* IPFILTER_LOG */ 2863 0 stevel 2864 0 stevel 2865 0 stevel /* ------------------------------------------------------------------------ */ 2866 0 stevel /* Function: ipf_cksum */ 2867 0 stevel /* Returns: u_short - IP header checksum */ 2868 0 stevel /* Parameters: addr(I) - pointer to start of buffer to checksum */ 2869 0 stevel /* len(I) - length of buffer in bytes */ 2870 0 stevel /* */ 2871 0 stevel /* Calculate the two's complement 16 bit checksum of the buffer passed. */ 2872 0 stevel /* */ 2873 0 stevel /* N.B.: addr should be 16bit aligned. */ 2874 0 stevel /* ------------------------------------------------------------------------ */ 2875 0 stevel u_short ipf_cksum(addr, len) 2876 0 stevel u_short *addr; 2877 0 stevel int len; 2878 0 stevel { 2879 0 stevel u_32_t sum = 0; 2880 0 stevel 2881 0 stevel for (sum = 0; len > 1; len -= 2) 2882 0 stevel sum += *addr++; 2883 0 stevel 2884 0 stevel /* mop up an odd byte, if necessary */ 2885 0 stevel if (len == 1) 2886 0 stevel sum += *(u_char *)addr; 2887 0 stevel 2888 0 stevel /* 2889 0 stevel * add back carry outs from top 16 bits to low 16 bits 2890 0 stevel */ 2891 0 stevel sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 2892 0 stevel sum += (sum >> 16); /* add carry */ 2893 0 stevel return (u_short)(~sum); 2894 0 stevel } 2895 0 stevel 2896 0 stevel 2897 0 stevel /* ------------------------------------------------------------------------ */ 2898 0 stevel /* Function: fr_cksum */ 2899 0 stevel /* Returns: u_short - layer 4 checksum */ 2900 2393 yz155240 /* Parameters: m(I ) - pointer to buffer holding packet */ 2901 2393 yz155240 /* ip(I) - pointer to IP header */ 2902 2393 yz155240 /* l4proto(I) - protocol to caclulate checksum for */ 2903 2393 yz155240 /* l4hdr(I) - pointer to layer 4 header */ 2904 0 stevel /* */ 2905 0 stevel /* Calculates the TCP checksum for the packet held in "m", using the data */ 2906 0 stevel /* in the IP header "ip" to seed it. */ 2907 0 stevel /* */ 2908 0 stevel /* NB: This function assumes we've pullup'd enough for all of the IP header */ 2909 0 stevel /* and the TCP header. We also assume that data blocks aren't allocated in */ 2910 0 stevel /* odd sizes. */ 2911 2393 yz155240 /* */ 2912 2393 yz155240 /* Expects ip_len to be in host byte order when called. */ 2913 0 stevel /* ------------------------------------------------------------------------ */ 2914 0 stevel u_short fr_cksum(m, ip, l4proto, l4hdr) 2915 0 stevel mb_t *m; 2916 0 stevel ip_t *ip; 2917 0 stevel int l4proto; 2918 0 stevel void *l4hdr; 2919 0 stevel { 2920 0 stevel u_short *sp, slen, sumsave, l4hlen, *csump; 2921 0 stevel u_int sum, sum2; 2922 0 stevel int hlen; 2923 0 stevel #ifdef USE_INET6 2924 0 stevel ip6_t *ip6; 2925 0 stevel #endif 2926 0 stevel 2927 0 stevel csump = NULL; 2928 0 stevel sumsave = 0; 2929 0 stevel l4hlen = 0; 2930 0 stevel sp = NULL; 2931 0 stevel slen = 0; 2932 0 stevel hlen = 0; 2933 0 stevel sum = 0; 2934 0 stevel 2935 0 stevel /* 2936 0 stevel * Add up IP Header portion 2937 0 stevel */ 2938 0 stevel #ifdef USE_INET6 2939 0 stevel if (IP_V(ip) == 4) { 2940 0 stevel #endif 2941 0 stevel hlen = IP_HL(ip) << 2; 2942 0 stevel slen = ip->ip_len - hlen; 2943 2393 yz155240 sum = htons((u_short)l4proto); 2944 0 stevel sum += htons(slen); 2945 0 stevel sp = (u_short *)&ip->ip_src; 2946 0 stevel sum += *sp++; /* ip_src */ 2947 0 stevel sum += *sp++; 2948 0 stevel sum += *sp++; /* ip_dst */ 2949 0 stevel sum += *sp++; 2950 0 stevel #ifdef USE_INET6 2951 0 stevel } else if (IP_V(ip) == 6) { 2952 0 stevel ip6 = (ip6_t *)ip; 2953 0 stevel hlen = sizeof(*ip6); 2954 0 stevel slen = ntohs(ip6->ip6_plen); 2955 2393 yz155240 sum = htons((u_short)l4proto); 2956 0 stevel sum += htons(slen); 2957 0 stevel sp = (u_short *)&ip6->ip6_src; 2958 0 stevel sum += *sp++; /* ip6_src */ 2959 0 stevel sum += *sp++; 2960 0 stevel sum += *sp++; 2961 0 stevel sum += *sp++; 2962 0 stevel sum += *sp++; 2963 0 stevel sum += *sp++; 2964 0 stevel sum += *sp++; 2965 0 stevel sum += *sp++; 2966 0 stevel sum += *sp++; /* ip6_dst */ 2967 0 stevel sum += *sp++; 2968 0 stevel sum += *sp++; 2969 0 stevel sum += *sp++; 2970 0 stevel sum += *sp++; 2971 0 stevel sum += *sp++; 2972 0 stevel sum += *sp++; 2973 637 ml37995 sum += *sp++; 2974 0 stevel } 2975 0 stevel #endif 2976 0 stevel 2977 0 stevel switch (l4proto) 2978 0 stevel { 2979 0 stevel case IPPROTO_UDP : 2980 0 stevel csump = &((udphdr_t *)l4hdr)->uh_sum; 2981 0 stevel l4hlen = sizeof(udphdr_t); 2982 0 stevel break; 2983 0 stevel 2984 0 stevel case IPPROTO_TCP : 2985 0 stevel csump = &((tcphdr_t *)l4hdr)->th_sum; 2986 0 stevel l4hlen = sizeof(tcphdr_t); 2987 0 stevel break; 2988 0 stevel case IPPROTO_ICMP : 2989 0 stevel csump = &((icmphdr_t *)l4hdr)->icmp_cksum; 2990 0 stevel l4hlen = 4; 2991 2393 yz155240 sum = 0; 2992 0 stevel break; 2993 0 stevel default : 2994 0 stevel break; 2995 0 stevel } 2996 0 stevel 2997 0 stevel if (csump != NULL) { 2998 0 stevel sumsave = *csump; 2999 0 stevel *csump = 0; 3000 0 stevel } 3001 0 stevel 3002 0 stevel l4hlen = l4hlen; /* LINT */ 3003 0 stevel 3004 0 stevel #ifdef _KERNEL 3005 0 stevel # ifdef MENTAT 3006 0 stevel { 3007 0 stevel void *rp = m->b_rptr; 3008 0 stevel 3009 0 stevel if ((unsigned char *)ip > m->b_rptr && (unsigned char *)ip < m->b_wptr) 3010 0 stevel m->b_rptr = (u_char *)ip; 3011 0 stevel sum2 = ip_cksum(m, hlen, sum); /* hlen == offset */ 3012 0 stevel m->b_rptr = rp; 3013 0 stevel sum2 = (sum2 & 0xffff) + (sum2 >> 16); 3014 0 stevel sum2 = ~sum2 & 0xffff; 3015 2393 yz155240 } 3016 0 stevel # else /* MENTAT */ 3017 0 stevel # if defined(BSD) || defined(sun) 3018 0 stevel # if BSD >= 199103 3019 0 stevel m->m_data += hlen; 3020 0 stevel # else 3021 0 stevel m->m_off += hlen; 3022 0 stevel # endif 3023 0 stevel m->m_len -= hlen; 3024 0 stevel sum2 = in_cksum(m, slen); 3025 0 stevel m->m_len += hlen; 3026 0 stevel # if BSD >= 199103 3027 0 stevel m->m_data -= hlen; 3028 0 stevel # else 3029 0 stevel m->m_off -= hlen; 3030 0 stevel # endif 3031 0 stevel /* 3032 0 stevel * Both sum and sum2 are partial sums, so combine them together. 3033 0 stevel */ 3034 0 stevel sum += ~sum2 & 0xffff; 3035 0 stevel while (sum > 0xffff) 3036 0 stevel sum = (sum & 0xffff) + (sum >> 16); 3037 0 stevel sum2 = ~sum & 0xffff; 3038 0 stevel # else /* defined(BSD) || defined(sun) */ 3039 0 stevel { 3040 0 stevel union { 3041 0 stevel u_char c[2]; 3042 0 stevel u_short s; 3043 0 stevel } bytes; 3044 0 stevel u_short len = ip->ip_len; 3045 0 stevel # if defined(__sgi) 3046 0 stevel int add; 3047 0 stevel # endif 3048 0 stevel 3049 0 stevel /* 3050 0 stevel * Add up IP Header portion 3051 0 stevel */ 3052 0 stevel if (sp != (u_short *)l4hdr) 3053 0 stevel sp = (u_short *)l4hdr; 3054 0 stevel 3055 2393 yz155240 switch (l4proto) 3056 0 stevel { 3057 0 stevel case IPPROTO_UDP : 3058 0 stevel sum += *sp++; /* sport */ 3059 0 stevel sum += *sp++; /* dport */ 3060 0 stevel sum += *sp++; /* udp length */ 3061 0 stevel sum += *sp++; /* checksum */ 3062 0 stevel break; 3063 0 stevel 3064 0 stevel case IPPROTO_TCP : 3065 0 stevel sum += *sp++; /* sport */ 3066 0 stevel sum += *sp++; /* dport */ 3067 0 stevel sum += *sp++; /* seq */ 3068 0 stevel sum += *sp++; 3069 0 stevel sum += *sp++; /* ack */ 3070 0 stevel sum += *sp++; 3071 0 stevel sum += *sp++; /* off */ 3072 0 stevel sum += *sp++; /* win */ 3073 0 stevel sum += *sp++; /* checksum */ 3074 0 stevel sum += *sp++; /* urp */ 3075 2393 yz155240 break; 3076 2393 yz155240 case IPPROTO_ICMP : 3077 2393 yz155240 sum = *sp++; /* type/code */ 3078 2393 yz155240 sum += *sp++; /* checksum */ 3079 0 stevel break; 3080 0 stevel } 3081 0 stevel 3082 0 stevel # ifdef __sgi 3083 0 stevel /* 3084 0 stevel * In case we had to copy the IP & TCP header out of mbufs, 3085 0 stevel * skip over the mbuf bits which are the header 3086 0 stevel */ 3087 0 stevel if ((caddr_t)ip != mtod(m, caddr_t)) { 3088 0 stevel hlen = (caddr_t)sp - (caddr_t)ip; 3089 0 stevel while (hlen) { 3090 0 stevel add = MIN(hlen, m->m_len); 3091 0 stevel sp = (u_short *)(mtod(m, caddr_t) + add); 3092 0 stevel hlen -= add; 3093 0 stevel if (add == m->m_len) { 3094 0 stevel m = m->m_next; 3095 0 stevel if (!hlen) { 3096 0 stevel if (!m) 3097 0 stevel break; 3098 0 stevel sp = mtod(m, u_short *); 3099 0 stevel } 3100 0 stevel PANIC((!m),("fr_cksum(1): not enough data")); 3101 0 stevel } 3102 0 stevel } 3103 0 stevel } 3104 0 stevel # endif 3105 0 stevel 3106 2393 yz155240 len -= (l4hlen + hlen); 3107 0 stevel if (len <= 0) 3108 0 stevel goto nodata; 3109 0 stevel 3110 0 stevel while (len > 1) { 3111 0 stevel if (((caddr_t)sp - mtod(m, caddr_t)) >= m->m_len) { 3112 0 stevel m = m->m_next; 3113 0 stevel PANIC((!m),("fr_cksum(2): not enough data")); 3114 0 stevel sp = mtod(m, u_short *); 3115 0 stevel } 3116 0 stevel if (((caddr_t)(sp + 1) - mtod(m, caddr_t)) > m->m_len) { 3117 0 stevel bytes.c[0] = *(u_char *)sp; 3118 0 stevel m = m->m_next; 3119 0 stevel PANIC((!m),("fr_cksum(3): not enough data")); 3120 0 stevel sp = mtod(m, u_short *); 3121 0 stevel bytes.c[1] = *(u_char *)sp; 3122 0 stevel sum += bytes.s; 3123 0 stevel sp = (u_short *)((u_char *)sp + 1); 3124 0 stevel } 3125 0 stevel if ((u_long)sp & 1) { 3126 0 stevel bcopy((char *)sp++, (char *)&bytes.s, sizeof(bytes.s)); 3127 0 stevel sum += bytes.s; 3128 0 stevel } else 3129 0 stevel sum += *sp++; 3130 0 stevel len -= 2; 3131 0 stevel } 3132 0 stevel 3133 0 stevel if (len != 0) 3134 0 stevel sum += ntohs(*(u_char *)sp << 8); 3135 0 stevel nodata: 3136 0 stevel while (sum > 0xffff) 3137 0 stevel sum = (sum & 0xffff) + (sum >> 16); 3138 0 stevel sum2 = (u_short)(~sum & 0xffff); 3139 0 stevel } 3140 0 stevel # endif /* defined(BSD) || defined(sun) */ 3141 0 stevel # endif /* MENTAT */ 3142 0 stevel #else /* _KERNEL */ 3143 0 stevel for (; slen > 1; slen -= 2) 3144 0 stevel sum += *sp++; 3145 0 stevel if (slen) 3146 0 stevel sum += ntohs(*(u_char *)sp << 8); 3147 0 stevel while (sum > 0xffff) 3148 0 stevel sum = (sum & 0xffff) + (sum >> 16); 3149 0 stevel sum2 = (u_short)(~sum & 0xffff); 3150 0 stevel #endif /* _KERNEL */ 3151 0 stevel if (csump != NULL) 3152 0 stevel *csump = sumsave; 3153 0