1 /* $NetBSD: fil.c,v 1.33 2020/04/09 18:20:40 christos Exp $ */ 2 3 /* 4 * Copyright (C) 2012 by Darren Reed. 5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 * 8 * Id: fil.c,v 1.1.1.2 2012/07/22 13:45:07 darrenr Exp $ 9 * 10 */ 11 #if defined(KERNEL) || defined(_KERNEL) 12 # undef KERNEL 13 # undef _KERNEL 14 # define KERNEL 1 15 # define _KERNEL 1 16 #endif 17 #include <sys/errno.h> 18 #include <sys/types.h> 19 #include <sys/param.h> 20 #include <sys/time.h> 21 #if defined(_KERNEL) && defined(__FreeBSD_version) && \ 22 (__FreeBSD_version >= 220000) 23 # if (__FreeBSD_version >= 400000) 24 # if !defined(IPFILTER_LKM) 25 # include "opt_inet6.h" 26 # endif 27 # if (__FreeBSD_version == 400019) 28 # define CSUM_DELAY_DATA 29 # endif 30 # endif 31 # include <sys/filio.h> 32 #else 33 # include <sys/ioctl.h> 34 #endif 35 #if (defined(__SVR4) || defined(__svr4__)) && defined(sun) 36 # include <sys/filio.h> 37 #endif 38 #if !defined(_AIX51) 39 # include <sys/fcntl.h> 40 #endif 41 #if defined(_KERNEL) 42 # include <sys/systm.h> 43 # include <sys/file.h> 44 #else 45 # include <stdio.h> 46 # include <string.h> 47 # include <stdlib.h> 48 # include <stddef.h> 49 # include <sys/file.h> 50 # define _KERNEL 51 # ifdef __OpenBSD__ 52 struct file; 53 # endif 54 # include <sys/uio.h> 55 # undef _KERNEL 56 #endif 57 #if !defined(__SVR4) && !defined(__svr4__) && !defined(__hpux) && \ 58 !defined(linux) 59 # include <sys/mbuf.h> 60 #else 61 # if !defined(linux) 62 # include <sys/byteorder.h> 63 # endif 64 # if (SOLARIS2 < 5) && defined(sun) 65 # include <sys/dditypes.h> 66 # endif 67 #endif 68 #ifdef __hpux 69 # define _NET_ROUTE_INCLUDED 70 #endif 71 #if !defined(linux) 72 # include <sys/protosw.h> 73 #endif 74 #include <sys/socket.h> 75 #include <net/if.h> 76 #ifdef sun 77 # include <net/af.h> 78 #endif 79 #include <netinet/in.h> 80 #include <netinet/in_systm.h> 81 #include <netinet/ip.h> 82 #if defined(__sgi) && defined(IFF_DRVRLOCK) /* IRIX 6 */ 83 # include <sys/hashing.h> 84 # include <netinet/in_var.h> 85 #endif 86 #include <netinet/tcp.h> 87 #if (!defined(__sgi) && !defined(AIX)) || defined(_KERNEL) 88 # include <netinet/udp.h> 89 # include <netinet/ip_icmp.h> 90 #endif 91 #ifdef __hpux 92 # undef _NET_ROUTE_INCLUDED 93 #endif 94 #ifdef __osf__ 95 # undef _RADIX_H_ 96 #endif 97 #include "netinet/ip_compat.h" 98 #ifdef USE_INET6 99 # include <netinet/icmp6.h> 100 # if !SOLARIS && defined(_KERNEL) && !defined(__osf__) && !defined(__hpux) 101 # include <netinet6/in6_var.h> 102 # endif 103 #endif 104 #include "netinet/ip_fil.h" 105 #include "netinet/ip_nat.h" 106 #include "netinet/ip_frag.h" 107 #include "netinet/ip_state.h" 108 #include "netinet/ip_proxy.h" 109 #include "netinet/ip_auth.h" 110 #ifdef IPFILTER_SCAN 111 # include "netinet/ip_scan.h" 112 #endif 113 #include "netinet/ip_sync.h" 114 #include "netinet/ip_lookup.h" 115 #include "netinet/ip_pool.h" 116 #include "netinet/ip_htable.h" 117 #ifdef IPFILTER_COMPILED 118 # include "netinet/ip_rules.h" 119 #endif 120 #if defined(IPFILTER_BPF) && defined(_KERNEL) 121 # include <net/bpf.h> 122 #endif 123 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 300000) 124 # include <sys/malloc.h> 125 #endif 126 #include "netinet/ipl.h" 127 128 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) 129 # include <sys/callout.h> 130 extern struct callout ipf_slowtimer_ch; 131 #endif 132 #if defined(__OpenBSD__) 133 # include <sys/timeout.h> 134 extern struct timeout ipf_slowtimer_ch; 135 #endif 136 #if defined(__NetBSD__) 137 #include <netinet/in_offload.h> 138 #endif 139 /* END OF INCLUDES */ 140 141 #if !defined(lint) 142 #if defined(__NetBSD__) 143 #include <sys/cdefs.h> 144 __KERNEL_RCSID(0, "$NetBSD: fil.c,v 1.33 2020/04/09 18:20:40 christos Exp $"); 145 #else 146 static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed"; 147 static const char rcsid[] = "@(#)Id: fil.c,v 1.1.1.2 2012/07/22 13:45:07 darrenr Exp $"; 148 #endif 149 #endif 150 151 #ifndef _KERNEL 152 # include "ipf.h" 153 # include "ipt.h" 154 extern int opts; 155 extern int blockreason; 156 #endif /* _KERNEL */ 157 158 #define FASTROUTE_RECURSION 159 160 #define LBUMP(x) softc->x++ 161 #define LBUMPD(x, y) do { softc->x.y++; DT(y); } while (0) 162 163 static INLINE int ipf_check_ipf(fr_info_t *, frentry_t *, int); 164 static u_32_t ipf_checkcipso(fr_info_t *, u_char *, int); 165 static u_32_t ipf_checkripso(u_char *); 166 static u_32_t ipf_decaps(fr_info_t *, u_32_t, int); 167 #ifdef IPFILTER_LOG 168 static frentry_t *ipf_dolog(fr_info_t *, u_32_t *); 169 #endif 170 static int ipf_flushlist(ipf_main_softc_t *, int *, frentry_t **); 171 static int ipf_flush_groups(ipf_main_softc_t *, frgroup_t **, int); 172 static ipfunc_t ipf_findfunc(ipfunc_t); 173 static void *ipf_findlookup(ipf_main_softc_t *, int, frentry_t *, 174 i6addr_t *, i6addr_t *); 175 static frentry_t *ipf_firewall(fr_info_t *, u_32_t *); 176 static int ipf_fr_matcharray(fr_info_t *, int *); 177 static int ipf_frruleiter(ipf_main_softc_t *, void *, int, void *); 178 static void ipf_funcfini(ipf_main_softc_t *, frentry_t *);; 179 static int ipf_funcinit(ipf_main_softc_t *, frentry_t *); 180 static int ipf_geniter(ipf_main_softc_t *, ipftoken_t *, 181 ipfgeniter_t *); 182 static void ipf_getstat(ipf_main_softc_t *, 183 struct friostat *, int); 184 static int ipf_group_flush(ipf_main_softc_t *, frgroup_t *); 185 static void ipf_group_free(frgroup_t *); 186 static int ipf_grpmapfini(struct ipf_main_softc_s *, frentry_t *); 187 static int ipf_grpmapinit(struct ipf_main_softc_s *, frentry_t *); 188 static frentry_t *ipf_nextrule(ipf_main_softc_t *, int, int, 189 frentry_t *, int); 190 static int ipf_portcheck(frpcmp_t *, u_32_t); 191 static INLINE int ipf_pr_ah(fr_info_t *); 192 static INLINE void ipf_pr_esp(fr_info_t *); 193 static INLINE void ipf_pr_gre(fr_info_t *); 194 static INLINE void ipf_pr_udp(fr_info_t *); 195 static INLINE void ipf_pr_tcp(fr_info_t *); 196 static INLINE void ipf_pr_icmp(fr_info_t *); 197 static INLINE void ipf_pr_ipv4hdr(fr_info_t *); 198 static INLINE void ipf_pr_short(fr_info_t *, int); 199 static INLINE int ipf_pr_tcpcommon(fr_info_t *); 200 static INLINE int ipf_pr_udpcommon(fr_info_t *); 201 static void ipf_rule_delete(ipf_main_softc_t *, frentry_t *f, 202 int, int); 203 static void ipf_rule_expire_insert(ipf_main_softc_t *, 204 frentry_t *, int); 205 static int ipf_synclist(ipf_main_softc_t *, frentry_t *, void *); 206 static void ipf_token_flush(ipf_main_softc_t *); 207 static void ipf_token_unlink(ipf_main_softc_t *, ipftoken_t *); 208 static ipftuneable_t *ipf_tune_findbyname(ipftuneable_t *, const char *); 209 static ipftuneable_t *ipf_tune_findbycookie(ipftuneable_t **, void *, 210 void **); 211 static int ipf_updateipid(fr_info_t *); 212 static int ipf_settimeout(struct ipf_main_softc_s *, 213 struct ipftuneable *, ipftuneval_t *); 214 215 216 /* 217 * bit values for identifying presence of individual IP options 218 * All of these tables should be ordered by increasing key value on the left 219 * hand side to allow for binary searching of the array and include a trailer 220 * with a 0 for the bitmask for linear searches to easily find the end with. 221 */ 222 static const struct optlist ipopts[20] = { 223 { IPOPT_NOP, 0x000001 }, 224 { IPOPT_RR, 0x000002 }, 225 { IPOPT_ZSU, 0x000004 }, 226 { IPOPT_MTUP, 0x000008 }, 227 { IPOPT_MTUR, 0x000010 }, 228 { IPOPT_ENCODE, 0x000020 }, 229 { IPOPT_TS, 0x000040 }, 230 { IPOPT_TR, 0x000080 }, 231 { IPOPT_SECURITY, 0x000100 }, 232 { IPOPT_LSRR, 0x000200 }, 233 { IPOPT_E_SEC, 0x000400 }, 234 { IPOPT_CIPSO, 0x000800 }, 235 { IPOPT_SATID, 0x001000 }, 236 { IPOPT_SSRR, 0x002000 }, 237 { IPOPT_ADDEXT, 0x004000 }, 238 { IPOPT_VISA, 0x008000 }, 239 { IPOPT_IMITD, 0x010000 }, 240 { IPOPT_EIP, 0x020000 }, 241 { IPOPT_FINN, 0x040000 }, 242 { 0, 0x000000 } 243 }; 244 245 #ifdef USE_INET6 246 static const struct optlist ip6exthdr[] = { 247 { IPPROTO_HOPOPTS, 0x000001 }, 248 { IPPROTO_IPV6, 0x000002 }, 249 { IPPROTO_ROUTING, 0x000004 }, 250 { IPPROTO_FRAGMENT, 0x000008 }, 251 { IPPROTO_ESP, 0x000010 }, 252 { IPPROTO_AH, 0x000020 }, 253 { IPPROTO_NONE, 0x000040 }, 254 { IPPROTO_DSTOPTS, 0x000080 }, 255 { IPPROTO_MOBILITY, 0x000100 }, 256 { 0, 0 } 257 }; 258 #endif 259 260 /* 261 * bit values for identifying presence of individual IP security options 262 */ 263 static const struct optlist secopt[8] = { 264 { IPSO_CLASS_RES4, 0x01 }, 265 { IPSO_CLASS_TOPS, 0x02 }, 266 { IPSO_CLASS_SECR, 0x04 }, 267 { IPSO_CLASS_RES3, 0x08 }, 268 { IPSO_CLASS_CONF, 0x10 }, 269 { IPSO_CLASS_UNCL, 0x20 }, 270 { IPSO_CLASS_RES2, 0x40 }, 271 { IPSO_CLASS_RES1, 0x80 } 272 }; 273 274 char ipfilter_version[] = IPL_VERSION; 275 276 int ipf_features = 0 277 #ifdef IPFILTER_LKM 278 | IPF_FEAT_LKM 279 #endif 280 #ifdef IPFILTER_LOG 281 | IPF_FEAT_LOG 282 #endif 283 | IPF_FEAT_LOOKUP 284 #ifdef IPFILTER_BPF 285 | IPF_FEAT_BPF 286 #endif 287 #ifdef IPFILTER_COMPILED 288 | IPF_FEAT_COMPILED 289 #endif 290 #ifdef IPFILTER_CKSUM 291 | IPF_FEAT_CKSUM 292 #endif 293 | IPF_FEAT_SYNC 294 #ifdef IPFILTER_SCAN 295 | IPF_FEAT_SCAN 296 #endif 297 #ifdef USE_INET6 298 | IPF_FEAT_IPV6 299 #endif 300 ; 301 302 303 /* 304 * Table of functions available for use with call rules. 305 */ 306 static ipfunc_resolve_t ipf_availfuncs[] = { 307 { "srcgrpmap", ipf_srcgrpmap, ipf_grpmapinit, ipf_grpmapfini }, 308 { "dstgrpmap", ipf_dstgrpmap, ipf_grpmapinit, ipf_grpmapfini }, 309 { "", NULL, NULL, NULL } 310 }; 311 312 static const ipftuneable_t ipf_main_tuneables[] = { 313 { { (void *)offsetof(struct ipf_main_softc_s, ipf_flags) }, 314 "ipf_flags", 0, 0xffffffff, 315 stsizeof(ipf_main_softc_t, ipf_flags), 316 0, NULL, NULL }, 317 { { (void *)offsetof(struct ipf_main_softc_s, ipf_active) }, 318 "active", 0, 0, 319 stsizeof(ipf_main_softc_t, ipf_active), 320 IPFT_RDONLY, NULL, NULL }, 321 { { (void *)offsetof(ipf_main_softc_t, ipf_control_forwarding) }, 322 "control_forwarding", 0, 1, 323 stsizeof(ipf_main_softc_t, ipf_control_forwarding), 324 0, NULL, NULL }, 325 { { (void *)offsetof(ipf_main_softc_t, ipf_update_ipid) }, 326 "update_ipid", 0, 1, 327 stsizeof(ipf_main_softc_t, ipf_update_ipid), 328 0, NULL, NULL }, 329 { { (void *)offsetof(ipf_main_softc_t, ipf_chksrc) }, 330 "chksrc", 0, 1, 331 stsizeof(ipf_main_softc_t, ipf_chksrc), 332 0, NULL, NULL }, 333 { { (void *)offsetof(ipf_main_softc_t, ipf_minttl) }, 334 "min_ttl", 0, 1, 335 stsizeof(ipf_main_softc_t, ipf_minttl), 336 0, NULL, NULL }, 337 { { (void *)offsetof(ipf_main_softc_t, ipf_icmpminfragmtu) }, 338 "icmp_minfragmtu", 0, 1, 339 stsizeof(ipf_main_softc_t, ipf_icmpminfragmtu), 340 0, NULL, NULL }, 341 { { (void *)offsetof(ipf_main_softc_t, ipf_pass) }, 342 "default_pass", 0, 0xffffffff, 343 stsizeof(ipf_main_softc_t, ipf_pass), 344 0, NULL, NULL }, 345 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpidletimeout) }, 346 "tcp_idle_timeout", 1, 0x7fffffff, 347 stsizeof(ipf_main_softc_t, ipf_tcpidletimeout), 348 0, NULL, ipf_settimeout }, 349 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosewait) }, 350 "tcp_close_wait", 1, 0x7fffffff, 351 stsizeof(ipf_main_softc_t, ipf_tcpclosewait), 352 0, NULL, ipf_settimeout }, 353 { { (void *)offsetof(ipf_main_softc_t, ipf_tcplastack) }, 354 "tcp_last_ack", 1, 0x7fffffff, 355 stsizeof(ipf_main_softc_t, ipf_tcplastack), 356 0, NULL, ipf_settimeout }, 357 { { (void *)offsetof(ipf_main_softc_t, ipf_tcptimeout) }, 358 "tcp_timeout", 1, 0x7fffffff, 359 stsizeof(ipf_main_softc_t, ipf_tcptimeout), 360 0, NULL, ipf_settimeout }, 361 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynsent) }, 362 "tcp_syn_sent", 1, 0x7fffffff, 363 stsizeof(ipf_main_softc_t, ipf_tcpsynsent), 364 0, NULL, ipf_settimeout }, 365 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynrecv) }, 366 "tcp_syn_received", 1, 0x7fffffff, 367 stsizeof(ipf_main_softc_t, ipf_tcpsynrecv), 368 0, NULL, ipf_settimeout }, 369 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosed) }, 370 "tcp_closed", 1, 0x7fffffff, 371 stsizeof(ipf_main_softc_t, ipf_tcpclosed), 372 0, NULL, ipf_settimeout }, 373 { { (void *)offsetof(ipf_main_softc_t, ipf_tcphalfclosed) }, 374 "tcp_half_closed", 1, 0x7fffffff, 375 stsizeof(ipf_main_softc_t, ipf_tcphalfclosed), 376 0, NULL, ipf_settimeout }, 377 { { (void *)offsetof(ipf_main_softc_t, ipf_tcptimewait) }, 378 "tcp_time_wait", 1, 0x7fffffff, 379 stsizeof(ipf_main_softc_t, ipf_tcptimewait), 380 0, NULL, ipf_settimeout }, 381 { { (void *)offsetof(ipf_main_softc_t, ipf_udptimeout) }, 382 "udp_timeout", 1, 0x7fffffff, 383 stsizeof(ipf_main_softc_t, ipf_udptimeout), 384 0, NULL, ipf_settimeout }, 385 { { (void *)offsetof(ipf_main_softc_t, ipf_udpacktimeout) }, 386 "udp_ack_timeout", 1, 0x7fffffff, 387 stsizeof(ipf_main_softc_t, ipf_udpacktimeout), 388 0, NULL, ipf_settimeout }, 389 { { (void *)offsetof(ipf_main_softc_t, ipf_icmptimeout) }, 390 "icmp_timeout", 1, 0x7fffffff, 391 stsizeof(ipf_main_softc_t, ipf_icmptimeout), 392 0, NULL, ipf_settimeout }, 393 { { (void *)offsetof(ipf_main_softc_t, ipf_icmpacktimeout) }, 394 "icmp_ack_timeout", 1, 0x7fffffff, 395 stsizeof(ipf_main_softc_t, ipf_icmpacktimeout), 396 0, NULL, ipf_settimeout }, 397 { { (void *)offsetof(ipf_main_softc_t, ipf_iptimeout) }, 398 "ip_timeout", 1, 0x7fffffff, 399 stsizeof(ipf_main_softc_t, ipf_iptimeout), 400 0, NULL, ipf_settimeout }, 401 #if defined(INSTANCES) && defined(_KERNEL) 402 { { (void *)offsetof(ipf_main_softc_t, ipf_get_loopback) }, 403 "intercept_loopback", 0, 1, 404 stsizeof(ipf_main_softc_t, ipf_get_loopback), 405 0, NULL, ipf_set_loopback }, 406 #endif 407 { { 0 }, 408 NULL, 0, 0, 409 0, 410 0, NULL, NULL } 411 }; 412 413 414 /* 415 * The next section of code is a a collection of small routines that set 416 * fields in the fr_info_t structure passed based on properties of the 417 * current packet. There are different routines for the same protocol 418 * for each of IPv4 and IPv6. Adding a new protocol, for which there 419 * will "special" inspection for setup, is now more easily done by adding 420 * a new routine and expanding the ipf_pr_ipinit*() function rather than by 421 * adding more code to a growing switch statement. 422 */ 423 #ifdef USE_INET6 424 static INLINE int ipf_pr_ah6(fr_info_t *); 425 static INLINE void ipf_pr_esp6(fr_info_t *); 426 static INLINE void ipf_pr_gre6(fr_info_t *); 427 static INLINE void ipf_pr_udp6(fr_info_t *); 428 static INLINE void ipf_pr_tcp6(fr_info_t *); 429 static INLINE void ipf_pr_icmp6(fr_info_t *); 430 static INLINE void ipf_pr_ipv6hdr(fr_info_t *); 431 static INLINE void ipf_pr_short6(fr_info_t *, int); 432 static INLINE int ipf_pr_hopopts6(fr_info_t *); 433 static INLINE int ipf_pr_mobility6(fr_info_t *); 434 static INLINE int ipf_pr_routing6(fr_info_t *); 435 static INLINE int ipf_pr_dstopts6(fr_info_t *); 436 static INLINE int ipf_pr_fragment6(fr_info_t *); 437 static INLINE struct ip6_ext *ipf_pr_ipv6exthdr(fr_info_t *, int, int); 438 439 440 /* ------------------------------------------------------------------------ */ 441 /* Function: ipf_pr_short6 */ 442 /* Returns: void */ 443 /* Parameters: fin(I) - pointer to packet information */ 444 /* xmin(I) - minimum header size */ 445 /* */ 446 /* IPv6 Only */ 447 /* This is function enforces the 'is a packet too short to be legit' rule */ 448 /* for IPv6 and marks the packet with FI_SHORT if so. See function comment */ 449 /* for ipf_pr_short() for more details. */ 450 /* ------------------------------------------------------------------------ */ 451 static INLINE void 452 ipf_pr_short6(fr_info_t *fin, int xmin) 453 { 454 455 if (fin->fin_dlen < xmin) 456 fin->fin_flx |= FI_SHORT; 457 } 458 459 460 /* ------------------------------------------------------------------------ */ 461 /* Function: ipf_pr_ipv6hdr */ 462 /* Returns: void */ 463 /* Parameters: fin(I) - pointer to packet information */ 464 /* */ 465 /* IPv6 Only */ 466 /* Copy values from the IPv6 header into the fr_info_t struct and call the */ 467 /* per-protocol analyzer if it exists. In validating the packet, a protocol*/ 468 /* analyzer may pullup or free the packet itself so we need to be vigiliant */ 469 /* of that possibility arising. */ 470 /* ------------------------------------------------------------------------ */ 471 static INLINE void 472 ipf_pr_ipv6hdr(fr_info_t *fin) 473 { 474 ip6_t *ip6 = (ip6_t *)fin->fin_ip; 475 int p, go = 1, i, hdrcount; 476 fr_ip_t *fi = &fin->fin_fi; 477 478 fin->fin_off = 0; 479 480 fi->fi_tos = 0; 481 fi->fi_optmsk = 0; 482 fi->fi_secmsk = 0; 483 fi->fi_auth = 0; 484 485 p = ip6->ip6_nxt; 486 fin->fin_crc = p; 487 fi->fi_ttl = ip6->ip6_hlim; 488 fi->fi_src.in6 = ip6->ip6_src; 489 fin->fin_crc += fi->fi_src.i6[0]; 490 fin->fin_crc += fi->fi_src.i6[1]; 491 fin->fin_crc += fi->fi_src.i6[2]; 492 fin->fin_crc += fi->fi_src.i6[3]; 493 fi->fi_dst.in6 = ip6->ip6_dst; 494 fin->fin_crc += fi->fi_dst.i6[0]; 495 fin->fin_crc += fi->fi_dst.i6[1]; 496 fin->fin_crc += fi->fi_dst.i6[2]; 497 fin->fin_crc += fi->fi_dst.i6[3]; 498 fin->fin_id = 0; 499 if (IN6_IS_ADDR_MULTICAST(&fi->fi_dst.in6)) 500 fin->fin_flx |= FI_MULTICAST|FI_MBCAST; 501 502 hdrcount = 0; 503 while (go && !(fin->fin_flx & FI_SHORT)) { 504 switch (p) 505 { 506 case IPPROTO_UDP : 507 ipf_pr_udp6(fin); 508 go = 0; 509 break; 510 511 case IPPROTO_TCP : 512 ipf_pr_tcp6(fin); 513 go = 0; 514 break; 515 516 case IPPROTO_ICMPV6 : 517 ipf_pr_icmp6(fin); 518 go = 0; 519 break; 520 521 case IPPROTO_GRE : 522 ipf_pr_gre6(fin); 523 go = 0; 524 break; 525 526 case IPPROTO_HOPOPTS : 527 p = ipf_pr_hopopts6(fin); 528 break; 529 530 case IPPROTO_MOBILITY : 531 p = ipf_pr_mobility6(fin); 532 break; 533 534 case IPPROTO_DSTOPTS : 535 p = ipf_pr_dstopts6(fin); 536 break; 537 538 case IPPROTO_ROUTING : 539 p = ipf_pr_routing6(fin); 540 break; 541 542 case IPPROTO_AH : 543 p = ipf_pr_ah6(fin); 544 break; 545 546 case IPPROTO_ESP : 547 ipf_pr_esp6(fin); 548 go = 0; 549 break; 550 551 case IPPROTO_IPV6 : 552 for (i = 0; ip6exthdr[i].ol_bit != 0; i++) 553 if (ip6exthdr[i].ol_val == p) { 554 fin->fin_flx |= ip6exthdr[i].ol_bit; 555 break; 556 } 557 go = 0; 558 break; 559 560 case IPPROTO_NONE : 561 go = 0; 562 break; 563 564 case IPPROTO_FRAGMENT : 565 p = ipf_pr_fragment6(fin); 566 /* 567 * Given that the only fragments we want to let through 568 * (where fin_off != 0) are those where the non-first 569 * fragments only have data, we can safely stop looking 570 * at headers if this is a non-leading fragment. 571 */ 572 if (fin->fin_off != 0) 573 go = 0; 574 break; 575 576 default : 577 go = 0; 578 break; 579 } 580 hdrcount++; 581 582 /* 583 * It is important to note that at this point, for the 584 * extension headers (go != 0), the entire header may not have 585 * been pulled up when the code gets to this point. This is 586 * only done for "go != 0" because the other header handlers 587 * will all pullup their complete header. The other indicator 588 * of an incomplete packet is that this was just an extension 589 * header. 590 */ 591 if ((go != 0) && (p != IPPROTO_NONE) && 592 (ipf_pr_pullup(fin, 0) == -1)) { 593 p = IPPROTO_NONE; 594 break; 595 } 596 } 597 598 /* 599 * Some of the above functions, like ipf_pr_esp6(), can call ipf_pullup 600 * and destroy whatever packet was here. The caller of this function 601 * expects us to return if there is a problem with ipf_pullup. 602 */ 603 if (fin->fin_m == NULL) { 604 ipf_main_softc_t *softc = fin->fin_main_soft; 605 606 LBUMPD(ipf_stats[fin->fin_out], fr_v6_bad); 607 return; 608 } 609 610 fi->fi_p = p; 611 612 /* 613 * IPv6 fragment case 1 - see comment for ipf_pr_fragment6(). 614 * "go != 0" imples the above loop hasn't arrived at a layer 4 header. 615 */ 616 if ((go != 0) && (fin->fin_flx & FI_FRAG) && (fin->fin_off == 0)) { 617 ipf_main_softc_t *softc = fin->fin_main_soft; 618 619 fin->fin_flx |= FI_BAD; 620 DT2(ipf_fi_bad_ipv6_frag_1, fr_info_t *, fin, int, go); 621 LBUMPD(ipf_stats[fin->fin_out], fr_v6_badfrag); 622 LBUMP(ipf_stats[fin->fin_out].fr_v6_bad); 623 } 624 } 625 626 627 /* ------------------------------------------------------------------------ */ 628 /* Function: ipf_pr_ipv6exthdr */ 629 /* Returns: struct ip6_ext * - pointer to the start of the next header */ 630 /* or NULL if there is a prolblem. */ 631 /* Parameters: fin(I) - pointer to packet information */ 632 /* multiple(I) - flag indicating yes/no if multiple occurances */ 633 /* of this extension header are allowed. */ 634 /* proto(I) - protocol number for this extension header */ 635 /* */ 636 /* IPv6 Only */ 637 /* This function embodies a number of common checks that all IPv6 extension */ 638 /* headers must be subjected to. For example, making sure the packet is */ 639 /* big enough for it to be in, checking if it is repeated and setting a */ 640 /* flag to indicate its presence. */ 641 /* ------------------------------------------------------------------------ */ 642 static INLINE struct ip6_ext * 643 ipf_pr_ipv6exthdr(fr_info_t *fin, int multiple, int proto) 644 { 645 ipf_main_softc_t *softc = fin->fin_main_soft; 646 struct ip6_ext *hdr; 647 u_short shift; 648 int i; 649 650 fin->fin_flx |= FI_V6EXTHDR; 651 652 /* 8 is default length of extension hdr */ 653 if ((fin->fin_dlen - 8) < 0) { 654 fin->fin_flx |= FI_SHORT; 655 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_short); 656 return NULL; 657 } 658 659 if (ipf_pr_pullup(fin, 8) == -1) { 660 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_pullup); 661 return NULL; 662 } 663 664 hdr = fin->fin_dp; 665 switch (proto) 666 { 667 case IPPROTO_FRAGMENT : 668 shift = 8; 669 break; 670 default : 671 shift = 8 + (hdr->ip6e_len << 3); 672 break; 673 } 674 675 if (shift > fin->fin_dlen) { /* Nasty extension header length? */ 676 fin->fin_flx |= FI_BAD; 677 DT3(ipf_fi_bad_pr_ipv6exthdr_len, fr_info_t *, fin, u_short, shift, u_short, fin->fin_dlen); 678 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_hlen); 679 return NULL; 680 } 681 682 fin->fin_dp = (char *)fin->fin_dp + shift; 683 fin->fin_dlen -= shift; 684 685 /* 686 * If we have seen a fragment header, do not set any flags to indicate 687 * the presence of this extension header as it has no impact on the 688 * end result until after it has been defragmented. 689 */ 690 if (fin->fin_flx & FI_FRAG) 691 return hdr; 692 693 for (i = 0; ip6exthdr[i].ol_bit != 0; i++) 694 if (ip6exthdr[i].ol_val == proto) { 695 /* 696 * Most IPv6 extension headers are only allowed once. 697 */ 698 if ((multiple == 0) && 699 ((fin->fin_optmsk & ip6exthdr[i].ol_bit) != 0)) { 700 fin->fin_flx |= FI_BAD; 701 DT2(ipf_fi_bad_ipv6exthdr_once, fr_info_t *, fin, u_int, (fin->fin_optmsk & ip6exthdr[i].ol_bit)); 702 } else 703 fin->fin_optmsk |= ip6exthdr[i].ol_bit; 704 break; 705 } 706 707 return hdr; 708 } 709 710 711 /* ------------------------------------------------------------------------ */ 712 /* Function: ipf_pr_hopopts6 */ 713 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 714 /* Parameters: fin(I) - pointer to packet information */ 715 /* */ 716 /* IPv6 Only */ 717 /* This is function checks pending hop by hop options extension header */ 718 /* ------------------------------------------------------------------------ */ 719 static INLINE int 720 ipf_pr_hopopts6(fr_info_t *fin) 721 { 722 struct ip6_ext *hdr; 723 724 hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS); 725 if (hdr == NULL) 726 return IPPROTO_NONE; 727 return hdr->ip6e_nxt; 728 } 729 730 731 /* ------------------------------------------------------------------------ */ 732 /* Function: ipf_pr_mobility6 */ 733 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 734 /* Parameters: fin(I) - pointer to packet information */ 735 /* */ 736 /* IPv6 Only */ 737 /* This is function checks the IPv6 mobility extension header */ 738 /* ------------------------------------------------------------------------ */ 739 static INLINE int 740 ipf_pr_mobility6(fr_info_t *fin) 741 { 742 struct ip6_ext *hdr; 743 744 hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_MOBILITY); 745 if (hdr == NULL) 746 return IPPROTO_NONE; 747 return hdr->ip6e_nxt; 748 } 749 750 751 /* ------------------------------------------------------------------------ */ 752 /* Function: ipf_pr_routing6 */ 753 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 754 /* Parameters: fin(I) - pointer to packet information */ 755 /* */ 756 /* IPv6 Only */ 757 /* This is function checks pending routing extension header */ 758 /* ------------------------------------------------------------------------ */ 759 static INLINE int 760 ipf_pr_routing6(fr_info_t *fin) 761 { 762 struct ip6_routing *hdr; 763 764 hdr = (struct ip6_routing *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_ROUTING); 765 if (hdr == NULL) 766 return IPPROTO_NONE; 767 768 switch (hdr->ip6r_type) 769 { 770 case 0 : 771 /* 772 * Nasty extension header length? 773 */ 774 if (((hdr->ip6r_len >> 1) < hdr->ip6r_segleft) || 775 (hdr->ip6r_segleft && (hdr->ip6r_len & 1))) { 776 ipf_main_softc_t *softc = fin->fin_main_soft; 777 778 fin->fin_flx |= FI_BAD; 779 DT1(ipf_fi_bad_routing6, fr_info_t *, fin); 780 LBUMPD(ipf_stats[fin->fin_out], fr_v6_rh_bad); 781 return IPPROTO_NONE; 782 } 783 break; 784 785 default : 786 break; 787 } 788 789 return hdr->ip6r_nxt; 790 } 791 792 793 /* ------------------------------------------------------------------------ */ 794 /* Function: ipf_pr_fragment6 */ 795 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 796 /* Parameters: fin(I) - pointer to packet information */ 797 /* */ 798 /* IPv6 Only */ 799 /* Examine the IPv6 fragment header and extract fragment offset information.*/ 800 /* */ 801 /* Fragments in IPv6 are extraordinarily difficult to deal with - much more */ 802 /* so than in IPv4. There are 5 cases of fragments with IPv6 that all */ 803 /* packets with a fragment header can fit into. They are as follows: */ 804 /* */ 805 /* 1. [IPv6][0-n EH][FH][0-n EH] (no L4HDR present) */ 806 /* 2. [IPV6][0-n EH][FH][0-n EH][L4HDR part] (short) */ 807 /* 3. [IPV6][0-n EH][FH][L4HDR part][0-n data] (short) */ 808 /* 4. [IPV6][0-n EH][FH][0-n EH][L4HDR][0-n data] */ 809 /* 5. [IPV6][0-n EH][FH][data] */ 810 /* */ 811 /* IPV6 = IPv6 header, FH = Fragment Header, */ 812 /* 0-n EH = 0 or more extension headers, 0-n data = 0 or more bytes of data */ 813 /* */ 814 /* Packets that match 1, 2, 3 will be dropped as the only reasonable */ 815 /* scenario in which they happen is in extreme circumstances that are most */ 816 /* likely to be an indication of an attack rather than normal traffic. */ 817 /* A type 3 packet may be sent by an attacked after a type 4 packet. There */ 818 /* are two rules that can be used to guard against type 3 packets: L4 */ 819 /* headers must always be in a packet that has the offset field set to 0 */ 820 /* and no packet is allowed to overlay that where offset = 0. */ 821 /* ------------------------------------------------------------------------ */ 822 static INLINE int 823 ipf_pr_fragment6(fr_info_t *fin) 824 { 825 ipf_main_softc_t *softc = fin->fin_main_soft; 826 struct ip6_frag *frag; 827 828 fin->fin_flx |= FI_FRAG; 829 830 frag = (struct ip6_frag *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT); 831 if (frag == NULL) { 832 LBUMPD(ipf_stats[fin->fin_out], fr_v6_frag_bad); 833 return IPPROTO_NONE; 834 } 835 836 if ((frag->ip6f_offlg & IP6F_MORE_FRAG) != 0) { 837 /* 838 * Any fragment that isn't the last fragment must have its 839 * length as a multiple of 8. 840 */ 841 if ((fin->fin_plen & 7) != 0) { 842 fin->fin_flx |= FI_BAD; 843 DT2(ipf_fi_bad_frag_not_8, fr_info_t *, fin, u_int, (fin->fin_plen & 7)); 844 } 845 } 846 847 fin->fin_fraghdr = frag; 848 fin->fin_id = frag->ip6f_ident; 849 fin->fin_off = ntohs(frag->ip6f_offlg & IP6F_OFF_MASK); 850 if (fin->fin_off != 0) 851 fin->fin_flx |= FI_FRAGBODY; 852 853 /* 854 * Jumbograms aren't handled, so the max. length is 64k 855 */ 856 if ((fin->fin_off << 3) + fin->fin_dlen > 65535) { 857 fin->fin_flx |= FI_BAD; 858 DT2(ipf_fi_bad_jumbogram, fr_info_t *, fin, u_int, ((fin->fin_off << 3) + fin->fin_dlen)); 859 } 860 861 /* 862 * We don't know where the transport layer header (or whatever is next 863 * is), as it could be behind destination options (amongst others) so 864 * return the fragment header as the type of packet this is. Note that 865 * this effectively disables the fragment cache for > 1 protocol at a 866 * time. 867 */ 868 return frag->ip6f_nxt; 869 } 870 871 872 /* ------------------------------------------------------------------------ */ 873 /* Function: ipf_pr_dstopts6 */ 874 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 875 /* Parameters: fin(I) - pointer to packet information */ 876 /* */ 877 /* IPv6 Only */ 878 /* This is function checks pending destination options extension header */ 879 /* ------------------------------------------------------------------------ */ 880 static INLINE int 881 ipf_pr_dstopts6(fr_info_t *fin) 882 { 883 ipf_main_softc_t *softc = fin->fin_main_soft; 884 struct ip6_ext *hdr; 885 886 hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_DSTOPTS); 887 if (hdr == NULL) { 888 LBUMPD(ipf_stats[fin->fin_out], fr_v6_dst_bad); 889 return IPPROTO_NONE; 890 } 891 return hdr->ip6e_nxt; 892 } 893 894 895 /* ------------------------------------------------------------------------ */ 896 /* Function: ipf_pr_icmp6 */ 897 /* Returns: void */ 898 /* Parameters: fin(I) - pointer to packet information */ 899 /* */ 900 /* IPv6 Only */ 901 /* This routine is mainly concerned with determining the minimum valid size */ 902 /* for an ICMPv6 packet. */ 903 /* ------------------------------------------------------------------------ */ 904 static INLINE void 905 ipf_pr_icmp6(fr_info_t *fin) 906 { 907 int minicmpsz = sizeof(struct icmp6_hdr); 908 struct icmp6_hdr *icmp6; 909 910 if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1) { 911 ipf_main_softc_t *softc = fin->fin_main_soft; 912 913 LBUMPD(ipf_stats[fin->fin_out], fr_v6_icmp6_pullup); 914 return; 915 } 916 917 if (fin->fin_dlen > 1) { 918 ip6_t *ip6; 919 920 icmp6 = fin->fin_dp; 921 922 fin->fin_data[0] = *(u_short *)icmp6; 923 924 if ((icmp6->icmp6_type & ICMP6_INFOMSG_MASK) != 0) 925 fin->fin_flx |= FI_ICMPQUERY; 926 927 switch (icmp6->icmp6_type) 928 { 929 case ICMP6_ECHO_REPLY : 930 case ICMP6_ECHO_REQUEST : 931 if (fin->fin_dlen >= 6) 932 fin->fin_data[1] = icmp6->icmp6_id; 933 minicmpsz = ICMP6ERR_MINPKTLEN - sizeof(ip6_t); 934 break; 935 936 case ICMP6_DST_UNREACH : 937 case ICMP6_PACKET_TOO_BIG : 938 case ICMP6_TIME_EXCEEDED : 939 case ICMP6_PARAM_PROB : 940 fin->fin_flx |= FI_ICMPERR; 941 minicmpsz = ICMP6ERR_IPICMPHLEN - sizeof(ip6_t); 942 if (fin->fin_plen < ICMP6ERR_IPICMPHLEN) 943 break; 944 945 if (M_LEN(fin->fin_m) < fin->fin_plen) { 946 if (ipf_coalesce(fin) != 1) 947 return; 948 } 949 950 if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN) == -1) 951 return; 952 953 /* 954 * If the destination of this packet doesn't match the 955 * source of the original packet then this packet is 956 * not correct. 957 */ 958 icmp6 = fin->fin_dp; 959 ip6 = (ip6_t *)((char *)icmp6 + ICMPERR_ICMPHLEN); 960 if (IP6_NEQ(&fin->fin_fi.fi_dst, 961 &ip6->ip6_src)) { 962 fin->fin_flx |= FI_BAD; 963 DT1(ipf_fi_bad_icmp6, fr_info_t *, fin); 964 } 965 break; 966 default : 967 break; 968 } 969 } 970 971 ipf_pr_short6(fin, minicmpsz); 972 if ((fin->fin_flx & (FI_SHORT|FI_BAD)) == 0) { 973 u_char p = fin->fin_p; 974 975 fin->fin_p = IPPROTO_ICMPV6; 976 ipf_checkv6sum(fin); 977 fin->fin_p = p; 978 } 979 } 980 981 982 /* ------------------------------------------------------------------------ */ 983 /* Function: ipf_pr_udp6 */ 984 /* Returns: void */ 985 /* Parameters: fin(I) - pointer to packet information */ 986 /* */ 987 /* IPv6 Only */ 988 /* Analyse the packet for IPv6/UDP properties. */ 989 /* Is not expected to be called for fragmented packets. */ 990 /* ------------------------------------------------------------------------ */ 991 static INLINE void 992 ipf_pr_udp6(fr_info_t *fin) 993 { 994 995 if (ipf_pr_udpcommon(fin) == 0) { 996 u_char p = fin->fin_p; 997 998 fin->fin_p = IPPROTO_UDP; 999 ipf_checkv6sum(fin); 1000 fin->fin_p = p; 1001 } 1002 } 1003 1004 1005 /* ------------------------------------------------------------------------ */ 1006 /* Function: ipf_pr_tcp6 */ 1007 /* Returns: void */ 1008 /* Parameters: fin(I) - pointer to packet information */ 1009 /* */ 1010 /* IPv6 Only */ 1011 /* Analyse the packet for IPv6/TCP properties. */ 1012 /* Is not expected to be called for fragmented packets. */ 1013 /* ------------------------------------------------------------------------ */ 1014 static INLINE void 1015 ipf_pr_tcp6(fr_info_t *fin) 1016 { 1017 1018 if (ipf_pr_tcpcommon(fin) == 0) { 1019 u_char p = fin->fin_p; 1020 1021 fin->fin_p = IPPROTO_TCP; 1022 ipf_checkv6sum(fin); 1023 fin->fin_p = p; 1024 } 1025 } 1026 1027 1028 /* ------------------------------------------------------------------------ */ 1029 /* Function: ipf_pr_esp6 */ 1030 /* Returns: void */ 1031 /* Parameters: fin(I) - pointer to packet information */ 1032 /* */ 1033 /* IPv6 Only */ 1034 /* Analyse the packet for ESP properties. */ 1035 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ 1036 /* even though the newer ESP packets must also have a sequence number that */ 1037 /* is 32bits as well, it is not possible(?) to determine the version from a */ 1038 /* simple packet header. */ 1039 /* ------------------------------------------------------------------------ */ 1040 static INLINE void 1041 ipf_pr_esp6(fr_info_t *fin) 1042 { 1043 1044 if ((fin->fin_off == 0) && (ipf_pr_pullup(fin, 8) == -1)) { 1045 ipf_main_softc_t *softc = fin->fin_main_soft; 1046 1047 LBUMPD(ipf_stats[fin->fin_out], fr_v6_esp_pullup); 1048 return; 1049 } 1050 } 1051 1052 1053 /* ------------------------------------------------------------------------ */ 1054 /* Function: ipf_pr_ah6 */ 1055 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 1056 /* Parameters: fin(I) - pointer to packet information */ 1057 /* */ 1058 /* IPv6 Only */ 1059 /* Analyse the packet for AH properties. */ 1060 /* The minimum length is taken to be the combination of all fields in the */ 1061 /* header being present and no authentication data (null algorithm used.) */ 1062 /* ------------------------------------------------------------------------ */ 1063 static INLINE int 1064 ipf_pr_ah6(fr_info_t *fin) 1065 { 1066 authhdr_t *ah; 1067 1068 fin->fin_flx |= FI_AH; 1069 1070 ah = (authhdr_t *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS); 1071 if (ah == NULL) { 1072 ipf_main_softc_t *softc = fin->fin_main_soft; 1073 1074 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ah_bad); 1075 return IPPROTO_NONE; 1076 } 1077 1078 ipf_pr_short6(fin, sizeof(*ah)); 1079 1080 /* 1081 * No need for another pullup, ipf_pr_ipv6exthdr() will pullup 1082 * enough data to satisfy ah_next (the very first one.) 1083 */ 1084 return ah->ah_next; 1085 } 1086 1087 1088 /* ------------------------------------------------------------------------ */ 1089 /* Function: ipf_pr_gre6 */ 1090 /* Returns: void */ 1091 /* Parameters: fin(I) - pointer to packet information */ 1092 /* */ 1093 /* Analyse the packet for GRE properties. */ 1094 /* ------------------------------------------------------------------------ */ 1095 static INLINE void 1096 ipf_pr_gre6(fr_info_t *fin) 1097 { 1098 grehdr_t *gre; 1099 1100 if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) { 1101 ipf_main_softc_t *softc = fin->fin_main_soft; 1102 1103 LBUMPD(ipf_stats[fin->fin_out], fr_v6_gre_pullup); 1104 return; 1105 } 1106 1107 gre = fin->fin_dp; 1108 if (GRE_REV(gre->gr_flags) == 1) 1109 fin->fin_data[0] = gre->gr_call; 1110 } 1111 #endif /* USE_INET6 */ 1112 1113 1114 /* ------------------------------------------------------------------------ */ 1115 /* Function: ipf_pr_pullup */ 1116 /* Returns: int - 0 == pullup succeeded, -1 == failure */ 1117 /* Parameters: fin(I) - pointer to packet information */ 1118 /* plen(I) - length (excluding L3 header) to pullup */ 1119 /* */ 1120 /* Short inline function to cut down on code duplication to perform a call */ 1121 /* to ipf_pullup to ensure there is the required amount of data, */ 1122 /* consecutively in the packet buffer. */ 1123 /* */ 1124 /* This function pulls up 'extra' data at the location of fin_dp. fin_dp */ 1125 /* points to the first byte after the complete layer 3 header, which will */ 1126 /* include all of the known extension headers for IPv6 or options for IPv4. */ 1127 /* */ 1128 /* Since fr_pullup() expects the total length of bytes to be pulled up, it */ 1129 /* is necessary to add those we can already assume to be pulled up (fin_dp */ 1130 /* - fin_ip) to what is passed through. */ 1131 /* ------------------------------------------------------------------------ */ 1132 int 1133 ipf_pr_pullup(fr_info_t *fin, int plen) 1134 { 1135 ipf_main_softc_t *softc = fin->fin_main_soft; 1136 1137 if (fin->fin_m != NULL) { 1138 if (fin->fin_dp != NULL) 1139 plen += (char *)fin->fin_dp - 1140 ((char *)fin->fin_ip + fin->fin_hlen); 1141 plen += fin->fin_hlen; 1142 if (M_LEN(fin->fin_m) < plen + fin->fin_ipoff) { 1143 #if defined(_KERNEL) 1144 if (ipf_pullup(fin->fin_m, fin, plen) == NULL) { 1145 DT(ipf_pullup_fail); 1146 LBUMP(ipf_stats[fin->fin_out].fr_pull[1]); 1147 return -1; 1148 } 1149 LBUMP(ipf_stats[fin->fin_out].fr_pull[0]); 1150 #else 1151 LBUMP(ipf_stats[fin->fin_out].fr_pull[1]); 1152 /* 1153 * Fake ipf_pullup failing 1154 */ 1155 fin->fin_reason = FRB_PULLUP; 1156 *fin->fin_mp = NULL; 1157 fin->fin_m = NULL; 1158 fin->fin_ip = NULL; 1159 return -1; 1160 #endif 1161 } 1162 } 1163 return 0; 1164 } 1165 1166 1167 /* ------------------------------------------------------------------------ */ 1168 /* Function: ipf_pr_short */ 1169 /* Returns: void */ 1170 /* Parameters: fin(I) - pointer to packet information */ 1171 /* xmin(I) - minimum header size */ 1172 /* */ 1173 /* Check if a packet is "short" as defined by xmin. The rule we are */ 1174 /* applying here is that the packet must not be fragmented within the layer */ 1175 /* 4 header. That is, it must not be a fragment that has its offset set to */ 1176 /* start within the layer 4 header (hdrmin) or if it is at offset 0, the */ 1177 /* entire layer 4 header must be present (min). */ 1178 /* ------------------------------------------------------------------------ */ 1179 static INLINE void 1180 ipf_pr_short(fr_info_t *fin, int xmin) 1181 { 1182 1183 if (fin->fin_off == 0) { 1184 if (fin->fin_dlen < xmin) 1185 fin->fin_flx |= FI_SHORT; 1186 } else if (fin->fin_off < xmin) { 1187 fin->fin_flx |= FI_SHORT; 1188 } 1189 } 1190 1191 1192 /* ------------------------------------------------------------------------ */ 1193 /* Function: ipf_pr_icmp */ 1194 /* Returns: void */ 1195 /* Parameters: fin(I) - pointer to packet information */ 1196 /* */ 1197 /* IPv4 Only */ 1198 /* Do a sanity check on the packet for ICMP (v4). In nearly all cases, */ 1199 /* except extrememly bad packets, both type and code will be present. */ 1200 /* The expected minimum size of an ICMP packet is very much dependent on */ 1201 /* the type of it. */ 1202 /* */ 1203 /* XXX - other ICMP sanity checks? */ 1204 /* ------------------------------------------------------------------------ */ 1205 static INLINE void 1206 ipf_pr_icmp(fr_info_t *fin) 1207 { 1208 ipf_main_softc_t *softc = fin->fin_main_soft; 1209 int minicmpsz = sizeof(struct icmp); 1210 icmphdr_t *icmp; 1211 ip_t *oip; 1212 1213 ipf_pr_short(fin, ICMPERR_ICMPHLEN); 1214 1215 if (fin->fin_off != 0) { 1216 LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_frag); 1217 return; 1218 } 1219 1220 if (ipf_pr_pullup(fin, ICMPERR_ICMPHLEN) == -1) { 1221 LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_pullup); 1222 return; 1223 } 1224 1225 icmp = fin->fin_dp; 1226 1227 fin->fin_data[0] = *(u_short *)icmp; 1228 fin->fin_data[1] = icmp->icmp_id; 1229 1230 switch (icmp->icmp_type) 1231 { 1232 case ICMP_ECHOREPLY : 1233 case ICMP_ECHO : 1234 /* Router discovery messaes - RFC 1256 */ 1235 case ICMP_ROUTERADVERT : 1236 case ICMP_ROUTERSOLICIT : 1237 fin->fin_flx |= FI_ICMPQUERY; 1238 minicmpsz = ICMP_MINLEN; 1239 break; 1240 /* 1241 * type(1) + code(1) + cksum(2) + id(2) seq(2) + 1242 * 3 * timestamp(3 * 4) 1243 */ 1244 case ICMP_TSTAMP : 1245 case ICMP_TSTAMPREPLY : 1246 fin->fin_flx |= FI_ICMPQUERY; 1247 minicmpsz = 20; 1248 break; 1249 /* 1250 * type(1) + code(1) + cksum(2) + id(2) seq(2) + 1251 * mask(4) 1252 */ 1253 case ICMP_IREQ : 1254 case ICMP_IREQREPLY : 1255 case ICMP_MASKREQ : 1256 case ICMP_MASKREPLY : 1257 fin->fin_flx |= FI_ICMPQUERY; 1258 minicmpsz = 12; 1259 break; 1260 /* 1261 * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+) 1262 */ 1263 case ICMP_UNREACH : 1264 #ifdef icmp_nextmtu 1265 if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG) { 1266 if (icmp->icmp_nextmtu < softc->ipf_icmpminfragmtu) { 1267 fin->fin_flx |= FI_BAD; 1268 DT3(ipf_fi_bad_icmp_nextmtu, fr_info_t *, fin, u_int, icmp->icmp_nextmtu, u_int, softc->ipf_icmpminfragmtu); 1269 } 1270 } 1271 #endif 1272 /* FALLTHROUGH */ 1273 case ICMP_SOURCEQUENCH : 1274 case ICMP_REDIRECT : 1275 case ICMP_TIMXCEED : 1276 case ICMP_PARAMPROB : 1277 fin->fin_flx |= FI_ICMPERR; 1278 if (ipf_coalesce(fin) != 1) { 1279 LBUMPD(ipf_stats[fin->fin_out], fr_icmp_coalesce); 1280 return; 1281 } 1282 1283 /* 1284 * ICMP error packets should not be generated for IP 1285 * packets that are a fragment that isn't the first 1286 * fragment. 1287 */ 1288 oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN); 1289 if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0) { 1290 fin->fin_flx |= FI_BAD; 1291 DT2(ipf_fi_bad_icmp_err, fr_info_t, fin, u_int, (ntohs(oip->ip_off) & IP_OFFMASK)); 1292 } 1293 1294 /* 1295 * If the destination of this packet doesn't match the 1296 * source of the original packet then this packet is 1297 * not correct. 1298 */ 1299 if (oip->ip_src.s_addr != fin->fin_daddr) { 1300 fin->fin_flx |= FI_BAD; 1301 DT1(ipf_fi_bad_src_ne_dst, fr_info_t *, fin); 1302 } 1303 break; 1304 default : 1305 break; 1306 } 1307 1308 ipf_pr_short(fin, minicmpsz); 1309 1310 ipf_checkv4sum(fin); 1311 } 1312 1313 1314 /* ------------------------------------------------------------------------ */ 1315 /* Function: ipf_pr_tcpcommon */ 1316 /* Returns: int - 0 = header ok, 1 = bad packet, -1 = buffer error */ 1317 /* Parameters: fin(I) - pointer to packet information */ 1318 /* */ 1319 /* TCP header sanity checking. Look for bad combinations of TCP flags, */ 1320 /* and make some checks with how they interact with other fields. */ 1321 /* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is */ 1322 /* valid and mark the packet as bad if not. */ 1323 /* ------------------------------------------------------------------------ */ 1324 static INLINE int 1325 ipf_pr_tcpcommon(fr_info_t *fin) 1326 { 1327 ipf_main_softc_t *softc = fin->fin_main_soft; 1328 int flags, tlen; 1329 tcphdr_t *tcp; 1330 1331 fin->fin_flx |= FI_TCPUDP; 1332 if (fin->fin_off != 0) { 1333 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_frag); 1334 return 0; 1335 } 1336 1337 if (ipf_pr_pullup(fin, sizeof(*tcp)) == -1) { 1338 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup); 1339 return -1; 1340 } 1341 1342 tcp = fin->fin_dp; 1343 if (fin->fin_dlen > 3) { 1344 fin->fin_sport = ntohs(tcp->th_sport); 1345 fin->fin_dport = ntohs(tcp->th_dport); 1346 } 1347 1348 if ((fin->fin_flx & FI_SHORT) != 0) { 1349 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_short); 1350 return 1; 1351 } 1352 1353 /* 1354 * Use of the TCP data offset *must* result in a value that is at 1355 * least the same size as the TCP header. 1356 */ 1357 tlen = TCP_OFF(tcp) << 2; 1358 if (tlen < sizeof(tcphdr_t)) { 1359 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_small); 1360 fin->fin_flx |= FI_BAD; 1361 DT3(ipf_fi_bad_tlen, fr_info_t, fin, u_int, tlen, u_int, sizeof(tcphdr_t)); 1362 return 1; 1363 } 1364 1365 flags = tcp->th_flags; 1366 fin->fin_tcpf = tcp->th_flags; 1367 1368 /* 1369 * If the urgent flag is set, then the urgent pointer must 1370 * also be set and vice versa. Good TCP packets do not have 1371 * just one of these set. 1372 */ 1373 if ((flags & TH_URG) != 0 && (tcp->th_urp == 0)) { 1374 fin->fin_flx |= FI_BAD; 1375 DT3(ipf_fi_bad_th_urg, fr_info_t*, fin, u_int, (flags & TH_URG), u_int, tcp->th_urp); 1376 #if 0 1377 } else if ((flags & TH_URG) == 0 && (tcp->th_urp != 0)) { 1378 /* 1379 * Ignore this case (#if 0) as it shows up in "real" 1380 * traffic with bogus values in the urgent pointer field. 1381 */ 1382 fin->fin_flx |= FI_BAD; 1383 DT3(ipf_fi_bad_th_urg0, fr_info_t *, fin, u_int, (flags & TH_URG), u_int, tcp->th_urp); 1384 #endif 1385 } else if (((flags & (TH_SYN|TH_FIN)) != 0) && 1386 ((flags & (TH_RST|TH_ACK)) == TH_RST)) { 1387 /* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */ 1388 fin->fin_flx |= FI_BAD; 1389 DT1(ipf_fi_bad_th_fin_rst_ack, fr_info_t, fin); 1390 #if 1 1391 } else if (((flags & TH_SYN) != 0) && 1392 ((flags & (TH_URG|TH_PUSH)) != 0)) { 1393 /* 1394 * SYN with URG and PUSH set is not for normal TCP but it is 1395 * possible(?) with T/TCP...but who uses T/TCP? 1396 */ 1397 fin->fin_flx |= FI_BAD; 1398 DT1(ipf_fi_bad_th_syn_urg_psh, fr_info_t *, fin); 1399 #endif 1400 } else if (!(flags & TH_ACK)) { 1401 /* 1402 * If the ack bit isn't set, then either the SYN or 1403 * RST bit must be set. If the SYN bit is set, then 1404 * we expect the ACK field to be 0. If the ACK is 1405 * not set and if URG, PSH or FIN are set, consdier 1406 * that to indicate a bad TCP packet. 1407 */ 1408 if ((flags == TH_SYN) && (tcp->th_ack != 0)) { 1409 /* 1410 * Cisco PIX sets the ACK field to a random value. 1411 * In light of this, do not set FI_BAD until a patch 1412 * is available from Cisco to ensure that 1413 * interoperability between existing systems is 1414 * achieved. 1415 */ 1416 /*fin->fin_flx |= FI_BAD*/; 1417 /*DT1(ipf_fi_bad_th_syn_ack, fr_info_t *, fin);*/ 1418 } else if (!(flags & (TH_RST|TH_SYN))) { 1419 fin->fin_flx |= FI_BAD; 1420 DT1(ipf_fi_bad_th_rst_syn, fr_info_t *, fin); 1421 } else if ((flags & (TH_URG|TH_PUSH|TH_FIN)) != 0) { 1422 fin->fin_flx |= FI_BAD; 1423 DT1(ipf_fi_bad_th_urg_push_fin, fr_info_t *, fin); 1424 } 1425 } 1426 if (fin->fin_flx & FI_BAD) { 1427 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_bad_flags); 1428 return 1; 1429 } 1430 1431 /* 1432 * At this point, it's not exactly clear what is to be gained by 1433 * marking up which TCP options are and are not present. The one we 1434 * are most interested in is the TCP window scale. This is only in 1435 * a SYN packet [RFC1323] so we don't need this here...? 1436 * Now if we were to analyse the header for passive fingerprinting, 1437 * then that might add some weight to adding this... 1438 */ 1439 if (tlen == sizeof(tcphdr_t)) { 1440 return 0; 1441 } 1442 1443 if (ipf_pr_pullup(fin, tlen) == -1) { 1444 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup); 1445 return -1; 1446 } 1447 1448 #if 0 1449 tcp = fin->fin_dp; 1450 ip = fin->fin_ip; 1451 s = (u_char *)(tcp + 1); 1452 off = IP_HL(ip) << 2; 1453 # ifdef _KERNEL 1454 if (fin->fin_mp != NULL) { 1455 mb_t *m = *fin->fin_mp; 1456 1457 if (off + tlen > M_LEN(m)) 1458 return; 1459 } 1460 # endif 1461 for (tlen -= (int)sizeof(*tcp); tlen > 0; ) { 1462 opt = *s; 1463 if (opt == '\0') 1464 break; 1465 else if (opt == TCPOPT_NOP) 1466 ol = 1; 1467 else { 1468 if (tlen < 2) 1469 break; 1470 ol = (int)*(s + 1); 1471 if (ol < 2 || ol > tlen) 1472 break; 1473 } 1474 1475 for (i = 9, mv = 4; mv >= 0; ) { 1476 op = ipopts + i; 1477 if (opt == (u_char)op->ol_val) { 1478 optmsk |= op->ol_bit; 1479 break; 1480 } 1481 } 1482 tlen -= ol; 1483 s += ol; 1484 } 1485 #endif /* 0 */ 1486 1487 return 0; 1488 } 1489 1490 1491 1492 /* ------------------------------------------------------------------------ */ 1493 /* Function: ipf_pr_udpcommon */ 1494 /* Returns: int - 0 = header ok, 1 = bad packet */ 1495 /* Parameters: fin(I) - pointer to packet information */ 1496 /* */ 1497 /* Extract the UDP source and destination ports, if present. If compiled */ 1498 /* with IPFILTER_CKSUM, check to see if the UDP checksum is valid. */ 1499 /* ------------------------------------------------------------------------ */ 1500 static INLINE int 1501 ipf_pr_udpcommon(fr_info_t *fin) 1502 { 1503 udphdr_t *udp; 1504 1505 fin->fin_flx |= FI_TCPUDP; 1506 1507 if (!fin->fin_off && (fin->fin_dlen > 3)) { 1508 if (ipf_pr_pullup(fin, sizeof(*udp)) == -1) { 1509 ipf_main_softc_t *softc = fin->fin_main_soft; 1510 1511 fin->fin_flx |= FI_SHORT; 1512 LBUMPD(ipf_stats[fin->fin_out], fr_udp_pullup); 1513 return 1; 1514 } 1515 1516 udp = fin->fin_dp; 1517 1518 fin->fin_sport = ntohs(udp->uh_sport); 1519 fin->fin_dport = ntohs(udp->uh_dport); 1520 } 1521 1522 return 0; 1523 } 1524 1525 1526 /* ------------------------------------------------------------------------ */ 1527 /* Function: ipf_pr_tcp */ 1528 /* Returns: void */ 1529 /* Parameters: fin(I) - pointer to packet information */ 1530 /* */ 1531 /* IPv4 Only */ 1532 /* Analyse the packet for IPv4/TCP properties. */ 1533 /* ------------------------------------------------------------------------ */ 1534 static INLINE void 1535 ipf_pr_tcp(fr_info_t *fin) 1536 { 1537 1538 ipf_pr_short(fin, sizeof(tcphdr_t)); 1539 1540 if (ipf_pr_tcpcommon(fin) == 0) 1541 ipf_checkv4sum(fin); 1542 } 1543 1544 1545 /* ------------------------------------------------------------------------ */ 1546 /* Function: ipf_pr_udp */ 1547 /* Returns: void */ 1548 /* Parameters: fin(I) - pointer to packet information */ 1549 /* */ 1550 /* IPv4 Only */ 1551 /* Analyse the packet for IPv4/UDP properties. */ 1552 /* ------------------------------------------------------------------------ */ 1553 static INLINE void 1554 ipf_pr_udp(fr_info_t *fin) 1555 { 1556 1557 ipf_pr_short(fin, sizeof(udphdr_t)); 1558 1559 if (ipf_pr_udpcommon(fin) == 0) 1560 ipf_checkv4sum(fin); 1561 } 1562 1563 1564 /* ------------------------------------------------------------------------ */ 1565 /* Function: ipf_pr_esp */ 1566 /* Returns: void */ 1567 /* Parameters: fin(I) - pointer to packet information */ 1568 /* */ 1569 /* Analyse the packet for ESP properties. */ 1570 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ 1571 /* even though the newer ESP packets must also have a sequence number that */ 1572 /* is 32bits as well, it is not possible(?) to determine the version from a */ 1573 /* simple packet header. */ 1574 /* ------------------------------------------------------------------------ */ 1575 static INLINE void 1576 ipf_pr_esp(fr_info_t *fin) 1577 { 1578 1579 if (fin->fin_off == 0) { 1580 ipf_pr_short(fin, 8); 1581 if (ipf_pr_pullup(fin, 8) == -1) { 1582 ipf_main_softc_t *softc = fin->fin_main_soft; 1583 1584 LBUMPD(ipf_stats[fin->fin_out], fr_v4_esp_pullup); 1585 } 1586 } 1587 } 1588 1589 1590 /* ------------------------------------------------------------------------ */ 1591 /* Function: ipf_pr_ah */ 1592 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 1593 /* Parameters: fin(I) - pointer to packet information */ 1594 /* */ 1595 /* Analyse the packet for AH properties. */ 1596 /* The minimum length is taken to be the combination of all fields in the */ 1597 /* header being present and no authentication data (null algorithm used.) */ 1598 /* ------------------------------------------------------------------------ */ 1599 static INLINE int 1600 ipf_pr_ah(fr_info_t *fin) 1601 { 1602 ipf_main_softc_t *softc = fin->fin_main_soft; 1603 authhdr_t *ah; 1604 int len; 1605 1606 fin->fin_flx |= FI_AH; 1607 ipf_pr_short(fin, sizeof(*ah)); 1608 1609 if (((fin->fin_flx & FI_SHORT) != 0) || (fin->fin_off != 0)) { 1610 LBUMPD(ipf_stats[fin->fin_out], fr_v4_ah_bad); 1611 return IPPROTO_NONE; 1612 } 1613 1614 if (ipf_pr_pullup(fin, sizeof(*ah)) == -1) { 1615 DT(fr_v4_ah_pullup_1); 1616 LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup); 1617 return IPPROTO_NONE; 1618 } 1619 1620 ah = (authhdr_t *)fin->fin_dp; 1621 1622 len = (ah->ah_plen + 2) << 2; 1623 ipf_pr_short(fin, len); 1624 if (ipf_pr_pullup(fin, len) == -1) { 1625 DT(fr_v4_ah_pullup_2); 1626 LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup); 1627 return IPPROTO_NONE; 1628 } 1629 1630 /* 1631 * Adjust fin_dp and fin_dlen for skipping over the authentication 1632 * header. 1633 */ 1634 fin->fin_dp = (char *)fin->fin_dp + len; 1635 fin->fin_dlen -= len; 1636 return ah->ah_next; 1637 } 1638 1639 1640 /* ------------------------------------------------------------------------ */ 1641 /* Function: ipf_pr_gre */ 1642 /* Returns: void */ 1643 /* Parameters: fin(I) - pointer to packet information */ 1644 /* */ 1645 /* Analyse the packet for GRE properties. */ 1646 /* ------------------------------------------------------------------------ */ 1647 static INLINE void 1648 ipf_pr_gre(fr_info_t *fin) 1649 { 1650 ipf_main_softc_t *softc = fin->fin_main_soft; 1651 grehdr_t *gre; 1652 1653 ipf_pr_short(fin, sizeof(grehdr_t)); 1654 1655 if (fin->fin_off != 0) { 1656 LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_frag); 1657 return; 1658 } 1659 1660 if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) { 1661 LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_pullup); 1662 return; 1663 } 1664 1665 gre = fin->fin_dp; 1666 if (GRE_REV(gre->gr_flags) == 1) 1667 fin->fin_data[0] = gre->gr_call; 1668 } 1669 1670 1671 /* ------------------------------------------------------------------------ */ 1672 /* Function: ipf_pr_ipv4hdr */ 1673 /* Returns: void */ 1674 /* Parameters: fin(I) - pointer to packet information */ 1675 /* */ 1676 /* IPv4 Only */ 1677 /* Analyze the IPv4 header and set fields in the fr_info_t structure. */ 1678 /* Check all options present and flag their presence if any exist. */ 1679 /* ------------------------------------------------------------------------ */ 1680 static INLINE void 1681 ipf_pr_ipv4hdr(fr_info_t *fin) 1682 { 1683 u_short optmsk = 0, secmsk = 0, auth = 0; 1684 int hlen, ol, mv, p, i; 1685 const struct optlist *op; 1686 u_char *s, opt; 1687 u_short off; 1688 fr_ip_t *fi; 1689 ip_t *ip; 1690 1691 fi = &fin->fin_fi; 1692 hlen = fin->fin_hlen; 1693 1694 ip = fin->fin_ip; 1695 p = ip->ip_p; 1696 fi->fi_p = p; 1697 fin->fin_crc = p; 1698 fi->fi_tos = ip->ip_tos; 1699 fin->fin_id = ntohs(ip->ip_id); 1700 off = ntohs(ip->ip_off); 1701 1702 /* Get both TTL and protocol */ 1703 fi->fi_p = ip->ip_p; 1704 fi->fi_ttl = ip->ip_ttl; 1705 1706 /* Zero out bits not used in IPv6 address */ 1707 fi->fi_src.i6[1] = 0; 1708 fi->fi_src.i6[2] = 0; 1709 fi->fi_src.i6[3] = 0; 1710 fi->fi_dst.i6[1] = 0; 1711 fi->fi_dst.i6[2] = 0; 1712 fi->fi_dst.i6[3] = 0; 1713 1714 fi->fi_saddr = ip->ip_src.s_addr; 1715 fin->fin_crc += fi->fi_saddr; 1716 fi->fi_daddr = ip->ip_dst.s_addr; 1717 fin->fin_crc += fi->fi_daddr; 1718 if (IN_CLASSD(fi->fi_daddr)) 1719 fin->fin_flx |= FI_MULTICAST|FI_MBCAST; 1720 1721 /* 1722 * set packet attribute flags based on the offset and 1723 * calculate the byte offset that it represents. 1724 */ 1725 off &= IP_MF|IP_OFFMASK; 1726 if (off != 0) { 1727 int morefrag = off & IP_MF; 1728 fi->fi_flx |= FI_FRAG; 1729 off &= IP_OFFMASK; 1730 if (off != 0) { 1731 if (off == 1 && p == IPPROTO_TCP) { 1732 fin->fin_flx |= FI_SHORT; /* RFC 3128 */ 1733 DT1(ipf_fi_tcp_frag_off_1, fr_info_t *, fin); 1734 } 1735 1736 fin->fin_flx |= FI_FRAGBODY; 1737 off <<= 3; 1738 if ((off + fin->fin_dlen > 65535) || 1739 (fin->fin_dlen == 0) || 1740 ((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) { 1741 /* 1742 * The length of the packet, starting at its 1743 * offset cannot exceed 65535 (0xffff) as the 1744 * length of an IP packet is only 16 bits. 1745 * 1746 * Any fragment that isn't the last fragment 1747 * must have a length greater than 0 and it 1748 * must be an even multiple of 8. 1749 */ 1750 fi->fi_flx |= FI_BAD; 1751 DT1(ipf_fi_bad_fragbody_gt_65535, fr_info_t *, fin); 1752 } 1753 } 1754 } 1755 fin->fin_off = off; 1756 1757 /* 1758 * Call per-protocol setup and checking 1759 */ 1760 if (p == IPPROTO_AH) { 1761 /* 1762 * Treat AH differently because we expect there to be another 1763 * layer 4 header after it. 1764 */ 1765 p = ipf_pr_ah(fin); 1766 } 1767 1768 switch (p) 1769 { 1770 case IPPROTO_UDP : 1771 ipf_pr_udp(fin); 1772 break; 1773 case IPPROTO_TCP : 1774 ipf_pr_tcp(fin); 1775 break; 1776 case IPPROTO_ICMP : 1777 ipf_pr_icmp(fin); 1778 break; 1779 case IPPROTO_ESP : 1780 ipf_pr_esp(fin); 1781 break; 1782 case IPPROTO_GRE : 1783 ipf_pr_gre(fin); 1784 break; 1785 } 1786 1787 ip = fin->fin_ip; 1788 if (ip == NULL) 1789 return; 1790 1791 /* 1792 * If it is a standard IP header (no options), set the flag fields 1793 * which relate to options to 0. 1794 */ 1795 if (hlen == sizeof(*ip)) { 1796 fi->fi_optmsk = 0; 1797 fi->fi_secmsk = 0; 1798 fi->fi_auth = 0; 1799 return; 1800 } 1801 1802 /* 1803 * So the IP header has some IP options attached. Walk the entire 1804 * list of options present with this packet and set flags to indicate 1805 * which ones are here and which ones are not. For the somewhat out 1806 * of date and obscure security classification options, set a flag to 1807 * represent which classification is present. 1808 */ 1809 fi->fi_flx |= FI_OPTIONS; 1810 1811 for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) { 1812 opt = *s; 1813 if (opt == '\0') 1814 break; 1815 else if (opt == IPOPT_NOP) 1816 ol = 1; 1817 else { 1818 if (hlen < 2) 1819 break; 1820 ol = (int)*(s + 1); 1821 if (ol < 2 || ol > hlen) 1822 break; 1823 } 1824 for (i = 9, mv = 4; mv >= 0; ) { 1825 op = ipopts + i; 1826 1827 if ((opt == (u_char)op->ol_val) && (ol > 4)) { 1828 u_32_t doi; 1829 1830 switch (opt) 1831 { 1832 case IPOPT_SECURITY : 1833 if (optmsk & op->ol_bit) { 1834 fin->fin_flx |= FI_BAD; 1835 DT2(ipf_fi_bad_ipopt_security, fr_info_t *, fin, u_short, (optmsk & op->ol_bit)); 1836 } else { 1837 doi = ipf_checkripso(s); 1838 secmsk = doi >> 16; 1839 auth = doi & 0xffff; 1840 } 1841 break; 1842 1843 case IPOPT_CIPSO : 1844 1845 if (optmsk & op->ol_bit) { 1846 fin->fin_flx |= FI_BAD; 1847 DT2(ipf_fi_bad_ipopt_cipso, fr_info_t *, fin, u_short, (optmsk & op->ol_bit)); 1848 } else { 1849 doi = ipf_checkcipso(fin, 1850 s, ol); 1851 secmsk = doi >> 16; 1852 auth = doi & 0xffff; 1853 } 1854 break; 1855 } 1856 optmsk |= op->ol_bit; 1857 } 1858 1859 if (opt < op->ol_val) 1860 i -= mv; 1861 else 1862 i += mv; 1863 mv--; 1864 } 1865 hlen -= ol; 1866 s += ol; 1867 } 1868 1869 /* 1870 * 1871 */ 1872 if (auth && !(auth & 0x0100)) 1873 auth &= 0xff00; 1874 fi->fi_optmsk = optmsk; 1875 fi->fi_secmsk = secmsk; 1876 fi->fi_auth = auth; 1877 } 1878 1879 1880 /* ------------------------------------------------------------------------ */ 1881 /* Function: ipf_checkripso */ 1882 /* Returns: void */ 1883 /* Parameters: s(I) - pointer to start of RIPSO option */ 1884 /* */ 1885 /* ------------------------------------------------------------------------ */ 1886 static u_32_t 1887 ipf_checkripso(u_char *s) 1888 { 1889 const struct optlist *sp; 1890 u_short secmsk = 0, auth = 0; 1891 u_char sec; 1892 int j, m; 1893 1894 sec = *(s + 2); /* classification */ 1895 for (j = 3, m = 2; m >= 0; ) { 1896 sp = secopt + j; 1897 if (sec == sp->ol_val) { 1898 secmsk |= sp->ol_bit; 1899 auth = *(s + 3); 1900 auth *= 256; 1901 auth += *(s + 4); 1902 break; 1903 } 1904 if (sec < sp->ol_val) 1905 j -= m; 1906 else 1907 j += m; 1908 m--; 1909 } 1910 1911 return (secmsk << 16) | auth; 1912 } 1913 1914 1915 /* ------------------------------------------------------------------------ */ 1916 /* Function: ipf_checkcipso */ 1917 /* Returns: u_32_t - 0 = failure, else the doi from the header */ 1918 /* Parameters: fin(IO) - pointer to packet information */ 1919 /* s(I) - pointer to start of CIPSO option */ 1920 /* ol(I) - length of CIPSO option field */ 1921 /* */ 1922 /* This function returns the domain of integrity (DOI) field from the CIPSO */ 1923 /* header and returns that whilst also storing the highest sensitivity */ 1924 /* value found in the fr_info_t structure. */ 1925 /* */ 1926 /* No attempt is made to extract the category bitmaps as these are defined */ 1927 /* by the user (rather than the protocol) and can be rather numerous on the */ 1928 /* end nodes. */ 1929 /* ------------------------------------------------------------------------ */ 1930 static u_32_t 1931 ipf_checkcipso(fr_info_t *fin, u_char *s, int ol) 1932 { 1933 ipf_main_softc_t *softc = fin->fin_main_soft; 1934 fr_ip_t *fi; 1935 u_32_t doi; 1936 u_char *t, tag, tlen, sensitivity; 1937 int len; 1938 1939 if (ol < 6 || ol > 40) { 1940 LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_bad); 1941 fin->fin_flx |= FI_BAD; 1942 DT2(ipf_fi_bad_checkcipso_ol, fr_info_t *, fin, u_int, ol); 1943 return 0; 1944 } 1945 1946 fi = &fin->fin_fi; 1947 fi->fi_sensitivity = 0; 1948 /* 1949 * The DOI field MUST be there. 1950 */ 1951 bcopy(s + 2, &doi, sizeof(doi)); 1952 1953 t = (u_char *)s + 6; 1954 for (len = ol - 6; len >= 2; len -= tlen, t+= tlen) { 1955 tag = *t; 1956 tlen = *(t + 1); 1957 if (tlen > len || tlen < 4 || tlen > 34) { 1958 LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_tlen); 1959 fin->fin_flx |= FI_BAD; 1960 DT2(ipf_fi_bad_checkcipso_tlen, fr_info_t *, fin, u_int, tlen); 1961 return 0; 1962 } 1963 1964 sensitivity = 0; 1965 /* 1966 * Tag numbers 0, 1, 2, 5 are laid out in the CIPSO Internet 1967 * draft (16 July 1992) that has expired. 1968 */ 1969 if (tag == 0) { 1970 fin->fin_flx |= FI_BAD; 1971 DT2(ipf_fi_bad_checkcipso_tag, fr_info_t *, fin, u_int, tag); 1972 continue; 1973 } else if (tag == 1) { 1974 if (*(t + 2) != 0) { 1975 fin->fin_flx |= FI_BAD; 1976 DT2(ipf_fi_bad_checkcipso_tag1_t2, fr_info_t *, fin, u_int, (*t + 2)); 1977 continue; 1978 } 1979 sensitivity = *(t + 3); 1980 /* Category bitmap for categories 0-239 */ 1981 1982 } else if (tag == 4) { 1983 if (*(t + 2) != 0) { 1984 fin->fin_flx |= FI_BAD; 1985 DT2(ipf_fi_bad_checkcipso_tag4_t2, fr_info_t *, fin, u_int, (*t + 2)); 1986 continue; 1987 } 1988 sensitivity = *(t + 3); 1989 /* Enumerated categories, 16bits each, upto 15 */ 1990 1991 } else if (tag == 5) { 1992 if (*(t + 2) != 0) { 1993 fin->fin_flx |= FI_BAD; 1994 DT2(ipf_fi_bad_checkcipso_tag5_t2, fr_info_t *, fin, u_int, (*t + 2)); 1995 continue; 1996 } 1997 sensitivity = *(t + 3); 1998 /* Range of categories (2*16bits), up to 7 pairs */ 1999 2000 } else if (tag > 127) { 2001 /* Custom defined DOI */ 2002 ; 2003 } else { 2004 DT2(ipf_fi_bad_checkcipso_tag127, fr_info_t *, fin, u_int, tag); 2005 fin->fin_flx |= FI_BAD; 2006 continue; 2007 } 2008 2009 if (sensitivity > fi->fi_sensitivity) 2010 fi->fi_sensitivity = sensitivity; 2011 } 2012 2013 return doi; 2014 } 2015 2016 2017 /* ------------------------------------------------------------------------ */ 2018 /* Function: ipf_makefrip */ 2019 /* Returns: int - 0 == packet ok, -1 == packet freed */ 2020 /* Parameters: hlen(I) - length of IP packet header */ 2021 /* ip(I) - pointer to the IP header */ 2022 /* fin(IO) - pointer to packet information */ 2023 /* */ 2024 /* Compact the IP header into a structure which contains just the info. */ 2025 /* which is useful for comparing IP headers with and store this information */ 2026 /* in the fr_info_t structure pointer to by fin. At present, it is assumed */ 2027 /* this function will be called with either an IPv4 or IPv6 packet. */ 2028 /* ------------------------------------------------------------------------ */ 2029 int 2030 ipf_makefrip(int hlen, ip_t *ip, fr_info_t *fin) 2031 { 2032 ipf_main_softc_t *softc = fin->fin_main_soft; 2033 int v; 2034 2035 fin->fin_depth = 0; 2036 fin->fin_hlen = (u_short)hlen; 2037 fin->fin_ip = ip; 2038 fin->fin_rule = 0xffffffff; 2039 fin->fin_group[0] = -1; 2040 fin->fin_group[1] = '\0'; 2041 fin->fin_dp = (char *)ip + hlen; 2042 2043 v = fin->fin_v; 2044 if (v == 4) { 2045 fin->fin_plen = ntohs(ip->ip_len); 2046 fin->fin_dlen = fin->fin_plen - hlen; 2047 ipf_pr_ipv4hdr(fin); 2048 #ifdef USE_INET6 2049 } else if (v == 6) { 2050 fin->fin_plen = ntohs(((ip6_t *)ip)->ip6_plen); 2051 fin->fin_dlen = fin->fin_plen; 2052 fin->fin_plen += hlen; 2053 2054 ipf_pr_ipv6hdr(fin); 2055 #endif 2056 } 2057 if (fin->fin_ip == NULL) { 2058 LBUMP(ipf_stats[fin->fin_out].fr_ip_freed); 2059 return -1; 2060 } 2061 return 0; 2062 } 2063 2064 2065 /* ------------------------------------------------------------------------ */ 2066 /* Function: ipf_portcheck */ 2067 /* Returns: int - 1 == port matched, 0 == port match failed */ 2068 /* Parameters: frp(I) - pointer to port check `expression' */ 2069 /* pop(I) - port number to evaluate */ 2070 /* */ 2071 /* Perform a comparison of a port number against some other(s), using a */ 2072 /* structure with compare information stored in it. */ 2073 /* ------------------------------------------------------------------------ */ 2074 static INLINE int 2075 ipf_portcheck(frpcmp_t *frp, u_32_t pop) 2076 { 2077 int err = 1; 2078 u_32_t po; 2079 2080 po = frp->frp_port; 2081 2082 /* 2083 * Do opposite test to that required and continue if that succeeds. 2084 */ 2085 switch (frp->frp_cmp) 2086 { 2087 case FR_EQUAL : 2088 if (pop != po) /* EQUAL */ 2089 err = 0; 2090 break; 2091 case FR_NEQUAL : 2092 if (pop == po) /* NOTEQUAL */ 2093 err = 0; 2094 break; 2095 case FR_LESST : 2096 if (pop >= po) /* LESSTHAN */ 2097 err = 0; 2098 break; 2099 case FR_GREATERT : 2100 if (pop <= po) /* GREATERTHAN */ 2101 err = 0; 2102 break; 2103 case FR_LESSTE : 2104 if (pop > po) /* LT or EQ */ 2105 err = 0; 2106 break; 2107 case FR_GREATERTE : 2108 if (pop < po) /* GT or EQ */ 2109 err = 0; 2110 break; 2111 case FR_OUTRANGE : 2112 if (pop >= po && pop <= frp->frp_top) /* Out of range */ 2113 err = 0; 2114 break; 2115 case FR_INRANGE : 2116 if (pop <= po || pop >= frp->frp_top) /* In range */ 2117 err = 0; 2118 break; 2119 case FR_INCRANGE : 2120 if (pop < po || pop > frp->frp_top) /* Inclusive range */ 2121 err = 0; 2122 break; 2123 default : 2124 break; 2125 } 2126 return err; 2127 } 2128 2129 2130 /* ------------------------------------------------------------------------ */ 2131 /* Function: ipf_tcpudpchk */ 2132 /* Returns: int - 1 == protocol matched, 0 == check failed */ 2133 /* Parameters: fda(I) - pointer to packet information */ 2134 /* ft(I) - pointer to structure with comparison data */ 2135 /* */ 2136 /* Compares the current pcket (assuming it is TCP/UDP) information with a */ 2137 /* structure containing information that we want to match against. */ 2138 /* ------------------------------------------------------------------------ */ 2139 int 2140 ipf_tcpudpchk(fr_ip_t *fi, frtuc_t *ft) 2141 { 2142 int err = 1; 2143 2144 /* 2145 * Both ports should *always* be in the first fragment. 2146 * So far, I cannot find any cases where they can not be. 2147 * 2148 * compare destination ports 2149 */ 2150 if (ft->ftu_dcmp) 2151 err = ipf_portcheck(&ft->ftu_dst, fi->fi_ports[1]); 2152 2153 /* 2154 * compare source ports 2155 */ 2156 if (err && ft->ftu_scmp) 2157 err = ipf_portcheck(&ft->ftu_src, fi->fi_ports[0]); 2158 2159 /* 2160 * If we don't have all the TCP/UDP header, then how can we 2161 * expect to do any sort of match on it ? If we were looking for 2162 * TCP flags, then NO match. If not, then match (which should 2163 * satisfy the "short" class too). 2164 */ 2165 if (err && (fi->fi_p == IPPROTO_TCP)) { 2166 if (fi->fi_flx & FI_SHORT) 2167 return !(ft->ftu_tcpf | ft->ftu_tcpfm); 2168 /* 2169 * Match the flags ? If not, abort this match. 2170 */ 2171 if (ft->ftu_tcpfm && 2172 ft->ftu_tcpf != (fi->fi_tcpf & ft->ftu_tcpfm)) { 2173 FR_DEBUG(("f. %#x & %#x != %#x\n", fi->fi_tcpf, 2174 ft->ftu_tcpfm, ft->ftu_tcpf)); 2175 err = 0; 2176 } 2177 } 2178 return err; 2179 } 2180 2181 2182 /* ------------------------------------------------------------------------ */ 2183 /* Function: ipf_check_ipf */ 2184 /* Returns: int - 0 == match, else no match */ 2185 /* Parameters: fin(I) - pointer to packet information */ 2186 /* fr(I) - pointer to filter rule */ 2187 /* portcmp(I) - flag indicating whether to attempt matching on */ 2188 /* TCP/UDP port data. */ 2189 /* */ 2190 /* Check to see if a packet matches an IPFilter rule. Checks of addresses, */ 2191 /* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */ 2192 /* this function. */ 2193 /* ------------------------------------------------------------------------ */ 2194 static INLINE int 2195 ipf_check_ipf(fr_info_t *fin, frentry_t *fr, int portcmp) 2196 { 2197 u_32_t *ld, *lm, *lip; 2198 fripf_t *fri; 2199 fr_ip_t *fi; 2200 int i; 2201 2202 fi = &fin->fin_fi; 2203 fri = fr->fr_ipf; 2204 lip = (u_32_t *)fi; 2205 lm = (u_32_t *)&fri->fri_mip; 2206 ld = (u_32_t *)&fri->fri_ip; 2207 2208 /* 2209 * first 32 bits to check coversion: 2210 * IP version, TOS, TTL, protocol 2211 */ 2212 i = ((*lip & *lm) != *ld); 2213 FR_DEBUG(("0. %#08x & %#08x != %#08x\n", 2214 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2215 if (i) 2216 return 1; 2217 2218 /* 2219 * Next 32 bits is a constructed bitmask indicating which IP options 2220 * are present (if any) in this packet. 2221 */ 2222 lip++, lm++, ld++; 2223 i = ((*lip & *lm) != *ld); 2224 FR_DEBUG(("1. %#08x & %#08x != %#08x\n", 2225 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2226 if (i != 0) 2227 return 1; 2228 2229 lip++, lm++, ld++; 2230 /* 2231 * Unrolled loops (4 each, for 32 bits) for address checks. 2232 */ 2233 /* 2234 * Check the source address. 2235 */ 2236 if (fr->fr_satype == FRI_LOOKUP) { 2237 i = (*fr->fr_srcfunc)(fin->fin_main_soft, fr->fr_srcptr, 2238 fi->fi_v, lip, fin->fin_plen); 2239 if (i == -1) 2240 return 1; 2241 lip += 3; 2242 lm += 3; 2243 ld += 3; 2244 } else { 2245 i = ((*lip & *lm) != *ld); 2246 FR_DEBUG(("2a. %#08x & %#08x != %#08x\n", 2247 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2248 if (fi->fi_v == 6) { 2249 lip++, lm++, ld++; 2250 i |= ((*lip & *lm) != *ld); 2251 FR_DEBUG(("2b. %#08x & %#08x != %#08x\n", 2252 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2253 lip++, lm++, ld++; 2254 i |= ((*lip & *lm) != *ld); 2255 FR_DEBUG(("2c. %#08x & %#08x != %#08x\n", 2256 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2257 lip++, lm++, ld++; 2258 i |= ((*lip & *lm) != *ld); 2259 FR_DEBUG(("2d. %#08x & %#08x != %#08x\n", 2260 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2261 } else { 2262 lip += 3; 2263 lm += 3; 2264 ld += 3; 2265 } 2266 } 2267 i ^= (fr->fr_flags & FR_NOTSRCIP) >> 6; 2268 if (i != 0) 2269 return 1; 2270 2271 /* 2272 * Check the destination address. 2273 */ 2274 lip++, lm++, ld++; 2275 if (fr->fr_datype == FRI_LOOKUP) { 2276 i = (*fr->fr_dstfunc)(fin->fin_main_soft, fr->fr_dstptr, 2277 fi->fi_v, lip, fin->fin_plen); 2278 if (i == -1) 2279 return 1; 2280 lip += 3; 2281 lm += 3; 2282 ld += 3; 2283 } else { 2284 i = ((*lip & *lm) != *ld); 2285 FR_DEBUG(("3a. %#08x & %#08x != %#08x\n", 2286 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2287 if (fi->fi_v == 6) { 2288 lip++, lm++, ld++; 2289 i |= ((*lip & *lm) != *ld); 2290 FR_DEBUG(("3b. %#08x & %#08x != %#08x\n", 2291 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2292 lip++, lm++, ld++; 2293 i |= ((*lip & *lm) != *ld); 2294 FR_DEBUG(("3c. %#08x & %#08x != %#08x\n", 2295 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2296 lip++, lm++, ld++; 2297 i |= ((*lip & *lm) != *ld); 2298 FR_DEBUG(("3d. %#08x & %#08x != %#08x\n", 2299 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2300 } else { 2301 lip += 3; 2302 lm += 3; 2303 ld += 3; 2304 } 2305 } 2306 i ^= (fr->fr_flags & FR_NOTDSTIP) >> 7; 2307 if (i != 0) 2308 return 1; 2309 /* 2310 * IP addresses matched. The next 32bits contains: 2311 * mast of old IP header security & authentication bits. 2312 */ 2313 lip++, lm++, ld++; 2314 i = (*ld - (*lip & *lm)); 2315 FR_DEBUG(("4. %#08x & %#08x != %#08x\n", *lip, *lm, *ld)); 2316 2317 /* 2318 * Next we have 32 bits of packet flags. 2319 */ 2320 lip++, lm++, ld++; 2321 i |= (*ld - (*lip & *lm)); 2322 FR_DEBUG(("5. %#08x & %#08x != %#08x\n", *lip, *lm, *ld)); 2323 2324 if (i == 0) { 2325 /* 2326 * If a fragment, then only the first has what we're 2327 * looking for here... 2328 */ 2329 if (portcmp) { 2330 if (!ipf_tcpudpchk(&fin->fin_fi, &fr->fr_tuc)) 2331 i = 1; 2332 } else { 2333 if (fr->fr_dcmp || fr->fr_scmp || 2334 fr->fr_tcpf || fr->fr_tcpfm) 2335 i = 1; 2336 if (fr->fr_icmpm || fr->fr_icmp) { 2337 if (((fi->fi_p != IPPROTO_ICMP) && 2338 (fi->fi_p != IPPROTO_ICMPV6)) || 2339 fin->fin_off || (fin->fin_dlen < 2)) 2340 i = 1; 2341 else if ((fin->fin_data[0] & fr->fr_icmpm) != 2342 fr->fr_icmp) { 2343 FR_DEBUG(("i. %#x & %#x != %#x\n", 2344 fin->fin_data[0], 2345 fr->fr_icmpm, fr->fr_icmp)); 2346 i = 1; 2347 } 2348 } 2349 } 2350 } 2351 return i; 2352 } 2353 2354 2355 /* ------------------------------------------------------------------------ */ 2356 /* Function: ipf_scanlist */ 2357 /* Returns: int - result flags of scanning filter list */ 2358 /* Parameters: fin(I) - pointer to packet information */ 2359 /* pass(I) - default result to return for filtering */ 2360 /* */ 2361 /* Check the input/output list of rules for a match to the current packet. */ 2362 /* If a match is found, the value of fr_flags from the rule becomes the */ 2363 /* return value and fin->fin_fr points to the matched rule. */ 2364 /* */ 2365 /* This function may be called recusively upto 16 times (limit inbuilt.) */ 2366 /* When unwinding, it should finish up with fin_depth as 0. */ 2367 /* */ 2368 /* Could be per interface, but this gets real nasty when you don't have, */ 2369 /* or can't easily change, the kernel source code to . */ 2370 /* ------------------------------------------------------------------------ */ 2371 int 2372 ipf_scanlist(fr_info_t *fin, u_32_t pass) 2373 { 2374 ipf_main_softc_t *softc = fin->fin_main_soft; 2375 int rulen, portcmp, off, skip; 2376 struct frentry *fr, *fnext; 2377 u_32_t passt, passo; 2378 2379 /* 2380 * Do not allow nesting deeper than 16 levels. 2381 */ 2382 if (fin->fin_depth >= 16) 2383 return pass; 2384 2385 fr = fin->fin_fr; 2386 2387 /* 2388 * If there are no rules in this list, return now. 2389 */ 2390 if (fr == NULL) 2391 return pass; 2392 2393 skip = 0; 2394 portcmp = 0; 2395 fin->fin_depth++; 2396 fin->fin_fr = NULL; 2397 off = fin->fin_off; 2398 2399 if ((fin->fin_flx & FI_TCPUDP) && (fin->fin_dlen > 3) && !off) 2400 portcmp = 1; 2401 2402 for (rulen = 0; fr; fr = fnext, rulen++) { 2403 fnext = fr->fr_next; 2404 if (skip != 0) { 2405 FR_VERBOSE(("SKIP %d (%#x)\n", skip, fr->fr_flags)); 2406 skip--; 2407 continue; 2408 } 2409 2410 /* 2411 * In all checks below, a null (zero) value in the 2412 * filter struture is taken to mean a wildcard. 2413 * 2414 * check that we are working for the right interface 2415 */ 2416 #ifdef _KERNEL 2417 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) 2418 continue; 2419 #else 2420 if (opts & (OPT_VERBOSE|OPT_DEBUG)) 2421 printf("\n"); 2422 FR_VERBOSE(("%c", FR_ISSKIP(pass) ? 's' : 2423 FR_ISPASS(pass) ? 'p' : 2424 FR_ISACCOUNT(pass) ? 'A' : 2425 FR_ISAUTH(pass) ? 'a' : 2426 (pass & FR_NOMATCH) ? 'n' :'b')); 2427 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) 2428 continue; 2429 FR_VERBOSE((":i")); 2430 #endif 2431 2432 switch (fr->fr_type) 2433 { 2434 case FR_T_IPF : 2435 case FR_T_IPF_BUILTIN : 2436 if (ipf_check_ipf(fin, fr, portcmp)) 2437 continue; 2438 break; 2439 #if defined(IPFILTER_BPF) 2440 case FR_T_BPFOPC : 2441 case FR_T_BPFOPC_BUILTIN : 2442 { 2443 u_char *mc; 2444 int wlen; 2445 2446 if (*fin->fin_mp == NULL) 2447 continue; 2448 if (fin->fin_family != fr->fr_family) 2449 continue; 2450 mc = (u_char *)fin->fin_m; 2451 wlen = fin->fin_dlen + fin->fin_hlen; 2452 if (!bpf_filter(fr->fr_data, mc, wlen, 0)) 2453 continue; 2454 break; 2455 } 2456 #endif 2457 case FR_T_CALLFUNC_BUILTIN : 2458 { 2459 frentry_t *f; 2460 2461 f = (*fr->fr_func)(fin, &pass); 2462 if (f != NULL) 2463 fr = f; 2464 else 2465 continue; 2466 break; 2467 } 2468 2469 case FR_T_IPFEXPR : 2470 case FR_T_IPFEXPR_BUILTIN : 2471 if (fin->fin_family != fr->fr_family) 2472 continue; 2473 if (ipf_fr_matcharray(fin, fr->fr_data) == 0) 2474 continue; 2475 break; 2476 2477 default : 2478 break; 2479 } 2480 2481 if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) { 2482 if (fin->fin_nattag == NULL) 2483 continue; 2484 if (ipf_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0) 2485 continue; 2486 } 2487 FR_VERBOSE(("=%d/%d.%d *", fr->fr_grhead, fr->fr_group, rulen)); 2488 2489 passt = fr->fr_flags; 2490 2491 /* 2492 * If the rule is a "call now" rule, then call the function 2493 * in the rule, if it exists and use the results from that. 2494 * If the function pointer is bad, just make like we ignore 2495 * it, except for increasing the hit counter. 2496 */ 2497 if ((passt & FR_CALLNOW) != 0) { 2498 frentry_t *frs; 2499 2500 ATOMIC_INC64(fr->fr_hits); 2501 if ((fr->fr_func == NULL) || 2502 (fr->fr_func == (ipfunc_t)-1)) 2503 continue; 2504 2505 frs = fin->fin_fr; 2506 fin->fin_fr = fr; 2507 fr = (*fr->fr_func)(fin, &passt); 2508 if (fr == NULL) { 2509 fin->fin_fr = frs; 2510 continue; 2511 } 2512 passt = fr->fr_flags; 2513 } 2514 fin->fin_fr = fr; 2515 2516 #ifdef IPFILTER_LOG 2517 /* 2518 * Just log this packet... 2519 */ 2520 if ((passt & FR_LOGMASK) == FR_LOG) { 2521 if (ipf_log_pkt(fin, passt) == -1) { 2522 if (passt & FR_LOGORBLOCK) { 2523 DT(frb_logfail); 2524 passt &= ~FR_CMDMASK; 2525 passt |= FR_BLOCK|FR_QUICK; 2526 fin->fin_reason = FRB_LOGFAIL; 2527 } 2528 } 2529 } 2530 #endif /* IPFILTER_LOG */ 2531 2532 MUTEX_ENTER(&fr->fr_lock); 2533 fr->fr_bytes += (U_QUAD_T)fin->fin_plen; 2534 fr->fr_hits++; 2535 MUTEX_EXIT(&fr->fr_lock); 2536 fin->fin_rule = rulen; 2537 2538 passo = pass; 2539 if (FR_ISSKIP(passt)) { 2540 skip = fr->fr_arg; 2541 continue; 2542 } else if (((passt & FR_LOGMASK) != FR_LOG) && 2543 ((passt & FR_LOGMASK) != FR_DECAPSULATE)) { 2544 pass = passt; 2545 } 2546 2547 if (passt & (FR_RETICMP|FR_FAKEICMP)) 2548 fin->fin_icode = fr->fr_icode; 2549 2550 if (fr->fr_group != -1) { 2551 (void) strncpy(fin->fin_group, 2552 FR_NAME(fr, fr_group), 2553 strlen(FR_NAME(fr, fr_group))); 2554 } else { 2555 fin->fin_group[0] = '\0'; 2556 } 2557 2558 FR_DEBUG(("pass %#x/%#x/%x\n", passo, pass, passt)); 2559 2560 if (fr->fr_grphead != NULL) { 2561 fin->fin_fr = fr->fr_grphead->fg_start; 2562 FR_VERBOSE(("group %s\n", FR_NAME(fr, fr_grhead))); 2563 2564 if (FR_ISDECAPS(passt)) 2565 passt = ipf_decaps(fin, pass, fr->fr_icode); 2566 else 2567 passt = ipf_scanlist(fin, pass); 2568 2569 if (fin->fin_fr == NULL) { 2570 fin->fin_rule = rulen; 2571 if (fr->fr_group != -1) 2572 (void) strncpy(fin->fin_group, 2573 fr->fr_names + 2574 fr->fr_group, 2575 strlen(fr->fr_names + 2576 fr->fr_group)); 2577 fin->fin_fr = fr; 2578 passt = pass; 2579 } 2580 pass = passt; 2581 } 2582 2583 if (pass & FR_QUICK) { 2584 /* 2585 * Finally, if we've asked to track state for this 2586 * packet, set it up. Add state for "quick" rules 2587 * here so that if the action fails we can consider 2588 * the rule to "not match" and keep on processing 2589 * filter rules. 2590 */ 2591 if ((pass & FR_KEEPSTATE) && !FR_ISAUTH(pass) && 2592 !(fin->fin_flx & FI_STATE)) { 2593 int out = fin->fin_out; 2594 2595 fin->fin_fr = fr; 2596 if (ipf_state_add(softc, fin, NULL, 0) == 0) { 2597 LBUMPD(ipf_stats[out], fr_ads); 2598 } else { 2599 LBUMPD(ipf_stats[out], fr_bads); 2600 pass = passo; 2601 continue; 2602 } 2603 } 2604 break; 2605 } 2606 } 2607 fin->fin_depth--; 2608 return pass; 2609 } 2610 2611 2612 /* ------------------------------------------------------------------------ */ 2613 /* Function: ipf_acctpkt */ 2614 /* Returns: frentry_t* - always returns NULL */ 2615 /* Parameters: fin(I) - pointer to packet information */ 2616 /* passp(IO) - pointer to current/new filter decision (unused) */ 2617 /* */ 2618 /* Checks a packet against accounting rules, if there are any for the given */ 2619 /* IP protocol version. */ 2620 /* */ 2621 /* N.B.: this function returns NULL to match the prototype used by other */ 2622 /* functions called from the IPFilter "mainline" in ipf_check(). */ 2623 /* ------------------------------------------------------------------------ */ 2624 frentry_t * 2625 ipf_acctpkt(fr_info_t *fin, u_32_t *passp) 2626 { 2627 ipf_main_softc_t *softc = fin->fin_main_soft; 2628 char group[FR_GROUPLEN]; 2629 frentry_t *fr, *frsave; 2630 u_32_t pass, rulen; 2631 2632 passp = passp; 2633 fr = softc->ipf_acct[fin->fin_out][softc->ipf_active]; 2634 2635 if (fr != NULL) { 2636 frsave = fin->fin_fr; 2637 bcopy(fin->fin_group, group, FR_GROUPLEN); 2638 rulen = fin->fin_rule; 2639 fin->fin_fr = fr; 2640 pass = ipf_scanlist(fin, FR_NOMATCH); 2641 if (FR_ISACCOUNT(pass)) { 2642 LBUMPD(ipf_stats[0], fr_acct); 2643 } 2644 fin->fin_fr = frsave; 2645 bcopy(group, fin->fin_group, FR_GROUPLEN); 2646 fin->fin_rule = rulen; 2647 } 2648 return NULL; 2649 } 2650 2651 2652 /* ------------------------------------------------------------------------ */ 2653 /* Function: ipf_firewall */ 2654 /* Returns: frentry_t* - returns pointer to matched rule, if no matches */ 2655 /* were found, returns NULL. */ 2656 /* Parameters: fin(I) - pointer to packet information */ 2657 /* passp(IO) - pointer to current/new filter decision (unused) */ 2658 /* */ 2659 /* Applies an appropriate set of firewall rules to the packet, to see if */ 2660 /* there are any matches. The first check is to see if a match can be seen */ 2661 /* in the cache. If not, then search an appropriate list of rules. Once a */ 2662 /* matching rule is found, take any appropriate actions as defined by the */ 2663 /* rule - except logging. */ 2664 /* ------------------------------------------------------------------------ */ 2665 static frentry_t * 2666 ipf_firewall(fr_info_t *fin, u_32_t *passp) 2667 { 2668 ipf_main_softc_t *softc = fin->fin_main_soft; 2669 frentry_t *fr; 2670 u_32_t pass; 2671 int out; 2672 2673 out = fin->fin_out; 2674 pass = *passp; 2675 2676 /* 2677 * This rule cache will only affect packets that are not being 2678 * statefully filtered. 2679 */ 2680 fin->fin_fr = softc->ipf_rules[out][softc->ipf_active]; 2681 if (fin->fin_fr != NULL) 2682 pass = ipf_scanlist(fin, softc->ipf_pass); 2683 2684 if ((pass & FR_NOMATCH)) { 2685 LBUMPD(ipf_stats[out], fr_nom); 2686 } 2687 fr = fin->fin_fr; 2688 2689 /* 2690 * Apply packets per second rate-limiting to a rule as required. 2691 */ 2692 if ((fr != NULL) && (fr->fr_pps != 0) && 2693 !ppsratecheck(&fr->fr_lastpkt, &fr->fr_curpps, fr->fr_pps)) { 2694 DT2(frb_ppsrate, fr_info_t *, fin, frentry_t *, fr); 2695 pass &= ~(FR_CMDMASK|FR_RETICMP|FR_RETRST); 2696 pass |= FR_BLOCK; 2697 LBUMPD(ipf_stats[out], fr_ppshit); 2698 fin->fin_reason = FRB_PPSRATE; 2699 } 2700 2701 /* 2702 * If we fail to add a packet to the authorization queue, then we 2703 * drop the packet later. However, if it was added then pretend 2704 * we've dropped it already. 2705 */ 2706 if (FR_ISAUTH(pass)) { 2707 if (ipf_auth_new(fin->fin_m, fin) != 0) { 2708 DT1(frb_authnew, fr_info_t *, fin); 2709 fin->fin_m = *fin->fin_mp = NULL; 2710 fin->fin_reason = FRB_AUTHNEW; 2711 fin->fin_error = 0; 2712 } else { 2713 IPFERROR(1); 2714 fin->fin_error = ENOSPC; 2715 } 2716 } 2717 2718 if ((fr != NULL) && (fr->fr_func != NULL) && 2719 (fr->fr_func != (ipfunc_t)-1) && !(pass & FR_CALLNOW)) 2720 (void) (*fr->fr_func)(fin, &pass); 2721 2722 /* 2723 * If a rule is a pre-auth rule, check again in the list of rules 2724 * loaded for authenticated use. It does not particulary matter 2725 * if this search fails because a "preauth" result, from a rule, 2726 * is treated as "not a pass", hence the packet is blocked. 2727 */ 2728 if (FR_ISPREAUTH(pass)) { 2729 pass = ipf_auth_pre_scanlist(softc, fin, pass); 2730 } 2731 2732 /* 2733 * If the rule has "keep frag" and the packet is actually a fragment, 2734 * then create a fragment state entry. 2735 */ 2736 if (pass & FR_KEEPFRAG) { 2737 if (fin->fin_flx & FI_FRAG) { 2738 if (ipf_frag_new(softc, fin, pass) == -1) { 2739 LBUMP(ipf_stats[out].fr_bnfr); 2740 } else { 2741 LBUMP(ipf_stats[out].fr_nfr); 2742 } 2743 } else { 2744 LBUMP(ipf_stats[out].fr_cfr); 2745 } 2746 } 2747 2748 fr = fin->fin_fr; 2749 *passp = pass; 2750 2751 return fr; 2752 } 2753 2754 2755 /* ------------------------------------------------------------------------ */ 2756 /* Function: ipf_check */ 2757 /* Returns: int - 0 == packet allowed through, */ 2758 /* User space: */ 2759 /* -1 == packet blocked */ 2760 /* 1 == packet not matched */ 2761 /* -2 == requires authentication */ 2762 /* Kernel: */ 2763 /* > 0 == filter error # for packet */ 2764 /* Parameters: ip(I) - pointer to start of IPv4/6 packet */ 2765 /* hlen(I) - length of header */ 2766 /* ifp(I) - pointer to interface this packet is on */ 2767 /* out(I) - 0 == packet going in, 1 == packet going out */ 2768 /* mp(IO) - pointer to caller's buffer pointer that holds this */ 2769 /* IP packet. */ 2770 /* Solaris & HP-UX ONLY : */ 2771 /* qpi(I) - pointer to STREAMS queue information for this */ 2772 /* interface & direction. */ 2773 /* */ 2774 /* ipf_check() is the master function for all IPFilter packet processing. */ 2775 /* It orchestrates: Network Address Translation (NAT), checking for packet */ 2776 /* authorisation (or pre-authorisation), presence of related state info., */ 2777 /* generating log entries, IP packet accounting, routing of packets as */ 2778 /* directed by firewall rules and of course whether or not to allow the */ 2779 /* packet to be further processed by the kernel. */ 2780 /* */ 2781 /* For packets blocked, the contents of "mp" will be NULL'd and the buffer */ 2782 /* freed. Packets passed may be returned with the pointer pointed to by */ 2783 /* by "mp" changed to a new buffer. */ 2784 /* ------------------------------------------------------------------------ */ 2785 int 2786 ipf_check(void *ctx, ip_t *ip, int hlen, void *ifp, int out, 2787 #if defined(_KERNEL) && defined(MENTAT) 2788 void *qif, 2789 #endif 2790 mb_t **mp) 2791 { 2792 /* 2793 * The above really sucks, but short of writing a diff 2794 */ 2795 ipf_main_softc_t *softc = ctx; 2796 fr_info_t frinfo; 2797 fr_info_t *fin = &frinfo; 2798 u_32_t pass = softc->ipf_pass; 2799 frentry_t *fr = NULL; 2800 int v = IP_V(ip); 2801 mb_t *mc = NULL; 2802 mb_t *m; 2803 /* 2804 * The first part of ipf_check() deals with making sure that what goes 2805 * into the filtering engine makes some sense. Information about the 2806 * the packet is distilled, collected into a fr_info_t structure and 2807 * the an attempt to ensure the buffer the packet is in is big enough 2808 * to hold all the required packet headers. 2809 */ 2810 #ifdef _KERNEL 2811 # ifdef MENTAT 2812 qpktinfo_t *qpi = qif; 2813 2814 # ifdef __sparc 2815 if ((u_int)ip & 0x3) 2816 return 2; 2817 # endif 2818 # else 2819 SPL_INT(s); 2820 # endif 2821 2822 if (softc->ipf_running <= 0) { 2823 return 0; 2824 } 2825 2826 bzero((char *)fin, sizeof(*fin)); 2827 2828 # ifdef MENTAT 2829 if (qpi->qpi_flags & QF_BROADCAST) 2830 fin->fin_flx |= FI_MBCAST|FI_BROADCAST; 2831 if (qpi->qpi_flags & QF_MULTICAST) 2832 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2833 m = qpi->qpi_m; 2834 fin->fin_qfm = m; 2835 fin->fin_qpi = qpi; 2836 # else /* MENTAT */ 2837 2838 m = *mp; 2839 2840 # if defined(M_MCAST) 2841 if ((m->m_flags & M_MCAST) != 0) 2842 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2843 # endif 2844 # if defined(M_MLOOP) 2845 if ((m->m_flags & M_MLOOP) != 0) 2846 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2847 # endif 2848 # if defined(M_BCAST) 2849 if ((m->m_flags & M_BCAST) != 0) 2850 fin->fin_flx |= FI_MBCAST|FI_BROADCAST; 2851 # endif 2852 # ifdef M_CANFASTFWD 2853 /* 2854 * XXX For now, IP Filter and fast-forwarding of cached flows 2855 * XXX are mutually exclusive. Eventually, IP Filter should 2856 * XXX get a "can-fast-forward" filter rule. 2857 */ 2858 m->m_flags &= ~M_CANFASTFWD; 2859 # endif /* M_CANFASTFWD */ 2860 # if defined(CSUM_DELAY_DATA) && (!defined(__FreeBSD_version) || \ 2861 (__FreeBSD_version < 501108)) 2862 /* 2863 * disable delayed checksums. 2864 */ 2865 if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 2866 in_undefer_cksum_tcpudp(m); 2867 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 2868 } 2869 # endif /* CSUM_DELAY_DATA */ 2870 # endif /* MENTAT */ 2871 #else 2872 bzero((char *)fin, sizeof(*fin)); 2873 m = *mp; 2874 # if defined(M_MCAST) 2875 if ((m->m_flags & M_MCAST) != 0) 2876 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2877 # endif 2878 # if defined(M_MLOOP) 2879 if ((m->m_flags & M_MLOOP) != 0) 2880 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2881 # endif 2882 # if defined(M_BCAST) 2883 if ((m->m_flags & M_BCAST) != 0) 2884 fin->fin_flx |= FI_MBCAST|FI_BROADCAST; 2885 # endif 2886 #endif /* _KERNEL */ 2887 2888 fin->fin_v = v; 2889 fin->fin_m = m; 2890 fin->fin_ip = ip; 2891 fin->fin_mp = mp; 2892 fin->fin_out = out; 2893 fin->fin_ifp = ifp; 2894 fin->fin_error = ENETUNREACH; 2895 fin->fin_hlen = (u_short)hlen; 2896 fin->fin_dp = (char *)ip + hlen; 2897 fin->fin_main_soft = softc; 2898 2899 fin->fin_ipoff = (char *)ip - MTOD(m, char *); 2900 2901 SPL_NET(s); 2902 2903 #ifdef USE_INET6 2904 if (v == 6) { 2905 LBUMP(ipf_stats[out].fr_ipv6); 2906 /* 2907 * Jumbo grams are quite likely too big for internal buffer 2908 * structures to handle comfortably, for now, so just drop 2909 * them. 2910 */ 2911 if (((ip6_t *)ip)->ip6_plen == 0) { 2912 DT1(frb_jumbo, ip6_t *, (ip6_t *)ip); 2913 pass = FR_BLOCK|FR_NOMATCH; 2914 fin->fin_reason = FRB_JUMBO; 2915 goto finished; 2916 } 2917 fin->fin_family = AF_INET6; 2918 } else 2919 #endif 2920 { 2921 fin->fin_family = AF_INET; 2922 } 2923 2924 if (ipf_makefrip(hlen, ip, fin) == -1) { 2925 DT1(frb_makefrip, fr_info_t *, fin); 2926 pass = FR_BLOCK|FR_NOMATCH; 2927 fin->fin_reason = FRB_MAKEFRIP; 2928 goto finished; 2929 } 2930 2931 /* 2932 * For at least IPv6 packets, if a m_pullup() fails then this pointer 2933 * becomes NULL and so we have no packet to free. 2934 */ 2935 if (*fin->fin_mp == NULL) 2936 goto finished; 2937 2938 if (!out) { 2939 if (v == 4) { 2940 if (softc->ipf_chksrc && !ipf_verifysrc(fin)) { 2941 LBUMPD(ipf_stats[0], fr_v4_badsrc); 2942 fin->fin_flx |= FI_BADSRC; 2943 } 2944 if (fin->fin_ip->ip_ttl < softc->ipf_minttl) { 2945 LBUMPD(ipf_stats[0], fr_v4_badttl); 2946 fin->fin_flx |= FI_LOWTTL; 2947 } 2948 } 2949 #ifdef USE_INET6 2950 else if (v == 6) { 2951 if (((ip6_t *)ip)->ip6_hlim < softc->ipf_minttl) { 2952 LBUMPD(ipf_stats[0], fr_v6_badttl); 2953 fin->fin_flx |= FI_LOWTTL; 2954 } 2955 } 2956 #endif 2957 } 2958 2959 if (fin->fin_flx & FI_SHORT) { 2960 LBUMPD(ipf_stats[out], fr_short); 2961 } 2962 2963 READ_ENTER(&softc->ipf_mutex); 2964 2965 if (!out) { 2966 switch (fin->fin_v) 2967 { 2968 case 4 : 2969 if (ipf_nat_checkin(fin, &pass) == -1) { 2970 goto filterdone; 2971 } 2972 break; 2973 #ifdef USE_INET6 2974 case 6 : 2975 if (ipf_nat6_checkin(fin, &pass) == -1) { 2976 goto filterdone; 2977 } 2978 break; 2979 #endif 2980 default : 2981 break; 2982 } 2983 } 2984 /* 2985 * Check auth now. 2986 * If a packet is found in the auth table, then skip checking 2987 * the access lists for permission but we do need to consider 2988 * the result as if it were from the ACL's. In addition, being 2989 * found in the auth table means it has been seen before, so do 2990 * not pass it through accounting (again), lest it be counted twice. 2991 */ 2992 fr = ipf_auth_check(fin, &pass); 2993 if (!out && (fr == NULL)) 2994 (void) ipf_acctpkt(fin, NULL); 2995 2996 if (fr == NULL) { 2997 if ((fin->fin_flx & FI_FRAG) != 0) 2998 fr = ipf_frag_known(fin, &pass); 2999 3000 if (fr == NULL) 3001 fr = ipf_state_check(fin, &pass); 3002 } 3003 3004 if ((pass & FR_NOMATCH) || (fr == NULL)) 3005 fr = ipf_firewall(fin, &pass); 3006 3007 /* 3008 * If we've asked to track state for this packet, set it up. 3009 * Here rather than ipf_firewall because ipf_checkauth may decide 3010 * to return a packet for "keep state" 3011 */ 3012 if ((pass & FR_KEEPSTATE) && (fin->fin_m != NULL) && 3013 !(fin->fin_flx & FI_STATE)) { 3014 if (ipf_state_add(softc, fin, NULL, 0) == 0) { 3015 LBUMP(ipf_stats[out].fr_ads); 3016 } else { 3017 LBUMP(ipf_stats[out].fr_bads); 3018 if (FR_ISPASS(pass)) { 3019 DT(frb_stateadd); 3020 pass &= ~FR_CMDMASK; 3021 pass |= FR_BLOCK; 3022 fin->fin_reason = FRB_STATEADD; 3023 } 3024 } 3025 } 3026 3027 fin->fin_fr = fr; 3028 if ((fr != NULL) && !(fin->fin_flx & FI_STATE)) { 3029 fin->fin_dif = &fr->fr_dif; 3030 fin->fin_tif = &fr->fr_tifs[fin->fin_rev]; 3031 } 3032 3033 /* 3034 * Only count/translate packets which will be passed on, out the 3035 * interface. 3036 */ 3037 if (out && FR_ISPASS(pass)) { 3038 (void) ipf_acctpkt(fin, NULL); 3039 3040 switch (fin->fin_v) 3041 { 3042 case 4 : 3043 if (ipf_nat_checkout(fin, &pass) == -1) { 3044 ; 3045 } else if ((softc->ipf_update_ipid != 0) && (v == 4)) { 3046 if (ipf_updateipid(fin) == -1) { 3047 DT(frb_updateipid); 3048 LBUMP(ipf_stats[1].fr_ipud); 3049 pass &= ~FR_CMDMASK; 3050 pass |= FR_BLOCK; 3051 fin->fin_reason = FRB_UPDATEIPID; 3052 } else { 3053 LBUMP(ipf_stats[0].fr_ipud); 3054 } 3055 } 3056 break; 3057 #ifdef USE_INET6 3058 case 6 : 3059 (void) ipf_nat6_checkout(fin, &pass); 3060 break; 3061 #endif 3062 default : 3063 break; 3064 } 3065 } 3066 3067 filterdone: 3068 #ifdef IPFILTER_LOG 3069 if ((softc->ipf_flags & FF_LOGGING) || (pass & FR_LOGMASK)) { 3070 (void) ipf_dolog(fin, &pass); 3071 } 3072 #endif 3073 3074 /* 3075 * The FI_STATE flag is cleared here so that calling ipf_state_check 3076 * will work when called from inside of fr_fastroute. Although 3077 * there is a similar flag, FI_NATED, for NAT, it does have the same 3078 * impact on code execution. 3079 */ 3080 fin->fin_flx &= ~FI_STATE; 3081 3082 #if defined(FASTROUTE_RECURSION) 3083 /* 3084 * Up the reference on fr_lock and exit ipf_mutex. The generation of 3085 * a packet below can sometimes cause a recursive call into IPFilter. 3086 * On those platforms where that does happen, we need to hang onto 3087 * the filter rule just in case someone decides to remove or flush it 3088 * in the meantime. 3089 */ 3090 if (fr != NULL) { 3091 MUTEX_ENTER(&fr->fr_lock); 3092 fr->fr_ref++; 3093 MUTEX_EXIT(&fr->fr_lock); 3094 } 3095 3096 RWLOCK_EXIT(&softc->ipf_mutex); 3097 #endif 3098 3099 if ((pass & FR_RETMASK) != 0) { 3100 /* 3101 * Should we return an ICMP packet to indicate error 3102 * status passing through the packet filter ? 3103 * WARNING: ICMP error packets AND TCP RST packets should 3104 * ONLY be sent in repsonse to incoming packets. Sending 3105 * them in response to outbound packets can result in a 3106 * panic on some operating systems. 3107 */ 3108 if (!out) { 3109 if (pass & FR_RETICMP) { 3110 int dst; 3111 3112 if ((pass & FR_RETMASK) == FR_FAKEICMP) 3113 dst = 1; 3114 else 3115 dst = 0; 3116 (void) ipf_send_icmp_err(ICMP_UNREACH, fin, 3117 dst); 3118 LBUMP(ipf_stats[0].fr_ret); 3119 } else if (((pass & FR_RETMASK) == FR_RETRST) && 3120 !(fin->fin_flx & FI_SHORT)) { 3121 if (((fin->fin_flx & FI_OOW) != 0) || 3122 (ipf_send_reset(fin) == 0)) { 3123 LBUMP(ipf_stats[1].fr_ret); 3124 } 3125 } 3126 3127 /* 3128 * When using return-* with auth rules, the auth code 3129 * takes over disposing of this packet. 3130 */ 3131 if (FR_ISAUTH(pass) && (fin->fin_m != NULL)) { 3132 DT1(frb_authcapture, fr_info_t *, fin); 3133 fin->fin_m = *fin->fin_mp = NULL; 3134 fin->fin_reason = FRB_AUTHCAPTURE; 3135 m = NULL; 3136 } 3137 } else { 3138 if (pass & FR_RETRST) { 3139 fin->fin_error = ECONNRESET; 3140 } 3141 } 3142 } 3143 3144 /* 3145 * After the above so that ICMP unreachables and TCP RSTs get 3146 * created properly. 3147 */ 3148 if (FR_ISBLOCK(pass) && (fin->fin_flx & FI_NEWNAT)) 3149 ipf_nat_uncreate(fin); 3150 3151 /* 3152 * If we didn't drop off the bottom of the list of rules (and thus 3153 * the 'current' rule fr is not NULL), then we may have some extra 3154 * instructions about what to do with a packet. 3155 * Once we're finished return to our caller, freeing the packet if 3156 * we are dropping it. 3157 */ 3158 if (fr != NULL) { 3159 frdest_t *fdp; 3160 3161 /* 3162 * Generate a duplicated packet first because ipf_fastroute 3163 * can lead to fin_m being free'd... not good. 3164 */ 3165 fdp = fin->fin_dif; 3166 if ((fdp != NULL) && (fdp->fd_ptr != NULL) && 3167 (fdp->fd_ptr != (void *)-1) && (fin->fin_m != NULL)) { 3168 mc = M_COPY(fin->fin_m); 3169 if (mc != NULL) 3170 ipf_fastroute(mc, &mc, fin, fdp); 3171 } 3172 3173 fdp = fin->fin_tif; 3174 if (!out && (pass & FR_FASTROUTE)) { 3175 /* 3176 * For fastroute rule, no destination interface defined 3177 * so pass NULL as the frdest_t parameter 3178 */ 3179 (void) ipf_fastroute(fin->fin_m, mp, fin, NULL); 3180 m = *mp = NULL; 3181 } else if ((fdp != NULL) && (fdp->fd_ptr != NULL) && 3182 (fdp->fd_ptr != (struct ifnet *)-1)) { 3183 /* this is for to rules: */ 3184 ipf_fastroute(fin->fin_m, mp, fin, fdp); 3185 m = *mp = NULL; 3186 } 3187 3188 #if defined(FASTROUTE_RECURSION) 3189 (void) ipf_derefrule(softc, &fr); 3190 #endif 3191 } 3192 #if !defined(FASTROUTE_RECURSION) 3193 RWLOCK_EXIT(&softc->ipf_mutex); 3194 #endif 3195 3196 finished: 3197 if (!FR_ISPASS(pass)) { 3198 LBUMP(ipf_stats[out].fr_block); 3199 if (*mp != NULL) { 3200 #ifdef _KERNEL 3201 FREE_MB_T(*mp); 3202 #endif 3203 m = *mp = NULL; 3204 } 3205 } else { 3206 LBUMP(ipf_stats[out].fr_pass); 3207 #if defined(_KERNEL) && defined(__sgi) 3208 if ((fin->fin_hbuf != NULL) && 3209 (mtod(fin->fin_m, struct ip *) != fin->fin_ip)) { 3210 COPYBACK(fin->fin_m, 0, fin->fin_plen, fin->fin_hbuf); 3211 } 3212 #endif 3213 } 3214 3215 SPL_X(s); 3216 3217 #ifdef _KERNEL 3218 if (FR_ISPASS(pass)) 3219 return 0; 3220 LBUMP(ipf_stats[out].fr_blocked[fin->fin_reason]); 3221 return fin->fin_error; 3222 #else /* _KERNEL */ 3223 if (*mp != NULL) 3224 (*mp)->mb_ifp = fin->fin_ifp; 3225 blockreason = fin->fin_reason; 3226 FR_VERBOSE(("fin_flx %#x pass %#x ", fin->fin_flx, pass)); 3227 /*if ((pass & FR_CMDMASK) == (softc->ipf_pass & FR_CMDMASK))*/ 3228 if ((pass & FR_NOMATCH) != 0) 3229 return 1; 3230 3231 if ((pass & FR_RETMASK) != 0) 3232 switch (pass & FR_RETMASK) 3233 { 3234 case FR_RETRST : 3235 return 3; 3236 case FR_RETICMP : 3237 return 4; 3238 case FR_FAKEICMP : 3239 return 5; 3240 } 3241 3242 switch (pass & FR_CMDMASK) 3243 { 3244 case FR_PASS : 3245 return 0; 3246 case FR_BLOCK : 3247 return -1; 3248 case FR_AUTH : 3249 return -2; 3250 case FR_ACCOUNT : 3251 return -3; 3252 case FR_PREAUTH : 3253 return -4; 3254 } 3255 return 2; 3256 #endif /* _KERNEL */ 3257 } 3258 3259 3260 #ifdef IPFILTER_LOG 3261 /* ------------------------------------------------------------------------ */ 3262 /* Function: ipf_dolog */ 3263 /* Returns: frentry_t* - returns contents of fin_fr (no change made) */ 3264 /* Parameters: fin(I) - pointer to packet information */ 3265 /* passp(IO) - pointer to current/new filter decision (unused) */ 3266 /* */ 3267 /* Checks flags set to see how a packet should be logged, if it is to be */ 3268 /* logged. Adjust statistics based on its success or not. */ 3269 /* ------------------------------------------------------------------------ */ 3270 frentry_t * 3271 ipf_dolog(fr_info_t *fin, u_32_t *passp) 3272 { 3273 ipf_main_softc_t *softc = fin->fin_main_soft; 3274 u_32_t pass; 3275 int out; 3276 3277 out = fin->fin_out; 3278 pass = *passp; 3279 3280 if ((softc->ipf_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) { 3281 pass |= FF_LOGNOMATCH; 3282 LBUMPD(ipf_stats[out], fr_npkl); 3283 goto logit; 3284 3285 } else if (((pass & FR_LOGMASK) == FR_LOGP) || 3286 (FR_ISPASS(pass) && (softc->ipf_flags & FF_LOGPASS))) { 3287 if ((pass & FR_LOGMASK) != FR_LOGP) 3288 pass |= FF_LOGPASS; 3289 LBUMPD(ipf_stats[out], fr_ppkl); 3290 goto logit; 3291 3292 } else if (((pass & FR_LOGMASK) == FR_LOGB) || 3293 (FR_ISBLOCK(pass) && (softc->ipf_flags & FF_LOGBLOCK))) { 3294 if ((pass & FR_LOGMASK) != FR_LOGB) 3295 pass |= FF_LOGBLOCK; 3296 LBUMPD(ipf_stats[out], fr_bpkl); 3297 3298 logit: 3299 if (ipf_log_pkt(fin, pass) == -1) { 3300 /* 3301 * If the "or-block" option has been used then 3302 * block the packet if we failed to log it. 3303 */ 3304 if ((pass & FR_LOGORBLOCK) && FR_ISPASS(pass)) { 3305 DT1(frb_logfail2, u_int, pass); 3306 pass &= ~FR_CMDMASK; 3307 pass |= FR_BLOCK; 3308 fin->fin_reason = FRB_LOGFAIL2; 3309 } 3310 } 3311 *passp = pass; 3312 } 3313 3314 return fin->fin_fr; 3315 } 3316 #endif /* IPFILTER_LOG */ 3317 3318 3319 /* ------------------------------------------------------------------------ */ 3320 /* Function: ipf_cksum */ 3321 /* Returns: u_short - IP header checksum */ 3322 /* Parameters: addr(I) - pointer to start of buffer to checksum */ 3323 /* len(I) - length of buffer in bytes */ 3324 /* */ 3325 /* Calculate the two's complement 16 bit checksum of the buffer passed. */ 3326 /* */ 3327 /* N.B.: addr should be 16bit aligned. */ 3328 /* ------------------------------------------------------------------------ */ 3329 u_short 3330 ipf_cksum(u_short *addr, int len) 3331 { 3332 u_32_t sum = 0; 3333 3334 for (sum = 0; len > 1; len -= 2) 3335 sum += *addr++; 3336 3337 /* mop up an odd byte, if necessary */ 3338 if (len == 1) 3339 sum += *(u_char *)addr; 3340 3341 /* 3342 * add back carry outs from top 16 bits to low 16 bits 3343 */ 3344 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 3345 sum += (sum >> 16); /* add carry */ 3346 return (u_short)(~sum); 3347 } 3348 3349 3350 /* ------------------------------------------------------------------------ */ 3351 /* Function: fr_cksum */ 3352 /* Returns: u_short - layer 4 checksum */ 3353 /* Parameters: fin(I) - pointer to packet information */ 3354 /* ip(I) - pointer to IP header */ 3355 /* l4proto(I) - protocol to caclulate checksum for */ 3356 /* l4hdr(I) - pointer to layer 4 header */ 3357 /* */ 3358 /* Calculates the TCP checksum for the packet held in "m", using the data */ 3359 /* in the IP header "ip" to seed it. */ 3360 /* */ 3361 /* NB: This function assumes we've pullup'd enough for all of the IP header */ 3362 /* and the TCP header. We also assume that data blocks aren't allocated in */ 3363 /* odd sizes. */ 3364 /* */ 3365 /* Expects ip_len and ip_off to be in network byte order when called. */ 3366 /* ------------------------------------------------------------------------ */ 3367 u_short 3368 fr_cksum(fr_info_t *fin, ip_t *ip, int l4proto, void *l4hdr) 3369 { 3370 u_short *sp, slen, sumsave, *csump; 3371 u_int sum, sum2; 3372 int hlen; 3373 int off; 3374 #ifdef USE_INET6 3375 ip6_t *ip6; 3376 #endif 3377 3378 csump = NULL; 3379 sumsave = 0; 3380 sp = NULL; 3381 slen = 0; 3382 hlen = 0; 3383 sum = 0; 3384 3385 sum = htons((u_short)l4proto); 3386 /* 3387 * Add up IP Header portion 3388 */ 3389 #ifdef USE_INET6 3390 if (IP_V(ip) == 4) { 3391 #endif 3392 hlen = IP_HL(ip) << 2; 3393 off = hlen; 3394 sp = (u_short *)&ip->ip_src; 3395 sum += *sp++; /* ip_src */ 3396 sum += *sp++; 3397 sum += *sp++; /* ip_dst */ 3398 sum += *sp++; 3399 #ifdef USE_INET6 3400 } else if (IP_V(ip) == 6) { 3401 ip6 = (ip6_t *)ip; 3402 hlen = sizeof(*ip6); 3403 off = ((char *)fin->fin_dp - (char *)fin->fin_ip); 3404 sp = (u_short *)&ip6->ip6_src; 3405 sum += *sp++; /* ip6_src */ 3406 sum += *sp++; 3407 sum += *sp++; 3408 sum += *sp++; 3409 sum += *sp++; 3410 sum += *sp++; 3411 sum += *sp++; 3412 sum += *sp++; 3413 /* This needs to be routing header aware. */ 3414 sum += *sp++; /* ip6_dst */ 3415 sum += *sp++; 3416 sum += *sp++; 3417 sum += *sp++; 3418 sum += *sp++; 3419 sum += *sp++; 3420 sum += *sp++; 3421 sum += *sp++; 3422 } else { 3423 return 0xffff; 3424 } 3425 #endif 3426 slen = fin->fin_plen - off; 3427 sum += htons(slen); 3428 3429 switch (l4proto) 3430 { 3431 case IPPROTO_UDP : 3432 csump = &((udphdr_t *)l4hdr)->uh_sum; 3433 break; 3434 3435 case IPPROTO_TCP : 3436 csump = &((tcphdr_t *)l4hdr)->th_sum; 3437 break; 3438 case IPPROTO_ICMP : 3439 csump = &((icmphdr_t *)l4hdr)->icmp_cksum; 3440 sum = 0; /* Pseudo-checksum is not included */ 3441 break; 3442 #ifdef USE_INET6 3443 case IPPROTO_ICMPV6 : 3444 csump = &((struct icmp6_hdr *)l4hdr)->icmp6_cksum; 3445 break; 3446 #endif 3447 default : 3448 break; 3449 } 3450 3451 if (csump != NULL) { 3452 sumsave = *csump; 3453 *csump = 0; 3454 } 3455 3456 sum2 = ipf_pcksum(fin, off, sum); 3457 if (csump != NULL) 3458 *csump = sumsave; 3459 return sum2; 3460 } 3461 3462 3463 /* ------------------------------------------------------------------------ */ 3464 /* Function: ipf_findgroup */ 3465 /* Returns: frgroup_t * - NULL = group not found, else pointer to group */ 3466 /* Parameters: softc(I) - pointer to soft context main structure */ 3467 /* group(I) - group name to search for */ 3468 /* unit(I) - device to which this group belongs */ 3469 /* set(I) - which set of rules (inactive/inactive) this is */ 3470 /* fgpp(O) - pointer to place to store pointer to the pointer */ 3471 /* to where to add the next (last) group or where */ 3472 /* to delete group from. */ 3473 /* */ 3474 /* Search amongst the defined groups for a particular group number. */ 3475 /* ------------------------------------------------------------------------ */ 3476 frgroup_t * 3477 ipf_findgroup(ipf_main_softc_t *softc, char *group, minor_t unit, int set, 3478 frgroup_t ***fgpp) 3479 { 3480 frgroup_t *fg, **fgp; 3481 3482 /* 3483 * Which list of groups to search in is dependent on which list of 3484 * rules are being operated on. 3485 */ 3486 fgp = &softc->ipf_groups[unit][set]; 3487 3488 while ((fg = *fgp) != NULL) { 3489 if (strncmp(group, fg->fg_name, FR_GROUPLEN) == 0) 3490 break; 3491 else 3492 fgp = &fg->fg_next; 3493 } 3494 if (fgpp != NULL) 3495 *fgpp = fgp; 3496 return fg; 3497 } 3498 3499 3500 /* ------------------------------------------------------------------------ */ 3501 /* Function: ipf_group_add */ 3502 /* Returns: frgroup_t * - NULL == did not create group, */ 3503 /* != NULL == pointer to the group */ 3504 /* Parameters: softc(I) - pointer to soft context main structure */ 3505 /* num(I) - group number to add */ 3506 /* head(I) - rule pointer that is using this as the head */ 3507 /* flags(I) - rule flags which describe the type of rule it is */ 3508 /* unit(I) - device to which this group will belong to */ 3509 /* set(I) - which set of rules (inactive/inactive) this is */ 3510 /* Write Locks: ipf_mutex */ 3511 /* */ 3512 /* Add a new group head, or if it already exists, increase the reference */ 3513 /* count to it. */ 3514 /* ------------------------------------------------------------------------ */ 3515 frgroup_t * 3516 ipf_group_add(ipf_main_softc_t *softc, char *group, void *head, u_32_t flags, 3517 minor_t unit, int set) 3518 { 3519 frgroup_t *fg, **fgp; 3520 u_32_t gflags; 3521 3522 if (group == NULL) 3523 return NULL; 3524 3525 if (unit == IPL_LOGIPF && *group == '\0') 3526 return NULL; 3527 3528 fgp = NULL; 3529 gflags = flags & FR_INOUT; 3530 3531 fg = ipf_findgroup(softc, group, unit, set, &fgp); 3532 if (fg != NULL) { 3533 if (fg->fg_head == NULL && head != NULL) 3534 fg->fg_head = head; 3535 if (fg->fg_flags == 0) 3536 fg->fg_flags = gflags; 3537 else if (gflags != fg->fg_flags) 3538 return NULL; 3539 fg->fg_ref++; 3540 return fg; 3541 } 3542 3543 KMALLOC(fg, frgroup_t *); 3544 if (fg != NULL) { 3545 fg->fg_head = head; 3546 fg->fg_start = NULL; 3547 fg->fg_next = *fgp; 3548 bcopy(group, fg->fg_name, strlen(group) + 1); 3549 fg->fg_flags = gflags; 3550 fg->fg_ref = 1; 3551 fg->fg_set = &softc->ipf_groups[unit][set]; 3552 *fgp = fg; 3553 } 3554 return fg; 3555 } 3556 3557 3558 /* ------------------------------------------------------------------------ */ 3559 /* Function: ipf_group_del */ 3560 /* Returns: int - number of rules deleted */ 3561 /* Parameters: softc(I) - pointer to soft context main structure */ 3562 /* group(I) - group name to delete */ 3563 /* fr(I) - filter rule from which group is referenced */ 3564 /* Write Locks: ipf_mutex */ 3565 /* */ 3566 /* This function is called whenever a reference to a group is to be dropped */ 3567 /* and thus its reference count needs to be lowered and the group free'd if */ 3568 /* the reference count reaches zero. Passing in fr is really for the sole */ 3569 /* purpose of knowing when the head rule is being deleted. */ 3570 /* ------------------------------------------------------------------------ */ 3571 void 3572 ipf_group_del(ipf_main_softc_t *softc, frgroup_t *group, frentry_t *fr) 3573 { 3574 3575 if (group->fg_head == fr) 3576 group->fg_head = NULL; 3577 3578 group->fg_ref--; 3579 if ((group->fg_ref == 0) && (group->fg_start == NULL)) 3580 ipf_group_free(group); 3581 } 3582 3583 3584 /* ------------------------------------------------------------------------ */ 3585 /* Function: ipf_group_free */ 3586 /* Returns: Nil */ 3587 /* Parameters: group(I) - pointer to filter rule group */ 3588 /* */ 3589 /* Remove the group from the list of groups and free it. */ 3590 /* ------------------------------------------------------------------------ */ 3591 static void 3592 ipf_group_free(frgroup_t *group) 3593 { 3594 frgroup_t **gp; 3595 3596 for (gp = group->fg_set; *gp != NULL; gp = &(*gp)->fg_next) { 3597 if (*gp == group) { 3598 *gp = group->fg_next; 3599 break; 3600 } 3601 } 3602 KFREE(group); 3603 } 3604 3605 3606 /* ------------------------------------------------------------------------ */ 3607 /* Function: ipf_group_flush */ 3608 /* Returns: int - number of rules flush from group */ 3609 /* Parameters: softc(I) - pointer to soft context main structure */ 3610 /* Parameters: group(I) - pointer to filter rule group */ 3611 /* */ 3612 /* Remove all of the rules that currently are listed under the given group. */ 3613 /* ------------------------------------------------------------------------ */ 3614 static int 3615 ipf_group_flush(ipf_main_softc_t *softc, frgroup_t *group) 3616 { 3617 int gone = 0; 3618 3619 (void) ipf_flushlist(softc, &gone, &group->fg_start); 3620 3621 return gone; 3622 } 3623 3624 3625 /* ------------------------------------------------------------------------ */ 3626 /* Function: ipf_getrulen */ 3627 /* Returns: frentry_t * - NULL == not found, else pointer to rule n */ 3628 /* Parameters: softc(I) - pointer to soft context main structure */ 3629 /* Parameters: unit(I) - device for which to count the rule's number */ 3630 /* flags(I) - which set of rules to find the rule in */ 3631 /* group(I) - group name */ 3632 /* n(I) - rule number to find */ 3633 /* */ 3634 /* Find rule # n in group # g and return a pointer to it. Return NULl if */ 3635 /* group # g doesn't exist or there are less than n rules in the group. */ 3636 /* ------------------------------------------------------------------------ */ 3637 frentry_t * 3638 ipf_getrulen(ipf_main_softc_t *softc, int unit, char *group, u_32_t n) 3639 { 3640 frentry_t *fr; 3641 frgroup_t *fg; 3642 3643 fg = ipf_findgroup(softc, group, unit, softc->ipf_active, NULL); 3644 if (fg == NULL) 3645 return NULL; 3646 for (fr = fg->fg_start; fr && n; fr = fr->fr_next, n--) 3647 ; 3648 if (n != 0) 3649 return NULL; 3650 return fr; 3651 } 3652 3653 3654 /* ------------------------------------------------------------------------ */ 3655 /* Function: ipf_flushlist */ 3656 /* Returns: int - >= 0 - number of flushed rules */ 3657 /* Parameters: softc(I) - pointer to soft context main structure */ 3658 /* nfreedp(O) - pointer to int where flush count is stored */ 3659 /* listp(I) - pointer to list to flush pointer */ 3660 /* Write Locks: ipf_mutex */ 3661 /* */ 3662 /* Recursively flush rules from the list, descending groups as they are */ 3663 /* encountered. if a rule is the head of a group and it has lost all its */ 3664 /* group members, then also delete the group reference. nfreedp is needed */ 3665 /* to store the accumulating count of rules removed, whereas the returned */ 3666 /* value is just the number removed from the current list. The latter is */ 3667 /* needed to correctly adjust reference counts on rules that define groups. */ 3668 /* */ 3669 /* NOTE: Rules not loaded from user space cannot be flushed. */ 3670 /* ------------------------------------------------------------------------ */ 3671 static int 3672 ipf_flushlist(ipf_main_softc_t *softc, int *nfreedp, frentry_t **listp) 3673 { 3674 int freed = 0; 3675 frentry_t *fp; 3676 3677 while ((fp = *listp) != NULL) { 3678 if ((fp->fr_type & FR_T_BUILTIN) || 3679 !(fp->fr_flags & FR_COPIED)) { 3680 listp = &fp->fr_next; 3681 continue; 3682 } 3683 *listp = fp->fr_next; 3684 if (fp->fr_next != NULL) 3685 fp->fr_next->fr_pnext = fp->fr_pnext; 3686 fp->fr_pnext = NULL; 3687 3688 if (fp->fr_grphead != NULL) { 3689 freed += ipf_group_flush(softc, fp->fr_grphead); 3690 fp->fr_names[fp->fr_grhead] = '\0'; 3691 } 3692 3693 if (fp->fr_icmpgrp != NULL) { 3694 freed += ipf_group_flush(softc, fp->fr_icmpgrp); 3695 fp->fr_names[fp->fr_icmphead] = '\0'; 3696 } 3697 3698 if (fp->fr_srctrack.ht_max_nodes) 3699 ipf_rb_ht_flush(&fp->fr_srctrack); 3700 3701 fp->fr_next = NULL; 3702 3703 ASSERT(fp->fr_ref > 0); 3704 if (ipf_derefrule(softc, &fp) == 0) 3705 freed++; 3706 } 3707 *nfreedp += freed; 3708 return freed; 3709 } 3710 3711 3712 /* ------------------------------------------------------------------------ */ 3713 /* Function: ipf_flush */ 3714 /* Returns: int - >= 0 - number of flushed rules */ 3715 /* Parameters: softc(I) - pointer to soft context main structure */ 3716 /* unit(I) - device for which to flush rules */ 3717 /* flags(I) - which set of rules to flush */ 3718 /* */ 3719 /* Calls flushlist() for all filter rules (accounting, firewall - both IPv4 */ 3720 /* and IPv6) as defined by the value of flags. */ 3721 /* ------------------------------------------------------------------------ */ 3722 int 3723 ipf_flush(ipf_main_softc_t *softc, minor_t unit, int flags) 3724 { 3725 int flushed = 0, set; 3726 3727 WRITE_ENTER(&softc->ipf_mutex); 3728 3729 set = softc->ipf_active; 3730 if ((flags & FR_INACTIVE) == FR_INACTIVE) 3731 set = 1 - set; 3732 3733 if (flags & FR_OUTQUE) { 3734 ipf_flushlist(softc, &flushed, &softc->ipf_rules[1][set]); 3735 ipf_flushlist(softc, &flushed, &softc->ipf_acct[1][set]); 3736 } 3737 if (flags & FR_INQUE) { 3738 ipf_flushlist(softc, &flushed, &softc->ipf_rules[0][set]); 3739 ipf_flushlist(softc, &flushed, &softc->ipf_acct[0][set]); 3740 } 3741 3742 flushed += ipf_flush_groups(softc, &softc->ipf_groups[unit][set], 3743 flags & (FR_INQUE|FR_OUTQUE)); 3744 3745 RWLOCK_EXIT(&softc->ipf_mutex); 3746 3747 if (unit == IPL_LOGIPF) { 3748 int tmp; 3749 3750 tmp = ipf_flush(softc, IPL_LOGCOUNT, flags); 3751 if (tmp >= 0) 3752 flushed += tmp; 3753 } 3754 return flushed; 3755 } 3756 3757 3758 /* ------------------------------------------------------------------------ */ 3759 /* Function: ipf_flush_groups */ 3760 /* Returns: int - >= 0 - number of flushed rules */ 3761 /* Parameters: softc(I) - soft context pointerto work with */ 3762 /* grhead(I) - pointer to the start of the group list to flush */ 3763 /* flags(I) - which set of rules to flush */ 3764 /* */ 3765 /* Walk through all of the groups under the given group head and remove all */ 3766 /* of those that match the flags passed in. The for loop here is bit more */ 3767 /* complicated than usual because the removal of a rule with ipf_derefrule */ 3768 /* may end up removing not only the structure pointed to by "fg" but also */ 3769 /* what is fg_next and fg_next after that. So if a filter rule is actually */ 3770 /* removed from the group then it is necessary to start again. */ 3771 /* ------------------------------------------------------------------------ */ 3772 static int 3773 ipf_flush_groups( ipf_main_softc_t *softc, frgroup_t **grhead, int flags) 3774 { 3775 frentry_t *fr, **frp; 3776 frgroup_t *fg, **fgp; 3777 int flushed = 0; 3778 int removed = 0; 3779 3780 for (fgp = grhead; (fg = *fgp) != NULL; ) { 3781 while ((fg != NULL) && ((fg->fg_flags & flags) == 0)) 3782 fg = fg->fg_next; 3783 if (fg == NULL) 3784 break; 3785 removed = 0; 3786 frp = &fg->fg_start; 3787 while ((removed == 0) && ((fr = *frp) != NULL)) { 3788 if ((fr->fr_flags & flags) == 0) { 3789 frp = &fr->fr_next; 3790 } else { 3791 if (fr->fr_next != NULL) 3792 fr->fr_next->fr_pnext = fr->fr_pnext; 3793 *frp = fr->fr_next; 3794 fr->fr_pnext = NULL; 3795 fr->fr_next = NULL; 3796 (void) ipf_derefrule(softc, &fr); 3797 flushed++; 3798 removed++; 3799 } 3800 } 3801 if (removed == 0) 3802 fgp = &fg->fg_next; 3803 } 3804 return flushed; 3805 } 3806 3807 3808 /* ------------------------------------------------------------------------ */ 3809 /* Function: memstr */ 3810 /* Returns: char * - NULL if failed, != NULL pointer to matching bytes */ 3811 /* Parameters: src(I) - pointer to byte sequence to match */ 3812 /* dst(I) - pointer to byte sequence to search */ 3813 /* slen(I) - match length */ 3814 /* dlen(I) - length available to search in */ 3815 /* */ 3816 /* Search dst for a sequence of bytes matching those at src and extend for */ 3817 /* slen bytes. */ 3818 /* ------------------------------------------------------------------------ */ 3819 char * 3820 memstr(const char *src, char *dst, size_t slen, size_t dlen) 3821 { 3822 char *s = NULL; 3823 3824 while (dlen >= slen) { 3825 if (memcmp(src, dst, slen) == 0) { 3826 s = dst; 3827 break; 3828 } 3829 dst++; 3830 dlen--; 3831 } 3832 return s; 3833 } 3834 3835 3836 /* ------------------------------------------------------------------------ */ 3837 /* Function: ipf_fixskip */ 3838 /* Returns: Nil */ 3839 /* Parameters: listp(IO) - pointer to start of list with skip rule */ 3840 /* rp(I) - rule added/removed with skip in it. */ 3841 /* addremove(I) - adjustment (-1/+1) to make to skip count, */ 3842 /* depending on whether a rule was just added */ 3843 /* or removed. */ 3844 /* */ 3845 /* Adjust all the rules in a list which would have skip'd past the position */ 3846 /* where we are inserting to skip to the right place given the change. */ 3847 /* ------------------------------------------------------------------------ */ 3848 void 3849 ipf_fixskip(frentry_t **listp, frentry_t *rp, int addremove) 3850 { 3851 int rules, rn; 3852 frentry_t *fp; 3853 3854 rules = 0; 3855 for (fp = *listp; (fp != NULL) && (fp != rp); fp = fp->fr_next) 3856 rules++; 3857 3858 if (!fp) 3859 return; 3860 3861 for (rn = 0, fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++) 3862 if (FR_ISSKIP(fp->fr_flags) && (rn + fp->fr_arg >= rules)) 3863 fp->fr_arg += addremove; 3864 } 3865 3866 3867 #ifdef _KERNEL 3868 /* ------------------------------------------------------------------------ */ 3869 /* Function: count4bits */ 3870 /* Returns: int - >= 0 - number of consecutive bits in input */ 3871 /* Parameters: ip(I) - 32bit IP address */ 3872 /* */ 3873 /* IPv4 ONLY */ 3874 /* count consecutive 1's in bit mask. If the mask generated by counting */ 3875 /* consecutive 1's is different to that passed, return -1, else return # */ 3876 /* of bits. */ 3877 /* ------------------------------------------------------------------------ */ 3878 int 3879 count4bits(u_32_t ip) 3880 { 3881 u_32_t ipn; 3882 int cnt = 0, i, j; 3883 3884 ip = ipn = ntohl(ip); 3885 for (i = 32; i; i--, ipn *= 2) 3886 if (ipn & 0x80000000) 3887 cnt++; 3888 else 3889 break; 3890 ipn = 0; 3891 for (i = 32, j = cnt; i; i--, j--) { 3892 ipn *= 2; 3893 if (j > 0) 3894 ipn++; 3895 } 3896 if (ipn == ip) 3897 return cnt; 3898 return -1; 3899 } 3900 3901 3902 /* ------------------------------------------------------------------------ */ 3903 /* Function: count6bits */ 3904 /* Returns: int - >= 0 - number of consecutive bits in input */ 3905 /* Parameters: msk(I) - pointer to start of IPv6 bitmask */ 3906 /* */ 3907 /* IPv6 ONLY */ 3908 /* count consecutive 1's in bit mask. */ 3909 /* ------------------------------------------------------------------------ */ 3910 # ifdef USE_INET6 3911 int 3912 count6bits(u_32_t *msk) 3913 { 3914 int i = 0, k; 3915 u_32_t j; 3916 3917 for (k = 3; k >= 0; k--) 3918 if (msk[k] == 0xffffffff) 3919 i += 32; 3920 else { 3921 for (j = msk[k]; j; j <<= 1) 3922 if (j & 0x80000000) 3923 i++; 3924 } 3925 return i; 3926 } 3927 # endif 3928 #endif /* _KERNEL */ 3929 3930 3931 /* ------------------------------------------------------------------------ */ 3932 /* Function: ipf_synclist */ 3933 /* Returns: int - 0 = no failures, else indication of first failure */ 3934 /* Parameters: fr(I) - start of filter list to sync interface names for */ 3935 /* ifp(I) - interface pointer for limiting sync lookups */ 3936 /* Write Locks: ipf_mutex */ 3937 /* */ 3938 /* Walk through a list of filter rules and resolve any interface names into */ 3939 /* pointers. Where dynamic addresses are used, also update the IP address */ 3940 /* used in the rule. The interface pointer is used to limit the lookups to */ 3941 /* a specific set of matching names if it is non-NULL. */ 3942 /* Errors can occur when resolving the destination name of to/dup-to fields */ 3943 /* when the name points to a pool and that pool doest not exist. If this */ 3944 /* does happen then it is necessary to check if there are any lookup refs */ 3945 /* that need to be dropped before returning with an error. */ 3946 /* ------------------------------------------------------------------------ */ 3947 static int 3948 ipf_synclist(ipf_main_softc_t *softc, frentry_t *fr, void *ifp) 3949 { 3950 frentry_t *frt, *start = fr; 3951 frdest_t *fdp; 3952 char *name; 3953 int error; 3954 void *ifa; 3955 int v, i; 3956 3957 error = 0; 3958 3959 for (; fr; fr = fr->fr_next) { 3960 if (fr->fr_family == AF_INET) 3961 v = 4; 3962 else if (fr->fr_family == AF_INET6) 3963 v = 6; 3964 else 3965 v = 0; 3966 3967 /* 3968 * Lookup all the interface names that are part of the rule. 3969 */ 3970 for (i = 0; i < 4; i++) { 3971 if ((ifp != NULL) && (fr->fr_ifas[i] != ifp)) 3972 continue; 3973 if (fr->fr_ifnames[i] == -1) 3974 continue; 3975 name = FR_NAME(fr, fr_ifnames[i]); 3976 fr->fr_ifas[i] = ipf_resolvenic(softc, name, v); 3977 } 3978 3979 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) { 3980 if (fr->fr_satype != FRI_NORMAL && 3981 fr->fr_satype != FRI_LOOKUP) { 3982 ifa = ipf_resolvenic(softc, fr->fr_names + 3983 fr->fr_sifpidx, v); 3984 ipf_ifpaddr(softc, v, fr->fr_satype, ifa, 3985 &fr->fr_src6, &fr->fr_smsk6); 3986 } 3987 if (fr->fr_datype != FRI_NORMAL && 3988 fr->fr_datype != FRI_LOOKUP) { 3989 ifa = ipf_resolvenic(softc, fr->fr_names + 3990 fr->fr_sifpidx, v); 3991 ipf_ifpaddr(softc, v, fr->fr_datype, ifa, 3992 &fr->fr_dst6, &fr->fr_dmsk6); 3993 } 3994 } 3995 3996 fdp = &fr->fr_tifs[0]; 3997 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) { 3998 error = ipf_resolvedest(softc, fr->fr_names, fdp, v); 3999 if (error != 0) 4000 goto unwind; 4001 } 4002 4003 fdp = &fr->fr_tifs[1]; 4004 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) { 4005 error = ipf_resolvedest(softc, fr->fr_names, fdp, v); 4006 if (error != 0) 4007 goto unwind; 4008 } 4009 4010 fdp = &fr->fr_dif; 4011 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) { 4012 error = ipf_resolvedest(softc, fr->fr_names, fdp, v); 4013 if (error != 0) 4014 goto unwind; 4015 } 4016 4017 if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 4018 (fr->fr_satype == FRI_LOOKUP) && (fr->fr_srcptr == NULL)) { 4019 fr->fr_srcptr = ipf_lookup_res_num(softc, 4020 fr->fr_srctype, 4021 IPL_LOGIPF, 4022 fr->fr_srcnum, 4023 &fr->fr_srcfunc); 4024 } 4025 if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 4026 (fr->fr_datype == FRI_LOOKUP) && (fr->fr_dstptr == NULL)) { 4027 fr->fr_dstptr = ipf_lookup_res_num(softc, 4028 fr->fr_dsttype, 4029 IPL_LOGIPF, 4030 fr->fr_dstnum, 4031 &fr->fr_dstfunc); 4032 } 4033 } 4034 return 0; 4035 4036 unwind: 4037 for (frt = start; frt != fr; fr = fr->fr_next) { 4038 if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 4039 (frt->fr_satype == FRI_LOOKUP) && (frt->fr_srcptr != NULL)) 4040 ipf_lookup_deref(softc, frt->fr_srctype, 4041 frt->fr_srcptr); 4042 if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 4043 (frt->fr_datype == FRI_LOOKUP) && (frt->fr_dstptr != NULL)) 4044 ipf_lookup_deref(softc, frt->fr_dsttype, 4045 frt->fr_dstptr); 4046 } 4047 return error; 4048 } 4049 4050 4051 /* ------------------------------------------------------------------------ */ 4052 /* Function: ipf_sync */ 4053 /* Returns: void */ 4054 /* Parameters: Nil */ 4055 /* */ 4056 /* ipf_sync() is called when we suspect that the interface list or */ 4057 /* information about interfaces (like IP#) has changed. Go through all */ 4058 /* filter rules, NAT entries and the state table and check if anything */ 4059 /* needs to be changed/updated. */ 4060 /* ------------------------------------------------------------------------ */ 4061 int 4062 ipf_sync(ipf_main_softc_t *softc, void *ifp) 4063 { 4064 int i; 4065 4066 # if !SOLARIS 4067 ipf_nat_sync(softc, ifp); 4068 ipf_state_sync(softc, ifp); 4069 ipf_lookup_sync(softc, ifp); 4070 # endif 4071 4072 WRITE_ENTER(&softc->ipf_mutex); 4073 (void) ipf_synclist(softc, softc->ipf_acct[0][softc->ipf_active], ifp); 4074 (void) ipf_synclist(softc, softc->ipf_acct[1][softc->ipf_active], ifp); 4075 (void) ipf_synclist(softc, softc->ipf_rules[0][softc->ipf_active], ifp); 4076 (void) ipf_synclist(softc, softc->ipf_rules[1][softc->ipf_active], ifp); 4077 4078 for (i = 0; i < IPL_LOGSIZE; i++) { 4079 frgroup_t *g; 4080 4081 for (g = softc->ipf_groups[i][0]; g != NULL; g = g->fg_next) 4082 (void) ipf_synclist(softc, g->fg_start, ifp); 4083 for (g = softc->ipf_groups[i][1]; g != NULL; g = g->fg_next) 4084 (void) ipf_synclist(softc, g->fg_start, ifp); 4085 } 4086 RWLOCK_EXIT(&softc->ipf_mutex); 4087 4088 return 0; 4089 } 4090 4091 4092 /* 4093 * In the functions below, bcopy() is called because the pointer being 4094 * copied _from_ in this instance is a pointer to a char buf (which could 4095 * end up being unaligned) and on the kernel's local stack. 4096 */ 4097 /* ------------------------------------------------------------------------ */ 4098 /* Function: copyinptr */ 4099 /* Returns: int - 0 = success, else failure */ 4100 /* Parameters: src(I) - pointer to the source address */ 4101 /* dst(I) - destination address */ 4102 /* size(I) - number of bytes to copy */ 4103 /* */ 4104 /* Copy a block of data in from user space, given a pointer to the pointer */ 4105 /* to start copying from (src) and a pointer to where to store it (dst). */ 4106 /* NB: src - pointer to user space pointer, dst - kernel space pointer */ 4107 /* ------------------------------------------------------------------------ */ 4108 int 4109 copyinptr(ipf_main_softc_t *softc, void *src, void *dst, size_t size) 4110 { 4111 void *ca; 4112 int error; 4113 4114 # if SOLARIS 4115 error = COPYIN(src, &ca, sizeof(ca)); 4116 if (error != 0) 4117 return error; 4118 # else 4119 bcopy(src, (void *)&ca, sizeof(ca)); 4120 # endif 4121 error = COPYIN(ca, dst, size); 4122 if (error != 0) { 4123 IPFERROR(3); 4124 error = EFAULT; 4125 } 4126 return error; 4127 } 4128 4129 4130 /* ------------------------------------------------------------------------ */ 4131 /* Function: copyoutptr */ 4132 /* Returns: int - 0 = success, else failure */ 4133 /* Parameters: src(I) - pointer to the source address */ 4134 /* dst(I) - destination address */ 4135 /* size(I) - number of bytes to copy */ 4136 /* */ 4137 /* Copy a block of data out to user space, given a pointer to the pointer */ 4138 /* to start copying from (src) and a pointer to where to store it (dst). */ 4139 /* NB: src - kernel space pointer, dst - pointer to user space pointer. */ 4140 /* ------------------------------------------------------------------------ */ 4141 int 4142 copyoutptr(ipf_main_softc_t *softc, void *src, void *dst, size_t size) 4143 { 4144 void *ca; 4145 int error; 4146 4147 bcopy(dst, &ca, sizeof(ca)); 4148 error = COPYOUT(src, ca, size); 4149 if (error != 0) { 4150 IPFERROR(4); 4151 error = EFAULT; 4152 } 4153 return error; 4154 } 4155 #ifdef _KERNEL 4156 #endif 4157 4158 4159 /* ------------------------------------------------------------------------ */ 4160 /* Function: ipf_lock */ 4161 /* Returns: int - 0 = success, else error */ 4162 /* Parameters: data(I) - pointer to lock value to set */ 4163 /* lockp(O) - pointer to location to store old lock value */ 4164 /* */ 4165 /* Get the new value for the lock integer, set it and return the old value */ 4166 /* in *lockp. */ 4167 /* ------------------------------------------------------------------------ */ 4168 int 4169 ipf_lock(void *data, int *lockp) 4170 { 4171 int arg, err; 4172 4173 err = BCOPYIN(data, &arg, sizeof(arg)); 4174 if (err != 0) 4175 return EFAULT; 4176 err = BCOPYOUT(lockp, data, sizeof(*lockp)); 4177 if (err != 0) 4178 return EFAULT; 4179 *lockp = arg; 4180 return 0; 4181 } 4182 4183 4184 /* ------------------------------------------------------------------------ */ 4185 /* Function: ipf_getstat */ 4186 /* Returns: Nil */ 4187 /* Parameters: softc(I) - pointer to soft context main structure */ 4188 /* fiop(I) - pointer to ipfilter stats structure */ 4189 /* rev(I) - version claim by program doing ioctl */ 4190 /* */ 4191 /* Stores a copy of current pointers, counters, etc, in the friostat */ 4192 /* structure. */ 4193 /* If IPFILTER_COMPAT is compiled, we pretend to be whatever version the */ 4194 /* program is looking for. This ensure that validation of the version it */ 4195 /* expects will always succeed. Thus kernels with IPFILTER_COMPAT will */ 4196 /* allow older binaries to work but kernels without it will not. */ 4197 /* ------------------------------------------------------------------------ */ 4198 /*ARGSUSED*/ 4199 static void 4200 ipf_getstat(ipf_main_softc_t *softc, friostat_t *fiop, int rev) 4201 { 4202 int i; 4203 4204 bcopy((char *)softc->ipf_stats, (char *)fiop->f_st, 4205 sizeof(ipf_statistics_t) * 2); 4206 fiop->f_locks[IPL_LOGSTATE] = -1; 4207 fiop->f_locks[IPL_LOGNAT] = -1; 4208 fiop->f_locks[IPL_LOGIPF] = -1; 4209 fiop->f_locks[IPL_LOGAUTH] = -1; 4210 4211 fiop->f_ipf[0][0] = softc->ipf_rules[0][0]; 4212 fiop->f_acct[0][0] = softc->ipf_acct[0][0]; 4213 fiop->f_ipf[0][1] = softc->ipf_rules[0][1]; 4214 fiop->f_acct[0][1] = softc->ipf_acct[0][1]; 4215 fiop->f_ipf[1][0] = softc->ipf_rules[1][0]; 4216 fiop->f_acct[1][0] = softc->ipf_acct[1][0]; 4217 fiop->f_ipf[1][1] = softc->ipf_rules[1][1]; 4218 fiop->f_acct[1][1] = softc->ipf_acct[1][1]; 4219 4220 fiop->f_ticks = softc->ipf_ticks; 4221 fiop->f_active = softc->ipf_active; 4222 fiop->f_froute[0] = softc->ipf_frouteok[0]; 4223 fiop->f_froute[1] = softc->ipf_frouteok[1]; 4224 fiop->f_rb_no_mem = softc->ipf_rb_no_mem; 4225 fiop->f_rb_node_max = softc->ipf_rb_node_max; 4226 4227 fiop->f_running = softc->ipf_running; 4228 for (i = 0; i < IPL_LOGSIZE; i++) { 4229 fiop->f_groups[i][0] = softc->ipf_groups[i][0]; 4230 fiop->f_groups[i][1] = softc->ipf_groups[i][1]; 4231 } 4232 #ifdef IPFILTER_LOG 4233 fiop->f_log_ok = ipf_log_logok(softc, IPL_LOGIPF); 4234 fiop->f_log_fail = ipf_log_failures(softc, IPL_LOGIPF); 4235 fiop->f_logging = 1; 4236 #else 4237 fiop->f_log_ok = 0; 4238 fiop->f_log_fail = 0; 4239 fiop->f_logging = 0; 4240 #endif 4241 fiop->f_defpass = softc->ipf_pass; 4242 fiop->f_features = ipf_features; 4243 4244 #ifdef IPFILTER_COMPAT 4245 snprintf(fiop->f_version, sizeof(fiop->f_version), 4246 "IP Filter: v%d.%d.%d", (rev / 1000000) % 100, 4247 (rev / 10000) % 100, (rev / 100) % 100); 4248 #else 4249 rev = rev; 4250 (void) strncpy(fiop->f_version, ipfilter_version, 4251 sizeof(fiop->f_version)); 4252 fiop->f_version[sizeof(fiop->f_version) - 1] = '\0'; 4253 #endif 4254 } 4255 4256 4257 #ifdef USE_INET6 4258 int icmptoicmp6types[ICMP_MAXTYPE+1] = { 4259 ICMP6_ECHO_REPLY, /* 0: ICMP_ECHOREPLY */ 4260 -1, /* 1: UNUSED */ 4261 -1, /* 2: UNUSED */ 4262 ICMP6_DST_UNREACH, /* 3: ICMP_UNREACH */ 4263 -1, /* 4: ICMP_SOURCEQUENCH */ 4264 ND_REDIRECT, /* 5: ICMP_REDIRECT */ 4265 -1, /* 6: UNUSED */ 4266 -1, /* 7: UNUSED */ 4267 ICMP6_ECHO_REQUEST, /* 8: ICMP_ECHO */ 4268 -1, /* 9: UNUSED */ 4269 -1, /* 10: UNUSED */ 4270 ICMP6_TIME_EXCEEDED, /* 11: ICMP_TIMXCEED */ 4271 ICMP6_PARAM_PROB, /* 12: ICMP_PARAMPROB */ 4272 -1, /* 13: ICMP_TSTAMP */ 4273 -1, /* 14: ICMP_TSTAMPREPLY */ 4274 -1, /* 15: ICMP_IREQ */ 4275 -1, /* 16: ICMP_IREQREPLY */ 4276 -1, /* 17: ICMP_MASKREQ */ 4277 -1, /* 18: ICMP_MASKREPLY */ 4278 }; 4279 4280 4281 int icmptoicmp6unreach[ICMP_MAX_UNREACH] = { 4282 ICMP6_DST_UNREACH_ADDR, /* 0: ICMP_UNREACH_NET */ 4283 ICMP6_DST_UNREACH_ADDR, /* 1: ICMP_UNREACH_HOST */ 4284 -1, /* 2: ICMP_UNREACH_PROTOCOL */ 4285 ICMP6_DST_UNREACH_NOPORT, /* 3: ICMP_UNREACH_PORT */ 4286 -1, /* 4: ICMP_UNREACH_NEEDFRAG */ 4287 ICMP6_DST_UNREACH_NOTNEIGHBOR, /* 5: ICMP_UNREACH_SRCFAIL */ 4288 ICMP6_DST_UNREACH_ADDR, /* 6: ICMP_UNREACH_NET_UNKNOWN */ 4289 ICMP6_DST_UNREACH_ADDR, /* 7: ICMP_UNREACH_HOST_UNKNOWN */ 4290 -1, /* 8: ICMP_UNREACH_ISOLATED */ 4291 ICMP6_DST_UNREACH_ADMIN, /* 9: ICMP_UNREACH_NET_PROHIB */ 4292 ICMP6_DST_UNREACH_ADMIN, /* 10: ICMP_UNREACH_HOST_PROHIB */ 4293 -1, /* 11: ICMP_UNREACH_TOSNET */ 4294 -1, /* 12: ICMP_UNREACH_TOSHOST */ 4295 ICMP6_DST_UNREACH_ADMIN, /* 13: ICMP_UNREACH_ADMIN_PROHIBIT */ 4296 }; 4297 int icmpreplytype6[ICMP6_MAXTYPE + 1]; 4298 #endif 4299 4300 int icmpreplytype4[ICMP_MAXTYPE + 1]; 4301 4302 4303 /* ------------------------------------------------------------------------ */ 4304 /* Function: ipf_matchicmpqueryreply */ 4305 /* Returns: int - 1 if "icmp" is a valid reply to "ic" else 0. */ 4306 /* Parameters: v(I) - IP protocol version (4 or 6) */ 4307 /* ic(I) - ICMP information */ 4308 /* icmp(I) - ICMP packet header */ 4309 /* rev(I) - direction (0 = forward/1 = reverse) of packet */ 4310 /* */ 4311 /* Check if the ICMP packet defined by the header pointed to by icmp is a */ 4312 /* reply to one as described by what's in ic. If it is a match, return 1, */ 4313 /* else return 0 for no match. */ 4314 /* ------------------------------------------------------------------------ */ 4315 int 4316 ipf_matchicmpqueryreply(int v, icmpinfo_t *ic, icmphdr_t *icmp, int rev) 4317 { 4318 int ictype; 4319 4320 ictype = ic->ici_type; 4321 4322 if (v == 4) { 4323 /* 4324 * If we matched its type on the way in, then when going out 4325 * it will still be the same type. 4326 */ 4327 if ((!rev && (icmp->icmp_type == ictype)) || 4328 (rev && (icmpreplytype4[ictype] == icmp->icmp_type))) { 4329 if (icmp->icmp_type != ICMP_ECHOREPLY) 4330 return 1; 4331 if (icmp->icmp_id == ic->ici_id) 4332 return 1; 4333 } 4334 } 4335 #ifdef USE_INET6 4336 else if (v == 6) { 4337 if ((!rev && (icmp->icmp_type == ictype)) || 4338 (rev && (icmpreplytype6[ictype] == icmp->icmp_type))) { 4339 if (icmp->icmp_type != ICMP6_ECHO_REPLY) 4340 return 1; 4341 if (icmp->icmp_id == ic->ici_id) 4342 return 1; 4343 } 4344 } 4345 #endif 4346 return 0; 4347 } 4348 4349 /* ------------------------------------------------------------------------ */ 4350 /* Function: ipf_rule_compare */ 4351 /* Parameters: fr1(I) - first rule structure to compare */ 4352 /* fr2(I) - second rule structure to compare */ 4353 /* Returns: int - 0 == rules are the same, else mismatch */ 4354 /* */ 4355 /* Compare two rules and return 0 if they match or a number indicating */ 4356 /* which of the individual checks failed. */ 4357 /* ------------------------------------------------------------------------ */ 4358 static int 4359 ipf_rule_compare(frentry_t *fr1, frentry_t *fr2) 4360 { 4361 if (fr1->fr_cksum != fr2->fr_cksum) 4362 return 1; 4363 if (fr1->fr_size != fr2->fr_size) 4364 return 2; 4365 if (fr1->fr_dsize != fr2->fr_dsize) 4366 return 3; 4367 if (memcmp(&fr1->fr_func, &fr2->fr_func, 4368 fr1->fr_size - offsetof(struct frentry, fr_func)) != 0) 4369 return 4; 4370 if (fr1->fr_data && !fr2->fr_data) 4371 return 5; 4372 if (!fr1->fr_data && fr2->fr_data) 4373 return 6; 4374 if (fr1->fr_data) { 4375 if (memcmp(fr1->fr_caddr, fr2->fr_caddr, fr1->fr_dsize)) 4376 return 7; 4377 } 4378 return 0; 4379 } 4380 4381 4382 /* ------------------------------------------------------------------------ */ 4383 /* Function: frrequest */ 4384 /* Returns: int - 0 == success, > 0 == errno value */ 4385 /* Parameters: unit(I) - device for which this is for */ 4386 /* req(I) - ioctl command (SIOC*) */ 4387 /* data(I) - pointr to ioctl data */ 4388 /* set(I) - 1 or 0 (filter set) */ 4389 /* makecopy(I) - flag indicating whether data points to a rule */ 4390 /* in kernel space & hence doesn't need copying. */ 4391 /* */ 4392 /* This function handles all the requests which operate on the list of */ 4393 /* filter rules. This includes adding, deleting, insertion. It is also */ 4394 /* responsible for creating groups when a "head" rule is loaded. Interface */ 4395 /* names are resolved here and other sanity checks are made on the content */ 4396 /* of the rule structure being loaded. If a rule has user defined timeouts */ 4397 /* then make sure they are created and initialised before exiting. */ 4398 /* ------------------------------------------------------------------------ */ 4399 int 4400 frrequest(ipf_main_softc_t *softc, int unit, ioctlcmd_t req, void *data, 4401 int set, int makecopy) 4402 { 4403 int error = 0, in, family, addrem, need_free = 0; 4404 frentry_t frd, *fp, *f, **fprev, **ftail; 4405 void *ptr, *uptr; 4406 u_int *p, *pp; 4407 frgroup_t *fg; 4408 char *group; 4409 4410 ptr = NULL; 4411 fg = NULL; 4412 fp = &frd; 4413 if (makecopy != 0) { 4414 bzero(fp, sizeof(frd)); 4415 error = ipf_inobj(softc, data, NULL, fp, IPFOBJ_FRENTRY); 4416 if (error) { 4417 return error; 4418 } 4419 if ((fp->fr_type & FR_T_BUILTIN) != 0) { 4420 IPFERROR(6); 4421 return EINVAL; 4422 } 4423 KMALLOCS(f, frentry_t *, fp->fr_size); 4424 if (f == NULL) { 4425 IPFERROR(131); 4426 return ENOMEM; 4427 } 4428 bzero(f, fp->fr_size); 4429 error = ipf_inobjsz(softc, data, f, IPFOBJ_FRENTRY, 4430 fp->fr_size); 4431 if (error) { 4432 KFREES(f, fp->fr_size); 4433 return error; 4434 } 4435 4436 fp = f; 4437 f = NULL; 4438 fp->fr_next = NULL; 4439 fp->fr_dnext = NULL; 4440 fp->fr_pnext = NULL; 4441 fp->fr_pdnext = NULL; 4442 fp->fr_grp = NULL; 4443 fp->fr_grphead = NULL; 4444 fp->fr_icmpgrp = NULL; 4445 fp->fr_isc = (void *)-1; 4446 fp->fr_ptr = NULL; 4447 fp->fr_ref = 0; 4448 fp->fr_flags |= FR_COPIED; 4449 } else { 4450 fp = (frentry_t *)data; 4451 if ((fp->fr_type & FR_T_BUILTIN) == 0) { 4452 IPFERROR(7); 4453 return EINVAL; 4454 } 4455 fp->fr_flags &= ~FR_COPIED; 4456 } 4457 4458 if (((fp->fr_dsize == 0) && (fp->fr_data != NULL)) || 4459 ((fp->fr_dsize != 0) && (fp->fr_data == NULL))) { 4460 IPFERROR(8); 4461 error = EINVAL; 4462 goto donenolock; 4463 } 4464 4465 family = fp->fr_family; 4466 uptr = fp->fr_data; 4467 4468 if (req == (ioctlcmd_t)SIOCINAFR || req == (ioctlcmd_t)SIOCINIFR || 4469 req == (ioctlcmd_t)SIOCADAFR || req == (ioctlcmd_t)SIOCADIFR) 4470 addrem = 0; 4471 else if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR) 4472 addrem = 1; 4473 else if (req == (ioctlcmd_t)SIOCZRLST) 4474 addrem = 2; 4475 else { 4476 IPFERROR(9); 4477 error = EINVAL; 4478 goto donenolock; 4479 } 4480 4481 /* 4482 * Only filter rules for IPv4 or IPv6 are accepted. 4483 */ 4484 if (family == AF_INET) { 4485 /*EMPTY*/; 4486 #ifdef USE_INET6 4487 } else if (family == AF_INET6) { 4488 /*EMPTY*/; 4489 #endif 4490 } else if (family != 0) { 4491 IPFERROR(10); 4492 error = EINVAL; 4493 goto donenolock; 4494 } 4495 4496 /* 4497 * If the rule is being loaded from user space, i.e. we had to copy it 4498 * into kernel space, then do not trust the function pointer in the 4499 * rule. 4500 */ 4501 if ((makecopy == 1) && (fp->fr_func != NULL)) { 4502 if (ipf_findfunc(fp->fr_func) == NULL) { 4503 IPFERROR(11); 4504 error = ESRCH; 4505 goto donenolock; 4506 } 4507 4508 if (addrem == 0) { 4509 error = ipf_funcinit(softc, fp); 4510 if (error != 0) 4511 goto donenolock; 4512 } 4513 } 4514 if ((fp->fr_flags & FR_CALLNOW) && 4515 ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) { 4516 IPFERROR(142); 4517 error = ESRCH; 4518 goto donenolock; 4519 } 4520 if (((fp->fr_flags & FR_CMDMASK) == FR_CALL) && 4521 ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) { 4522 IPFERROR(143); 4523 error = ESRCH; 4524 goto donenolock; 4525 } 4526 4527 ptr = NULL; 4528 4529 if (FR_ISACCOUNT(fp->fr_flags)) 4530 unit = IPL_LOGCOUNT; 4531 4532 /* 4533 * Check that each group name in the rule has a start index that 4534 * is valid. 4535 */ 4536 if (fp->fr_icmphead != -1) { 4537 if ((fp->fr_icmphead < 0) || 4538 (fp->fr_icmphead >= fp->fr_namelen)) { 4539 IPFERROR(136); 4540 error = EINVAL; 4541 goto donenolock; 4542 } 4543 if (!strcmp(FR_NAME(fp, fr_icmphead), "0")) 4544 fp->fr_names[fp->fr_icmphead] = '\0'; 4545 } 4546 4547 if (fp->fr_grhead != -1) { 4548 if ((fp->fr_grhead < 0) || 4549 (fp->fr_grhead >= fp->fr_namelen)) { 4550 IPFERROR(137); 4551 error = EINVAL; 4552 goto donenolock; 4553 } 4554 if (!strcmp(FR_NAME(fp, fr_grhead), "0")) 4555 fp->fr_names[fp->fr_grhead] = '\0'; 4556 } 4557 4558 if (fp->fr_group != -1) { 4559 if ((fp->fr_group < 0) || 4560 (fp->fr_group >= fp->fr_namelen)) { 4561 IPFERROR(138); 4562 error = EINVAL; 4563 goto donenolock; 4564 } 4565 if ((req != (int)SIOCZRLST) && (fp->fr_group != -1)) { 4566 /* 4567 * Allow loading rules that are in groups to cause 4568 * them to be created if they don't already exit. 4569 */ 4570 group = FR_NAME(fp, fr_group); 4571 if (addrem == 0) { 4572 fg = ipf_group_add(softc, group, NULL, 4573 fp->fr_flags, unit, set); 4574 if (fg == NULL) { 4575 IPFERROR(152); 4576 error = ESRCH; 4577 goto donenolock; 4578 } 4579 fp->fr_grp = fg; 4580 } else { 4581 fg = ipf_findgroup(softc, group, unit, 4582 set, NULL); 4583 if (fg == NULL) { 4584 IPFERROR(12); 4585 error = ESRCH; 4586 goto donenolock; 4587 } 4588 } 4589 4590 if (fg->fg_flags == 0) { 4591 fg->fg_flags = fp->fr_flags & FR_INOUT; 4592 } else if (fg->fg_flags != (fp->fr_flags & FR_INOUT)) { 4593 IPFERROR(13); 4594 error = ESRCH; 4595 goto donenolock; 4596 } 4597 } 4598 } else { 4599 /* 4600 * If a rule is going to be part of a group then it does 4601 * not matter whether it is an in or out rule, but if it 4602 * isn't in a group, then it does... 4603 */ 4604 if ((fp->fr_flags & (FR_INQUE|FR_OUTQUE)) == 0) { 4605 IPFERROR(14); 4606 error = EINVAL; 4607 goto donenolock; 4608 } 4609 } 4610 in = (fp->fr_flags & FR_INQUE) ? 0 : 1; 4611 4612 /* 4613 * Work out which rule list this change is being applied to. 4614 */ 4615 ftail = NULL; 4616 fprev = NULL; 4617 if (unit == IPL_LOGAUTH) { 4618 if ((fp->fr_tifs[0].fd_ptr != NULL) || 4619 (fp->fr_tifs[1].fd_ptr != NULL) || 4620 (fp->fr_dif.fd_ptr != NULL) || 4621 (fp->fr_flags & FR_FASTROUTE)) { 4622 IPFERROR(145); 4623 error = EINVAL; 4624 goto donenolock; 4625 } 4626 fprev = ipf_auth_rulehead(softc); 4627 } else { 4628 if (FR_ISACCOUNT(fp->fr_flags)) 4629 fprev = &softc->ipf_acct[in][set]; 4630 else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0) 4631 fprev = &softc->ipf_rules[in][set]; 4632 } 4633 if (fprev == NULL) { 4634 IPFERROR(15); 4635 error = ESRCH; 4636 goto donenolock; 4637 } 4638 4639 if (fg != NULL) 4640 fprev = &fg->fg_start; 4641 4642 /* 4643 * Copy in extra data for the rule. 4644 */ 4645 if (fp->fr_dsize != 0) { 4646 if (makecopy != 0) { 4647 KMALLOCS(ptr, void *, fp->fr_dsize); 4648 if (ptr == NULL) { 4649 IPFERROR(16); 4650 error = ENOMEM; 4651 goto donenolock; 4652 } 4653 4654 /* 4655 * The bcopy case is for when the data is appended 4656 * to the rule by ipf_in_compat(). 4657 */ 4658 if (uptr >= (void *)fp && 4659 uptr < (void *)((char *)fp + fp->fr_size)) { 4660 bcopy(uptr, ptr, fp->fr_dsize); 4661 error = 0; 4662 } else { 4663 error = COPYIN(uptr, ptr, fp->fr_dsize); 4664 if (error != 0) { 4665 IPFERROR(17); 4666 error = EFAULT; 4667 goto donenolock; 4668 } 4669 } 4670 } else { 4671 ptr = uptr; 4672 } 4673 fp->fr_data = ptr; 4674 } else { 4675 fp->fr_data = NULL; 4676 } 4677 4678 /* 4679 * Perform per-rule type sanity checks of their members. 4680 * All code after this needs to be aware that allocated memory 4681 * may need to be free'd before exiting. 4682 */ 4683 switch (fp->fr_type & ~FR_T_BUILTIN) 4684 { 4685 #if defined(IPFILTER_BPF) 4686 case FR_T_BPFOPC : 4687 if (fp->fr_dsize == 0) { 4688 IPFERROR(19); 4689 error = EINVAL; 4690 break; 4691 } 4692 if (!bpf_validate(ptr, fp->fr_dsize/sizeof(struct bpf_insn))) { 4693 IPFERROR(20); 4694 error = EINVAL; 4695 break; 4696 } 4697 break; 4698 #endif 4699 case FR_T_IPF : 4700 /* 4701 * Preparation for error case at the bottom of this function. 4702 */ 4703 if (fp->fr_datype == FRI_LOOKUP) 4704 fp->fr_dstptr = NULL; 4705 if (fp->fr_satype == FRI_LOOKUP) 4706 fp->fr_srcptr = NULL; 4707 4708 if (fp->fr_dsize != sizeof(fripf_t)) { 4709 IPFERROR(21); 4710 error = EINVAL; 4711 break; 4712 } 4713 4714 /* 4715 * Allowing a rule with both "keep state" and "with oow" is 4716 * pointless because adding a state entry to the table will 4717 * fail with the out of window (oow) flag set. 4718 */ 4719 if ((fp->fr_flags & FR_KEEPSTATE) && (fp->fr_flx & FI_OOW)) { 4720 IPFERROR(22); 4721 error = EINVAL; 4722 break; 4723 } 4724 4725 switch (fp->fr_satype) 4726 { 4727 case FRI_BROADCAST : 4728 case FRI_DYNAMIC : 4729 case FRI_NETWORK : 4730 case FRI_NETMASKED : 4731 case FRI_PEERADDR : 4732 if (fp->fr_sifpidx < 0) { 4733 IPFERROR(23); 4734 error = EINVAL; 4735 } 4736 break; 4737 case FRI_LOOKUP : 4738 fp->fr_srcptr = ipf_findlookup(softc, unit, fp, 4739 &fp->fr_src6, 4740 &fp->fr_smsk6); 4741 if (fp->fr_srcfunc == NULL) { 4742 IPFERROR(132); 4743 error = ESRCH; 4744 break; 4745 } 4746 break; 4747 case FRI_NORMAL : 4748 break; 4749 default : 4750 IPFERROR(133); 4751 error = EINVAL; 4752 break; 4753 } 4754 if (error != 0) 4755 break; 4756 4757 switch (fp->fr_datype) 4758 { 4759 case FRI_BROADCAST : 4760 case FRI_DYNAMIC : 4761 case FRI_NETWORK : 4762 case FRI_NETMASKED : 4763 case FRI_PEERADDR : 4764 if (fp->fr_difpidx < 0) { 4765 IPFERROR(24); 4766 error = EINVAL; 4767 } 4768 break; 4769 case FRI_LOOKUP : 4770 fp->fr_dstptr = ipf_findlookup(softc, unit, fp, 4771 &fp->fr_dst6, 4772 &fp->fr_dmsk6); 4773 if (fp->fr_dstfunc == NULL) { 4774 IPFERROR(134); 4775 error = ESRCH; 4776 } 4777 break; 4778 case FRI_NORMAL : 4779 break; 4780 default : 4781 IPFERROR(135); 4782 error = EINVAL; 4783 } 4784 break; 4785 4786 case FR_T_NONE : 4787 case FR_T_CALLFUNC : 4788 case FR_T_COMPIPF : 4789 break; 4790 4791 case FR_T_IPFEXPR : 4792 if (ipf_matcharray_verify(fp->fr_data, fp->fr_dsize) == -1) { 4793 IPFERROR(25); 4794 error = EINVAL; 4795 } 4796 break; 4797 4798 default : 4799 IPFERROR(26); 4800 error = EINVAL; 4801 break; 4802 } 4803 if (error != 0) 4804 goto donenolock; 4805 4806 if (fp->fr_tif.fd_name != -1) { 4807 if ((fp->fr_tif.fd_name < 0) || 4808 (fp->fr_tif.fd_name >= fp->fr_namelen)) { 4809 IPFERROR(139); 4810 error = EINVAL; 4811 goto donenolock; 4812 } 4813 } 4814 4815 if (fp->fr_dif.fd_name != -1) { 4816 if ((fp->fr_dif.fd_name < 0) || 4817 (fp->fr_dif.fd_name >= fp->fr_namelen)) { 4818 IPFERROR(140); 4819 error = EINVAL; 4820 goto donenolock; 4821 } 4822 } 4823 4824 if (fp->fr_rif.fd_name != -1) { 4825 if ((fp->fr_rif.fd_name < 0) || 4826 (fp->fr_rif.fd_name >= fp->fr_namelen)) { 4827 IPFERROR(141); 4828 error = EINVAL; 4829 goto donenolock; 4830 } 4831 } 4832 4833 /* 4834 * Lookup all the interface names that are part of the rule. 4835 */ 4836 error = ipf_synclist(softc, fp, NULL); 4837 if (error != 0) 4838 goto donenolock; 4839 fp->fr_statecnt = 0; 4840 if (fp->fr_srctrack.ht_max_nodes != 0) 4841 ipf_rb_ht_init(&fp->fr_srctrack); 4842 4843 /* 4844 * Look for an existing matching filter rule, but don't include the 4845 * next or interface pointer in the comparison (fr_next, fr_ifa). 4846 * This elminates rules which are indentical being loaded. Checksum 4847 * the constant part of the filter rule to make comparisons quicker 4848 * (this meaning no pointers are included). 4849 */ 4850 for (fp->fr_cksum = 0, p = (u_int *)&fp->fr_func, pp = &fp->fr_cksum; 4851 p < pp; p++) 4852 fp->fr_cksum += *p; 4853 pp = (u_int *)((char *)fp->fr_caddr + fp->fr_dsize); 4854 for (p = (u_int *)fp->fr_data; p < pp; p++) 4855 fp->fr_cksum += *p; 4856 4857 WRITE_ENTER(&softc->ipf_mutex); 4858 4859 /* 4860 * Now that the filter rule lists are locked, we can walk the 4861 * chain of them without fear. 4862 */ 4863 ftail = fprev; 4864 for (f = *ftail; (f = *ftail) != NULL; ftail = &f->fr_next) { 4865 if (fp->fr_collect <= f->fr_collect) { 4866 ftail = fprev; 4867 f = NULL; 4868 break; 4869 } 4870 fprev = ftail; 4871 } 4872 4873 for (; (f = *ftail) != NULL; ftail = &f->fr_next) { 4874 DT2(rule_cmp, frentry_t *, fp, frentry_t *, f); 4875 if (ipf_rule_compare(fp, f) == 0) 4876 break; 4877 } 4878 4879 /* 4880 * If zero'ing statistics, copy current to caller and zero. 4881 */ 4882 if (addrem == 2) { 4883 if (f == NULL) { 4884 IPFERROR(27); 4885 error = ESRCH; 4886 } else { 4887 /* 4888 * Copy and reduce lock because of impending copyout. 4889 * Well we should, but if we do then the atomicity of 4890 * this call and the correctness of fr_hits and 4891 * fr_bytes cannot be guaranteed. As it is, this code 4892 * only resets them to 0 if they are successfully 4893 * copied out into user space. 4894 */ 4895 bcopy((char *)f, (char *)fp, f->fr_size); 4896 /* MUTEX_DOWNGRADE(&softc->ipf_mutex); */ 4897 4898 /* 4899 * When we copy this rule back out, set the data 4900 * pointer to be what it was in user space. 4901 */ 4902 fp->fr_data = uptr; 4903 error = ipf_outobj(softc, data, fp, IPFOBJ_FRENTRY); 4904 4905 if (error == 0) { 4906 if ((f->fr_dsize != 0) && (uptr != NULL)) { 4907 error = COPYOUT(f->fr_data, uptr, 4908 f->fr_dsize); 4909 if (error != 0) { 4910 IPFERROR(28); 4911 error = EFAULT; 4912 } 4913 } 4914 if (error == 0) { 4915 f->fr_hits = 0; 4916 f->fr_bytes = 0; 4917 } 4918 } 4919 } 4920 4921 if (makecopy != 0) { 4922 if (ptr != NULL) { 4923 KFREES(ptr, fp->fr_dsize); 4924 } 4925 KFREES(fp, fp->fr_size); 4926 } 4927 RWLOCK_EXIT(&softc->ipf_mutex); 4928 return error; 4929 } 4930 4931 if (!f) { 4932 /* 4933 * At the end of this, ftail must point to the place where the 4934 * new rule is to be saved/inserted/added. 4935 * For SIOCAD*FR, this should be the last rule in the group of 4936 * rules that have equal fr_collect fields. 4937 * For SIOCIN*FR, ... 4938 */ 4939 if (req == (ioctlcmd_t)SIOCADAFR || 4940 req == (ioctlcmd_t)SIOCADIFR) { 4941 4942 for (ftail = fprev; (f = *ftail) != NULL; ) { 4943 if (f->fr_collect > fp->fr_collect) 4944 break; 4945 ftail = &f->fr_next; 4946 fprev = ftail; 4947 } 4948 ftail = fprev; 4949 f = NULL; 4950 ptr = NULL; 4951 } else if (req == (ioctlcmd_t)SIOCINAFR || 4952 req == (ioctlcmd_t)SIOCINIFR) { 4953 while ((f = *fprev) != NULL) { 4954 if (f->fr_collect >= fp->fr_collect) 4955 break; 4956 fprev = &f->fr_next; 4957 } 4958 ftail = fprev; 4959 if (fp->fr_hits != 0) { 4960 while (fp->fr_hits && (f = *ftail)) { 4961 if (f->fr_collect != fp->fr_collect) 4962 break; 4963 fprev = ftail; 4964 ftail = &f->fr_next; 4965 fp->fr_hits--; 4966 } 4967 } 4968 f = NULL; 4969 ptr = NULL; 4970 } 4971 } 4972 4973 /* 4974 * Request to remove a rule. 4975 */ 4976 if (addrem == 1) { 4977 if (!f) { 4978 IPFERROR(29); 4979 error = ESRCH; 4980 } else { 4981 /* 4982 * Do not allow activity from user space to interfere 4983 * with rules not loaded that way. 4984 */ 4985 if ((makecopy == 1) && !(f->fr_flags & FR_COPIED)) { 4986 IPFERROR(30); 4987 error = EPERM; 4988 goto done; 4989 } 4990 4991 /* 4992 * Return EBUSY if the rule is being reference by 4993 * something else (eg state information.) 4994 */ 4995 if (f->fr_ref > 1) { 4996 IPFERROR(31); 4997 error = EBUSY; 4998 goto done; 4999 } 5000 #ifdef IPFILTER_SCAN 5001 if (f->fr_isctag != -1 && 5002 (f->fr_isc != (struct ipscan *)-1)) 5003 ipf_scan_detachfr(f); 5004 #endif 5005 5006 if (unit == IPL_LOGAUTH) { 5007 error = ipf_auth_precmd(softc, req, f, ftail); 5008 goto done; 5009 } 5010 5011 ipf_rule_delete(softc, f, unit, set); 5012 5013 need_free = makecopy; 5014 } 5015 } else { 5016 /* 5017 * Not removing, so we must be adding/inserting a rule. 5018 */ 5019 if (f != NULL) { 5020 IPFERROR(32); 5021 error = EEXIST; 5022 goto done; 5023 } 5024 if (unit == IPL_LOGAUTH) { 5025 error = ipf_auth_precmd(softc, req, fp, ftail); 5026 goto done; 5027 } 5028 5029 MUTEX_NUKE(&fp->fr_lock); 5030 MUTEX_INIT(&fp->fr_lock, "filter rule lock"); 5031 if (fp->fr_die != 0) 5032 ipf_rule_expire_insert(softc, fp, set); 5033 5034 fp->fr_hits = 0; 5035 if (makecopy != 0) 5036 fp->fr_ref = 1; 5037 fp->fr_pnext = ftail; 5038 fp->fr_next = *ftail; 5039 if (fp->fr_next != NULL) 5040 fp->fr_next->fr_pnext = &fp->fr_next; 5041 *ftail = fp; 5042 if (addrem == 0) 5043 ipf_fixskip(ftail, fp, 1); 5044 5045 fp->fr_icmpgrp = NULL; 5046 if (fp->fr_icmphead != -1) { 5047 group = FR_NAME(fp, fr_icmphead); 5048 fg = ipf_group_add(softc, group, fp, 0, unit, set); 5049 fp->fr_icmpgrp = fg; 5050 } 5051 5052 fp->fr_grphead = NULL; 5053 if (fp->fr_grhead != -1) { 5054 group = FR_NAME(fp, fr_grhead); 5055 fg = ipf_group_add(softc, group, fp, fp->fr_flags, 5056 unit, set); 5057 fp->fr_grphead = fg; 5058 } 5059 } 5060 done: 5061 RWLOCK_EXIT(&softc->ipf_mutex); 5062 donenolock: 5063 if (need_free || (error != 0)) { 5064 if ((fp->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) { 5065 if ((fp->fr_satype == FRI_LOOKUP) && 5066 (fp->fr_srcptr != NULL)) 5067 ipf_lookup_deref(softc, fp->fr_srctype, 5068 fp->fr_srcptr); 5069 if ((fp->fr_datype == FRI_LOOKUP) && 5070 (fp->fr_dstptr != NULL)) 5071 ipf_lookup_deref(softc, fp->fr_dsttype, 5072 fp->fr_dstptr); 5073 } 5074 if (fp->fr_grp != NULL) { 5075 WRITE_ENTER(&softc->ipf_mutex); 5076 ipf_group_del(softc, fp->fr_grp, fp); 5077 RWLOCK_EXIT(&softc->ipf_mutex); 5078 } 5079 if ((ptr != NULL) && (makecopy != 0)) { 5080 KFREES(ptr, fp->fr_dsize); 5081 } 5082 KFREES(fp, fp->fr_size); 5083 } 5084 return (error); 5085 } 5086 5087 5088 /* ------------------------------------------------------------------------ */ 5089 /* Function: ipf_rule_delete */ 5090 /* Returns: Nil */ 5091 /* Parameters: softc(I) - pointer to soft context main structure */ 5092 /* f(I) - pointer to the rule being deleted */ 5093 /* ftail(I) - pointer to the pointer to f */ 5094 /* unit(I) - device for which this is for */ 5095 /* set(I) - 1 or 0 (filter set) */ 5096 /* */ 5097 /* This function attempts to do what it can to delete a filter rule: remove */ 5098 /* it from any linked lists and remove any groups it is responsible for. */ 5099 /* But in the end, removing a rule can only drop the reference count - we */ 5100 /* must use that as the guide for whether or not it can be freed. */ 5101 /* ------------------------------------------------------------------------ */ 5102 static void 5103 ipf_rule_delete(ipf_main_softc_t *softc, frentry_t *f, int unit, int set) 5104 { 5105 5106 /* 5107 * If fr_pdnext is set, then the rule is on the expire list, so 5108 * remove it from there. 5109 */ 5110 if (f->fr_pdnext != NULL) { 5111 *f->fr_pdnext = f->fr_dnext; 5112 if (f->fr_dnext != NULL) 5113 f->fr_dnext->fr_pdnext = f->fr_pdnext; 5114 f->fr_pdnext = NULL; 5115 f->fr_dnext = NULL; 5116 } 5117 5118 ipf_fixskip(f->fr_pnext, f, -1); 5119 if (f->fr_pnext != NULL) 5120 *f->fr_pnext = f->fr_next; 5121 if (f->fr_next != NULL) 5122 f->fr_next->fr_pnext = f->fr_pnext; 5123 f->fr_pnext = NULL; 5124 f->fr_next = NULL; 5125 5126 (void) ipf_derefrule(softc, &f); 5127 } 5128 5129 /* ------------------------------------------------------------------------ */ 5130 /* Function: ipf_rule_expire_insert */ 5131 /* Returns: Nil */ 5132 /* Parameters: softc(I) - pointer to soft context main structure */ 5133 /* f(I) - pointer to rule to be added to expire list */ 5134 /* set(I) - 1 or 0 (filter set) */ 5135 /* */ 5136 /* If the new rule has a given expiration time, insert it into the list of */ 5137 /* expiring rules with the ones to be removed first added to the front of */ 5138 /* the list. The insertion is O(n) but it is kept sorted for quick scans at */ 5139 /* expiration interval checks. */ 5140 /* ------------------------------------------------------------------------ */ 5141 static void 5142 ipf_rule_expire_insert(ipf_main_softc_t *softc, frentry_t *f, int set) 5143 { 5144 frentry_t *fr; 5145 5146 /* 5147 */ 5148 5149 f->fr_die = softc->ipf_ticks + IPF_TTLVAL(f->fr_die); 5150 for (fr = softc->ipf_rule_explist[set]; fr != NULL; 5151 fr = fr->fr_dnext) { 5152 if (f->fr_die < fr->fr_die) 5153 break; 5154 if (fr->fr_dnext == NULL) { 5155 /* 5156 * We've got to the last rule and everything 5157 * wanted to be expired before this new node, 5158 * so we have to tack it on the end... 5159 */ 5160 fr->fr_dnext = f; 5161 f->fr_pdnext = &fr->fr_dnext; 5162 fr = NULL; 5163 break; 5164 } 5165 } 5166 5167 if (softc->ipf_rule_explist[set] == NULL) { 5168 softc->ipf_rule_explist[set] = f; 5169 f->fr_pdnext = &softc->ipf_rule_explist[set]; 5170 } else if (fr != NULL) { 5171 f->fr_dnext = fr; 5172 f->fr_pdnext = fr->fr_pdnext; 5173 fr->fr_pdnext = &f->fr_dnext; 5174 } 5175 } 5176 5177 5178 /* ------------------------------------------------------------------------ */ 5179 /* Function: ipf_findlookup */ 5180 /* Returns: NULL = failure, else success */ 5181 /* Parameters: softc(I) - pointer to soft context main structure */ 5182 /* unit(I) - ipf device we want to find match for */ 5183 /* fp(I) - rule for which lookup is for */ 5184 /* addrp(I) - pointer to lookup information in address struct */ 5185 /* maskp(O) - pointer to lookup information for storage */ 5186 /* */ 5187 /* When using pools and hash tables to store addresses for matching in */ 5188 /* rules, it is necessary to resolve both the object referred to by the */ 5189 /* name or address (and return that pointer) and also provide the means by */ 5190 /* which to determine if an address belongs to that object to make the */ 5191 /* packet matching quicker. */ 5192 /* ------------------------------------------------------------------------ */ 5193 static void * 5194 ipf_findlookup(ipf_main_softc_t *softc, int unit, frentry_t *fr, 5195 i6addr_t *addrp, i6addr_t *maskp) 5196 { 5197 void *ptr = NULL; 5198 5199 switch (addrp->iplookupsubtype) 5200 { 5201 case 0 : 5202 ptr = ipf_lookup_res_num(softc, unit, addrp->iplookuptype, 5203 addrp->iplookupnum, 5204 &maskp->iplookupfunc); 5205 break; 5206 case 1 : 5207 if (addrp->iplookupname < 0) 5208 break; 5209 if (addrp->iplookupname >= fr->fr_namelen) 5210 break; 5211 ptr = ipf_lookup_res_name(softc, unit, addrp->iplookuptype, 5212 fr->fr_names + addrp->iplookupname, 5213 &maskp->iplookupfunc); 5214 break; 5215 default : 5216 break; 5217 } 5218 5219 return ptr; 5220 } 5221 5222 5223 /* ------------------------------------------------------------------------ */ 5224 /* Function: ipf_funcinit */ 5225 /* Returns: int - 0 == success, else ESRCH: cannot resolve rule details */ 5226 /* Parameters: softc(I) - pointer to soft context main structure */ 5227 /* fr(I) - pointer to filter rule */ 5228 /* */ 5229 /* If a rule is a call rule, then check if the function it points to needs */ 5230 /* an init function to be called now the rule has been loaded. */ 5231 /* ------------------------------------------------------------------------ */ 5232 static int 5233 ipf_funcinit(ipf_main_softc_t *softc, frentry_t *fr) 5234 { 5235 ipfunc_resolve_t *ft; 5236 int err; 5237 5238 IPFERROR(34); 5239 err = ESRCH; 5240 5241 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5242 if (ft->ipfu_addr == fr->fr_func) { 5243 err = 0; 5244 if (ft->ipfu_init != NULL) 5245 err = (*ft->ipfu_init)(softc, fr); 5246 break; 5247 } 5248 return err; 5249 } 5250 5251 5252 /* ------------------------------------------------------------------------ */ 5253 /* Function: ipf_funcfini */ 5254 /* Returns: Nil */ 5255 /* Parameters: softc(I) - pointer to soft context main structure */ 5256 /* fr(I) - pointer to filter rule */ 5257 /* */ 5258 /* For a given filter rule, call the matching "fini" function if the rule */ 5259 /* is using a known function that would have resulted in the "init" being */ 5260 /* called for ealier. */ 5261 /* ------------------------------------------------------------------------ */ 5262 static void 5263 ipf_funcfini(ipf_main_softc_t *softc, frentry_t *fr) 5264 { 5265 ipfunc_resolve_t *ft; 5266 5267 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5268 if (ft->ipfu_addr == fr->fr_func) { 5269 if (ft->ipfu_fini != NULL) 5270 (void) (*ft->ipfu_fini)(softc, fr); 5271 break; 5272 } 5273 } 5274 5275 5276 /* ------------------------------------------------------------------------ */ 5277 /* Function: ipf_findfunc */ 5278 /* Returns: ipfunc_t - pointer to function if found, else NULL */ 5279 /* Parameters: funcptr(I) - function pointer to lookup */ 5280 /* */ 5281 /* Look for a function in the table of known functions. */ 5282 /* ------------------------------------------------------------------------ */ 5283 static ipfunc_t 5284 ipf_findfunc(ipfunc_t funcptr) 5285 { 5286 ipfunc_resolve_t *ft; 5287 5288 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5289 if (ft->ipfu_addr == funcptr) 5290 return funcptr; 5291 return NULL; 5292 } 5293 5294 5295 /* ------------------------------------------------------------------------ */ 5296 /* Function: ipf_resolvefunc */ 5297 /* Returns: int - 0 == success, else error */ 5298 /* Parameters: data(IO) - ioctl data pointer to ipfunc_resolve_t struct */ 5299 /* */ 5300 /* Copy in a ipfunc_resolve_t structure and then fill in the missing field. */ 5301 /* This will either be the function name (if the pointer is set) or the */ 5302 /* function pointer if the name is set. When found, fill in the other one */ 5303 /* so that the entire, complete, structure can be copied back to user space.*/ 5304 /* ------------------------------------------------------------------------ */ 5305 int 5306 ipf_resolvefunc(ipf_main_softc_t *softc, void *data) 5307 { 5308 ipfunc_resolve_t res, *ft; 5309 int error; 5310 5311 error = BCOPYIN(data, &res, sizeof(res)); 5312 if (error != 0) { 5313 IPFERROR(123); 5314 return EFAULT; 5315 } 5316 5317 if (res.ipfu_addr == NULL && res.ipfu_name[0] != '\0') { 5318 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5319 if (strncmp(res.ipfu_name, ft->ipfu_name, 5320 sizeof(res.ipfu_name)) == 0) { 5321 res.ipfu_addr = ft->ipfu_addr; 5322 res.ipfu_init = ft->ipfu_init; 5323 if (COPYOUT(&res, data, sizeof(res)) != 0) { 5324 IPFERROR(35); 5325 return EFAULT; 5326 } 5327 return 0; 5328 } 5329 } 5330 if (res.ipfu_addr != NULL && res.ipfu_name[0] == '\0') { 5331 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5332 if (ft->ipfu_addr == res.ipfu_addr) { 5333 (void) strncpy(res.ipfu_name, ft->ipfu_name, 5334 sizeof(res.ipfu_name)); 5335 res.ipfu_init = ft->ipfu_init; 5336 if (COPYOUT(&res, data, sizeof(res)) != 0) { 5337 IPFERROR(36); 5338 return EFAULT; 5339 } 5340 return 0; 5341 } 5342 } 5343 IPFERROR(37); 5344 return ESRCH; 5345 } 5346 5347 5348 #if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && \ 5349 !defined(__FreeBSD__)) || \ 5350 FREEBSD_LT_REV(501000) || NETBSD_LT_REV(105000000) || \ 5351 OPENBSD_LT_REV(200006) 5352 /* 5353 * From: NetBSD 5354 * ppsratecheck(): packets (or events) per second limitation. 5355 */ 5356 int 5357 ppsratecheck(lasttime, curpps, maxpps) 5358 struct timeval *lasttime; 5359 int *curpps; 5360 int maxpps; /* maximum pps allowed */ 5361 { 5362 struct timeval tv, delta; 5363 int rv; 5364 5365 GETKTIME(&tv); 5366 5367 delta.tv_sec = tv.tv_sec - lasttime->tv_sec; 5368 delta.tv_usec = tv.tv_usec - lasttime->tv_usec; 5369 if (delta.tv_usec < 0) { 5370 delta.tv_sec--; 5371 delta.tv_usec += 1000000; 5372 } 5373 5374 /* 5375 * check for 0,0 is so that the message will be seen at least once. 5376 * if more than one second have passed since the last update of 5377 * lasttime, reset the counter. 5378 * 5379 * we do increment *curpps even in *curpps < maxpps case, as some may 5380 * try to use *curpps for stat purposes as well. 5381 */ 5382 if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) || 5383 delta.tv_sec >= 1) { 5384 *lasttime = tv; 5385 *curpps = 0; 5386 rv = 1; 5387 } else if (maxpps < 0) 5388 rv = 1; 5389 else if (*curpps < maxpps) 5390 rv = 1; 5391 else 5392 rv = 0; 5393 *curpps = *curpps + 1; 5394 5395 return (rv); 5396 } 5397 #endif 5398 5399 5400 /* ------------------------------------------------------------------------ */ 5401 /* Function: ipf_derefrule */ 5402 /* Returns: int - 0 == rule freed up, else rule not freed */ 5403 /* Parameters: fr(I) - pointer to filter rule */ 5404 /* */ 5405 /* Decrement the reference counter to a rule by one. If it reaches zero, */ 5406 /* free it and any associated storage space being used by it. */ 5407 /* ------------------------------------------------------------------------ */ 5408 int 5409 ipf_derefrule(ipf_main_softc_t *softc, frentry_t **frp) 5410 { 5411 frentry_t *fr; 5412 frdest_t *fdp; 5413 5414 fr = *frp; 5415 *frp = NULL; 5416 5417 MUTEX_ENTER(&fr->fr_lock); 5418 fr->fr_ref--; 5419 if (fr->fr_ref == 0) { 5420 MUTEX_EXIT(&fr->fr_lock); 5421 MUTEX_DESTROY(&fr->fr_lock); 5422 5423 ipf_funcfini(softc, fr); 5424 5425 fdp = &fr->fr_tif; 5426 if (fdp->fd_type == FRD_DSTLIST) 5427 ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr); 5428 5429 fdp = &fr->fr_rif; 5430 if (fdp->fd_type == FRD_DSTLIST) 5431 ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr); 5432 5433 fdp = &fr->fr_dif; 5434 if (fdp->fd_type == FRD_DSTLIST) 5435 ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr); 5436 5437 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF && 5438 fr->fr_satype == FRI_LOOKUP) 5439 ipf_lookup_deref(softc, fr->fr_srctype, fr->fr_srcptr); 5440 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF && 5441 fr->fr_datype == FRI_LOOKUP) 5442 ipf_lookup_deref(softc, fr->fr_dsttype, fr->fr_dstptr); 5443 5444 if (fr->fr_grp != NULL) 5445 ipf_group_del(softc, fr->fr_grp, fr); 5446 5447 if (fr->fr_grphead != NULL) 5448 ipf_group_del(softc, fr->fr_grphead, fr); 5449 5450 if (fr->fr_icmpgrp != NULL) 5451 ipf_group_del(softc, fr->fr_icmpgrp, fr); 5452 5453 if ((fr->fr_flags & FR_COPIED) != 0) { 5454 if (fr->fr_dsize) { 5455 KFREES(fr->fr_data, fr->fr_dsize); 5456 } 5457 KFREES(fr, fr->fr_size); 5458 return 0; 5459 } 5460 return 1; 5461 } else { 5462 MUTEX_EXIT(&fr->fr_lock); 5463 } 5464 return -1; 5465 } 5466 5467 5468 /* ------------------------------------------------------------------------ */ 5469 /* Function: ipf_grpmapinit */ 5470 /* Returns: int - 0 == success, else ESRCH because table entry not found*/ 5471 /* Parameters: fr(I) - pointer to rule to find hash table for */ 5472 /* */ 5473 /* Looks for group hash table fr_arg and stores a pointer to it in fr_ptr. */ 5474 /* fr_ptr is later used by ipf_srcgrpmap and ipf_dstgrpmap. */ 5475 /* ------------------------------------------------------------------------ */ 5476 static int 5477 ipf_grpmapinit(ipf_main_softc_t *softc, frentry_t *fr) 5478 { 5479 char name[FR_GROUPLEN]; 5480 iphtable_t *iph; 5481 5482 (void) snprintf(name, sizeof(name), "%d", fr->fr_arg); 5483 iph = ipf_lookup_find_htable(softc, IPL_LOGIPF, name); 5484 if (iph == NULL) { 5485 IPFERROR(38); 5486 return ESRCH; 5487 } 5488 if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT)) { 5489 IPFERROR(39); 5490 return ESRCH; 5491 } 5492 iph->iph_ref++; 5493 fr->fr_ptr = iph; 5494 return 0; 5495 } 5496 5497 5498 /* ------------------------------------------------------------------------ */ 5499 /* Function: ipf_grpmapfini */ 5500 /* Returns: int - 0 == success, else ESRCH because table entry not found*/ 5501 /* Parameters: softc(I) - pointer to soft context main structure */ 5502 /* fr(I) - pointer to rule to release hash table for */ 5503 /* */ 5504 /* For rules that have had ipf_grpmapinit called, ipf_lookup_deref needs to */ 5505 /* be called to undo what ipf_grpmapinit caused to be done. */ 5506 /* ------------------------------------------------------------------------ */ 5507 static int 5508 ipf_grpmapfini(ipf_main_softc_t *softc, frentry_t *fr) 5509 { 5510 iphtable_t *iph; 5511 iph = fr->fr_ptr; 5512 if (iph != NULL) 5513 ipf_lookup_deref(softc, IPLT_HASH, iph); 5514 return 0; 5515 } 5516 5517 5518 /* ------------------------------------------------------------------------ */ 5519 /* Function: ipf_srcgrpmap */ 5520 /* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ 5521 /* Parameters: fin(I) - pointer to packet information */ 5522 /* passp(IO) - pointer to current/new filter decision (unused) */ 5523 /* */ 5524 /* Look for a rule group head in a hash table, using the source address as */ 5525 /* the key, and descend into that group and continue matching rules against */ 5526 /* the packet. */ 5527 /* ------------------------------------------------------------------------ */ 5528 frentry_t * 5529 ipf_srcgrpmap(fr_info_t *fin, u_32_t *passp) 5530 { 5531 frgroup_t *fg; 5532 void *rval; 5533 5534 rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr, 5535 &fin->fin_src); 5536 if (rval == NULL) 5537 return NULL; 5538 5539 fg = rval; 5540 fin->fin_fr = fg->fg_start; 5541 (void) ipf_scanlist(fin, *passp); 5542 return fin->fin_fr; 5543 } 5544 5545 5546 /* ------------------------------------------------------------------------ */ 5547 /* Function: ipf_dstgrpmap */ 5548 /* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ 5549 /* Parameters: fin(I) - pointer to packet information */ 5550 /* passp(IO) - pointer to current/new filter decision (unused) */ 5551 /* */ 5552 /* Look for a rule group head in a hash table, using the destination */ 5553 /* address as the key, and descend into that group and continue matching */ 5554 /* rules against the packet. */ 5555 /* ------------------------------------------------------------------------ */ 5556 frentry_t * 5557 ipf_dstgrpmap(fr_info_t *fin, u_32_t *passp) 5558 { 5559 frgroup_t *fg; 5560 void *rval; 5561 5562 rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr, 5563 &fin->fin_dst); 5564 if (rval == NULL) 5565 return NULL; 5566 5567 fg = rval; 5568 fin->fin_fr = fg->fg_start; 5569 (void) ipf_scanlist(fin, *passp); 5570 return fin->fin_fr; 5571 } 5572 5573 /* 5574 * Queue functions 5575 * =============== 5576 * These functions manage objects on queues for efficient timeouts. There 5577 * are a number of system defined queues as well as user defined timeouts. 5578 * It is expected that a lock is held in the domain in which the queue 5579 * belongs (i.e. either state or NAT) when calling any of these functions 5580 * that prevents ipf_freetimeoutqueue() from being called at the same time 5581 * as any other. 5582 */ 5583 5584 5585 /* ------------------------------------------------------------------------ */ 5586 /* Function: ipf_addtimeoutqueue */ 5587 /* Returns: struct ifqtq * - NULL if malloc fails, else pointer to */ 5588 /* timeout queue with given interval. */ 5589 /* Parameters: parent(I) - pointer to pointer to parent node of this list */ 5590 /* of interface queues. */ 5591 /* seconds(I) - timeout value in seconds for this queue. */ 5592 /* */ 5593 /* This routine first looks for a timeout queue that matches the interval */ 5594 /* being requested. If it finds one, increments the reference counter and */ 5595 /* returns a pointer to it. If none are found, it allocates a new one and */ 5596 /* inserts it at the top of the list. */ 5597 /* */ 5598 /* Locking. */ 5599 /* It is assumed that the caller of this function has an appropriate lock */ 5600 /* held (exclusively) in the domain that encompases 'parent'. */ 5601 /* ------------------------------------------------------------------------ */ 5602 ipftq_t * 5603 ipf_addtimeoutqueue(ipf_main_softc_t *softc, ipftq_t **parent, u_int seconds) 5604 { 5605 ipftq_t *ifq; 5606 u_int period; 5607 5608 period = seconds * IPF_HZ_DIVIDE; 5609 5610 MUTEX_ENTER(&softc->ipf_timeoutlock); 5611 for (ifq = *parent; ifq != NULL; ifq = ifq->ifq_next) { 5612 if (ifq->ifq_ttl == period) { 5613 /* 5614 * Reset the delete flag, if set, so the structure 5615 * gets reused rather than freed and reallocated. 5616 */ 5617 MUTEX_ENTER(&ifq->ifq_lock); 5618 ifq->ifq_flags &= ~IFQF_DELETE; 5619 ifq->ifq_ref++; 5620 MUTEX_EXIT(&ifq->ifq_lock); 5621 MUTEX_EXIT(&softc->ipf_timeoutlock); 5622 5623 return ifq; 5624 } 5625 } 5626 5627 KMALLOC(ifq, ipftq_t *); 5628 if (ifq != NULL) { 5629 MUTEX_NUKE(&ifq->ifq_lock); 5630 IPFTQ_INIT(ifq, period, "ipftq mutex"); 5631 ifq->ifq_next = *parent; 5632 ifq->ifq_pnext = parent; 5633 ifq->ifq_flags = IFQF_USER; 5634 ifq->ifq_ref++; 5635 *parent = ifq; 5636 softc->ipf_userifqs++; 5637 } 5638 MUTEX_EXIT(&softc->ipf_timeoutlock); 5639 return ifq; 5640 } 5641 5642 5643 /* ------------------------------------------------------------------------ */ 5644 /* Function: ipf_deletetimeoutqueue */ 5645 /* Returns: int - new reference count value of the timeout queue */ 5646 /* Parameters: ifq(I) - timeout queue which is losing a reference. */ 5647 /* Locks: ifq->ifq_lock */ 5648 /* */ 5649 /* This routine must be called when we're discarding a pointer to a timeout */ 5650 /* queue object, taking care of the reference counter. */ 5651 /* */ 5652 /* Now that this just sets a DELETE flag, it requires the expire code to */ 5653 /* check the list of user defined timeout queues and call the free function */ 5654 /* below (currently commented out) to stop memory leaking. It is done this */ 5655 /* way because the locking may not be sufficient to safely do a free when */ 5656 /* this function is called. */ 5657 /* ------------------------------------------------------------------------ */ 5658 int 5659 ipf_deletetimeoutqueue(ipftq_t *ifq) 5660 { 5661 5662 ifq->ifq_ref--; 5663 if ((ifq->ifq_ref == 0) && ((ifq->ifq_flags & IFQF_USER) != 0)) { 5664 ifq->ifq_flags |= IFQF_DELETE; 5665 } 5666 5667 return ifq->ifq_ref; 5668 } 5669 5670 5671 /* ------------------------------------------------------------------------ */ 5672 /* Function: ipf_freetimeoutqueue */ 5673 /* Parameters: ifq(I) - timeout queue which is losing a reference. */ 5674 /* Returns: Nil */ 5675 /* */ 5676 /* Locking: */ 5677 /* It is assumed that the caller of this function has an appropriate lock */ 5678 /* held (exclusively) in the domain that encompases the callers "domain". */ 5679 /* The ifq_lock for this structure should not be held. */ 5680 /* */ 5681 /* Remove a user defined timeout queue from the list of queues it is in and */ 5682 /* tidy up after this is done. */ 5683 /* ------------------------------------------------------------------------ */ 5684 void 5685 ipf_freetimeoutqueue(ipf_main_softc_t *softc, ipftq_t *ifq) 5686 { 5687 5688 if (((ifq->ifq_flags & IFQF_DELETE) == 0) || (ifq->ifq_ref != 0) || 5689 ((ifq->ifq_flags & IFQF_USER) == 0)) { 5690 printf("ipf_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n", 5691 (u_long)ifq, ifq->ifq_flags, ifq->ifq_ttl, 5692 ifq->ifq_ref); 5693 return; 5694 } 5695 5696 /* 5697 * Remove from its position in the list. 5698 */ 5699 *ifq->ifq_pnext = ifq->ifq_next; 5700 if (ifq->ifq_next != NULL) 5701 ifq->ifq_next->ifq_pnext = ifq->ifq_pnext; 5702 ifq->ifq_next = NULL; 5703 ifq->ifq_pnext = NULL; 5704 5705 MUTEX_DESTROY(&ifq->ifq_lock); 5706 ATOMIC_DEC(softc->ipf_userifqs); 5707 KFREE(ifq); 5708 } 5709 5710 5711 /* ------------------------------------------------------------------------ */ 5712 /* Function: ipf_deletequeueentry */ 5713 /* Returns: Nil */ 5714 /* Parameters: tqe(I) - timeout queue entry to delete */ 5715 /* */ 5716 /* Remove a tail queue entry from its queue and make it an orphan. */ 5717 /* ipf_deletetimeoutqueue is called to make sure the reference count on the */ 5718 /* queue is correct. We can't, however, call ipf_freetimeoutqueue because */ 5719 /* the correct lock(s) may not be held that would make it safe to do so. */ 5720 /* ------------------------------------------------------------------------ */ 5721 void 5722 ipf_deletequeueentry(ipftqent_t *tqe) 5723 { 5724 ipftq_t *ifq; 5725 5726 ifq = tqe->tqe_ifq; 5727 5728 MUTEX_ENTER(&ifq->ifq_lock); 5729 5730 if (tqe->tqe_pnext != NULL) { 5731 *tqe->tqe_pnext = tqe->tqe_next; 5732 if (tqe->tqe_next != NULL) 5733 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5734 else /* we must be the tail anyway */ 5735 ifq->ifq_tail = tqe->tqe_pnext; 5736 5737 tqe->tqe_pnext = NULL; 5738 tqe->tqe_ifq = NULL; 5739 } 5740 5741 (void) ipf_deletetimeoutqueue(ifq); 5742 ASSERT(ifq->ifq_ref > 0); 5743 5744 MUTEX_EXIT(&ifq->ifq_lock); 5745 } 5746 5747 5748 /* ------------------------------------------------------------------------ */ 5749 /* Function: ipf_queuefront */ 5750 /* Returns: Nil */ 5751 /* Parameters: tqe(I) - pointer to timeout queue entry */ 5752 /* */ 5753 /* Move a queue entry to the front of the queue, if it isn't already there. */ 5754 /* ------------------------------------------------------------------------ */ 5755 void 5756 ipf_queuefront(ipftqent_t *tqe) 5757 { 5758 ipftq_t *ifq; 5759 5760 ifq = tqe->tqe_ifq; 5761 if (ifq == NULL) 5762 return; 5763 5764 MUTEX_ENTER(&ifq->ifq_lock); 5765 if (ifq->ifq_head != tqe) { 5766 *tqe->tqe_pnext = tqe->tqe_next; 5767 if (tqe->tqe_next) 5768 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5769 else 5770 ifq->ifq_tail = tqe->tqe_pnext; 5771 5772 tqe->tqe_next = ifq->ifq_head; 5773 ifq->ifq_head->tqe_pnext = &tqe->tqe_next; 5774 ifq->ifq_head = tqe; 5775 tqe->tqe_pnext = &ifq->ifq_head; 5776 } 5777 MUTEX_EXIT(&ifq->ifq_lock); 5778 } 5779 5780 5781 /* ------------------------------------------------------------------------ */ 5782 /* Function: ipf_queueback */ 5783 /* Returns: Nil */ 5784 /* Parameters: ticks(I) - ipf tick time to use with this call */ 5785 /* tqe(I) - pointer to timeout queue entry */ 5786 /* */ 5787 /* Move a queue entry to the back of the queue, if it isn't already there. */ 5788 /* We use use ticks to calculate the expiration and mark for when we last */ 5789 /* touched the structure. */ 5790 /* ------------------------------------------------------------------------ */ 5791 void 5792 ipf_queueback(u_long ticks, ipftqent_t *tqe) 5793 { 5794 ipftq_t *ifq; 5795 5796 ifq = tqe->tqe_ifq; 5797 if (ifq == NULL) 5798 return; 5799 tqe->tqe_die = ticks + ifq->ifq_ttl; 5800 tqe->tqe_touched = ticks; 5801 5802 MUTEX_ENTER(&ifq->ifq_lock); 5803 if (tqe->tqe_next != NULL) { /* at the end already ? */ 5804 /* 5805 * Remove from list 5806 */ 5807 *tqe->tqe_pnext = tqe->tqe_next; 5808 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5809 5810 /* 5811 * Make it the last entry. 5812 */ 5813 tqe->tqe_next = NULL; 5814 tqe->tqe_pnext = ifq->ifq_tail; 5815 *ifq->ifq_tail = tqe; 5816 ifq->ifq_tail = &tqe->tqe_next; 5817 } 5818 MUTEX_EXIT(&ifq->ifq_lock); 5819 } 5820 5821 5822 /* ------------------------------------------------------------------------ */ 5823 /* Function: ipf_queueappend */ 5824 /* Returns: Nil */ 5825 /* Parameters: ticks(I) - ipf tick time to use with this call */ 5826 /* tqe(I) - pointer to timeout queue entry */ 5827 /* ifq(I) - pointer to timeout queue */ 5828 /* parent(I) - owing object pointer */ 5829 /* */ 5830 /* Add a new item to this queue and put it on the very end. */ 5831 /* We use use ticks to calculate the expiration and mark for when we last */ 5832 /* touched the structure. */ 5833 /* ------------------------------------------------------------------------ */ 5834 void 5835 ipf_queueappend(u_long ticks, ipftqent_t *tqe, ipftq_t *ifq, void *parent) 5836 { 5837 5838 MUTEX_ENTER(&ifq->ifq_lock); 5839 tqe->tqe_parent = parent; 5840 tqe->tqe_pnext = ifq->ifq_tail; 5841 *ifq->ifq_tail = tqe; 5842 ifq->ifq_tail = &tqe->tqe_next; 5843 tqe->tqe_next = NULL; 5844 tqe->tqe_ifq = ifq; 5845 tqe->tqe_die = ticks + ifq->ifq_ttl; 5846 tqe->tqe_touched = ticks; 5847 ifq->ifq_ref++; 5848 MUTEX_EXIT(&ifq->ifq_lock); 5849 } 5850 5851 5852 /* ------------------------------------------------------------------------ */ 5853 /* Function: ipf_movequeue */ 5854 /* Returns: Nil */ 5855 /* Parameters: tq(I) - pointer to timeout queue information */ 5856 /* oifp(I) - old timeout queue entry was on */ 5857 /* nifp(I) - new timeout queue to put entry on */ 5858 /* */ 5859 /* Move a queue entry from one timeout queue to another timeout queue. */ 5860 /* If it notices that the current entry is already last and does not need */ 5861 /* to move queue, the return. */ 5862 /* ------------------------------------------------------------------------ */ 5863 void 5864 ipf_movequeue(u_long ticks, ipftqent_t *tqe, ipftq_t *oifq, ipftq_t *nifq) 5865 { 5866 5867 /* 5868 * If the queue hasn't changed and we last touched this entry at the 5869 * same ipf time, then we're not going to achieve anything by either 5870 * changing the ttl or moving it on the queue. 5871 */ 5872 if (oifq == nifq && tqe->tqe_touched == ticks) 5873 return; 5874 5875 /* 5876 * For any of this to be outside the lock, there is a risk that two 5877 * packets entering simultaneously, with one changing to a different 5878 * queue and one not, could end up with things in a bizarre state. 5879 */ 5880 MUTEX_ENTER(&oifq->ifq_lock); 5881 5882 tqe->tqe_touched = ticks; 5883 tqe->tqe_die = ticks + nifq->ifq_ttl; 5884 /* 5885 * Is the operation here going to be a no-op ? 5886 */ 5887 if (oifq == nifq) { 5888 if ((tqe->tqe_next == NULL) || 5889 (tqe->tqe_next->tqe_die == tqe->tqe_die)) { 5890 MUTEX_EXIT(&oifq->ifq_lock); 5891 return; 5892 } 5893 } 5894 5895 /* 5896 * Remove from the old queue 5897 */ 5898 *tqe->tqe_pnext = tqe->tqe_next; 5899 if (tqe->tqe_next) 5900 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5901 else 5902 oifq->ifq_tail = tqe->tqe_pnext; 5903 tqe->tqe_next = NULL; 5904 5905 /* 5906 * If we're moving from one queue to another, release the 5907 * lock on the old queue and get a lock on the new queue. 5908 * For user defined queues, if we're moving off it, call 5909 * delete in case it can now be freed. 5910 */ 5911 if (oifq != nifq) { 5912 tqe->tqe_ifq = NULL; 5913 5914 (void) ipf_deletetimeoutqueue(oifq); 5915 5916 MUTEX_EXIT(&oifq->ifq_lock); 5917 5918 MUTEX_ENTER(&nifq->ifq_lock); 5919 5920 tqe->tqe_ifq = nifq; 5921 nifq->ifq_ref++; 5922 } 5923 5924 /* 5925 * Add to the bottom of the new queue 5926 */ 5927 tqe->tqe_pnext = nifq->ifq_tail; 5928 *nifq->ifq_tail = tqe; 5929 nifq->ifq_tail = &tqe->tqe_next; 5930 MUTEX_EXIT(&nifq->ifq_lock); 5931 } 5932 5933 5934 /* ------------------------------------------------------------------------ */ 5935 /* Function: ipf_updateipid */ 5936 /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 5937 /* Parameters: fin(I) - pointer to packet information */ 5938 /* */ 5939 /* When we are doing NAT, change the IP of every packet to represent a */ 5940 /* single sequence of packets coming from the host, hiding any host */ 5941 /* specific sequencing that might otherwise be revealed. If the packet is */ 5942 /* a fragment, then store the 'new' IPid in the fragment cache and look up */ 5943 /* the fragment cache for non-leading fragments. If a non-leading fragment */ 5944 /* has no match in the cache, return an error. */ 5945 /* ------------------------------------------------------------------------ */ 5946 static int 5947 ipf_updateipid(fr_info_t *fin) 5948 { 5949 u_short id, ido, sums; 5950 u_32_t sumd, sum; 5951 ip_t *ip; 5952 5953 if (fin->fin_off != 0) { 5954 sum = ipf_frag_ipidknown(fin); 5955 if (sum == 0xffffffff) 5956 return -1; 5957 sum &= 0xffff; 5958 id = (u_short)sum; 5959 } else { 5960 id = ipf_nextipid(fin); 5961 if (fin->fin_off == 0 && (fin->fin_flx & FI_FRAG) != 0) 5962 (void) ipf_frag_ipidnew(fin, (u_32_t)id); 5963 } 5964 5965 ip = fin->fin_ip; 5966 ido = ntohs(ip->ip_id); 5967 if (id == ido) 5968 return 0; 5969 ip->ip_id = htons(id); 5970 CALC_SUMD(ido, id, sumd); /* DESTRUCTIVE MACRO! id,ido change */ 5971 sum = (~ntohs(ip->ip_sum)) & 0xffff; 5972 sum += sumd; 5973 sum = (sum >> 16) + (sum & 0xffff); 5974 sum = (sum >> 16) + (sum & 0xffff); 5975 sums = ~(u_short)sum; 5976 ip->ip_sum = htons(sums); 5977 return 0; 5978 } 5979 5980 5981 #ifdef NEED_FRGETIFNAME 5982 /* ------------------------------------------------------------------------ */ 5983 /* Function: ipf_getifname */ 5984 /* Returns: char * - pointer to interface name */ 5985 /* Parameters: ifp(I) - pointer to network interface */ 5986 /* buffer(O) - pointer to where to store interface name */ 5987 /* */ 5988 /* Constructs an interface name in the buffer passed. The buffer passed is */ 5989 /* expected to be at least LIFNAMSIZ in bytes big. If buffer is passed in */ 5990 /* as a NULL pointer then return a pointer to a static array. */ 5991 /* ------------------------------------------------------------------------ */ 5992 char * 5993 ipf_getifname(ifp, buffer) 5994 struct ifnet *ifp; 5995 char *buffer; 5996 { 5997 static char namebuf[LIFNAMSIZ]; 5998 # if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \ 5999 defined(__sgi) || defined(linux) || defined(_AIX51) || \ 6000 (defined(sun) && !defined(__SVR4) && !defined(__svr4__)) 6001 int unit, space; 6002 char temp[20]; 6003 char *s; 6004 # endif 6005 6006 if (buffer == NULL) 6007 buffer = namebuf; 6008 (void) strncpy(buffer, ifp->if_name, LIFNAMSIZ); 6009 buffer[LIFNAMSIZ - 1] = '\0'; 6010 # if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \ 6011 defined(__sgi) || defined(_AIX51) || \ 6012 (defined(sun) && !defined(__SVR4) && !defined(__svr4__)) 6013 for (s = buffer; *s; s++) 6014 ; 6015 unit = ifp->if_unit; 6016 space = LIFNAMSIZ - (s - buffer); 6017 if ((space > 0) && (unit >= 0)) { 6018 snprintf(temp, sizeof(temp), "%d", unit); 6019 (void) strncpy(s, temp, space); 6020 s[space - 1] = '\0'; 6021 } 6022 # endif 6023 return buffer; 6024 } 6025 #endif 6026 6027 6028 /* ------------------------------------------------------------------------ */ 6029 /* Function: ipf_ioctlswitch */ 6030 /* Returns: int - -1 continue processing, else ioctl return value */ 6031 /* Parameters: unit(I) - device unit opened */ 6032 /* data(I) - pointer to ioctl data */ 6033 /* cmd(I) - ioctl command */ 6034 /* mode(I) - mode value */ 6035 /* uid(I) - uid making the ioctl call */ 6036 /* ctx(I) - pointer to context data */ 6037 /* */ 6038 /* Based on the value of unit, call the appropriate ioctl handler or return */ 6039 /* EIO if ipfilter is not running. Also checks if write perms are req'd */ 6040 /* for the device in order to execute the ioctl. A special case is made */ 6041 /* SIOCIPFINTERROR so that the same code isn't required in every handler. */ 6042 /* The context data pointer is passed through as this is used as the key */ 6043 /* for locating a matching token for continued access for walking lists, */ 6044 /* etc. */ 6045 /* ------------------------------------------------------------------------ */ 6046 int 6047 ipf_ioctlswitch(ipf_main_softc_t *softc, int unit, void *data, ioctlcmd_t cmd, 6048 int mode, int uid, void *ctx) 6049 { 6050 int error = 0; 6051 6052 switch (cmd) 6053 { 6054 case SIOCIPFINTERROR : 6055 error = BCOPYOUT(&softc->ipf_interror, data, 6056 sizeof(softc->ipf_interror)); 6057 if (error != 0) { 6058 IPFERROR(40); 6059 error = EFAULT; 6060 } 6061 return error; 6062 default : 6063 break; 6064 } 6065 6066 switch (unit) 6067 { 6068 case IPL_LOGIPF : 6069 error = ipf_ipf_ioctl(softc, data, cmd, mode, uid, ctx); 6070 break; 6071 case IPL_LOGNAT : 6072 if (softc->ipf_running > 0) { 6073 error = ipf_nat_ioctl(softc, data, cmd, mode, 6074 uid, ctx); 6075 } else { 6076 IPFERROR(42); 6077 error = EIO; 6078 } 6079 break; 6080 case IPL_LOGSTATE : 6081 if (softc->ipf_running > 0) { 6082 error = ipf_state_ioctl(softc, data, cmd, mode, 6083 uid, ctx); 6084 } else { 6085 IPFERROR(43); 6086 error = EIO; 6087 } 6088 break; 6089 case IPL_LOGAUTH : 6090 if (softc->ipf_running > 0) { 6091 error = ipf_auth_ioctl(softc, data, cmd, mode, 6092 uid, ctx); 6093 } else { 6094 IPFERROR(44); 6095 error = EIO; 6096 } 6097 break; 6098 case IPL_LOGSYNC : 6099 if (softc->ipf_running > 0) { 6100 error = ipf_sync_ioctl(softc, data, cmd, mode, 6101 uid, ctx); 6102 } else { 6103 error = EIO; 6104 IPFERROR(45); 6105 } 6106 break; 6107 case IPL_LOGSCAN : 6108 #ifdef IPFILTER_SCAN 6109 if (softc->ipf_running > 0) 6110 error = ipf_scan_ioctl(softc, data, cmd, mode, 6111 uid, ctx); 6112 else 6113 #endif 6114 { 6115 error = EIO; 6116 IPFERROR(46); 6117 } 6118 break; 6119 case IPL_LOGLOOKUP : 6120 if (softc->ipf_running > 0) { 6121 error = ipf_lookup_ioctl(softc, data, cmd, mode, 6122 uid, ctx); 6123 } else { 6124 error = EIO; 6125 IPFERROR(47); 6126 } 6127 break; 6128 default : 6129 IPFERROR(48); 6130 error = EIO; 6131 break; 6132 } 6133 6134 return error; 6135 } 6136 6137 6138 /* 6139 * This array defines the expected size of objects coming into the kernel 6140 * for the various recognised object types. The first column is flags (see 6141 * below), 2nd column is current size, 3rd column is the version number of 6142 * when the current size became current. 6143 * Flags: 6144 * 1 = minimum size, not absolute size 6145 */ 6146 static int ipf_objbytes[IPFOBJ_COUNT][3] = { 6147 { 1, sizeof(struct frentry), 5010000 }, /* 0 */ 6148 { 1, sizeof(struct friostat), 5010000 }, 6149 { 0, sizeof(struct fr_info), 5010000 }, 6150 { 0, sizeof(struct ipf_authstat), 4010100 }, 6151 { 0, sizeof(struct ipfrstat), 5010000 }, 6152 { 1, sizeof(struct ipnat), 5010000 }, /* 5 */ 6153 { 0, sizeof(struct natstat), 5010000 }, 6154 { 0, sizeof(struct ipstate_save), 5010000 }, 6155 { 1, sizeof(struct nat_save), 5010000 }, 6156 { 0, sizeof(struct natlookup), 5010000 }, 6157 { 1, sizeof(struct ipstate), 5010000 }, /* 10 */ 6158 { 0, sizeof(struct ips_stat), 5010000 }, 6159 { 0, sizeof(struct frauth), 5010000 }, 6160 { 0, sizeof(struct ipftune), 4010100 }, 6161 { 0, sizeof(struct nat), 5010000 }, 6162 { 0, sizeof(struct ipfruleiter), 4011400 }, /* 15 */ 6163 { 0, sizeof(struct ipfgeniter), 4011400 }, 6164 { 0, sizeof(struct ipftable), 4011400 }, 6165 { 0, sizeof(struct ipflookupiter), 4011400 }, 6166 { 0, sizeof(struct ipftq) * IPF_TCP_NSTATES }, 6167 { 1, 0, 0 }, /* IPFEXPR */ 6168 { 0, 0, 0 }, /* PROXYCTL */ 6169 { 0, sizeof (struct fripf), 5010000 } 6170 }; 6171 6172 6173 /* ------------------------------------------------------------------------ */ 6174 /* Function: ipf_inobj */ 6175 /* Returns: int - 0 = success, else failure */ 6176 /* Parameters: softc(I) - soft context pointerto work with */ 6177 /* data(I) - pointer to ioctl data */ 6178 /* objp(O) - where to store ipfobj structure */ 6179 /* ptr(I) - pointer to data to copy out */ 6180 /* type(I) - type of structure being moved */ 6181 /* */ 6182 /* Copy in the contents of what the ipfobj_t points to. In future, we */ 6183 /* add things to check for version numbers, sizes, etc, to make it backward */ 6184 /* compatible at the ABI for user land. */ 6185 /* If objp is not NULL then we assume that the caller wants to see what is */ 6186 /* in the ipfobj_t structure being copied in. As an example, this can tell */ 6187 /* the caller what version of ipfilter the ioctl program was written to. */ 6188 /* ------------------------------------------------------------------------ */ 6189 int 6190 ipf_inobj(ipf_main_softc_t *softc, void *data, ipfobj_t *objp, void *ptr, 6191 int type) 6192 { 6193 ipfobj_t obj; 6194 int error; 6195 int size; 6196 6197 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6198 IPFERROR(49); 6199 return EINVAL; 6200 } 6201 6202 if (objp == NULL) 6203 objp = &obj; 6204 error = BCOPYIN(data, objp, sizeof(*objp)); 6205 if (error != 0) { 6206 IPFERROR(124); 6207 return EFAULT; 6208 } 6209 6210 if (objp->ipfo_type != type) { 6211 IPFERROR(50); 6212 return EINVAL; 6213 } 6214 6215 if (objp->ipfo_rev >= ipf_objbytes[type][2]) { 6216 if ((ipf_objbytes[type][0] & 1) != 0) { 6217 if (objp->ipfo_size < ipf_objbytes[type][1]) { 6218 IPFERROR(51); 6219 return EINVAL; 6220 } 6221 size = ipf_objbytes[type][1]; 6222 } else if (objp->ipfo_size == ipf_objbytes[type][1]) { 6223 size = objp->ipfo_size; 6224 } else { 6225 IPFERROR(52); 6226 return EINVAL; 6227 } 6228 error = COPYIN(objp->ipfo_ptr, ptr, size); 6229 if (error != 0) { 6230 IPFERROR(55); 6231 error = EFAULT; 6232 } 6233 } else { 6234 #ifdef IPFILTER_COMPAT 6235 error = ipf_in_compat(softc, objp, ptr, 0); 6236 #else 6237 IPFERROR(54); 6238 error = EINVAL; 6239 #endif 6240 } 6241 return error; 6242 } 6243 6244 6245 /* ------------------------------------------------------------------------ */ 6246 /* Function: ipf_inobjsz */ 6247 /* Returns: int - 0 = success, else failure */ 6248 /* Parameters: softc(I) - soft context pointerto work with */ 6249 /* data(I) - pointer to ioctl data */ 6250 /* ptr(I) - pointer to store real data in */ 6251 /* type(I) - type of structure being moved */ 6252 /* sz(I) - size of data to copy */ 6253 /* */ 6254 /* As per ipf_inobj, except the size of the object to copy in is passed in */ 6255 /* but it must not be smaller than the size defined for the type and the */ 6256 /* type must allow for varied sized objects. The extra requirement here is */ 6257 /* that sz must match the size of the object being passed in - this is not */ 6258 /* not possible nor required in ipf_inobj(). */ 6259 /* ------------------------------------------------------------------------ */ 6260 int 6261 ipf_inobjsz(ipf_main_softc_t *softc, void *data, void *ptr, int type, int sz) 6262 { 6263 ipfobj_t obj; 6264 int error; 6265 6266 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6267 IPFERROR(56); 6268 return EINVAL; 6269 } 6270 6271 error = BCOPYIN(data, &obj, sizeof(obj)); 6272 if (error != 0) { 6273 IPFERROR(125); 6274 return EFAULT; 6275 } 6276 6277 if (obj.ipfo_type != type) { 6278 IPFERROR(58); 6279 return EINVAL; 6280 } 6281 6282 if (obj.ipfo_rev >= ipf_objbytes[type][2]) { 6283 if (((ipf_objbytes[type][0] & 1) == 0) || 6284 (sz < ipf_objbytes[type][1])) { 6285 IPFERROR(57); 6286 return EINVAL; 6287 } 6288 error = COPYIN(obj.ipfo_ptr, ptr, sz); 6289 if (error != 0) { 6290 IPFERROR(61); 6291 error = EFAULT; 6292 } 6293 } else { 6294 #ifdef IPFILTER_COMPAT 6295 error = ipf_in_compat(softc, &obj, ptr, sz); 6296 #else 6297 IPFERROR(60); 6298 error = EINVAL; 6299 #endif 6300 } 6301 return error; 6302 } 6303 6304 6305 /* ------------------------------------------------------------------------ */ 6306 /* Function: ipf_outobjsz */ 6307 /* Returns: int - 0 = success, else failure */ 6308 /* Parameters: data(I) - pointer to ioctl data */ 6309 /* ptr(I) - pointer to store real data in */ 6310 /* type(I) - type of structure being moved */ 6311 /* sz(I) - size of data to copy */ 6312 /* */ 6313 /* As per ipf_outobj, except the size of the object to copy out is passed in*/ 6314 /* but it must not be smaller than the size defined for the type and the */ 6315 /* type must allow for varied sized objects. The extra requirement here is */ 6316 /* that sz must match the size of the object being passed in - this is not */ 6317 /* not possible nor required in ipf_outobj(). */ 6318 /* ------------------------------------------------------------------------ */ 6319 int 6320 ipf_outobjsz(ipf_main_softc_t *softc, void *data, void *ptr, int type, int sz) 6321 { 6322 ipfobj_t obj; 6323 int error; 6324 6325 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6326 IPFERROR(62); 6327 return EINVAL; 6328 } 6329 6330 error = BCOPYIN(data, &obj, sizeof(obj)); 6331 if (error != 0) { 6332 IPFERROR(127); 6333 return EFAULT; 6334 } 6335 6336 if (obj.ipfo_type != type) { 6337 IPFERROR(63); 6338 return EINVAL; 6339 } 6340 6341 if (obj.ipfo_rev >= ipf_objbytes[type][2]) { 6342 if (((ipf_objbytes[type][0] & 1) == 0) || 6343 (sz < ipf_objbytes[type][1])) { 6344 IPFERROR(146); 6345 return EINVAL; 6346 } 6347 error = COPYOUT(ptr, obj.ipfo_ptr, sz); 6348 if (error != 0) { 6349 IPFERROR(66); 6350 error = EFAULT; 6351 } 6352 } else { 6353 #ifdef IPFILTER_COMPAT 6354 error = ipf_out_compat(softc, &obj, ptr); 6355 #else 6356 IPFERROR(65); 6357 error = EINVAL; 6358 #endif 6359 } 6360 return error; 6361 } 6362 6363 6364 /* ------------------------------------------------------------------------ */ 6365 /* Function: ipf_outobj */ 6366 /* Returns: int - 0 = success, else failure */ 6367 /* Parameters: data(I) - pointer to ioctl data */ 6368 /* ptr(I) - pointer to store real data in */ 6369 /* type(I) - type of structure being moved */ 6370 /* */ 6371 /* Copy out the contents of what ptr is to where ipfobj points to. In */ 6372 /* future, we add things to check for version numbers, sizes, etc, to make */ 6373 /* it backward compatible at the ABI for user land. */ 6374 /* ------------------------------------------------------------------------ */ 6375 int 6376 ipf_outobj(ipf_main_softc_t *softc, void *data, void *ptr, int type) 6377 { 6378 ipfobj_t obj; 6379 int error; 6380 6381 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6382 IPFERROR(67); 6383 return EINVAL; 6384 } 6385 6386 error = BCOPYIN(data, &obj, sizeof(obj)); 6387 if (error != 0) { 6388 IPFERROR(126); 6389 return EFAULT; 6390 } 6391 6392 if (obj.ipfo_type != type) { 6393 IPFERROR(68); 6394 return EINVAL; 6395 } 6396 6397 if (obj.ipfo_rev >= ipf_objbytes[type][2]) { 6398 if ((ipf_objbytes[type][0] & 1) != 0) { 6399 if (obj.ipfo_size < ipf_objbytes[type][1]) { 6400 IPFERROR(69); 6401 return EINVAL; 6402 } 6403 } else if (obj.ipfo_size != ipf_objbytes[type][1]) { 6404 IPFERROR(70); 6405 return EINVAL; 6406 } 6407 6408 error = COPYOUT(ptr, obj.ipfo_ptr, obj.ipfo_size); 6409 if (error != 0) { 6410 IPFERROR(73); 6411 error = EFAULT; 6412 } 6413 } else { 6414 #ifdef IPFILTER_COMPAT 6415 error = ipf_out_compat(softc, &obj, ptr); 6416 #else 6417 IPFERROR(72); 6418 error = EINVAL; 6419 #endif 6420 } 6421 return error; 6422 } 6423 6424 6425 /* ------------------------------------------------------------------------ */ 6426 /* Function: ipf_outobjk */ 6427 /* Returns: int - 0 = success, else failure */ 6428 /* Parameters: obj(I) - pointer to data description structure */ 6429 /* ptr(I) - pointer to kernel data to copy out */ 6430 /* */ 6431 /* In the above functions, the ipfobj_t structure is copied into the kernel,*/ 6432 /* telling ipfilter how to copy out data. In this instance, the ipfobj_t is */ 6433 /* already populated with information and now we just need to use it. */ 6434 /* There is no need for this function to have a "type" parameter as there */ 6435 /* is no point in validating information that comes from the kernel with */ 6436 /* itself. */ 6437 /* ------------------------------------------------------------------------ */ 6438 int 6439 ipf_outobjk(ipf_main_softc_t *softc, ipfobj_t *obj, void *ptr) 6440 { 6441 int type = obj->ipfo_type; 6442 int error; 6443 6444 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6445 IPFERROR(147); 6446 return EINVAL; 6447 } 6448 6449 if (obj->ipfo_rev >= ipf_objbytes[type][2]) { 6450 if ((ipf_objbytes[type][0] & 1) != 0) { 6451 if (obj->ipfo_size < ipf_objbytes[type][1]) { 6452 IPFERROR(148); 6453 return EINVAL; 6454 } 6455 6456 } else if (obj->ipfo_size != ipf_objbytes[type][1]) { 6457 IPFERROR(149); 6458 return EINVAL; 6459 } 6460 6461 error = COPYOUT(ptr, obj->ipfo_ptr, obj->ipfo_size); 6462 if (error != 0) { 6463 IPFERROR(150); 6464 error = EFAULT; 6465 } 6466 } else { 6467 #ifdef IPFILTER_COMPAT 6468 error = ipf_out_compat(softc, obj, ptr); 6469 #else 6470 IPFERROR(151); 6471 error = EINVAL; 6472 #endif 6473 } 6474 return error; 6475 } 6476 6477 6478 /* ------------------------------------------------------------------------ */ 6479 /* Function: ipf_checkl4sum */ 6480 /* Returns: int - 0 = good, -1 = bad, 1 = cannot check */ 6481 /* Parameters: fin(I) - pointer to packet information */ 6482 /* */ 6483 /* If possible, calculate the layer 4 checksum for the packet. If this is */ 6484 /* not possible, return without indicating a failure or success but in a */ 6485 /* way that is ditinguishable. This function should only be called by the */ 6486 /* ipf_checkv6sum() for each platform. */ 6487 /* ------------------------------------------------------------------------ */ 6488 int 6489 ipf_checkl4sum(fr_info_t *fin) 6490 { 6491 u_short sum, hdrsum, *csump; 6492 udphdr_t *udp; 6493 int dosum; 6494 6495 /* 6496 * If the TCP packet isn't a fragment, isn't too short and otherwise 6497 * isn't already considered "bad", then validate the checksum. If 6498 * this check fails then considered the packet to be "bad". 6499 */ 6500 if ((fin->fin_flx & (FI_FRAG|FI_SHORT|FI_BAD)) != 0) 6501 return 1; 6502 6503 csump = NULL; 6504 hdrsum = 0; 6505 dosum = 0; 6506 sum = 0; 6507 6508 switch (fin->fin_p) 6509 { 6510 case IPPROTO_TCP : 6511 csump = &((tcphdr_t *)fin->fin_dp)->th_sum; 6512 dosum = 1; 6513 break; 6514 6515 case IPPROTO_UDP : 6516 udp = fin->fin_dp; 6517 if (udp->uh_sum != 0) { 6518 csump = &udp->uh_sum; 6519 dosum = 1; 6520 } 6521 break; 6522 6523 #ifdef USE_INET6 6524 case IPPROTO_ICMPV6 : 6525 csump = &((struct icmp6_hdr *)fin->fin_dp)->icmp6_cksum; 6526 dosum = 1; 6527 break; 6528 #endif 6529 6530 case IPPROTO_ICMP : 6531 csump = &((struct icmp *)fin->fin_dp)->icmp_cksum; 6532 dosum = 1; 6533 break; 6534 6535 default : 6536 return 1; 6537 /*NOTREACHED*/ 6538 } 6539 6540 if (csump != NULL) { 6541 hdrsum = *csump; 6542 if (fin->fin_p == IPPROTO_UDP && hdrsum == 0xffff) 6543 hdrsum = 0x0000; 6544 } 6545 6546 if (dosum) { 6547 sum = fr_cksum(fin, fin->fin_ip, fin->fin_p, fin->fin_dp); 6548 } 6549 #if !defined(_KERNEL) 6550 if (sum == hdrsum) { 6551 FR_DEBUG(("checkl4sum: %hx == %hx\n", sum, hdrsum)); 6552 } else { 6553 FR_DEBUG(("checkl4sum: %hx != %hx\n", sum, hdrsum)); 6554 } 6555 #endif 6556 DT2(l4sums, u_short, hdrsum, u_short, sum); 6557 if (hdrsum == sum) { 6558 fin->fin_cksum = FI_CK_SUMOK; 6559 return 0; 6560 } 6561 fin->fin_cksum = FI_CK_BAD; 6562 return -1; 6563 } 6564 6565 6566 /* ------------------------------------------------------------------------ */ 6567 /* Function: ipf_ifpfillv4addr */ 6568 /* Returns: int - 0 = address update, -1 = address not updated */ 6569 /* Parameters: atype(I) - type of network address update to perform */ 6570 /* sin(I) - pointer to source of address information */ 6571 /* mask(I) - pointer to source of netmask information */ 6572 /* inp(I) - pointer to destination address store */ 6573 /* inpmask(I) - pointer to destination netmask store */ 6574 /* */ 6575 /* Given a type of network address update (atype) to perform, copy */ 6576 /* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ 6577 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ 6578 /* which case the operation fails. For all values of atype other than */ 6579 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ 6580 /* value. */ 6581 /* ------------------------------------------------------------------------ */ 6582 int 6583 ipf_ifpfillv4addr(int atype, struct sockaddr_in *sin, struct sockaddr_in *mask, 6584 struct in_addr *inp, struct in_addr *inpmask) 6585 { 6586 if (inpmask != NULL && atype != FRI_NETMASKED) 6587 inpmask->s_addr = 0xffffffff; 6588 6589 if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { 6590 if (atype == FRI_NETMASKED) { 6591 if (inpmask == NULL) 6592 return -1; 6593 inpmask->s_addr = mask->sin_addr.s_addr; 6594 } 6595 inp->s_addr = sin->sin_addr.s_addr & mask->sin_addr.s_addr; 6596 } else { 6597 inp->s_addr = sin->sin_addr.s_addr; 6598 } 6599 return 0; 6600 } 6601 6602 6603 #ifdef USE_INET6 6604 /* ------------------------------------------------------------------------ */ 6605 /* Function: ipf_ifpfillv6addr */ 6606 /* Returns: int - 0 = address update, -1 = address not updated */ 6607 /* Parameters: atype(I) - type of network address update to perform */ 6608 /* sin(I) - pointer to source of address information */ 6609 /* mask(I) - pointer to source of netmask information */ 6610 /* inp(I) - pointer to destination address store */ 6611 /* inpmask(I) - pointer to destination netmask store */ 6612 /* */ 6613 /* Given a type of network address update (atype) to perform, copy */ 6614 /* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ 6615 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ 6616 /* which case the operation fails. For all values of atype other than */ 6617 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ 6618 /* value. */ 6619 /* ------------------------------------------------------------------------ */ 6620 int 6621 ipf_ifpfillv6addr(int atype, struct sockaddr_in6 *sin, 6622 struct sockaddr_in6 *mask, i6addr_t *inp, i6addr_t *inpmask) 6623 { 6624 i6addr_t *src, *and; 6625 6626 src = (i6addr_t *)&sin->sin6_addr; 6627 and = (i6addr_t *)&mask->sin6_addr; 6628 6629 if (inpmask != NULL && atype != FRI_NETMASKED) { 6630 inpmask->i6[0] = 0xffffffff; 6631 inpmask->i6[1] = 0xffffffff; 6632 inpmask->i6[2] = 0xffffffff; 6633 inpmask->i6[3] = 0xffffffff; 6634 } 6635 6636 if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { 6637 if (atype == FRI_NETMASKED) { 6638 if (inpmask == NULL) 6639 return -1; 6640 inpmask->i6[0] = and->i6[0]; 6641 inpmask->i6[1] = and->i6[1]; 6642 inpmask->i6[2] = and->i6[2]; 6643 inpmask->i6[3] = and->i6[3]; 6644 } 6645 6646 inp->i6[0] = src->i6[0] & and->i6[0]; 6647 inp->i6[1] = src->i6[1] & and->i6[1]; 6648 inp->i6[2] = src->i6[2] & and->i6[2]; 6649 inp->i6[3] = src->i6[3] & and->i6[3]; 6650 } else { 6651 inp->i6[0] = src->i6[0]; 6652 inp->i6[1] = src->i6[1]; 6653 inp->i6[2] = src->i6[2]; 6654 inp->i6[3] = src->i6[3]; 6655 } 6656 return 0; 6657 } 6658 #endif 6659 6660 6661 /* ------------------------------------------------------------------------ */ 6662 /* Function: ipf_matchtag */ 6663 /* Returns: 0 == mismatch, 1 == match. */ 6664 /* Parameters: tag1(I) - pointer to first tag to compare */ 6665 /* tag2(I) - pointer to second tag to compare */ 6666 /* */ 6667 /* Returns true (non-zero) or false(0) if the two tag structures can be */ 6668 /* considered to be a match or not match, respectively. The tag is 16 */ 6669 /* bytes long (16 characters) but that is overlayed with 4 32bit ints so */ 6670 /* compare the ints instead, for speed. tag1 is the master of the */ 6671 /* comparison. This function should only be called with both tag1 and tag2 */ 6672 /* as non-NULL pointers. */ 6673 /* ------------------------------------------------------------------------ */ 6674 int 6675 ipf_matchtag(ipftag_t *tag1, ipftag_t *tag2) 6676 { 6677 if (tag1 == tag2) 6678 return 1; 6679 6680 if ((tag1->ipt_num[0] == 0) && (tag2->ipt_num[0] == 0)) 6681 return 1; 6682 6683 if ((tag1->ipt_num[0] == tag2->ipt_num[0]) && 6684 (tag1->ipt_num[1] == tag2->ipt_num[1]) && 6685 (tag1->ipt_num[2] == tag2->ipt_num[2]) && 6686 (tag1->ipt_num[3] == tag2->ipt_num[3])) 6687 return 1; 6688 return 0; 6689 } 6690 6691 6692 /* ------------------------------------------------------------------------ */ 6693 /* Function: ipf_coalesce */ 6694 /* Returns: 1 == success, -1 == failure, 0 == no change */ 6695 /* Parameters: fin(I) - pointer to packet information */ 6696 /* */ 6697 /* Attempt to get all of the packet data into a single, contiguous buffer. */ 6698 /* If this call returns a failure then the buffers have also been freed. */ 6699 /* ------------------------------------------------------------------------ */ 6700 int 6701 ipf_coalesce(fr_info_t *fin) 6702 { 6703 6704 if ((fin->fin_flx & FI_COALESCE) != 0) 6705 return 1; 6706 6707 /* 6708 * If the mbuf pointers indicate that there is no mbuf to work with, 6709 * return but do not indicate success or failure. 6710 */ 6711 if (fin->fin_m == NULL || fin->fin_mp == NULL) 6712 return 0; 6713 6714 #if defined(_KERNEL) 6715 if (ipf_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) { 6716 ipf_main_softc_t *softc = fin->fin_main_soft; 6717 6718 DT1(frb_coalesce, fr_info_t *, fin); 6719 LBUMP(ipf_stats[fin->fin_out].fr_badcoalesces); 6720 # ifdef MENTAT 6721 FREE_MB_T(*fin->fin_mp); 6722 # endif 6723 fin->fin_reason = FRB_COALESCE; 6724 *fin->fin_mp = NULL; 6725 fin->fin_m = NULL; 6726 return -1; 6727 } 6728 #else 6729 fin = fin; /* LINT */ 6730 #endif 6731 return 1; 6732 } 6733 6734 6735 /* 6736 * The following table lists all of the tunable variables that can be 6737 * accessed via SIOCIPFGET/SIOCIPFSET/SIOCIPFGETNEXt. The format of each row 6738 * in the table below is as follows: 6739 * 6740 * pointer to value, name of value, minimum, maximum, size of the value's 6741 * container, value attribute flags 6742 * 6743 * For convienience, IPFT_RDONLY means the value is read-only, IPFT_WRDISABLED 6744 * means the value can only be written to when IPFilter is loaded but disabled. 6745 * The obvious implication is if neither of these are set then the value can be 6746 * changed at any time without harm. 6747 */ 6748 6749 6750 /* ------------------------------------------------------------------------ */ 6751 /* Function: ipf_tune_findbycookie */ 6752 /* Returns: NULL = search failed, else pointer to tune struct */ 6753 /* Parameters: cookie(I) - cookie value to search for amongst tuneables */ 6754 /* next(O) - pointer to place to store the cookie for the */ 6755 /* "next" tuneable, if it is desired. */ 6756 /* */ 6757 /* This function is used to walk through all of the existing tunables with */ 6758 /* successive calls. It searches the known tunables for the one which has */ 6759 /* a matching value for "cookie" - ie its address. When returning a match, */ 6760 /* the next one to be found may be returned inside next. */ 6761 /* ------------------------------------------------------------------------ */ 6762 static ipftuneable_t * 6763 ipf_tune_findbycookie(ipftuneable_t **ptop, void *cookie, void **next) 6764 { 6765 ipftuneable_t *ta, **tap; 6766 6767 for (ta = *ptop; ta->ipft_name != NULL; ta++) 6768 if (ta == cookie) { 6769 if (next != NULL) { 6770 /* 6771 * If the next entry in the array has a name 6772 * present, then return a pointer to it for 6773 * where to go next, else return a pointer to 6774 * the dynaminc list as a key to search there 6775 * next. This facilitates a weak linking of 6776 * the two "lists" together. 6777 */ 6778 if ((ta + 1)->ipft_name != NULL) 6779 *next = ta + 1; 6780 else 6781 *next = ptop; 6782 } 6783 return ta; 6784 } 6785 6786 for (tap = ptop; (ta = *tap) != NULL; tap = &ta->ipft_next) 6787 if (tap == cookie) { 6788 if (next != NULL) 6789 *next = &ta->ipft_next; 6790 return ta; 6791 } 6792 6793 if (next != NULL) 6794 *next = NULL; 6795 return NULL; 6796 } 6797 6798 6799 /* ------------------------------------------------------------------------ */ 6800 /* Function: ipf_tune_findbyname */ 6801 /* Returns: NULL = search failed, else pointer to tune struct */ 6802 /* Parameters: name(I) - name of the tuneable entry to find. */ 6803 /* */ 6804 /* Search the static array of tuneables and the list of dynamic tuneables */ 6805 /* for an entry with a matching name. If we can find one, return a pointer */ 6806 /* to the matching structure. */ 6807 /* ------------------------------------------------------------------------ */ 6808 static ipftuneable_t * 6809 ipf_tune_findbyname(ipftuneable_t *top, const char *name) 6810 { 6811 ipftuneable_t *ta; 6812 6813 for (ta = top; ta != NULL; ta = ta->ipft_next) 6814 if (!strcmp(ta->ipft_name, name)) { 6815 return ta; 6816 } 6817 6818 return NULL; 6819 } 6820 6821 6822 /* ------------------------------------------------------------------------ */ 6823 /* Function: ipf_tune_add_array */ 6824 /* Returns: int - 0 == success, else failure */ 6825 /* Parameters: newtune - pointer to new tune array to add to tuneables */ 6826 /* */ 6827 /* Appends tune structures from the array passed in (newtune) to the end of */ 6828 /* the current list of "dynamic" tuneable parameters. */ 6829 /* If any entry to be added is already present (by name) then the operation */ 6830 /* is aborted - entries that have been added are removed before returning. */ 6831 /* An entry with no name (NULL) is used as the indication that the end of */ 6832 /* the array has been reached. */ 6833 /* ------------------------------------------------------------------------ */ 6834 int 6835 ipf_tune_add_array(ipf_main_softc_t *softc, ipftuneable_t *newtune) 6836 { 6837 ipftuneable_t *nt, *dt; 6838 int error = 0; 6839 6840 for (nt = newtune; nt->ipft_name != NULL; nt++) { 6841 error = ipf_tune_add(softc, nt); 6842 if (error != 0) { 6843 for (dt = newtune; dt != nt; dt++) { 6844 (void) ipf_tune_del(softc, dt); 6845 } 6846 } 6847 } 6848 6849 return error; 6850 } 6851 6852 6853 /* ------------------------------------------------------------------------ */ 6854 /* Function: ipf_tune_array_link */ 6855 /* Returns: 0 == success, -1 == failure */ 6856 /* Parameters: softc(I) - soft context pointerto work with */ 6857 /* array(I) - pointer to an array of tuneables */ 6858 /* */ 6859 /* Given an array of tunables (array), append them to the current list of */ 6860 /* tuneables for this context (softc->ipf_tuners.) To properly prepare the */ 6861 /* the array for being appended to the list, initialise all of the next */ 6862 /* pointers so we don't need to walk parts of it with ++ and others with */ 6863 /* next. The array is expected to have an entry with a NULL name as the */ 6864 /* terminator. Trying to add an array with no non-NULL names will return as */ 6865 /* a failure. */ 6866 /* ------------------------------------------------------------------------ */ 6867 int 6868 ipf_tune_array_link(ipf_main_softc_t *softc, ipftuneable_t *array) 6869 { 6870 ipftuneable_t *t, **p; 6871 6872 t = array; 6873 if (t->ipft_name == NULL) 6874 return -1; 6875 6876 for (; t[1].ipft_name != NULL; t++) 6877 t[0].ipft_next = &t[1]; 6878 t->ipft_next = NULL; 6879 6880 /* 6881 * Since a pointer to the last entry isn't kept, we need to find it 6882 * each time we want to add new variables to the list. 6883 */ 6884 for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next) 6885 if (t->ipft_name == NULL) 6886 break; 6887 *p = array; 6888 6889 return 0; 6890 } 6891 6892 6893 /* ------------------------------------------------------------------------ */ 6894 /* Function: ipf_tune_array_unlink */ 6895 /* Returns: 0 == success, -1 == failure */ 6896 /* Parameters: softc(I) - soft context pointerto work with */ 6897 /* array(I) - pointer to an array of tuneables */ 6898 /* */ 6899 /* ------------------------------------------------------------------------ */ 6900 int 6901 ipf_tune_array_unlink(ipf_main_softc_t *softc, ipftuneable_t *array) 6902 { 6903 ipftuneable_t *t, **p; 6904 6905 for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next) 6906 if (t == array) 6907 break; 6908 if (t == NULL) 6909 return -1; 6910 6911 for (; t[1].ipft_name != NULL; t++) 6912 ; 6913 6914 *p = t->ipft_next; 6915 6916 return 0; 6917 } 6918 6919 6920 /* ------------------------------------------------------------------------ */ 6921 /* Function: ipf_tune_array_copy */ 6922 /* Returns: NULL = failure, else pointer to new array */ 6923 /* Parameters: base(I) - pointer to structure base */ 6924 /* size(I) - size of the array at template */ 6925 /* template(I) - original array to copy */ 6926 /* */ 6927 /* Allocate memory for a new set of tuneable values and copy everything */ 6928 /* from template into the new region of memory. The new region is full of */ 6929 /* uninitialised pointers (ipft_next) so set them up. Now, ipftp_offset... */ 6930 /* */ 6931 /* NOTE: the following assumes that sizeof(long) == sizeof(void *) */ 6932 /* In the array template, ipftp_offset is the offset (in bytes) of the */ 6933 /* location of the tuneable value inside the structure pointed to by base. */ 6934 /* As ipftp_offset is a union over the pointers to the tuneable values, if */ 6935 /* we add base to the copy's ipftp_offset, copy ends up with a pointer in */ 6936 /* ipftp_void that points to the stored value. */ 6937 /* ------------------------------------------------------------------------ */ 6938 ipftuneable_t * 6939 ipf_tune_array_copy(void *base, size_t size, const ipftuneable_t *template) 6940 { 6941 ipftuneable_t *copy; 6942 int i; 6943 6944 6945 KMALLOCS(copy, ipftuneable_t *, size); 6946 if (copy == NULL) { 6947 return NULL; 6948 } 6949 bcopy(template, copy, size); 6950 6951 for (i = 0; copy[i].ipft_name; i++) { 6952 copy[i].ipft_una.ipftp_offset += (u_long)base; 6953 copy[i].ipft_next = copy + i + 1; 6954 } 6955 6956 return copy; 6957 } 6958 6959 6960 /* ------------------------------------------------------------------------ */ 6961 /* Function: ipf_tune_add */ 6962 /* Returns: int - 0 == success, else failure */ 6963 /* Parameters: newtune - pointer to new tune entry to add to tuneables */ 6964 /* */ 6965 /* Appends tune structures from the array passed in (newtune) to the end of */ 6966 /* the current list of "dynamic" tuneable parameters. Once added, the */ 6967 /* owner of the object is not expected to ever change "ipft_next". */ 6968 /* ------------------------------------------------------------------------ */ 6969 int 6970 ipf_tune_add(ipf_main_softc_t *softc, ipftuneable_t *newtune) 6971 { 6972 ipftuneable_t *ta, **tap; 6973 6974 ta = ipf_tune_findbyname(softc->ipf_tuners, newtune->ipft_name); 6975 if (ta != NULL) { 6976 IPFERROR(74); 6977 return EEXIST; 6978 } 6979 6980 for (tap = &softc->ipf_tuners; *tap != NULL; tap = &(*tap)->ipft_next) 6981 ; 6982 6983 newtune->ipft_next = NULL; 6984 *tap = newtune; 6985 return 0; 6986 } 6987 6988 6989 /* ------------------------------------------------------------------------ */ 6990 /* Function: ipf_tune_del */ 6991 /* Returns: int - 0 == success, else failure */ 6992 /* Parameters: oldtune - pointer to tune entry to remove from the list of */ 6993 /* current dynamic tuneables */ 6994 /* */ 6995 /* Search for the tune structure, by pointer, in the list of those that are */ 6996 /* dynamically added at run time. If found, adjust the list so that this */ 6997 /* structure is no longer part of it. */ 6998 /* ------------------------------------------------------------------------ */ 6999 int 7000 ipf_tune_del(ipf_main_softc_t *softc, ipftuneable_t *oldtune) 7001 { 7002 ipftuneable_t *ta, **tap; 7003 int error = 0; 7004 7005 for (tap = &softc->ipf_tuners; (ta = *tap) != NULL; 7006 tap = &ta->ipft_next) { 7007 if (ta == oldtune) { 7008 *tap = oldtune->ipft_next; 7009 oldtune->ipft_next = NULL; 7010 break; 7011 } 7012 } 7013 7014 if (ta == NULL) { 7015 error = ESRCH; 7016 IPFERROR(75); 7017 } 7018 return error; 7019 } 7020 7021 7022 /* ------------------------------------------------------------------------ */ 7023 /* Function: ipf_tune_del_array */ 7024 /* Returns: int - 0 == success, else failure */ 7025 /* Parameters: oldtune - pointer to tuneables array */ 7026 /* */ 7027 /* Remove each tuneable entry in the array from the list of "dynamic" */ 7028 /* tunables. If one entry should fail to be found, an error will be */ 7029 /* returned and no further ones removed. */ 7030 /* An entry with a NULL name is used as the indicator of the last entry in */ 7031 /* the array. */ 7032 /* ------------------------------------------------------------------------ */ 7033 int 7034 ipf_tune_del_array(ipf_main_softc_t *softc, ipftuneable_t *oldtune) 7035 { 7036 ipftuneable_t *ot; 7037 int error = 0; 7038 7039 for (ot = oldtune; ot->ipft_name != NULL; ot++) { 7040 error = ipf_tune_del(softc, ot); 7041 if (error != 0) 7042 break; 7043 } 7044 7045 return error; 7046 7047 } 7048 7049 7050 /* ------------------------------------------------------------------------ */ 7051 /* Function: ipf_tune */ 7052 /* Returns: int - 0 == success, else failure */ 7053 /* Parameters: cmd(I) - ioctl command number */ 7054 /* data(I) - pointer to ioctl data structure */ 7055 /* */ 7056 /* Implement handling of SIOCIPFGETNEXT, SIOCIPFGET and SIOCIPFSET. These */ 7057 /* three ioctls provide the means to access and control global variables */ 7058 /* within IPFilter, allowing (for example) timeouts and table sizes to be */ 7059 /* changed without rebooting, reloading or recompiling. The initialisation */ 7060 /* and 'destruction' routines of the various components of ipfilter are all */ 7061 /* each responsible for handling their own values being too big. */ 7062 /* ------------------------------------------------------------------------ */ 7063 int 7064 ipf_ipftune(ipf_main_softc_t *softc, ioctlcmd_t cmd, void *data) 7065 { 7066 ipftuneable_t *ta; 7067 ipftune_t tu; 7068 void *cookie; 7069 int error; 7070 7071 error = ipf_inobj(softc, data, NULL, &tu, IPFOBJ_TUNEABLE); 7072 if (error != 0) 7073 return error; 7074 7075 tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0'; 7076 cookie = tu.ipft_cookie; 7077 ta = NULL; 7078 7079 switch (cmd) 7080 { 7081 case SIOCIPFGETNEXT : 7082 /* 7083 * If cookie is non-NULL, assume it to be a pointer to the last 7084 * entry we looked at, so find it (if possible) and return a 7085 * pointer to the next one after it. The last entry in the 7086 * the table is a NULL entry, so when we get to it, set cookie 7087 * to NULL and return that, indicating end of list, erstwhile 7088 * if we come in with cookie set to NULL, we are starting anew 7089 * at the front of the list. 7090 */ 7091 if (cookie != NULL) { 7092 ta = ipf_tune_findbycookie(&softc->ipf_tuners, 7093 cookie, &tu.ipft_cookie); 7094 } else { 7095 ta = softc->ipf_tuners; 7096 tu.ipft_cookie = ta + 1; 7097 } 7098 if (ta != NULL) { 7099 /* 7100 * Entry found, but does the data pointed to by that 7101 * row fit in what we can return? 7102 */ 7103 if (ta->ipft_sz > sizeof(tu.ipft_un)) { 7104 IPFERROR(76); 7105 return EINVAL; 7106 } 7107 7108 tu.ipft_vlong = 0; 7109 if (ta->ipft_sz == sizeof(u_long)) 7110 tu.ipft_vlong = *ta->ipft_plong; 7111 else if (ta->ipft_sz == sizeof(u_int)) 7112 tu.ipft_vint = *ta->ipft_pint; 7113 else if (ta->ipft_sz == sizeof(u_short)) 7114 tu.ipft_vshort = *ta->ipft_pshort; 7115 else if (ta->ipft_sz == sizeof(u_char)) 7116 tu.ipft_vchar = *ta->ipft_pchar; 7117 7118 tu.ipft_sz = ta->ipft_sz; 7119 tu.ipft_min = ta->ipft_min; 7120 tu.ipft_max = ta->ipft_max; 7121 tu.ipft_flags = ta->ipft_flags; 7122 bcopy(ta->ipft_name, tu.ipft_name, 7123 MIN(sizeof(tu.ipft_name), 7124 strlen(ta->ipft_name) + 1)); 7125 } 7126 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE); 7127 break; 7128 7129 case SIOCIPFGET : 7130 case SIOCIPFSET : 7131 /* 7132 * Search by name or by cookie value for a particular entry 7133 * in the tuning paramter table. 7134 */ 7135 IPFERROR(77); 7136 error = ESRCH; 7137 if (cookie != NULL) { 7138 ta = ipf_tune_findbycookie(&softc->ipf_tuners, 7139 cookie, NULL); 7140 if (ta != NULL) 7141 error = 0; 7142 } else if (tu.ipft_name[0] != '\0') { 7143 ta = ipf_tune_findbyname(softc->ipf_tuners, 7144 tu.ipft_name); 7145 if (ta != NULL) 7146 error = 0; 7147 } 7148 if (error != 0) 7149 break; 7150 7151 if (cmd == (ioctlcmd_t)SIOCIPFGET) { 7152 /* 7153 * Fetch the tuning parameters for a particular value 7154 */ 7155 tu.ipft_vlong = 0; 7156 if (ta->ipft_sz == sizeof(u_long)) 7157 tu.ipft_vlong = *ta->ipft_plong; 7158 else if (ta->ipft_sz == sizeof(u_int)) 7159 tu.ipft_vint = *ta->ipft_pint; 7160 else if (ta->ipft_sz == sizeof(u_short)) 7161 tu.ipft_vshort = *ta->ipft_pshort; 7162 else if (ta->ipft_sz == sizeof(u_char)) 7163 tu.ipft_vchar = *ta->ipft_pchar; 7164 tu.ipft_cookie = ta; 7165 tu.ipft_sz = ta->ipft_sz; 7166 tu.ipft_min = ta->ipft_min; 7167 tu.ipft_max = ta->ipft_max; 7168 tu.ipft_flags = ta->ipft_flags; 7169 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE); 7170 7171 } else if (cmd == (ioctlcmd_t)SIOCIPFSET) { 7172 /* 7173 * Set an internal parameter. The hard part here is 7174 * getting the new value safely and correctly out of 7175 * the kernel (given we only know its size, not type.) 7176 */ 7177 u_long in; 7178 7179 if (((ta->ipft_flags & IPFT_WRDISABLED) != 0) && 7180 (softc->ipf_running > 0)) { 7181 IPFERROR(78); 7182 error = EBUSY; 7183 break; 7184 } 7185 7186 in = tu.ipft_vlong; 7187 if (in < ta->ipft_min || in > ta->ipft_max) { 7188 IPFERROR(79); 7189 error = EINVAL; 7190 break; 7191 } 7192 7193 if (ta->ipft_func != NULL) { 7194 SPL_INT(s); 7195 7196 SPL_NET(s); 7197 error = (*ta->ipft_func)(softc, ta, 7198 &tu.ipft_un); 7199 SPL_X(s); 7200 7201 } else if (ta->ipft_sz == sizeof(u_long)) { 7202 tu.ipft_vlong = *ta->ipft_plong; 7203 *ta->ipft_plong = in; 7204 7205 } else if (ta->ipft_sz == sizeof(u_int)) { 7206 tu.ipft_vint = *ta->ipft_pint; 7207 *ta->ipft_pint = (u_int)(in & 0xffffffff); 7208 7209 } else if (ta->ipft_sz == sizeof(u_short)) { 7210 tu.ipft_vshort = *ta->ipft_pshort; 7211 *ta->ipft_pshort = (u_short)(in & 0xffff); 7212 7213 } else if (ta->ipft_sz == sizeof(u_char)) { 7214 tu.ipft_vchar = *ta->ipft_pchar; 7215 *ta->ipft_pchar = (u_char)(in & 0xff); 7216 } 7217 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE); 7218 } 7219 break; 7220 7221 default : 7222 IPFERROR(80); 7223 error = EINVAL; 7224 break; 7225 } 7226 7227 return error; 7228 } 7229 7230 7231 /* ------------------------------------------------------------------------ */ 7232 /* Function: ipf_zerostats */ 7233 /* Returns: int - 0 = success, else failure */ 7234 /* Parameters: data(O) - pointer to pointer for copying data back to */ 7235 /* */ 7236 /* Copies the current statistics out to userspace and then zero's the */ 7237 /* current ones in the kernel. The lock is only held across the bzero() as */ 7238 /* the copyout may result in paging (ie network activity.) */ 7239 /* ------------------------------------------------------------------------ */ 7240 int 7241 ipf_zerostats(ipf_main_softc_t *softc, void *data) 7242 { 7243 friostat_t fio; 7244 ipfobj_t obj; 7245 int error; 7246 7247 error = ipf_inobj(softc, data, &obj, &fio, IPFOBJ_IPFSTAT); 7248 if (error != 0) 7249 return error; 7250 ipf_getstat(softc, &fio, obj.ipfo_rev); 7251 error = ipf_outobj(softc, data, &fio, IPFOBJ_IPFSTAT); 7252 if (error != 0) 7253 return error; 7254 7255 WRITE_ENTER(&softc->ipf_mutex); 7256 bzero(&softc->ipf_stats, sizeof(softc->ipf_stats)); 7257 RWLOCK_EXIT(&softc->ipf_mutex); 7258 7259 return 0; 7260 } 7261 7262 7263 /* ------------------------------------------------------------------------ */ 7264 /* Function: ipf_resolvedest */ 7265 /* Returns: Nil */ 7266 /* Parameters: softc(I) - pointer to soft context main structure */ 7267 /* base(I) - where strings are stored */ 7268 /* fdp(IO) - pointer to destination information to resolve */ 7269 /* v(I) - IP protocol version to match */ 7270 /* */ 7271 /* Looks up an interface name in the frdest structure pointed to by fdp and */ 7272 /* if a matching name can be found for the particular IP protocol version */ 7273 /* then store the interface pointer in the frdest struct. If no match is */ 7274 /* found, then set the interface pointer to be -1 as NULL is considered to */ 7275 /* indicate there is no information at all in the structure. */ 7276 /* ------------------------------------------------------------------------ */ 7277 int 7278 ipf_resolvedest(ipf_main_softc_t *softc, char *base, frdest_t *fdp, int v) 7279 { 7280 int errval = 0; 7281 void *ifp; 7282 7283 ifp = NULL; 7284 7285 if (fdp->fd_name != -1) { 7286 if (fdp->fd_type == FRD_DSTLIST) { 7287 ifp = ipf_lookup_res_name(softc, IPL_LOGIPF, 7288 IPLT_DSTLIST, 7289 base + fdp->fd_name, 7290 NULL); 7291 if (ifp == NULL) { 7292 IPFERROR(144); 7293 errval = ESRCH; 7294 } 7295 } else { 7296 ifp = GETIFP(base + fdp->fd_name, v); 7297 } 7298 } 7299 fdp->fd_ptr = ifp; 7300 7301 return errval; 7302 } 7303 7304 7305 /* ------------------------------------------------------------------------ */ 7306 /* Function: ipf_resolvenic */ 7307 /* Returns: void* - NULL = wildcard name, -1 = failed to find NIC, else */ 7308 /* pointer to interface structure for NIC */ 7309 /* Parameters: softc(I)- pointer to soft context main structure */ 7310 /* name(I) - complete interface name */ 7311 /* v(I) - IP protocol version */ 7312 /* */ 7313 /* Look for a network interface structure that firstly has a matching name */ 7314 /* to that passed in and that is also being used for that IP protocol */ 7315 /* version (necessary on some platforms where there are separate listings */ 7316 /* for both IPv4 and IPv6 on the same physical NIC. */ 7317 /* */ 7318 /* ------------------------------------------------------------------------ */ 7319 void * 7320 ipf_resolvenic(ipf_main_softc_t *softc, char *name, int v) 7321 { 7322 void *nic; 7323 7324 softc = softc; /* gcc -Wextra */ 7325 if (name[0] == '\0') 7326 return NULL; 7327 7328 if ((name[1] == '\0') && ((name[0] == '-') || (name[0] == '*'))) { 7329 return NULL; 7330 } 7331 7332 nic = GETIFP(name, v); 7333 if (nic == NULL) 7334 nic = (void *)-1; 7335 return nic; 7336 } 7337 7338 7339 /* ------------------------------------------------------------------------ */ 7340 /* Function: ipf_token_expire */ 7341 /* Returns: None. */ 7342 /* Parameters: softc(I) - pointer to soft context main structure */ 7343 /* */ 7344 /* This function is run every ipf tick to see if there are any tokens that */ 7345 /* have been held for too long and need to be freed up. */ 7346 /* ------------------------------------------------------------------------ */ 7347 void 7348 ipf_token_expire(ipf_main_softc_t *softc) 7349 { 7350 ipftoken_t *it; 7351 7352 WRITE_ENTER(&softc->ipf_tokens); 7353 while ((it = softc->ipf_token_head) != NULL) { 7354 if (it->ipt_die > softc->ipf_ticks) 7355 break; 7356 7357 ipf_token_deref(softc, it); 7358 } 7359 RWLOCK_EXIT(&softc->ipf_tokens); 7360 } 7361 7362 7363 /* ------------------------------------------------------------------------ */ 7364 /* Function: ipf_token_flush */ 7365 /* Returns: None. */ 7366 /* Parameters: softc(I) - pointer to soft context main structure */ 7367 /* */ 7368 /* Loop through all of the existing tokens and call deref to see if they */ 7369 /* can be freed. Normally a function like this might just loop on */ 7370 /* ipf_token_head but there is a chance that a token might have a ref count */ 7371 /* of greater than one and in that case the the reference would drop twice */ 7372 /* by code that is only entitled to drop it once. */ 7373 /* ------------------------------------------------------------------------ */ 7374 static void 7375 ipf_token_flush(ipf_main_softc_t *softc) 7376 { 7377 ipftoken_t *it, *next; 7378 7379 WRITE_ENTER(&softc->ipf_tokens); 7380 for (it = softc->ipf_token_head; it != NULL; it = next) { 7381 next = it->ipt_next; 7382 (void) ipf_token_deref(softc, it); 7383 } 7384 RWLOCK_EXIT(&softc->ipf_tokens); 7385 } 7386 7387 7388 /* ------------------------------------------------------------------------ */ 7389 /* Function: ipf_token_del */ 7390 /* Returns: int - 0 = success, else error */ 7391 /* Parameters: softc(I)- pointer to soft context main structure */ 7392 /* type(I) - the token type to match */ 7393 /* uid(I) - uid owning the token */ 7394 /* ptr(I) - context pointer for the token */ 7395 /* */ 7396 /* This function looks for a a token in the current list that matches up */ 7397 /* the fields (type, uid, ptr). If none is found, ESRCH is returned, else */ 7398 /* call ipf_token_dewref() to remove it from the list. In the event that */ 7399 /* the token has a reference held elsewhere, setting ipt_complete to 2 */ 7400 /* enables debugging to distinguish between the two paths that ultimately */ 7401 /* lead to a token to be deleted. */ 7402 /* ------------------------------------------------------------------------ */ 7403 int 7404 ipf_token_del(ipf_main_softc_t *softc, int type, int uid, void *ptr) 7405 { 7406 ipftoken_t *it; 7407 int error; 7408 7409 IPFERROR(82); 7410 error = ESRCH; 7411 7412 WRITE_ENTER(&softc->ipf_tokens); 7413 for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) { 7414 if (ptr == it->ipt_ctx && type == it->ipt_type && 7415 uid == it->ipt_uid) { 7416 it->ipt_complete = 2; 7417 ipf_token_deref(softc, it); 7418 error = 0; 7419 break; 7420 } 7421 } 7422 RWLOCK_EXIT(&softc->ipf_tokens); 7423 7424 return error; 7425 } 7426 7427 7428 /* ------------------------------------------------------------------------ */ 7429 /* Function: ipf_token_mark_complete */ 7430 /* Returns: None. */ 7431 /* Parameters: token(I) - pointer to token structure */ 7432 /* */ 7433 /* Mark a token as being ineligable for being found with ipf_token_find. */ 7434 /* ------------------------------------------------------------------------ */ 7435 void 7436 ipf_token_mark_complete(ipftoken_t *token) 7437 { 7438 if (token->ipt_complete == 0) 7439 token->ipt_complete = 1; 7440 } 7441 7442 7443 /* ------------------------------------------------------------------------ */ 7444 /* Function: ipf_token_find */ 7445 /* Returns: ipftoken_t * - NULL if no memory, else pointer to token */ 7446 /* Parameters: softc(I)- pointer to soft context main structure */ 7447 /* type(I) - the token type to match */ 7448 /* uid(I) - uid owning the token */ 7449 /* ptr(I) - context pointer for the token */ 7450 /* */ 7451 /* This function looks for a live token in the list of current tokens that */ 7452 /* matches the tuple (type, uid, ptr). If one cannot be found then one is */ 7453 /* allocated. If one is found then it is moved to the top of the list of */ 7454 /* currently active tokens. */ 7455 /* ------------------------------------------------------------------------ */ 7456 ipftoken_t * 7457 ipf_token_find(ipf_main_softc_t *softc, int type, int uid, void *ptr) 7458 { 7459 ipftoken_t *it, *new; 7460 7461 KMALLOC(new, ipftoken_t *); 7462 if (new != NULL) 7463 bzero((char *)new, sizeof(*new)); 7464 7465 WRITE_ENTER(&softc->ipf_tokens); 7466 for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) { 7467 if ((ptr == it->ipt_ctx) && (type == it->ipt_type) && 7468 (uid == it->ipt_uid) && (it->ipt_complete < 2)) 7469 break; 7470 } 7471 7472 if (it == NULL) { 7473 it = new; 7474 new = NULL; 7475 if (it == NULL) { 7476 RWLOCK_EXIT(&softc->ipf_tokens); 7477 return NULL; 7478 } 7479 it->ipt_ctx = ptr; 7480 it->ipt_uid = uid; 7481 it->ipt_type = type; 7482 it->ipt_ref = 1; 7483 } else { 7484 if (new != NULL) { 7485 KFREE(new); 7486 new = NULL; 7487 } 7488 7489 if (it->ipt_complete > 0) 7490 it = NULL; 7491 else 7492 ipf_token_unlink(softc, it); 7493 } 7494 7495 if (it != NULL) { 7496 it->ipt_pnext = softc->ipf_token_tail; 7497 *softc->ipf_token_tail = it; 7498 softc->ipf_token_tail = &it->ipt_next; 7499 it->ipt_next = NULL; 7500 it->ipt_ref++; 7501 7502 it->ipt_die = softc->ipf_ticks + 20; 7503 } 7504 7505 RWLOCK_EXIT(&softc->ipf_tokens); 7506 7507 return it; 7508 } 7509 7510 7511 /* ------------------------------------------------------------------------ */ 7512 /* Function: ipf_token_unlink */ 7513 /* Returns: None. */ 7514 /* Parameters: softc(I) - pointer to soft context main structure */ 7515 /* token(I) - pointer to token structure */ 7516 /* Write Locks: ipf_tokens */ 7517 /* */ 7518 /* This function unlinks a token structure from the linked list of tokens */ 7519 /* that "own" it. The head pointer never needs to be explicitly adjusted */ 7520 /* but the tail does due to the linked list implementation. */ 7521 /* ------------------------------------------------------------------------ */ 7522 static void 7523 ipf_token_unlink(ipf_main_softc_t *softc, ipftoken_t *token) 7524 { 7525 7526 if (softc->ipf_token_tail == &token->ipt_next) 7527 softc->ipf_token_tail = token->ipt_pnext; 7528 7529 *token->ipt_pnext = token->ipt_next; 7530 if (token->ipt_next != NULL) 7531 token->ipt_next->ipt_pnext = token->ipt_pnext; 7532 token->ipt_next = NULL; 7533 token->ipt_pnext = NULL; 7534 } 7535 7536 7537 /* ------------------------------------------------------------------------ */ 7538 /* Function: ipf_token_deref */ 7539 /* Returns: int - 0 == token freed, else reference count */ 7540 /* Parameters: softc(I) - pointer to soft context main structure */ 7541 /* token(I) - pointer to token structure */ 7542 /* Write Locks: ipf_tokens */ 7543 /* */ 7544 /* Drop the reference count on the token structure and if it drops to zero, */ 7545 /* call the dereference function for the token type because it is then */ 7546 /* possible to free the token data structure. */ 7547 /* ------------------------------------------------------------------------ */ 7548 int 7549 ipf_token_deref(ipf_main_softc_t *softc, ipftoken_t *token) 7550 { 7551 void *data, **datap; 7552 7553 ASSERT(token->ipt_ref > 0); 7554 token->ipt_ref--; 7555 if (token->ipt_ref > 0) 7556 return token->ipt_ref; 7557 7558 data = token->ipt_data; 7559 datap = &data; 7560 7561 if ((data != NULL) && (data != (void *)-1)) { 7562 switch (token->ipt_type) 7563 { 7564 case IPFGENITER_IPF : 7565 (void) ipf_derefrule(softc, (frentry_t **)datap); 7566 break; 7567 case IPFGENITER_IPNAT : 7568 WRITE_ENTER(&softc->ipf_nat); 7569 ipf_nat_rule_deref(softc, (ipnat_t **)datap); 7570 RWLOCK_EXIT(&softc->ipf_nat); 7571 break; 7572 case IPFGENITER_NAT : 7573 ipf_nat_deref(softc, (nat_t **)datap); 7574 break; 7575 case IPFGENITER_STATE : 7576 ipf_state_deref(softc, (ipstate_t **)datap); 7577 break; 7578 case IPFGENITER_FRAG : 7579 ipf_frag_pkt_deref(softc, (ipfr_t **)datap); 7580 break; 7581 case IPFGENITER_NATFRAG : 7582 ipf_frag_nat_deref(softc, (ipfr_t **)datap); 7583 break; 7584 case IPFGENITER_HOSTMAP : 7585 WRITE_ENTER(&softc->ipf_nat); 7586 ipf_nat_hostmapdel(softc, (hostmap_t **)datap); 7587 RWLOCK_EXIT(&softc->ipf_nat); 7588 break; 7589 default : 7590 ipf_lookup_iterderef(softc, token->ipt_type, data); 7591 break; 7592 } 7593 } 7594 7595 ipf_token_unlink(softc, token); 7596 KFREE(token); 7597 return 0; 7598 } 7599 7600 7601 /* ------------------------------------------------------------------------ */ 7602 /* Function: ipf_nextrule */ 7603 /* Returns: frentry_t * - NULL == no more rules, else pointer to next */ 7604 /* Parameters: softc(I) - pointer to soft context main structure */ 7605 /* fr(I) - pointer to filter rule */ 7606 /* out(I) - 1 == out rules, 0 == input rules */ 7607 /* */ 7608 /* Starting with "fr", find the next rule to visit. This includes visiting */ 7609 /* the list of rule groups if either fr is NULL (empty list) or it is the */ 7610 /* last rule in the list. When walking rule lists, it is either input or */ 7611 /* output rules that are returned, never both. */ 7612 /* ------------------------------------------------------------------------ */ 7613 static frentry_t * 7614 ipf_nextrule(ipf_main_softc_t *softc, int active, int unit, 7615 frentry_t *fr, int out) 7616 { 7617 frentry_t *next; 7618 frgroup_t *fg; 7619 7620 if (fr != NULL && fr->fr_group != -1) { 7621 fg = ipf_findgroup(softc, fr->fr_names + fr->fr_group, 7622 unit, active, NULL); 7623 if (fg != NULL) 7624 fg = fg->fg_next; 7625 } else { 7626 fg = softc->ipf_groups[unit][active]; 7627 } 7628 7629 while (fg != NULL) { 7630 next = fg->fg_start; 7631 while (next != NULL) { 7632 if (out) { 7633 if (next->fr_flags & FR_OUTQUE) 7634 return next; 7635 } else if (next->fr_flags & FR_INQUE) { 7636 return next; 7637 } 7638 next = next->fr_next; 7639 } 7640 if (next == NULL) 7641 fg = fg->fg_next; 7642 } 7643 7644 return NULL; 7645 } 7646 7647 /* ------------------------------------------------------------------------ */ 7648 /* Function: ipf_getnextrule */ 7649 /* Returns: int - 0 = success, else error */ 7650 /* Parameters: softc(I)- pointer to soft context main structure */ 7651 /* t(I) - pointer to destination information to resolve */ 7652 /* ptr(I) - pointer to ipfobj_t to copyin from user space */ 7653 /* */ 7654 /* This function's first job is to bring in the ipfruleiter_t structure via */ 7655 /* the ipfobj_t structure to determine what should be the next rule to */ 7656 /* return. Once the ipfruleiter_t has been brought in, it then tries to */ 7657 /* find the 'next rule'. This may include searching rule group lists or */ 7658 /* just be as simple as looking at the 'next' field in the rule structure. */ 7659 /* When we have found the rule to return, increase its reference count and */ 7660 /* if we used an existing rule to get here, decrease its reference count. */ 7661 /* ------------------------------------------------------------------------ */ 7662 int 7663 ipf_getnextrule(ipf_main_softc_t *softc, ipftoken_t *t, void *ptr) 7664 { 7665 frentry_t *fr, *next, zero; 7666 ipfruleiter_t it; 7667 int error, out; 7668 frgroup_t *fg; 7669 ipfobj_t obj; 7670 int predict; 7671 char *dst; 7672 int unit; 7673 7674 if (t == NULL || ptr == NULL) { 7675 IPFERROR(84); 7676 return EFAULT; 7677 } 7678 7679 error = ipf_inobj(softc, ptr, &obj, &it, IPFOBJ_IPFITER); 7680 if (error != 0) 7681 return error; 7682 7683 if ((it.iri_inout < 0) || (it.iri_inout > 3)) { 7684 IPFERROR(85); 7685 return EINVAL; 7686 } 7687 if ((it.iri_active != 0) && (it.iri_active != 1)) { 7688 IPFERROR(86); 7689 return EINVAL; 7690 } 7691 if (it.iri_nrules == 0) { 7692 IPFERROR(87); 7693 return ENOSPC; 7694 } 7695 if (it.iri_rule == NULL) { 7696 IPFERROR(88); 7697 return EFAULT; 7698 } 7699 7700 fg = NULL; 7701 fr = t->ipt_data; 7702 if ((it.iri_inout & F_OUT) != 0) 7703 out = 1; 7704 else 7705 out = 0; 7706 if ((it.iri_inout & F_ACIN) != 0) 7707 unit = IPL_LOGCOUNT; 7708 else 7709 unit = IPL_LOGIPF; 7710 7711 READ_ENTER(&softc->ipf_mutex); 7712 if (fr == NULL) { 7713 if (*it.iri_group == '\0') { 7714 if (unit == IPL_LOGCOUNT) { 7715 next = softc->ipf_acct[out][it.iri_active]; 7716 } else { 7717 next = softc->ipf_rules[out][it.iri_active]; 7718 } 7719 if (next == NULL) 7720 next = ipf_nextrule(softc, it.iri_active, 7721 unit, NULL, out); 7722 } else { 7723 fg = ipf_findgroup(softc, it.iri_group, unit, 7724 it.iri_active, NULL); 7725 if (fg != NULL) 7726 next = fg->fg_start; 7727 else 7728 next = NULL; 7729 } 7730 } else { 7731 next = fr->fr_next; 7732 if (next == NULL) 7733 next = ipf_nextrule(softc, it.iri_active, unit, 7734 fr, out); 7735 } 7736 7737 if (next != NULL && next->fr_next != NULL) 7738 predict = 1; 7739 else if (ipf_nextrule(softc, it.iri_active, unit, next, out) != NULL) 7740 predict = 1; 7741 else 7742 predict = 0; 7743 7744 if (fr != NULL) 7745 (void) ipf_derefrule(softc, &fr); 7746 7747 obj.ipfo_type = IPFOBJ_FRENTRY; 7748 dst = (char *)it.iri_rule; 7749 7750 if (next != NULL) { 7751 obj.ipfo_size = next->fr_size; 7752 MUTEX_ENTER(&next->fr_lock); 7753 next->fr_ref++; 7754 MUTEX_EXIT(&next->fr_lock); 7755 t->ipt_data = next; 7756 } else { 7757 obj.ipfo_size = sizeof(frentry_t); 7758 bzero(&zero, sizeof(zero)); 7759 next = &zero; 7760 t->ipt_data = NULL; 7761 } 7762 it.iri_rule = predict ? next : NULL; 7763 if (predict == 0) 7764 ipf_token_mark_complete(t); 7765 7766 RWLOCK_EXIT(&softc->ipf_mutex); 7767 7768 obj.ipfo_ptr = dst; 7769 error = ipf_outobjk(softc, &obj, next); 7770 if (error == 0 && t->ipt_data != NULL) { 7771 dst += obj.ipfo_size; 7772 if (next->fr_data != NULL) { 7773 ipfobj_t dobj; 7774 7775 if (next->fr_type == FR_T_IPFEXPR) 7776 dobj.ipfo_type = IPFOBJ_IPFEXPR; 7777 else 7778 dobj.ipfo_type = IPFOBJ_FRIPF; 7779 dobj.ipfo_size = next->fr_dsize; 7780 dobj.ipfo_rev = obj.ipfo_rev; 7781 dobj.ipfo_ptr = dst; 7782 error = ipf_outobjk(softc, &dobj, next->fr_data); 7783 } 7784 } 7785 7786 if ((fr != NULL) && (next == &zero)) 7787 (void) ipf_derefrule(softc, &fr); 7788 7789 return error; 7790 } 7791 7792 7793 /* ------------------------------------------------------------------------ */ 7794 /* Function: ipf_frruleiter */ 7795 /* Returns: int - 0 = success, else error */ 7796 /* Parameters: softc(I)- pointer to soft context main structure */ 7797 /* data(I) - the token type to match */ 7798 /* uid(I) - uid owning the token */ 7799 /* ptr(I) - context pointer for the token */ 7800 /* */ 7801 /* This function serves as a stepping stone between ipf_ipf_ioctl and */ 7802 /* ipf_getnextrule. It's role is to find the right token in the kernel for */ 7803 /* the process doing the ioctl and use that to ask for the next rule. */ 7804 /* ------------------------------------------------------------------------ */ 7805 static int 7806 ipf_frruleiter(ipf_main_softc_t *softc, void *data, int uid, void *ctx) 7807 { 7808 ipftoken_t *token; 7809 ipfruleiter_t it; 7810 ipfobj_t obj; 7811 int error; 7812 7813 token = ipf_token_find(softc, IPFGENITER_IPF, uid, ctx); 7814 if (token != NULL) { 7815 error = ipf_getnextrule(softc, token, data); 7816 WRITE_ENTER(&softc->ipf_tokens); 7817 ipf_token_deref(softc, token); 7818 RWLOCK_EXIT(&softc->ipf_tokens); 7819 } else { 7820 error = ipf_inobj(softc, data, &obj, &it, IPFOBJ_IPFITER); 7821 if (error != 0) 7822 return error; 7823 it.iri_rule = NULL; 7824 error = ipf_outobj(softc, data, &it, IPFOBJ_IPFITER); 7825 } 7826 7827 return error; 7828 } 7829 7830 7831 /* ------------------------------------------------------------------------ */ 7832 /* Function: ipf_geniter */ 7833 /* Returns: int - 0 = success, else error */ 7834 /* Parameters: softc(I) - pointer to soft context main structure */ 7835 /* token(I) - pointer to ipftoken_t structure */ 7836 /* itp(I) - pointer to iterator data */ 7837 /* */ 7838 /* Decide which iterator function to call using information passed through */ 7839 /* the ipfgeniter_t structure at itp. */ 7840 /* ------------------------------------------------------------------------ */ 7841 static int 7842 ipf_geniter(ipf_main_softc_t *softc, ipftoken_t *token, ipfgeniter_t *itp) 7843 { 7844 int error; 7845 7846 switch (itp->igi_type) 7847 { 7848 case IPFGENITER_FRAG : 7849 error = ipf_frag_pkt_next(softc, token, itp); 7850 break; 7851 default : 7852 IPFERROR(92); 7853 error = EINVAL; 7854 break; 7855 } 7856 7857 return error; 7858 } 7859 7860 7861 /* ------------------------------------------------------------------------ */ 7862 /* Function: ipf_genericiter */ 7863 /* Returns: int - 0 = success, else error */ 7864 /* Parameters: softc(I)- pointer to soft context main structure */ 7865 /* data(I) - the token type to match */ 7866 /* uid(I) - uid owning the token */ 7867 /* ptr(I) - context pointer for the token */ 7868 /* */ 7869 /* Handle the SIOCGENITER ioctl for the ipfilter device. The primary role */ 7870 /* ------------------------------------------------------------------------ */ 7871 int 7872 ipf_genericiter(ipf_main_softc_t *softc, void *data, int uid, void *ctx) 7873 { 7874 ipftoken_t *token; 7875 ipfgeniter_t iter; 7876 int error; 7877 7878 error = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_GENITER); 7879 if (error != 0) 7880 return error; 7881 7882 token = ipf_token_find(softc, iter.igi_type, uid, ctx); 7883 if (token != NULL) { 7884 token->ipt_subtype = iter.igi_type; 7885 error = ipf_geniter(softc, token, &iter); 7886 WRITE_ENTER(&softc->ipf_tokens); 7887 ipf_token_deref(softc, token); 7888 RWLOCK_EXIT(&softc->ipf_tokens); 7889 } else { 7890 IPFERROR(93); 7891 error = 0; 7892 } 7893 7894 return error; 7895 } 7896 7897 7898 /* ------------------------------------------------------------------------ */ 7899 /* Function: ipf_ipf_ioctl */ 7900 /* Returns: int - 0 = success, else error */ 7901 /* Parameters: softc(I)- pointer to soft context main structure */ 7902 /* data(I) - the token type to match */ 7903 /* cmd(I) - the ioctl command number */ 7904 /* mode(I) - mode flags for the ioctl */ 7905 /* uid(I) - uid owning the token */ 7906 /* ptr(I) - context pointer for the token */ 7907 /* */ 7908 /* This function handles all of the ioctl command that are actually isssued */ 7909 /* to the /dev/ipl device. */ 7910 /* ------------------------------------------------------------------------ */ 7911 int 7912 ipf_ipf_ioctl(ipf_main_softc_t *softc, void *data, ioctlcmd_t cmd, int mode, 7913 int uid, void *ctx) 7914 { 7915 friostat_t fio; 7916 int error, tmp; 7917 ipfobj_t obj; 7918 SPL_INT(s); 7919 7920 switch (cmd) 7921 { 7922 case SIOCFRENB : 7923 if (!(mode & FWRITE)) { 7924 IPFERROR(94); 7925 error = EPERM; 7926 } else { 7927 error = BCOPYIN(data, &tmp, sizeof(tmp)); 7928 if (error != 0) { 7929 IPFERROR(95); 7930 error = EFAULT; 7931 break; 7932 } 7933 7934 WRITE_ENTER(&softc->ipf_global); 7935 if (tmp) { 7936 if (softc->ipf_running > 0) 7937 error = 0; 7938 else 7939 error = ipfattach(softc); 7940 if (error == 0) 7941 softc->ipf_running = 1; 7942 else 7943 (void) ipfdetach(softc); 7944 } else { 7945 if (softc->ipf_running == 1) 7946 error = ipfdetach(softc); 7947 else 7948 error = 0; 7949 if (error == 0) 7950 softc->ipf_running = -1; 7951 } 7952 RWLOCK_EXIT(&softc->ipf_global); 7953 } 7954 break; 7955 7956 case SIOCIPFSET : 7957 if (!(mode & FWRITE)) { 7958 IPFERROR(96); 7959 error = EPERM; 7960 break; 7961 } 7962 /* FALLTHRU */ 7963 case SIOCIPFGETNEXT : 7964 case SIOCIPFGET : 7965 error = ipf_ipftune(softc, cmd, (void *)data); 7966 break; 7967 7968 case SIOCSETFF : 7969 if (!(mode & FWRITE)) { 7970 IPFERROR(97); 7971 error = EPERM; 7972 } else { 7973 error = BCOPYIN(data, &softc->ipf_flags, 7974 sizeof(softc->ipf_flags)); 7975 if (error != 0) { 7976 IPFERROR(98); 7977 error = EFAULT; 7978 } 7979 } 7980 break; 7981 7982 case SIOCGETFF : 7983 error = BCOPYOUT(&softc->ipf_flags, data, 7984 sizeof(softc->ipf_flags)); 7985 if (error != 0) { 7986 IPFERROR(99); 7987 error = EFAULT; 7988 } 7989 break; 7990 7991 case SIOCFUNCL : 7992 error = ipf_resolvefunc(softc, (void *)data); 7993 break; 7994 7995 case SIOCINAFR : 7996 case SIOCRMAFR : 7997 case SIOCADAFR : 7998 case SIOCZRLST : 7999 if (!(mode & FWRITE)) { 8000 IPFERROR(100); 8001 error = EPERM; 8002 } else { 8003 error = frrequest(softc, IPL_LOGIPF, cmd, data, 8004 softc->ipf_active, 1); 8005 } 8006 break; 8007 8008 case SIOCINIFR : 8009 case SIOCRMIFR : 8010 case SIOCADIFR : 8011 if (!(mode & FWRITE)) { 8012 IPFERROR(101); 8013 error = EPERM; 8014 } else { 8015 error = frrequest(softc, IPL_LOGIPF, cmd, data, 8016 1 - softc->ipf_active, 1); 8017 } 8018 break; 8019 8020 case SIOCSWAPA : 8021 if (!(mode & FWRITE)) { 8022 IPFERROR(102); 8023 error = EPERM; 8024 } else { 8025 WRITE_ENTER(&softc->ipf_mutex); 8026 error = BCOPYOUT(&softc->ipf_active, data, 8027 sizeof(softc->ipf_active)); 8028 if (error != 0) { 8029 IPFERROR(103); 8030 error = EFAULT; 8031 } else { 8032 softc->ipf_active = 1 - softc->ipf_active; 8033 } 8034 RWLOCK_EXIT(&softc->ipf_mutex); 8035 } 8036 break; 8037 8038 case SIOCGETFS : 8039 error = ipf_inobj(softc, (void *)data, &obj, &fio, 8040 IPFOBJ_IPFSTAT); 8041 if (error != 0) 8042 break; 8043 ipf_getstat(softc, &fio, obj.ipfo_rev); 8044 error = ipf_outobj(softc, (void *)data, &fio, IPFOBJ_IPFSTAT); 8045 break; 8046 8047 case SIOCFRZST : 8048 if (!(mode & FWRITE)) { 8049 IPFERROR(104); 8050 error = EPERM; 8051 } else 8052 error = ipf_zerostats(softc, data); 8053 break; 8054 8055 case SIOCIPFFL : 8056 if (!(mode & FWRITE)) { 8057 IPFERROR(105); 8058 error = EPERM; 8059 } else { 8060 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8061 if (!error) { 8062 tmp = ipf_flush(softc, IPL_LOGIPF, tmp); 8063 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8064 if (error != 0) { 8065 IPFERROR(106); 8066 error = EFAULT; 8067 } 8068 } else { 8069 IPFERROR(107); 8070 error = EFAULT; 8071 } 8072 } 8073 break; 8074 8075 #ifdef USE_INET6 8076 case SIOCIPFL6 : 8077 if (!(mode & FWRITE)) { 8078 IPFERROR(108); 8079 error = EPERM; 8080 } else { 8081 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8082 if (!error) { 8083 tmp = ipf_flush(softc, IPL_LOGIPF, tmp); 8084 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8085 if (error != 0) { 8086 IPFERROR(109); 8087 error = EFAULT; 8088 } 8089 } else { 8090 IPFERROR(110); 8091 error = EFAULT; 8092 } 8093 } 8094 break; 8095 #endif 8096 8097 case SIOCSTLCK : 8098 if (!(mode & FWRITE)) { 8099 IPFERROR(122); 8100 error = EPERM; 8101 } else { 8102 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8103 if (error == 0) { 8104 ipf_state_setlock(softc->ipf_state_soft, tmp); 8105 ipf_nat_setlock(softc->ipf_nat_soft, tmp); 8106 ipf_frag_setlock(softc->ipf_frag_soft, tmp); 8107 ipf_auth_setlock(softc->ipf_auth_soft, tmp); 8108 } else { 8109 IPFERROR(111); 8110 error = EFAULT; 8111 } 8112 } 8113 break; 8114 8115 #ifdef IPFILTER_LOG 8116 case SIOCIPFFB : 8117 if (!(mode & FWRITE)) { 8118 IPFERROR(112); 8119 error = EPERM; 8120 } else { 8121 tmp = ipf_log_clear(softc, IPL_LOGIPF); 8122 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8123 if (error) { 8124 IPFERROR(113); 8125 error = EFAULT; 8126 } 8127 } 8128 break; 8129 #endif /* IPFILTER_LOG */ 8130 8131 case SIOCFRSYN : 8132 if (!(mode & FWRITE)) { 8133 IPFERROR(114); 8134 error = EPERM; 8135 } else { 8136 WRITE_ENTER(&softc->ipf_global); 8137 #if (defined(MENTAT) && defined(_KERNEL)) && !defined(INSTANCES) 8138 error = ipfsync(); 8139 #else 8140 ipf_sync(softc, NULL); 8141 error = 0; 8142 #endif 8143 RWLOCK_EXIT(&softc->ipf_global); 8144 8145 } 8146 break; 8147 8148 case SIOCGFRST : 8149 error = ipf_outobj(softc, (void *)data, 8150 ipf_frag_stats(softc->ipf_frag_soft), 8151 IPFOBJ_FRAGSTAT); 8152 break; 8153 8154 #ifdef IPFILTER_LOG 8155 case FIONREAD : 8156 tmp = ipf_log_bytesused(softc, IPL_LOGIPF); 8157 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8158 break; 8159 #endif 8160 8161 case SIOCIPFITER : 8162 SPL_SCHED(s); 8163 error = ipf_frruleiter(softc, data, uid, ctx); 8164 SPL_X(s); 8165 break; 8166 8167 case SIOCGENITER : 8168 SPL_SCHED(s); 8169 error = ipf_genericiter(softc, data, uid, ctx); 8170 SPL_X(s); 8171 break; 8172 8173 case SIOCIPFDELTOK : 8174 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8175 if (error == 0) { 8176 SPL_SCHED(s); 8177 error = ipf_token_del(softc, tmp, uid, ctx); 8178 SPL_X(s); 8179 } 8180 break; 8181 8182 default : 8183 IPFERROR(115); 8184 error = EINVAL; 8185 break; 8186 } 8187 8188 return error; 8189 } 8190 8191 8192 /* ------------------------------------------------------------------------ */ 8193 /* Function: ipf_decaps */ 8194 /* Returns: int - -1 == decapsulation failed, else bit mask of */ 8195 /* flags indicating packet filtering decision. */ 8196 /* Parameters: fin(I) - pointer to packet information */ 8197 /* pass(I) - IP protocol version to match */ 8198 /* l5proto(I) - layer 5 protocol to decode UDP data as. */ 8199 /* */ 8200 /* This function is called for packets that are wrapt up in other packets, */ 8201 /* for example, an IP packet that is the entire data segment for another IP */ 8202 /* packet. If the basic constraints for this are satisfied, change the */ 8203 /* buffer to point to the start of the inner packet and start processing */ 8204 /* rules belonging to the head group this rule specifies. */ 8205 /* ------------------------------------------------------------------------ */ 8206 u_32_t 8207 ipf_decaps(fr_info_t *fin, u_32_t pass, int l5proto) 8208 { 8209 fr_info_t fin2, *fino = NULL; 8210 int elen, hlen, nh; 8211 grehdr_t gre; 8212 ip_t *ip; 8213 mb_t *m; 8214 8215 if ((fin->fin_flx & FI_COALESCE) == 0) 8216 if (ipf_coalesce(fin) == -1) 8217 goto cantdecaps; 8218 8219 m = fin->fin_m; 8220 hlen = fin->fin_hlen; 8221 8222 switch (fin->fin_p) 8223 { 8224 case IPPROTO_UDP : 8225 /* 8226 * In this case, the specific protocol being decapsulated 8227 * inside UDP frames comes from the rule. 8228 */ 8229 nh = fin->fin_fr->fr_icode; 8230 break; 8231 8232 case IPPROTO_GRE : /* 47 */ 8233 bcopy(fin->fin_dp, (char *)&gre, sizeof(gre)); 8234 hlen += sizeof(grehdr_t); 8235 if (gre.gr_R|gre.gr_s) 8236 goto cantdecaps; 8237 if (gre.gr_C) 8238 hlen += 4; 8239 if (gre.gr_K) 8240 hlen += 4; 8241 if (gre.gr_S) 8242 hlen += 4; 8243 8244 nh = IPPROTO_IP; 8245 8246 /* 8247 * If the routing options flag is set, validate that it is 8248 * there and bounce over it. 8249 */ 8250 #if 0 8251 /* This is really heavy weight and lots of room for error, */ 8252 /* so for now, put it off and get the simple stuff right. */ 8253 if (gre.gr_R) { 8254 u_char off, len, *s; 8255 u_short af; 8256 int end; 8257 8258 end = 0; 8259 s = fin->fin_dp; 8260 s += hlen; 8261 aplen = fin->fin_plen - hlen; 8262 while (aplen > 3) { 8263 af = (s[0] << 8) | s[1]; 8264 off = s[2]; 8265 len = s[3]; 8266 aplen -= 4; 8267 s += 4; 8268 if (af == 0 && len == 0) { 8269 end = 1; 8270 break; 8271 } 8272 if (aplen < len) 8273 break; 8274 s += len; 8275 aplen -= len; 8276 } 8277 if (end != 1) 8278 goto cantdecaps; 8279 hlen = s - (u_char *)fin->fin_dp; 8280 } 8281 #endif 8282 break; 8283 8284 #ifdef IPPROTO_IPIP 8285 case IPPROTO_IPIP : /* 4 */ 8286 #endif 8287 nh = IPPROTO_IP; 8288 break; 8289 8290 default : /* Includes ESP, AH is special for IPv4 */ 8291 goto cantdecaps; 8292 } 8293 8294 switch (nh) 8295 { 8296 case IPPROTO_IP : 8297 case IPPROTO_IPV6 : 8298 break; 8299 default : 8300 goto cantdecaps; 8301 } 8302 8303 bcopy((char *)fin, (char *)&fin2, sizeof(fin2)); 8304 fino = fin; 8305 fin = &fin2; 8306 elen = hlen; 8307 #if defined(MENTAT) && defined(_KERNEL) 8308 m->b_rptr += elen; 8309 #else 8310 m->m_data += elen; 8311 m->m_len -= elen; 8312 #endif 8313 fin->fin_plen -= elen; 8314 8315 ip = (ip_t *)((char *)fin->fin_ip + elen); 8316 8317 /* 8318 * Make sure we have at least enough data for the network layer 8319 * header. 8320 */ 8321 if (IP_V(ip) == 4) 8322 hlen = IP_HL(ip) << 2; 8323 #ifdef USE_INET6 8324 else if (IP_V(ip) == 6) 8325 hlen = sizeof(ip6_t); 8326 #endif 8327 else 8328 goto cantdecaps2; 8329 8330 if (fin->fin_plen < hlen) 8331 goto cantdecaps2; 8332 8333 fin->fin_dp = (char *)ip + hlen; 8334 8335 if (IP_V(ip) == 4) { 8336 /* 8337 * Perform IPv4 header checksum validation. 8338 */ 8339 if (ipf_cksum((u_short *)ip, hlen)) 8340 goto cantdecaps2; 8341 } 8342 8343 if (ipf_makefrip(hlen, ip, fin) == -1) { 8344 cantdecaps2: 8345 if (m != NULL) { 8346 #if defined(MENTAT) && defined(_KERNEL) 8347 m->b_rptr -= elen; 8348 #else 8349 m->m_data -= elen; 8350 m->m_len += elen; 8351 #endif 8352 } 8353 cantdecaps: 8354 DT1(frb_decapfrip, fr_info_t *, fin); 8355 pass &= ~FR_CMDMASK; 8356 pass |= FR_BLOCK|FR_QUICK; 8357 fin->fin_reason = FRB_DECAPFRIP; 8358 return -1; 8359 } 8360 8361 pass = ipf_scanlist(fin, pass); 8362 8363 /* 8364 * Copy the packet filter "result" fields out of the fr_info_t struct 8365 * that is local to the decapsulation processing and back into the 8366 * one we were called with. 8367 */ 8368 fino->fin_flx = fin->fin_flx; 8369 fino->fin_rev = fin->fin_rev; 8370 fino->fin_icode = fin->fin_icode; 8371 fino->fin_rule = fin->fin_rule; 8372 (void) strncpy(fino->fin_group, fin->fin_group, FR_GROUPLEN); 8373 fino->fin_fr = fin->fin_fr; 8374 fino->fin_error = fin->fin_error; 8375 fino->fin_mp = fin->fin_mp; 8376 fino->fin_m = fin->fin_m; 8377 m = fin->fin_m; 8378 if (m != NULL) { 8379 #if defined(MENTAT) && defined(_KERNEL) 8380 m->b_rptr -= elen; 8381 #else 8382 m->m_data -= elen; 8383 m->m_len += elen; 8384 #endif 8385 } 8386 return pass; 8387 } 8388 8389 8390 /* ------------------------------------------------------------------------ */ 8391 /* Function: ipf_matcharray_load */ 8392 /* Returns: int - 0 = success, else error */ 8393 /* Parameters: softc(I) - pointer to soft context main structure */ 8394 /* data(I) - pointer to ioctl data */ 8395 /* objp(I) - ipfobj_t structure to load data into */ 8396 /* arrayptr(I) - pointer to location to store array pointer */ 8397 /* */ 8398 /* This function loads in a mathing array through the ipfobj_t struct that */ 8399 /* describes it. Sanity checking and array size limitations are enforced */ 8400 /* in this function to prevent userspace from trying to load in something */ 8401 /* that is insanely big. Once the size of the array is known, the memory */ 8402 /* required is malloc'd and returned through changing *arrayptr. The */ 8403 /* contents of the array are verified before returning. Only in the event */ 8404 /* of a successful call is the caller required to free up the malloc area. */ 8405 /* ------------------------------------------------------------------------ */ 8406 int 8407 ipf_matcharray_load(ipf_main_softc_t *softc, void *data, ipfobj_t *objp, 8408 int **arrayptr) 8409 { 8410 int arraysize, *array, error; 8411 8412 *arrayptr = NULL; 8413 8414 error = BCOPYIN(data, objp, sizeof(*objp)); 8415 if (error != 0) { 8416 IPFERROR(116); 8417 return EFAULT; 8418 } 8419 8420 if (objp->ipfo_type != IPFOBJ_IPFEXPR) { 8421 IPFERROR(117); 8422 return EINVAL; 8423 } 8424 8425 if (((objp->ipfo_size & 3) != 0) || (objp->ipfo_size == 0) || 8426 (objp->ipfo_size > 1024)) { 8427 IPFERROR(118); 8428 return EINVAL; 8429 } 8430 8431 arraysize = objp->ipfo_size * sizeof(*array); 8432 KMALLOCS(array, int *, arraysize); 8433 if (array == NULL) { 8434 IPFERROR(119); 8435 return ENOMEM; 8436 } 8437 8438 error = COPYIN(objp->ipfo_ptr, array, arraysize); 8439 if (error != 0) { 8440 KFREES(array, arraysize); 8441 IPFERROR(120); 8442 return EFAULT; 8443 } 8444 8445 if (ipf_matcharray_verify(array, arraysize) != 0) { 8446 KFREES(array, arraysize); 8447 IPFERROR(121); 8448 return EINVAL; 8449 } 8450 8451 *arrayptr = array; 8452 return 0; 8453 } 8454 8455 8456 /* ------------------------------------------------------------------------ */ 8457 /* Function: ipf_matcharray_verify */ 8458 /* Returns: Nil */ 8459 /* Parameters: array(I) - pointer to matching array */ 8460 /* arraysize(I) - number of elements in the array */ 8461 /* */ 8462 /* Verify the contents of a matching array by stepping through each element */ 8463 /* in it. The actual commands in the array are not verified for */ 8464 /* correctness, only that all of the sizes are correctly within limits. */ 8465 /* ------------------------------------------------------------------------ */ 8466 int 8467 ipf_matcharray_verify(int *array, int arraysize) 8468 { 8469 int i, nelem, maxidx; 8470 ipfexp_t *e; 8471 8472 nelem = arraysize / sizeof(*array); 8473 8474 /* 8475 * Currently, it makes no sense to have an array less than 6 8476 * elements long - the initial size at the from, a single operation 8477 * (minimum 4 in length) and a trailer, for a total of 6. 8478 */ 8479 if ((array[0] < 6) || (arraysize < 24) || (arraysize > 4096)) { 8480 return -1; 8481 } 8482 8483 /* 8484 * Verify the size of data pointed to by array with how long 8485 * the array claims to be itself. 8486 */ 8487 if (array[0] * sizeof(*array) != arraysize) { 8488 return -1; 8489 } 8490 8491 maxidx = nelem - 1; 8492 /* 8493 * The last opcode in this array should be an IPF_EXP_END. 8494 */ 8495 if (array[maxidx] != IPF_EXP_END) { 8496 return -1; 8497 } 8498 8499 for (i = 1; i < maxidx; ) { 8500 e = (ipfexp_t *)(array + i); 8501 8502 /* 8503 * The length of the bits to check must be at least 1 8504 * (or else there is nothing to comapre with!) and it 8505 * cannot exceed the length of the data present. 8506 */ 8507 if ((e->ipfe_size < 1 ) || 8508 (e->ipfe_size + i > maxidx)) { 8509 return -1; 8510 } 8511 i += e->ipfe_size; 8512 } 8513 return 0; 8514 } 8515 8516 8517 /* ------------------------------------------------------------------------ */ 8518 /* Function: ipf_fr_matcharray */ 8519 /* Returns: int - 0 = match failed, else positive match */ 8520 /* Parameters: fin(I) - pointer to packet information */ 8521 /* array(I) - pointer to matching array */ 8522 /* */ 8523 /* This function is used to apply a matching array against a packet and */ 8524 /* return an indication of whether or not the packet successfully matches */ 8525 /* all of the commands in it. */ 8526 /* ------------------------------------------------------------------------ */ 8527 static int 8528 ipf_fr_matcharray(fr_info_t *fin, int *array) 8529 { 8530 int i, n, *x, rv, p; 8531 ipfexp_t *e; 8532 8533 rv = 0; 8534 n = array[0]; 8535 x = array + 1; 8536 8537 for (; n > 0; x += 3 + x[3], rv = 0) { 8538 e = (ipfexp_t *)x; 8539 if (e->ipfe_cmd == IPF_EXP_END) 8540 break; 8541 n -= e->ipfe_size; 8542 8543 /* 8544 * The upper 16 bits currently store the protocol value. 8545 * This is currently used with TCP and UDP port compares and 8546 * allows "tcp.port = 80" without requiring an explicit 8547 " "ip.pr = tcp" first. 8548 */ 8549 p = e->ipfe_cmd >> 16; 8550 if ((p != 0) && (p != fin->fin_p)) 8551 break; 8552 8553 switch (e->ipfe_cmd) 8554 { 8555 case IPF_EXP_IP_PR : 8556 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8557 rv |= (fin->fin_p == e->ipfe_arg0[i]); 8558 } 8559 break; 8560 8561 case IPF_EXP_IP_SRCADDR : 8562 if (fin->fin_v != 4) 8563 break; 8564 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8565 rv |= ((fin->fin_saddr & 8566 e->ipfe_arg0[i * 2 + 1]) == 8567 e->ipfe_arg0[i * 2]); 8568 } 8569 break; 8570 8571 case IPF_EXP_IP_DSTADDR : 8572 if (fin->fin_v != 4) 8573 break; 8574 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8575 rv |= ((fin->fin_daddr & 8576 e->ipfe_arg0[i * 2 + 1]) == 8577 e->ipfe_arg0[i * 2]); 8578 } 8579 break; 8580 8581 case IPF_EXP_IP_ADDR : 8582 if (fin->fin_v != 4) 8583 break; 8584 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8585 rv |= ((fin->fin_saddr & 8586 e->ipfe_arg0[i * 2 + 1]) == 8587 e->ipfe_arg0[i * 2]) || 8588 ((fin->fin_daddr & 8589 e->ipfe_arg0[i * 2 + 1]) == 8590 e->ipfe_arg0[i * 2]); 8591 } 8592 break; 8593 8594 #ifdef USE_INET6 8595 case IPF_EXP_IP6_SRCADDR : 8596 if (fin->fin_v != 6) 8597 break; 8598 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8599 rv |= IP6_MASKEQ(&fin->fin_src6, 8600 &e->ipfe_arg0[i * 8 + 4], 8601 &e->ipfe_arg0[i * 8]); 8602 } 8603 break; 8604 8605 case IPF_EXP_IP6_DSTADDR : 8606 if (fin->fin_v != 6) 8607 break; 8608 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8609 rv |= IP6_MASKEQ(&fin->fin_dst6, 8610 &e->ipfe_arg0[i * 8 + 4], 8611 &e->ipfe_arg0[i * 8]); 8612 } 8613 break; 8614 8615 case IPF_EXP_IP6_ADDR : 8616 if (fin->fin_v != 6) 8617 break; 8618 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8619 rv |= IP6_MASKEQ(&fin->fin_src6, 8620 &e->ipfe_arg0[i * 8 + 4], 8621 &e->ipfe_arg0[i * 8]) || 8622 IP6_MASKEQ(&fin->fin_dst6, 8623 &e->ipfe_arg0[i * 8 + 4], 8624 &e->ipfe_arg0[i * 8]); 8625 } 8626 break; 8627 #endif 8628 8629 case IPF_EXP_UDP_PORT : 8630 case IPF_EXP_TCP_PORT : 8631 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8632 rv |= (fin->fin_sport == e->ipfe_arg0[i]) || 8633 (fin->fin_dport == e->ipfe_arg0[i]); 8634 } 8635 break; 8636 8637 case IPF_EXP_UDP_SPORT : 8638 case IPF_EXP_TCP_SPORT : 8639 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8640 rv |= (fin->fin_sport == e->ipfe_arg0[i]); 8641 } 8642 break; 8643 8644 case IPF_EXP_UDP_DPORT : 8645 case IPF_EXP_TCP_DPORT : 8646 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8647 rv |= (fin->fin_dport == e->ipfe_arg0[i]); 8648 } 8649 break; 8650 8651 case IPF_EXP_TCP_FLAGS : 8652 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8653 rv |= ((fin->fin_tcpf & 8654 e->ipfe_arg0[i * 2 + 1]) == 8655 e->ipfe_arg0[i * 2]); 8656 } 8657 break; 8658 } 8659 rv ^= e->ipfe_not; 8660 8661 if (rv == 0) 8662 break; 8663 } 8664 8665 return rv; 8666 } 8667 8668 8669 /* ------------------------------------------------------------------------ */ 8670 /* Function: ipf_queueflush */ 8671 /* Returns: int - number of entries flushed (0 = none) */ 8672 /* Parameters: softc(I) - pointer to soft context main structure */ 8673 /* deletefn(I) - function to call to delete entry */ 8674 /* ipfqs(I) - top of the list of ipf internal queues */ 8675 /* userqs(I) - top of the list of user defined timeouts */ 8676 /* */ 8677 /* This fucntion gets called when the state/NAT hash tables fill up and we */ 8678 /* need to try a bit harder to free up some space. The algorithm used here */ 8679 /* split into two parts but both halves have the same goal: to reduce the */ 8680 /* number of connections considered to be "active" to the low watermark. */ 8681 /* There are two steps in doing this: */ 8682 /* 1) Remove any TCP connections that are already considered to be "closed" */ 8683 /* but have not yet been removed from the state table. The two states */ 8684 /* TCPS_TIME_WAIT and TCPS_CLOSED are considered to be the perfect */ 8685 /* candidates for this style of removal. If freeing up entries in */ 8686 /* CLOSED or both CLOSED and TIME_WAIT brings us to the low watermark, */ 8687 /* we do not go on to step 2. */ 8688 /* */ 8689 /* 2) Look for the oldest entries on each timeout queue and free them if */ 8690 /* they are within the given window we are considering. Where the */ 8691 /* window starts and the steps taken to increase its size depend upon */ 8692 /* how long ipf has been running (ipf_ticks.) Anything modified in the */ 8693 /* last 30 seconds is not touched. */ 8694 /* touched */ 8695 /* die ipf_ticks 30*1.5 1800*1.5 | 43200*1.5 */ 8696 /* | | | | | | */ 8697 /* future <--+----------+--------+-----------+-----+-----+-----------> past */ 8698 /* now \_int=30s_/ \_int=1hr_/ \_int=12hr */ 8699 /* */ 8700 /* Points to note: */ 8701 /* - tqe_die is the time, in the future, when entries die. */ 8702 /* - tqe_die - ipf_ticks is how long left the connection has to live in ipf */ 8703 /* ticks. */ 8704 /* - tqe_touched is when the entry was last used by NAT/state */ 8705 /* - the closer tqe_touched is to ipf_ticks, the further tqe_die will be */ 8706 /* ipf_ticks any given timeout queue and vice versa. */ 8707 /* - both tqe_die and tqe_touched increase over time */ 8708 /* - timeout queues are sorted with the highest value of tqe_die at the */ 8709 /* bottom and therefore the smallest values of each are at the top */ 8710 /* - the pointer passed in as ipfqs should point to an array of timeout */ 8711 /* queues representing each of the TCP states */ 8712 /* */ 8713 /* We start by setting up a maximum range to scan for things to move of */ 8714 /* iend (newest) to istart (oldest) in chunks of "interval". If nothing is */ 8715 /* found in that range, "interval" is adjusted (so long as it isn't 30) and */ 8716 /* we start again with a new value for "iend" and "istart". This is */ 8717 /* continued until we either finish the scan of 30 second intervals or the */ 8718 /* low water mark is reached. */ 8719 /* ------------------------------------------------------------------------ */ 8720 int 8721 ipf_queueflush(ipf_main_softc_t *softc, ipftq_delete_fn_t deletefn, 8722 ipftq_t *ipfqs, ipftq_t *userqs, u_int *activep, int size, int low) 8723 { 8724 u_long interval, istart, iend; 8725 ipftq_t *ifq, *ifqnext; 8726 ipftqent_t *tqe, *tqn; 8727 int removed = 0; 8728 8729 for (tqn = ipfqs[IPF_TCPS_CLOSED].ifq_head; ((tqe = tqn) != NULL); ) { 8730 tqn = tqe->tqe_next; 8731 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8732 removed++; 8733 } 8734 if ((*activep * 100 / size) > low) { 8735 for (tqn = ipfqs[IPF_TCPS_TIME_WAIT].ifq_head; 8736 ((tqe = tqn) != NULL); ) { 8737 tqn = tqe->tqe_next; 8738 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8739 removed++; 8740 } 8741 } 8742 8743 if ((*activep * 100 / size) <= low) { 8744 return removed; 8745 } 8746 8747 /* 8748 * NOTE: Use of "* 15 / 10" is required here because if "* 1.5" is 8749 * used then the operations are upgraded to floating point 8750 * and kernels don't like floating point... 8751 */ 8752 if (softc->ipf_ticks > IPF_TTLVAL(43200 * 15 / 10)) { 8753 istart = IPF_TTLVAL(86400 * 4); 8754 interval = IPF_TTLVAL(43200); 8755 } else if (softc->ipf_ticks > IPF_TTLVAL(1800 * 15 / 10)) { 8756 istart = IPF_TTLVAL(43200); 8757 interval = IPF_TTLVAL(1800); 8758 } else if (softc->ipf_ticks > IPF_TTLVAL(30 * 15 / 10)) { 8759 istart = IPF_TTLVAL(1800); 8760 interval = IPF_TTLVAL(30); 8761 } else { 8762 return 0; 8763 } 8764 if (istart > softc->ipf_ticks) { 8765 if (softc->ipf_ticks - interval < interval) 8766 istart = interval; 8767 else 8768 istart = (softc->ipf_ticks / interval) * interval; 8769 } 8770 8771 iend = softc->ipf_ticks - interval; 8772 8773 while ((*activep * 100 / size) > low) { 8774 u_long try; 8775 8776 try = softc->ipf_ticks - istart; 8777 8778 for (ifq = ipfqs; ifq != NULL; ifq = ifq->ifq_next) { 8779 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { 8780 if (try < tqe->tqe_touched) 8781 break; 8782 tqn = tqe->tqe_next; 8783 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8784 removed++; 8785 } 8786 } 8787 8788 for (ifq = userqs; ifq != NULL; ifq = ifqnext) { 8789 ifqnext = ifq->ifq_next; 8790 8791 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { 8792 if (try < tqe->tqe_touched) 8793 break; 8794 tqn = tqe->tqe_next; 8795 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8796 removed++; 8797 } 8798 } 8799 8800 if (try >= iend) { 8801 if (interval == IPF_TTLVAL(43200)) { 8802 interval = IPF_TTLVAL(1800); 8803 } else if (interval == IPF_TTLVAL(1800)) { 8804 interval = IPF_TTLVAL(30); 8805 } else { 8806 break; 8807 } 8808 if (interval >= softc->ipf_ticks) 8809 break; 8810 8811 iend = softc->ipf_ticks - interval; 8812 } 8813 istart -= interval; 8814 } 8815 8816 return removed; 8817 } 8818 8819 8820 /* ------------------------------------------------------------------------ */ 8821 /* Function: ipf_deliverlocal */ 8822 /* Returns: int - 1 = local address, 0 = non-local address */ 8823 /* Parameters: softc(I) - pointer to soft context main structure */ 8824 /* ipversion(I) - IP protocol version (4 or 6) */ 8825 /* ifp(I) - network interface pointer */ 8826 /* ipaddr(I) - IPv4/6 destination address */ 8827 /* */ 8828 /* This fucntion is used to determine in the address "ipaddr" belongs to */ 8829 /* the network interface represented by ifp. */ 8830 /* ------------------------------------------------------------------------ */ 8831 int 8832 ipf_deliverlocal(ipf_main_softc_t *softc, int ipversion, void *ifp, 8833 i6addr_t *ipaddr) 8834 { 8835 i6addr_t addr; 8836 int islocal = 0; 8837 8838 if (ipversion == 4) { 8839 if (ipf_ifpaddr(softc, 4, FRI_NORMAL, ifp, &addr, NULL) == 0) { 8840 if (addr.in4.s_addr == ipaddr->in4.s_addr) 8841 islocal = 1; 8842 } 8843 8844 #ifdef USE_INET6 8845 } else if (ipversion == 6) { 8846 if (ipf_ifpaddr(softc, 6, FRI_NORMAL, ifp, &addr, NULL) == 0) { 8847 if (IP6_EQ(&addr, ipaddr)) 8848 islocal = 1; 8849 } 8850 #endif 8851 } 8852 8853 return islocal; 8854 } 8855 8856 8857 /* ------------------------------------------------------------------------ */ 8858 /* Function: ipf_settimeout */ 8859 /* Returns: int - 0 = success, -1 = failure */ 8860 /* Parameters: softc(I) - pointer to soft context main structure */ 8861 /* t(I) - pointer to tuneable array entry */ 8862 /* p(I) - pointer to values passed in to apply */ 8863 /* */ 8864 /* This function is called to set the timeout values for each distinct */ 8865 /* queue timeout that is available. When called, it calls into both the */ 8866 /* state and NAT code, telling them to update their timeout queues. */ 8867 /* ------------------------------------------------------------------------ */ 8868 static int 8869 ipf_settimeout(struct ipf_main_softc_s *softc, ipftuneable_t *t, 8870 ipftuneval_t *p) 8871 { 8872 8873 /* 8874 * ipf_interror should be set by the functions called here, not 8875 * by this function - it's just a middle man. 8876 */ 8877 if (ipf_state_settimeout(softc, t, p) == -1) 8878 return -1; 8879 if (ipf_nat_settimeout(softc, t, p) == -1) 8880 return -1; 8881 return 0; 8882 } 8883 8884 8885 /* ------------------------------------------------------------------------ */ 8886 /* Function: ipf_apply_timeout */ 8887 /* Returns: int - 0 = success, -1 = failure */ 8888 /* Parameters: head(I) - pointer to tuneable array entry */ 8889 /* seconds(I) - pointer to values passed in to apply */ 8890 /* */ 8891 /* This function applies a timeout of "seconds" to the timeout queue that */ 8892 /* is pointed to by "head". All entries on this list have an expiration */ 8893 /* set to be the current tick value of ipf plus the ttl. Given that this */ 8894 /* function should only be called when the delta is non-zero, the task is */ 8895 /* to walk the entire list and apply the change. The sort order will not */ 8896 /* change. The only catch is that this is O(n) across the list, so if the */ 8897 /* queue has lots of entries (10s of thousands or 100s of thousands), it */ 8898 /* could take a relatively long time to work through them all. */ 8899 /* ------------------------------------------------------------------------ */ 8900 void 8901 ipf_apply_timeout(ipftq_t *head, u_int seconds) 8902 { 8903 u_int oldtimeout, newtimeout; 8904 ipftqent_t *tqe; 8905 int delta; 8906 8907 MUTEX_ENTER(&head->ifq_lock); 8908 oldtimeout = head->ifq_ttl; 8909 newtimeout = IPF_TTLVAL(seconds); 8910 delta = oldtimeout - newtimeout; 8911 8912 head->ifq_ttl = newtimeout; 8913 8914 for (tqe = head->ifq_head; tqe != NULL; tqe = tqe->tqe_next) { 8915 tqe->tqe_die += delta; 8916 } 8917 MUTEX_EXIT(&head->ifq_lock); 8918 } 8919 8920 8921 /* ------------------------------------------------------------------------ */ 8922 /* Function: ipf_settimeout_tcp */ 8923 /* Returns: int - 0 = successfully applied, -1 = failed */ 8924 /* Parameters: t(I) - pointer to tuneable to change */ 8925 /* p(I) - pointer to new timeout information */ 8926 /* tab(I) - pointer to table of TCP queues */ 8927 /* */ 8928 /* This function applies the new timeout (p) to the TCP tunable (t) and */ 8929 /* updates all of the entries on the relevant timeout queue by calling */ 8930 /* ipf_apply_timeout(). */ 8931 /* ------------------------------------------------------------------------ */ 8932 int 8933 ipf_settimeout_tcp(ipftuneable_t *t, ipftuneval_t *p, ipftq_t *tab) 8934 { 8935 if (!strcmp(t->ipft_name, "tcp_idle_timeout") || 8936 !strcmp(t->ipft_name, "tcp_established")) { 8937 ipf_apply_timeout(&tab[IPF_TCPS_ESTABLISHED], p->ipftu_int); 8938 } else if (!strcmp(t->ipft_name, "tcp_close_wait")) { 8939 ipf_apply_timeout(&tab[IPF_TCPS_CLOSE_WAIT], p->ipftu_int); 8940 } else if (!strcmp(t->ipft_name, "tcp_last_ack")) { 8941 ipf_apply_timeout(&tab[IPF_TCPS_LAST_ACK], p->ipftu_int); 8942 } else if (!strcmp(t->ipft_name, "tcp_timeout")) { 8943 ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int); 8944 ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int); 8945 ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int); 8946 } else if (!strcmp(t->ipft_name, "tcp_listen")) { 8947 ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int); 8948 } else if (!strcmp(t->ipft_name, "tcp_half_established")) { 8949 ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int); 8950 } else if (!strcmp(t->ipft_name, "tcp_closing")) { 8951 ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int); 8952 } else if (!strcmp(t->ipft_name, "tcp_syn_received")) { 8953 ipf_apply_timeout(&tab[IPF_TCPS_SYN_RECEIVED], p->ipftu_int); 8954 } else if (!strcmp(t->ipft_name, "tcp_syn_sent")) { 8955 ipf_apply_timeout(&tab[IPF_TCPS_SYN_SENT], p->ipftu_int); 8956 } else if (!strcmp(t->ipft_name, "tcp_closed")) { 8957 ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int); 8958 } else if (!strcmp(t->ipft_name, "tcp_half_closed")) { 8959 ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int); 8960 } else if (!strcmp(t->ipft_name, "tcp_time_wait")) { 8961 ipf_apply_timeout(&tab[IPF_TCPS_TIME_WAIT], p->ipftu_int); 8962 } else { 8963 /* 8964 * ipf_interror isn't set here because it should be set 8965 * by whatever called this function. 8966 */ 8967 return -1; 8968 } 8969 return 0; 8970 } 8971 8972 8973 /* ------------------------------------------------------------------------ */ 8974 /* Function: ipf_main_soft_create */ 8975 /* Returns: NULL = failure, else success */ 8976 /* Parameters: arg(I) - pointer to soft context structure if already allocd */ 8977 /* */ 8978 /* Create the foundation soft context structure. In circumstances where it */ 8979 /* is not required to dynamically allocate the context, a pointer can be */ 8980 /* passed in (rather than NULL) to a structure to be initialised. */ 8981 /* The main thing of interest is that a number of locks are initialised */ 8982 /* here instead of in the where might be expected - in the relevant create */ 8983 /* function elsewhere. This is done because the current locking design has */ 8984 /* some areas where these locks are used outside of their module. */ 8985 /* Possibly the most important exercise that is done here is setting of all */ 8986 /* the timeout values, allowing them to be changed before init(). */ 8987 /* ------------------------------------------------------------------------ */ 8988 void * 8989 ipf_main_soft_create(void *arg) 8990 { 8991 ipf_main_softc_t *softc; 8992 8993 if (arg == NULL) { 8994 KMALLOC(softc, ipf_main_softc_t *); 8995 if (softc == NULL) 8996 return NULL; 8997 } else { 8998 softc = arg; 8999 } 9000 9001 bzero((char *)softc, sizeof(*softc)); 9002 9003 /* 9004 * This serves as a flag as to whether or not the softc should be 9005 * free'd when _destroy is called. 9006 */ 9007 softc->ipf_dynamic_softc = (arg == NULL) ? 1 : 0; 9008 9009 softc->ipf_tuners = ipf_tune_array_copy(softc, 9010 sizeof(ipf_main_tuneables), 9011 ipf_main_tuneables); 9012 if (softc->ipf_tuners == NULL) { 9013 ipf_main_soft_destroy(softc); 9014 return NULL; 9015 } 9016 9017 MUTEX_INIT(&softc->ipf_rw, "ipf rw mutex"); 9018 MUTEX_INIT(&softc->ipf_timeoutlock, "ipf timeout lock"); 9019 RWLOCK_INIT(&softc->ipf_global, "ipf filter load/unload mutex"); 9020 RWLOCK_INIT(&softc->ipf_mutex, "ipf filter rwlock"); 9021 RWLOCK_INIT(&softc->ipf_tokens, "ipf token rwlock"); 9022 RWLOCK_INIT(&softc->ipf_state, "ipf state rwlock"); 9023 RWLOCK_INIT(&softc->ipf_nat, "ipf IP NAT rwlock"); 9024 RWLOCK_INIT(&softc->ipf_poolrw, "ipf pool rwlock"); 9025 RWLOCK_INIT(&softc->ipf_frag, "ipf frag rwlock"); 9026 9027 softc->ipf_token_head = NULL; 9028 softc->ipf_token_tail = &softc->ipf_token_head; 9029 9030 softc->ipf_tcpidletimeout = FIVE_DAYS; 9031 softc->ipf_tcpclosewait = IPF_TTLVAL(2 * TCP_MSL); 9032 softc->ipf_tcplastack = IPF_TTLVAL(30); 9033 softc->ipf_tcptimewait = IPF_TTLVAL(2 * TCP_MSL); 9034 softc->ipf_tcptimeout = IPF_TTLVAL(2 * TCP_MSL); 9035 softc->ipf_tcpsynsent = IPF_TTLVAL(2 * TCP_MSL); 9036 softc->ipf_tcpsynrecv = IPF_TTLVAL(2 * TCP_MSL); 9037 softc->ipf_tcpclosed = IPF_TTLVAL(30); 9038 softc->ipf_tcphalfclosed = IPF_TTLVAL(2 * 3600); 9039 softc->ipf_udptimeout = IPF_TTLVAL(120); 9040 softc->ipf_udpacktimeout = IPF_TTLVAL(12); 9041 softc->ipf_icmptimeout = IPF_TTLVAL(60); 9042 softc->ipf_icmpacktimeout = IPF_TTLVAL(6); 9043 softc->ipf_iptimeout = IPF_TTLVAL(60); 9044 9045 #if defined(IPFILTER_DEFAULT_BLOCK) 9046 softc->ipf_pass = FR_BLOCK|FR_NOMATCH; 9047 #else 9048 softc->ipf_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH; 9049 #endif 9050 softc->ipf_minttl = 4; 9051 softc->ipf_icmpminfragmtu = 68; 9052 softc->ipf_flags = IPF_LOGGING; 9053 9054 return softc; 9055 } 9056 9057 /* ------------------------------------------------------------------------ */ 9058 /* Function: ipf_main_soft_init */ 9059 /* Returns: 0 = success, -1 = failure */ 9060 /* Parameters: softc(I) - pointer to soft context main structure */ 9061 /* */ 9062 /* A null-op function that exists as a placeholder so that the flow in */ 9063 /* other functions is obvious. */ 9064 /* ------------------------------------------------------------------------ */ 9065 /*ARGSUSED*/ 9066 int 9067 ipf_main_soft_init(ipf_main_softc_t *softc) 9068 { 9069 return 0; 9070 } 9071 9072 9073 /* ------------------------------------------------------------------------ */ 9074 /* Function: ipf_main_soft_destroy */ 9075 /* Returns: void */ 9076 /* Parameters: softc(I) - pointer to soft context main structure */ 9077 /* */ 9078 /* Undo everything that we did in ipf_main_soft_create. */ 9079 /* */ 9080 /* The most important check that needs to be made here is whether or not */ 9081 /* the structure was allocated by ipf_main_soft_create() by checking what */ 9082 /* value is stored in ipf_dynamic_main. */ 9083 /* ------------------------------------------------------------------------ */ 9084 /*ARGSUSED*/ 9085 void 9086 ipf_main_soft_destroy(ipf_main_softc_t *softc) 9087 { 9088 9089 RW_DESTROY(&softc->ipf_frag); 9090 RW_DESTROY(&softc->ipf_poolrw); 9091 RW_DESTROY(&softc->ipf_nat); 9092 RW_DESTROY(&softc->ipf_state); 9093 RW_DESTROY(&softc->ipf_tokens); 9094 RW_DESTROY(&softc->ipf_mutex); 9095 RW_DESTROY(&softc->ipf_global); 9096 MUTEX_DESTROY(&softc->ipf_timeoutlock); 9097 MUTEX_DESTROY(&softc->ipf_rw); 9098 9099 if (softc->ipf_tuners != NULL) { 9100 KFREES(softc->ipf_tuners, sizeof(ipf_main_tuneables)); 9101 } 9102 if (softc->ipf_dynamic_softc == 1) { 9103 KFREE(softc); 9104 } 9105 } 9106 9107 9108 /* ------------------------------------------------------------------------ */ 9109 /* Function: ipf_main_soft_fini */ 9110 /* Returns: 0 = success, -1 = failure */ 9111 /* Parameters: softc(I) - pointer to soft context main structure */ 9112 /* */ 9113 /* Clean out the rules which have been added since _init was last called, */ 9114 /* the only dynamic part of the mainline. */ 9115 /* ------------------------------------------------------------------------ */ 9116 int 9117 ipf_main_soft_fini(ipf_main_softc_t *softc) 9118 { 9119 (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE|FR_INACTIVE); 9120 (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE); 9121 (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE|FR_INACTIVE); 9122 (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE); 9123 9124 return 0; 9125 } 9126 9127 9128 /* ------------------------------------------------------------------------ */ 9129 /* Function: ipf_main_load */ 9130 /* Returns: 0 = success, -1 = failure */ 9131 /* Parameters: none */ 9132 /* */ 9133 /* Handle global initialisation that needs to be done for the base part of */ 9134 /* IPFilter. At present this just amounts to initialising some ICMP lookup */ 9135 /* arrays that get used by the state/NAT code. */ 9136 /* ------------------------------------------------------------------------ */ 9137 int 9138 ipf_main_load(void) 9139 { 9140 int i; 9141 9142 /* fill icmp reply type table */ 9143 for (i = 0; i <= ICMP_MAXTYPE; i++) 9144 icmpreplytype4[i] = -1; 9145 icmpreplytype4[ICMP_ECHO] = ICMP_ECHOREPLY; 9146 icmpreplytype4[ICMP_TSTAMP] = ICMP_TSTAMPREPLY; 9147 icmpreplytype4[ICMP_IREQ] = ICMP_IREQREPLY; 9148 icmpreplytype4[ICMP_MASKREQ] = ICMP_MASKREPLY; 9149 9150 #ifdef USE_INET6 9151 /* fill icmp reply type table */ 9152 for (i = 0; i <= ICMP6_MAXTYPE; i++) 9153 icmpreplytype6[i] = -1; 9154 icmpreplytype6[ICMP6_ECHO_REQUEST] = ICMP6_ECHO_REPLY; 9155 icmpreplytype6[ICMP6_MEMBERSHIP_QUERY] = ICMP6_MEMBERSHIP_REPORT; 9156 icmpreplytype6[ICMP6_NI_QUERY] = ICMP6_NI_REPLY; 9157 icmpreplytype6[ND_ROUTER_SOLICIT] = ND_ROUTER_ADVERT; 9158 icmpreplytype6[ND_NEIGHBOR_SOLICIT] = ND_NEIGHBOR_ADVERT; 9159 #endif 9160 9161 return 0; 9162 } 9163 9164 9165 /* ------------------------------------------------------------------------ */ 9166 /* Function: ipf_main_unload */ 9167 /* Returns: 0 = success, -1 = failure */ 9168 /* Parameters: none */ 9169 /* */ 9170 /* A null-op function that exists as a placeholder so that the flow in */ 9171 /* other functions is obvious. */ 9172 /* ------------------------------------------------------------------------ */ 9173 int 9174 ipf_main_unload(void) 9175 { 9176 return 0; 9177 } 9178 9179 9180 /* ------------------------------------------------------------------------ */ 9181 /* Function: ipf_load_all */ 9182 /* Returns: 0 = success, -1 = failure */ 9183 /* Parameters: none */ 9184 /* */ 9185 /* Work through all of the subsystems inside IPFilter and call the load */ 9186 /* function for each in an order that won't lead to a crash :) */ 9187 /* ------------------------------------------------------------------------ */ 9188 int 9189 ipf_load_all(void) 9190 { 9191 if (ipf_main_load() == -1) 9192 return -1; 9193 9194 if (ipf_state_main_load() == -1) 9195 return -1; 9196 9197 if (ipf_nat_main_load() == -1) 9198 return -1; 9199 9200 if (ipf_frag_main_load() == -1) 9201 return -1; 9202 9203 if (ipf_auth_main_load() == -1) 9204 return -1; 9205 9206 if (ipf_proxy_main_load() == -1) 9207 return -1; 9208 9209 return 0; 9210 } 9211 9212 9213 /* ------------------------------------------------------------------------ */ 9214 /* Function: ipf_unload_all */ 9215 /* Returns: 0 = success, -1 = failure */ 9216 /* Parameters: none */ 9217 /* */ 9218 /* Work through all of the subsystems inside IPFilter and call the unload */ 9219 /* function for each in an order that won't lead to a crash :) */ 9220 /* ------------------------------------------------------------------------ */ 9221 int 9222 ipf_unload_all(void) 9223 { 9224 if (ipf_proxy_main_unload() == -1) 9225 return -1; 9226 9227 if (ipf_auth_main_unload() == -1) 9228 return -1; 9229 9230 if (ipf_frag_main_unload() == -1) 9231 return -1; 9232 9233 if (ipf_nat_main_unload() == -1) 9234 return -1; 9235 9236 if (ipf_state_main_unload() == -1) 9237 return -1; 9238 9239 if (ipf_main_unload() == -1) 9240 return -1; 9241 9242 return 0; 9243 } 9244 9245 9246 /* ------------------------------------------------------------------------ */ 9247 /* Function: ipf_create_all */ 9248 /* Returns: NULL = failure, else success */ 9249 /* Parameters: arg(I) - pointer to soft context main structure */ 9250 /* */ 9251 /* Work through all of the subsystems inside IPFilter and call the create */ 9252 /* function for each in an order that won't lead to a crash :) */ 9253 /* ------------------------------------------------------------------------ */ 9254 ipf_main_softc_t * 9255 ipf_create_all(void *arg) 9256 { 9257 ipf_main_softc_t *softc; 9258 9259 softc = ipf_main_soft_create(arg); 9260 if (softc == NULL) 9261 return NULL; 9262 9263 #ifdef IPFILTER_LOG 9264 softc->ipf_log_soft = ipf_log_soft_create(softc); 9265 if (softc->ipf_log_soft == NULL) { 9266 ipf_destroy_all(softc); 9267 return NULL; 9268 } 9269 #endif 9270 9271 softc->ipf_lookup_soft = ipf_lookup_soft_create(softc); 9272 if (softc->ipf_lookup_soft == NULL) { 9273 ipf_destroy_all(softc); 9274 return NULL; 9275 } 9276 9277 softc->ipf_sync_soft = ipf_sync_soft_create(softc); 9278 if (softc->ipf_sync_soft == NULL) { 9279 ipf_destroy_all(softc); 9280 return NULL; 9281 } 9282 9283 softc->ipf_state_soft = ipf_state_soft_create(softc); 9284 if (softc->ipf_state_soft == NULL) { 9285 ipf_destroy_all(softc); 9286 return NULL; 9287 } 9288 9289 softc->ipf_nat_soft = ipf_nat_soft_create(softc); 9290 if (softc->ipf_nat_soft == NULL) { 9291 ipf_destroy_all(softc); 9292 return NULL; 9293 } 9294 9295 softc->ipf_frag_soft = ipf_frag_soft_create(softc); 9296 if (softc->ipf_frag_soft == NULL) { 9297 ipf_destroy_all(softc); 9298 return NULL; 9299 } 9300 9301 softc->ipf_auth_soft = ipf_auth_soft_create(softc); 9302 if (softc->ipf_auth_soft == NULL) { 9303 ipf_destroy_all(softc); 9304 return NULL; 9305 } 9306 9307 softc->ipf_proxy_soft = ipf_proxy_soft_create(softc); 9308 if (softc->ipf_proxy_soft == NULL) { 9309 ipf_destroy_all(softc); 9310 return NULL; 9311 } 9312 9313 return softc; 9314 } 9315 9316 9317 /* ------------------------------------------------------------------------ */ 9318 /* Function: ipf_destroy_all */ 9319 /* Returns: void */ 9320 /* Parameters: softc(I) - pointer to soft context main structure */ 9321 /* */ 9322 /* Work through all of the subsystems inside IPFilter and call the destroy */ 9323 /* function for each in an order that won't lead to a crash :) */ 9324 /* */ 9325 /* Every one of these functions is expected to succeed, so there is no */ 9326 /* checking of return values. */ 9327 /* ------------------------------------------------------------------------ */ 9328 void 9329 ipf_destroy_all(ipf_main_softc_t *softc) 9330 { 9331 9332 if (softc->ipf_state_soft != NULL) { 9333 ipf_state_soft_destroy(softc, softc->ipf_state_soft); 9334 softc->ipf_state_soft = NULL; 9335 } 9336 9337 if (softc->ipf_nat_soft != NULL) { 9338 ipf_nat_soft_destroy(softc, softc->ipf_nat_soft); 9339 softc->ipf_nat_soft = NULL; 9340 } 9341 9342 if (softc->ipf_frag_soft != NULL) { 9343 ipf_frag_soft_destroy(softc, softc->ipf_frag_soft); 9344 softc->ipf_frag_soft = NULL; 9345 } 9346 9347 if (softc->ipf_auth_soft != NULL) { 9348 ipf_auth_soft_destroy(softc, softc->ipf_auth_soft); 9349 softc->ipf_auth_soft = NULL; 9350 } 9351 9352 if (softc->ipf_proxy_soft != NULL) { 9353 ipf_proxy_soft_destroy(softc, softc->ipf_proxy_soft); 9354 softc->ipf_proxy_soft = NULL; 9355 } 9356 9357 if (softc->ipf_sync_soft != NULL) { 9358 ipf_sync_soft_destroy(softc, softc->ipf_sync_soft); 9359 softc->ipf_sync_soft = NULL; 9360 } 9361 9362 if (softc->ipf_lookup_soft != NULL) { 9363 ipf_lookup_soft_destroy(softc, softc->ipf_lookup_soft); 9364 softc->ipf_lookup_soft = NULL; 9365 } 9366 9367 #ifdef IPFILTER_LOG 9368 if (softc->ipf_log_soft != NULL) { 9369 ipf_log_soft_destroy(softc, softc->ipf_log_soft); 9370 softc->ipf_log_soft = NULL; 9371 } 9372 #endif 9373 9374 ipf_main_soft_destroy(softc); 9375 } 9376 9377 9378 /* ------------------------------------------------------------------------ */ 9379 /* Function: ipf_init_all */ 9380 /* Returns: 0 = success, -1 = failure */ 9381 /* Parameters: softc(I) - pointer to soft context main structure */ 9382 /* */ 9383 /* Work through all of the subsystems inside IPFilter and call the init */ 9384 /* function for each in an order that won't lead to a crash :) */ 9385 /* ------------------------------------------------------------------------ */ 9386 int 9387 ipf_init_all(ipf_main_softc_t *softc) 9388 { 9389 9390 if (ipf_main_soft_init(softc) == -1) 9391 return -1; 9392 9393 #ifdef IPFILTER_LOG 9394 if (ipf_log_soft_init(softc, softc->ipf_log_soft) == -1) 9395 return -1; 9396 #endif 9397 9398 if (ipf_lookup_soft_init(softc, softc->ipf_lookup_soft) == -1) 9399 return -1; 9400 9401 if (ipf_sync_soft_init(softc, softc->ipf_sync_soft) == -1) 9402 return -1; 9403 9404 if (ipf_state_soft_init(softc, softc->ipf_state_soft) == -1) 9405 return -1; 9406 9407 if (ipf_nat_soft_init(softc, softc->ipf_nat_soft) == -1) 9408 return -1; 9409 9410 if (ipf_frag_soft_init(softc, softc->ipf_frag_soft) == -1) 9411 return -1; 9412 9413 if (ipf_auth_soft_init(softc, softc->ipf_auth_soft) == -1) 9414 return -1; 9415 9416 if (ipf_proxy_soft_init(softc, softc->ipf_proxy_soft) == -1) 9417 return -1; 9418 9419 return 0; 9420 } 9421 9422 9423 /* ------------------------------------------------------------------------ */ 9424 /* Function: ipf_fini_all */ 9425 /* Returns: 0 = success, -1 = failure */ 9426 /* Parameters: softc(I) - pointer to soft context main structure */ 9427 /* */ 9428 /* Work through all of the subsystems inside IPFilter and call the fini */ 9429 /* function for each in an order that won't lead to a crash :) */ 9430 /* ------------------------------------------------------------------------ */ 9431 int 9432 ipf_fini_all(ipf_main_softc_t *softc) 9433 { 9434 9435 ipf_token_flush(softc); 9436 9437 if (ipf_proxy_soft_fini(softc, softc->ipf_proxy_soft) == -1) 9438 return -1; 9439 9440 if (ipf_auth_soft_fini(softc, softc->ipf_auth_soft) == -1) 9441 return -1; 9442 9443 if (ipf_frag_soft_fini(softc, softc->ipf_frag_soft) == -1) 9444 return -1; 9445 9446 if (ipf_nat_soft_fini(softc, softc->ipf_nat_soft) == -1) 9447 return -1; 9448 9449 if (ipf_state_soft_fini(softc, softc->ipf_state_soft) == -1) 9450 return -1; 9451 9452 if (ipf_sync_soft_fini(softc, softc->ipf_sync_soft) == -1) 9453 return -1; 9454 9455 if (ipf_lookup_soft_fini(softc, softc->ipf_lookup_soft) == -1) 9456 return -1; 9457 9458 #ifdef IPFILTER_LOG 9459 if (ipf_log_soft_fini(softc, softc->ipf_log_soft) == -1) 9460 return -1; 9461 #endif 9462 9463 if (ipf_main_soft_fini(softc) == -1) 9464 return -1; 9465 9466 return 0; 9467 } 9468 9469 9470 /* ------------------------------------------------------------------------ */ 9471 /* Function: ipf_rule_expire */ 9472 /* Returns: Nil */ 9473 /* Parameters: softc(I) - pointer to soft context main structure */ 9474 /* */ 9475 /* At present this function exists just to support temporary addition of */ 9476 /* firewall rules. Both inactive and active lists are scanned for items to */ 9477 /* purge, as by rights, the expiration is computed as soon as the rule is */ 9478 /* loaded in. */ 9479 /* ------------------------------------------------------------------------ */ 9480 void 9481 ipf_rule_expire(ipf_main_softc_t *softc) 9482 { 9483 frentry_t *fr; 9484 9485 if ((softc->ipf_rule_explist[0] == NULL) && 9486 (softc->ipf_rule_explist[1] == NULL)) 9487 return; 9488 9489 WRITE_ENTER(&softc->ipf_mutex); 9490 9491 while ((fr = softc->ipf_rule_explist[0]) != NULL) { 9492 /* 9493 * Because the list is kept sorted on insertion, the fist 9494 * one that dies in the future means no more work to do. 9495 */ 9496 if (fr->fr_die > softc->ipf_ticks) 9497 break; 9498 ipf_rule_delete(softc, fr, IPL_LOGIPF, 0); 9499 } 9500 9501 while ((fr = softc->ipf_rule_explist[1]) != NULL) { 9502 /* 9503 * Because the list is kept sorted on insertion, the fist 9504 * one that dies in the future means no more work to do. 9505 */ 9506 if (fr->fr_die > softc->ipf_ticks) 9507 break; 9508 ipf_rule_delete(softc, fr, IPL_LOGIPF, 1); 9509 } 9510 9511 RWLOCK_EXIT(&softc->ipf_mutex); 9512 } 9513 9514 9515 static int ipf_ht_node_cmp(const struct host_node_s *, const struct host_node_s *); 9516 static void ipf_ht_node_make_key(host_track_t *, host_node_t *, int, 9517 i6addr_t *); 9518 9519 RBI_CODE(ipf_rb, host_node_t, hn_entry, ipf_ht_node_cmp) 9520 9521 9522 /* ------------------------------------------------------------------------ */ 9523 /* Function: ipf_ht_node_cmp */ 9524 /* Returns: int - 0 == nodes are the same, .. */ 9525 /* Parameters: k1(I) - pointer to first key to compare */ 9526 /* k2(I) - pointer to second key to compare */ 9527 /* */ 9528 /* The "key" for the node is a combination of two fields: the address */ 9529 /* family and the address itself. */ 9530 /* */ 9531 /* Because we're not actually interpreting the address data, it isn't */ 9532 /* necessary to convert them to/from network/host byte order. The mask is */ 9533 /* just used to remove bits that aren't significant - it doesn't matter */ 9534 /* where they are, as long as they're always in the same place. */ 9535 /* */ 9536 /* As with IP6_EQ, comparing IPv6 addresses starts at the bottom because */ 9537 /* this is where individual ones will differ the most - but not true for */ 9538 /* for /48's, etc. */ 9539 /* ------------------------------------------------------------------------ */ 9540 static int 9541 ipf_ht_node_cmp(const struct host_node_s *k1, const struct host_node_s *k2) 9542 { 9543 int i; 9544 9545 i = (k2->hn_addr.adf_family - k1->hn_addr.adf_family); 9546 if (i != 0) 9547 return i; 9548 9549 if (k1->hn_addr.adf_family == AF_INET) 9550 return (k2->hn_addr.adf_addr.in4.s_addr - 9551 k1->hn_addr.adf_addr.in4.s_addr); 9552 9553 i = k2->hn_addr.adf_addr.i6[3] - k1->hn_addr.adf_addr.i6[3]; 9554 if (i != 0) 9555 return i; 9556 i = k2->hn_addr.adf_addr.i6[2] - k1->hn_addr.adf_addr.i6[2]; 9557 if (i != 0) 9558 return i; 9559 i = k2->hn_addr.adf_addr.i6[1] - k1->hn_addr.adf_addr.i6[1]; 9560 if (i != 0) 9561 return i; 9562 i = k2->hn_addr.adf_addr.i6[0] - k1->hn_addr.adf_addr.i6[0]; 9563 return i; 9564 } 9565 9566 9567 /* ------------------------------------------------------------------------ */ 9568 /* Function: ipf_ht_node_make_key */ 9569 /* Returns: Nil */ 9570 /* parameters: htp(I) - pointer to address tracking structure */ 9571 /* key(I) - where to store masked address for lookup */ 9572 /* family(I) - protocol family of address */ 9573 /* addr(I) - pointer to network address */ 9574 /* */ 9575 /* Using the "netmask" (number of bits) stored parent host tracking struct, */ 9576 /* copy the address passed in into the key structure whilst masking out the */ 9577 /* bits that we don't want. */ 9578 /* */ 9579 /* Because the parser will set ht_netmask to 128 if there is no protocol */ 9580 /* specified (the parser doesn't know if it should be a v4 or v6 rule), we */ 9581 /* have to be wary of that and not allow 32-128 to happen. */ 9582 /* ------------------------------------------------------------------------ */ 9583 static void 9584 ipf_ht_node_make_key(host_track_t *htp, host_node_t *key, int family, 9585 i6addr_t *addr) 9586 { 9587 key->hn_addr.adf_family = family; 9588 if (family == AF_INET) { 9589 u_32_t mask; 9590 int bits; 9591 9592 key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in4); 9593 bits = htp->ht_netmask; 9594 if (bits >= 32) { 9595 mask = 0xffffffff; 9596 } else { 9597 mask = htonl(0xffffffff << (32 - bits)); 9598 } 9599 key->hn_addr.adf_addr.in4.s_addr = addr->in4.s_addr & mask; 9600 #ifdef USE_INET6 9601 } else { 9602 int bits = htp->ht_netmask; 9603 9604 key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in6); 9605 if (bits > 96) { 9606 key->hn_addr.adf_addr.i6[3] = addr->i6[3] & 9607 htonl(0xffffffff << (128 - bits)); 9608 key->hn_addr.adf_addr.i6[2] = addr->i6[2]; 9609 key->hn_addr.adf_addr.i6[1] = addr->i6[2]; 9610 key->hn_addr.adf_addr.i6[0] = addr->i6[2]; 9611 } else if (bits > 64) { 9612 key->hn_addr.adf_addr.i6[3] = 0; 9613 key->hn_addr.adf_addr.i6[2] = addr->i6[2] & 9614 htonl(0xffffffff << (96 - bits)); 9615 key->hn_addr.adf_addr.i6[1] = addr->i6[1]; 9616 key->hn_addr.adf_addr.i6[0] = addr->i6[0]; 9617 } else if (bits > 32) { 9618 key->hn_addr.adf_addr.i6[3] = 0; 9619 key->hn_addr.adf_addr.i6[2] = 0; 9620 key->hn_addr.adf_addr.i6[1] = addr->i6[1] & 9621 htonl(0xffffffff << (64 - bits)); 9622 key->hn_addr.adf_addr.i6[0] = addr->i6[0]; 9623 } else { 9624 key->hn_addr.adf_addr.i6[3] = 0; 9625 key->hn_addr.adf_addr.i6[2] = 0; 9626 key->hn_addr.adf_addr.i6[1] = 0; 9627 key->hn_addr.adf_addr.i6[0] = addr->i6[0] & 9628 htonl(0xffffffff << (32 - bits)); 9629 } 9630 #endif 9631 } 9632 } 9633 9634 9635 /* ------------------------------------------------------------------------ */ 9636 /* Function: ipf_ht_node_add */ 9637 /* Returns: int - 0 == success, -1 == failure */ 9638 /* Parameters: softc(I) - pointer to soft context main structure */ 9639 /* htp(I) - pointer to address tracking structure */ 9640 /* family(I) - protocol family of address */ 9641 /* addr(I) - pointer to network address */ 9642 /* */ 9643 /* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS */ 9644 /* ipf_ht_node_del FROM RUNNING CONCURRENTLY ON THE SAME htp. */ 9645 /* */ 9646 /* After preparing the key with the address information to find, look in */ 9647 /* the red-black tree to see if the address is known. A successful call to */ 9648 /* this function can mean one of two things: a new node was added to the */ 9649 /* tree or a matching node exists and we're able to bump up its activity. */ 9650 /* ------------------------------------------------------------------------ */ 9651 int 9652 ipf_ht_node_add(ipf_main_softc_t *softc, host_track_t *htp, int family, 9653 i6addr_t *addr) 9654 { 9655 host_node_t *h; 9656 host_node_t k; 9657 9658 ipf_ht_node_make_key(htp, &k, family, addr); 9659 9660 h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k); 9661 if (h == NULL) { 9662 if (htp->ht_cur_nodes >= htp->ht_max_nodes) 9663 return -1; 9664 KMALLOC(h, host_node_t *); 9665 if (h == NULL) { 9666 DT(ipf_rb_no_mem); 9667 LBUMP(ipf_rb_no_mem); 9668 return -1; 9669 } 9670 9671 /* 9672 * If there was a macro to initialise the RB node then that 9673 * would get used here, but there isn't... 9674 */ 9675 bzero((char *)h, sizeof(*h)); 9676 h->hn_addr = k.hn_addr; 9677 h->hn_addr.adf_family = k.hn_addr.adf_family; 9678 RBI_INSERT(ipf_rb, &htp->ht_root, h); 9679 htp->ht_cur_nodes++; 9680 } else { 9681 if ((htp->ht_max_per_node != 0) && 9682 (h->hn_active >= htp->ht_max_per_node)) { 9683 DT(ipf_rb_node_max); 9684 LBUMP(ipf_rb_node_max); 9685 return -1; 9686 } 9687 } 9688 9689 h->hn_active++; 9690 9691 return 0; 9692 } 9693 9694 9695 /* ------------------------------------------------------------------------ */ 9696 /* Function: ipf_ht_node_del */ 9697 /* Returns: int - 0 == success, -1 == failure */ 9698 /* parameters: htp(I) - pointer to address tracking structure */ 9699 /* family(I) - protocol family of address */ 9700 /* addr(I) - pointer to network address */ 9701 /* */ 9702 /* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS */ 9703 /* ipf_ht_node_add FROM RUNNING CONCURRENTLY ON THE SAME htp. */ 9704 /* */ 9705 /* Try and find the address passed in amongst the leaves on this tree to */ 9706 /* be friend. If found then drop the active account for that node drops by */ 9707 /* one. If that count reaches 0, it is time to free it all up. */ 9708 /* ------------------------------------------------------------------------ */ 9709 int 9710 ipf_ht_node_del(host_track_t *htp, int family, i6addr_t *addr) 9711 { 9712 host_node_t *h; 9713 host_node_t k; 9714 9715 ipf_ht_node_make_key(htp, &k, family, addr); 9716 9717 h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k); 9718 if (h == NULL) { 9719 return -1; 9720 } else { 9721 h->hn_active--; 9722 if (h->hn_active == 0) { 9723 (void) RBI_DELETE(ipf_rb, &htp->ht_root, h); 9724 htp->ht_cur_nodes--; 9725 KFREE(h); 9726 } 9727 } 9728 9729 return 0; 9730 } 9731 9732 9733 /* ------------------------------------------------------------------------ */ 9734 /* Function: ipf_rb_ht_init */ 9735 /* Returns: Nil */ 9736 /* Parameters: head(I) - pointer to host tracking structure */ 9737 /* */ 9738 /* Initialise the host tracking structure to be ready for use above. */ 9739 /* ------------------------------------------------------------------------ */ 9740 void 9741 ipf_rb_ht_init(host_track_t *head) 9742 { 9743 memset(head, 0, sizeof(*head)); 9744 RBI_INIT(ipf_rb, &head->ht_root); 9745 } 9746 9747 9748 /* ------------------------------------------------------------------------ */ 9749 /* Function: ipf_rb_ht_freenode */ 9750 /* Returns: Nil */ 9751 /* Parameters: head(I) - pointer to host tracking structure */ 9752 /* arg(I) - additional argument from walk caller */ 9753 /* */ 9754 /* Free an actual host_node_t structure. */ 9755 /* ------------------------------------------------------------------------ */ 9756 void 9757 ipf_rb_ht_freenode(host_node_t *node, void *arg) 9758 { 9759 KFREE(node); 9760 } 9761 9762 9763 /* ------------------------------------------------------------------------ */ 9764 /* Function: ipf_rb_ht_flush */ 9765 /* Returns: Nil */ 9766 /* Parameters: head(I) - pointer to host tracking structure */ 9767 /* */ 9768 /* Remove all of the nodes in the tree tracking hosts by calling a walker */ 9769 /* and free'ing each one. */ 9770 /* ------------------------------------------------------------------------ */ 9771 void 9772 ipf_rb_ht_flush(host_track_t *head) 9773 { 9774 /* XXX - May use node members after freeing the node. */ 9775 RBI_WALK(ipf_rb, &head->ht_root, ipf_rb_ht_freenode, NULL); 9776 } 9777 9778 9779 /* ------------------------------------------------------------------------ */ 9780 /* Function: ipf_slowtimer */ 9781 /* Returns: Nil */ 9782 /* Parameters: ptr(I) - pointer to main ipf soft context structure */ 9783 /* */ 9784 /* Slowly expire held state for fragments. Timeouts are set * in */ 9785 /* expectation of this being called twice per second. */ 9786 /* ------------------------------------------------------------------------ */ 9787 void 9788 ipf_slowtimer(ipf_main_softc_t *softc) 9789 { 9790 9791 ipf_token_expire(softc); 9792 ipf_frag_expire(softc); 9793 ipf_state_expire(softc); 9794 ipf_nat_expire(softc); 9795 ipf_auth_expire(softc); 9796 ipf_lookup_expire(softc); 9797 ipf_rule_expire(softc); 9798 ipf_sync_expire(softc); 9799 softc->ipf_ticks++; 9800 # if defined(__OpenBSD__) 9801 timeout_add(&ipf_slowtimer_ch, hz/2); 9802 # endif 9803 } 9804 9805 9806 /* ------------------------------------------------------------------------ */ 9807 /* Function: ipf_inet_mask_add */ 9808 /* Returns: Nil */ 9809 /* Parameters: bits(I) - pointer to nat context information */ 9810 /* mtab(I) - pointer to mask hash table structure */ 9811 /* */ 9812 /* When called, bits represents the mask of a new NAT rule that has just */ 9813 /* been added. This function inserts a bitmask into the array of masks to */ 9814 /* search when searching for a matching NAT rule for a packet. */ 9815 /* Prevention of duplicate masks is achieved by checking the use count for */ 9816 /* a given netmask. */ 9817 /* ------------------------------------------------------------------------ */ 9818 void 9819 ipf_inet_mask_add(int bits, ipf_v4_masktab_t *mtab) 9820 { 9821 u_32_t mask; 9822 int i, j; 9823 9824 mtab->imt4_masks[bits]++; 9825 if (mtab->imt4_masks[bits] > 1) 9826 return; 9827 9828 if (bits == 0) 9829 mask = 0; 9830 else 9831 mask = 0xffffffff << (32 - bits); 9832 9833 for (i = 0; i < 33; i++) { 9834 if (ntohl(mtab->imt4_active[i]) < mask) { 9835 for (j = 32; j > i; j--) 9836 mtab->imt4_active[j] = mtab->imt4_active[j - 1]; 9837 mtab->imt4_active[i] = htonl(mask); 9838 break; 9839 } 9840 } 9841 mtab->imt4_max++; 9842 } 9843 9844 9845 /* ------------------------------------------------------------------------ */ 9846 /* Function: ipf_inet_mask_del */ 9847 /* Returns: Nil */ 9848 /* Parameters: bits(I) - number of bits set in the netmask */ 9849 /* mtab(I) - pointer to mask hash table structure */ 9850 /* */ 9851 /* Remove the 32bit bitmask represented by "bits" from the collection of */ 9852 /* netmasks stored inside of mtab. */ 9853 /* ------------------------------------------------------------------------ */ 9854 void 9855 ipf_inet_mask_del(int bits, ipf_v4_masktab_t *mtab) 9856 { 9857 u_32_t mask; 9858 int i, j; 9859 9860 mtab->imt4_masks[bits]--; 9861 if (mtab->imt4_masks[bits] > 0) 9862 return; 9863 9864 mask = htonl(0xffffffff << (32 - bits)); 9865 for (i = 0; i < 33; i++) { 9866 if (mtab->imt4_active[i] == mask) { 9867 for (j = i + 1; j < 33; j++) 9868 mtab->imt4_active[j - 1] = mtab->imt4_active[j]; 9869 break; 9870 } 9871 } 9872 mtab->imt4_max--; 9873 ASSERT(mtab->imt4_max >= 0); 9874 } 9875 9876 9877 #ifdef USE_INET6 9878 /* ------------------------------------------------------------------------ */ 9879 /* Function: ipf_inet6_mask_add */ 9880 /* Returns: Nil */ 9881 /* Parameters: bits(I) - number of bits set in mask */ 9882 /* mask(I) - pointer to mask to add */ 9883 /* mtab(I) - pointer to mask hash table structure */ 9884 /* */ 9885 /* When called, bitcount represents the mask of a IPv6 NAT map rule that */ 9886 /* has just been added. This function inserts a bitmask into the array of */ 9887 /* masks to search when searching for a matching NAT rule for a packet. */ 9888 /* Prevention of duplicate masks is achieved by checking the use count for */ 9889 /* a given netmask. */ 9890 /* ------------------------------------------------------------------------ */ 9891 void 9892 ipf_inet6_mask_add(int bits, i6addr_t *mask, ipf_v6_masktab_t *mtab) 9893 { 9894 i6addr_t zero; 9895 int i, j; 9896 9897 mtab->imt6_masks[bits]++; 9898 if (mtab->imt6_masks[bits] > 1) 9899 return; 9900 9901 if (bits == 0) { 9902 mask = &zero; 9903 zero.i6[0] = 0; 9904 zero.i6[1] = 0; 9905 zero.i6[2] = 0; 9906 zero.i6[3] = 0; 9907 } 9908 9909 for (i = 0; i < 129; i++) { 9910 if (IP6_LT(&mtab->imt6_active[i], mask)) { 9911 for (j = 128; j > i; j--) 9912 mtab->imt6_active[j] = mtab->imt6_active[j - 1]; 9913 mtab->imt6_active[i] = *mask; 9914 break; 9915 } 9916 } 9917 mtab->imt6_max++; 9918 } 9919 9920 9921 /* ------------------------------------------------------------------------ */ 9922 /* Function: ipf_inet6_mask_del */ 9923 /* Returns: Nil */ 9924 /* Parameters: bits(I) - number of bits set in mask */ 9925 /* mask(I) - pointer to mask to remove */ 9926 /* mtab(I) - pointer to mask hash table structure */ 9927 /* */ 9928 /* Remove the 128bit bitmask represented by "bits" from the collection of */ 9929 /* netmasks stored inside of mtab. */ 9930 /* ------------------------------------------------------------------------ */ 9931 void 9932 ipf_inet6_mask_del(int bits, i6addr_t *mask, ipf_v6_masktab_t *mtab) 9933 { 9934 i6addr_t zero; 9935 int i, j; 9936 9937 mtab->imt6_masks[bits]--; 9938 if (mtab->imt6_masks[bits] > 0) 9939 return; 9940 9941 if (bits == 0) 9942 mask = &zero; 9943 zero.i6[0] = 0; 9944 zero.i6[1] = 0; 9945 zero.i6[2] = 0; 9946 zero.i6[3] = 0; 9947 9948 for (i = 0; i < 129; i++) { 9949 if (IP6_EQ(&mtab->imt6_active[i], mask)) { 9950 for (j = i + 1; j < 129; j++) { 9951 mtab->imt6_active[j - 1] = mtab->imt6_active[j]; 9952 if (IP6_EQ(&mtab->imt6_active[j - 1], &zero)) 9953 break; 9954 } 9955 break; 9956 } 9957 } 9958 mtab->imt6_max--; 9959 ASSERT(mtab->imt6_max >= 0); 9960 } 9961 #endif 9962