1 /* $NetBSD: fil.c,v 1.39 2026/07/24 23:41:26 gutteridge 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.39 2026/07/24 23:41:26 gutteridge 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" implies 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 (fin->fin_m == NULL || 946 M_LEN(fin->fin_m) < fin->fin_plen) { 947 if (ipf_coalesce(fin) != 1) 948 return; 949 } 950 951 if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN) == -1) 952 return; 953 954 /* 955 * If the destination of this packet doesn't match the 956 * source of the original packet then this packet is 957 * not correct. 958 */ 959 icmp6 = fin->fin_dp; 960 ip6 = (ip6_t *)((char *)icmp6 + ICMPERR_ICMPHLEN); 961 if (IP6_NEQ(&fin->fin_fi.fi_dst, 962 &ip6->ip6_src)) { 963 fin->fin_flx |= FI_BAD; 964 DT1(ipf_fi_bad_icmp6, fr_info_t *, fin); 965 } 966 break; 967 default : 968 break; 969 } 970 } 971 972 ipf_pr_short6(fin, minicmpsz); 973 if ((fin->fin_flx & (FI_SHORT|FI_BAD)) == 0) { 974 u_char p = fin->fin_p; 975 976 fin->fin_p = IPPROTO_ICMPV6; 977 ipf_checkv6sum(fin); 978 fin->fin_p = p; 979 } 980 } 981 982 983 /* ------------------------------------------------------------------------ */ 984 /* Function: ipf_pr_udp6 */ 985 /* Returns: void */ 986 /* Parameters: fin(I) - pointer to packet information */ 987 /* */ 988 /* IPv6 Only */ 989 /* Analyse the packet for IPv6/UDP properties. */ 990 /* Is not expected to be called for fragmented packets. */ 991 /* ------------------------------------------------------------------------ */ 992 static INLINE void 993 ipf_pr_udp6(fr_info_t *fin) 994 { 995 996 if (ipf_pr_udpcommon(fin) == 0) { 997 u_char p = fin->fin_p; 998 999 fin->fin_p = IPPROTO_UDP; 1000 ipf_checkv6sum(fin); 1001 fin->fin_p = p; 1002 } 1003 } 1004 1005 1006 /* ------------------------------------------------------------------------ */ 1007 /* Function: ipf_pr_tcp6 */ 1008 /* Returns: void */ 1009 /* Parameters: fin(I) - pointer to packet information */ 1010 /* */ 1011 /* IPv6 Only */ 1012 /* Analyse the packet for IPv6/TCP properties. */ 1013 /* Is not expected to be called for fragmented packets. */ 1014 /* ------------------------------------------------------------------------ */ 1015 static INLINE void 1016 ipf_pr_tcp6(fr_info_t *fin) 1017 { 1018 1019 if (ipf_pr_tcpcommon(fin) == 0) { 1020 u_char p = fin->fin_p; 1021 1022 fin->fin_p = IPPROTO_TCP; 1023 ipf_checkv6sum(fin); 1024 fin->fin_p = p; 1025 } 1026 } 1027 1028 1029 /* ------------------------------------------------------------------------ */ 1030 /* Function: ipf_pr_esp6 */ 1031 /* Returns: void */ 1032 /* Parameters: fin(I) - pointer to packet information */ 1033 /* */ 1034 /* IPv6 Only */ 1035 /* Analyse the packet for ESP properties. */ 1036 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ 1037 /* even though the newer ESP packets must also have a sequence number that */ 1038 /* is 32bits as well, it is not possible(?) to determine the version from a */ 1039 /* simple packet header. */ 1040 /* ------------------------------------------------------------------------ */ 1041 static INLINE void 1042 ipf_pr_esp6(fr_info_t *fin) 1043 { 1044 1045 if ((fin->fin_off == 0) && (ipf_pr_pullup(fin, 8) == -1)) { 1046 ipf_main_softc_t *softc = fin->fin_main_soft; 1047 1048 LBUMPD(ipf_stats[fin->fin_out], fr_v6_esp_pullup); 1049 return; 1050 } 1051 } 1052 1053 1054 /* ------------------------------------------------------------------------ */ 1055 /* Function: ipf_pr_ah6 */ 1056 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 1057 /* Parameters: fin(I) - pointer to packet information */ 1058 /* */ 1059 /* IPv6 Only */ 1060 /* Analyse the packet for AH properties. */ 1061 /* The minimum length is taken to be the combination of all fields in the */ 1062 /* header being present and no authentication data (null algorithm used.) */ 1063 /* ------------------------------------------------------------------------ */ 1064 static INLINE int 1065 ipf_pr_ah6(fr_info_t *fin) 1066 { 1067 authhdr_t *ah; 1068 1069 fin->fin_flx |= FI_AH; 1070 1071 ah = (authhdr_t *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS); 1072 if (ah == NULL) { 1073 ipf_main_softc_t *softc = fin->fin_main_soft; 1074 1075 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ah_bad); 1076 return IPPROTO_NONE; 1077 } 1078 1079 ipf_pr_short6(fin, sizeof(*ah)); 1080 1081 /* 1082 * No need for another pullup, ipf_pr_ipv6exthdr() will pullup 1083 * enough data to satisfy ah_next (the very first one.) 1084 */ 1085 return ah->ah_next; 1086 } 1087 1088 1089 /* ------------------------------------------------------------------------ */ 1090 /* Function: ipf_pr_gre6 */ 1091 /* Returns: void */ 1092 /* Parameters: fin(I) - pointer to packet information */ 1093 /* */ 1094 /* Analyse the packet for GRE properties. */ 1095 /* ------------------------------------------------------------------------ */ 1096 static INLINE void 1097 ipf_pr_gre6(fr_info_t *fin) 1098 { 1099 grehdr_t *gre; 1100 1101 if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) { 1102 ipf_main_softc_t *softc = fin->fin_main_soft; 1103 1104 LBUMPD(ipf_stats[fin->fin_out], fr_v6_gre_pullup); 1105 return; 1106 } 1107 1108 gre = fin->fin_dp; 1109 if (GRE_REV(gre->gr_flags) == 1) 1110 fin->fin_data[0] = gre->gr_call; 1111 } 1112 #endif /* USE_INET6 */ 1113 1114 1115 /* ------------------------------------------------------------------------ */ 1116 /* Function: ipf_pr_pullup */ 1117 /* Returns: int - 0 == pullup succeeded, -1 == failure */ 1118 /* Parameters: fin(I) - pointer to packet information */ 1119 /* plen(I) - length (excluding L3 header) to pullup */ 1120 /* */ 1121 /* Short inline function to cut down on code duplication to perform a call */ 1122 /* to ipf_pullup to ensure there is the required amount of data, */ 1123 /* consecutively in the packet buffer. */ 1124 /* */ 1125 /* This function pulls up 'extra' data at the location of fin_dp. fin_dp */ 1126 /* points to the first byte after the complete layer 3 header, which will */ 1127 /* include all of the known extension headers for IPv6 or options for IPv4. */ 1128 /* */ 1129 /* Since fr_pullup() expects the total length of bytes to be pulled up, it */ 1130 /* is necessary to add those we can already assume to be pulled up (fin_dp */ 1131 /* - fin_ip) to what is passed through. */ 1132 /* ------------------------------------------------------------------------ */ 1133 int 1134 ipf_pr_pullup(fr_info_t *fin, int plen) 1135 { 1136 ipf_main_softc_t *softc = fin->fin_main_soft; 1137 1138 if (fin->fin_m != NULL) { 1139 if (fin->fin_dp != NULL) 1140 plen += (char *)fin->fin_dp - 1141 ((char *)fin->fin_ip + fin->fin_hlen); 1142 plen += fin->fin_hlen; 1143 if (M_LEN(fin->fin_m) < plen + fin->fin_ipoff) { 1144 #if defined(_KERNEL) 1145 if (ipf_pullup(fin->fin_m, fin, plen) == NULL) { 1146 DT1(ipf_pullup_fail, fr_info_t *, fin); 1147 LBUMP(ipf_stats[fin->fin_out].fr_pull[1]); 1148 fin->fin_reason = FRB_PULLUP; 1149 fin->fin_flx |= FI_BAD; 1150 return -1; 1151 } 1152 LBUMP(ipf_stats[fin->fin_out].fr_pull[0]); 1153 #else 1154 LBUMP(ipf_stats[fin->fin_out].fr_pull[1]); 1155 /* 1156 * Fake ipf_pullup failing 1157 */ 1158 fin->fin_reason = FRB_PULLUP; 1159 *fin->fin_mp = NULL; 1160 fin->fin_m = NULL; 1161 fin->fin_ip = NULL; 1162 fin->fin_flx |= FI_BAD; 1163 return -1; 1164 #endif 1165 } 1166 } 1167 return 0; 1168 } 1169 1170 1171 /* ------------------------------------------------------------------------ */ 1172 /* Function: ipf_pr_short */ 1173 /* Returns: void */ 1174 /* Parameters: fin(I) - pointer to packet information */ 1175 /* xmin(I) - minimum header size */ 1176 /* */ 1177 /* Check if a packet is "short" as defined by xmin. The rule we are */ 1178 /* applying here is that the packet must not be fragmented within the layer */ 1179 /* 4 header. That is, it must not be a fragment that has its offset set to */ 1180 /* start within the layer 4 header (hdrmin) or if it is at offset 0, the */ 1181 /* entire layer 4 header must be present (min). */ 1182 /* ------------------------------------------------------------------------ */ 1183 static INLINE void 1184 ipf_pr_short(fr_info_t *fin, int xmin) 1185 { 1186 1187 if (fin->fin_off == 0) { 1188 if (fin->fin_dlen < xmin) 1189 fin->fin_flx |= FI_SHORT; 1190 } else if (fin->fin_off < xmin) { 1191 fin->fin_flx |= FI_SHORT; 1192 } 1193 } 1194 1195 1196 /* ------------------------------------------------------------------------ */ 1197 /* Function: ipf_pr_icmp */ 1198 /* Returns: void */ 1199 /* Parameters: fin(I) - pointer to packet information */ 1200 /* */ 1201 /* IPv4 Only */ 1202 /* Do a sanity check on the packet for ICMP (v4). In nearly all cases, */ 1203 /* except extrememly bad packets, both type and code will be present. */ 1204 /* The expected minimum size of an ICMP packet is very much dependent on */ 1205 /* the type of it. */ 1206 /* */ 1207 /* XXX - other ICMP sanity checks? */ 1208 /* ------------------------------------------------------------------------ */ 1209 static INLINE void 1210 ipf_pr_icmp(fr_info_t *fin) 1211 { 1212 ipf_main_softc_t *softc = fin->fin_main_soft; 1213 int minicmpsz = sizeof(struct icmp); 1214 icmphdr_t *icmp; 1215 ip_t *oip; 1216 1217 ipf_pr_short(fin, ICMPERR_ICMPHLEN); 1218 1219 if (fin->fin_off != 0) { 1220 LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_frag); 1221 return; 1222 } 1223 1224 if (ipf_pr_pullup(fin, ICMPERR_ICMPHLEN) == -1) { 1225 LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_pullup); 1226 return; 1227 } 1228 1229 icmp = fin->fin_dp; 1230 1231 fin->fin_data[0] = *(u_short *)icmp; 1232 fin->fin_data[1] = icmp->icmp_id; 1233 1234 switch (icmp->icmp_type) 1235 { 1236 case ICMP_ECHOREPLY : 1237 case ICMP_ECHO : 1238 /* Router discovery messaes - RFC 1256 */ 1239 case ICMP_ROUTERADVERT : 1240 case ICMP_ROUTERSOLICIT : 1241 fin->fin_flx |= FI_ICMPQUERY; 1242 minicmpsz = ICMP_MINLEN; 1243 break; 1244 /* 1245 * type(1) + code(1) + cksum(2) + id(2) seq(2) + 1246 * 3 * timestamp(3 * 4) 1247 */ 1248 case ICMP_TSTAMP : 1249 case ICMP_TSTAMPREPLY : 1250 fin->fin_flx |= FI_ICMPQUERY; 1251 minicmpsz = 20; 1252 break; 1253 /* 1254 * type(1) + code(1) + cksum(2) + id(2) seq(2) + 1255 * mask(4) 1256 */ 1257 case ICMP_IREQ : 1258 case ICMP_IREQREPLY : 1259 case ICMP_MASKREQ : 1260 case ICMP_MASKREPLY : 1261 fin->fin_flx |= FI_ICMPQUERY; 1262 minicmpsz = 12; 1263 break; 1264 /* 1265 * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+) 1266 */ 1267 case ICMP_UNREACH : 1268 #ifdef icmp_nextmtu 1269 if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG) { 1270 if (icmp->icmp_nextmtu < softc->ipf_icmpminfragmtu) { 1271 fin->fin_flx |= FI_BAD; 1272 DT3(ipf_fi_bad_icmp_nextmtu, fr_info_t *, fin, u_int, icmp->icmp_nextmtu, u_int, softc->ipf_icmpminfragmtu); 1273 } 1274 } 1275 #endif 1276 /* FALLTHROUGH */ 1277 case ICMP_SOURCEQUENCH : 1278 case ICMP_REDIRECT : 1279 case ICMP_TIMXCEED : 1280 case ICMP_PARAMPROB : 1281 fin->fin_flx |= FI_ICMPERR; 1282 if (ipf_coalesce(fin) != 1) { 1283 LBUMPD(ipf_stats[fin->fin_out], fr_icmp_coalesce); 1284 return; 1285 } 1286 1287 /* 1288 * ICMP error packets should not be generated for IP 1289 * packets that are a fragment that isn't the first 1290 * fragment. 1291 */ 1292 oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN); 1293 if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0) { 1294 fin->fin_flx |= FI_BAD; 1295 DT2(ipf_fi_bad_icmp_err, fr_info_t, fin, u_int, (ntohs(oip->ip_off) & IP_OFFMASK)); 1296 } 1297 1298 /* 1299 * If the destination of this packet doesn't match the 1300 * source of the original packet then this packet is 1301 * not correct. 1302 */ 1303 if (oip->ip_src.s_addr != fin->fin_daddr) { 1304 fin->fin_flx |= FI_BAD; 1305 DT1(ipf_fi_bad_src_ne_dst, fr_info_t *, fin); 1306 } 1307 break; 1308 default : 1309 break; 1310 } 1311 1312 ipf_pr_short(fin, minicmpsz); 1313 1314 ipf_checkv4sum(fin); 1315 } 1316 1317 1318 /* ------------------------------------------------------------------------ */ 1319 /* Function: ipf_pr_tcpcommon */ 1320 /* Returns: int - 0 = header ok, 1 = bad packet, -1 = buffer error */ 1321 /* Parameters: fin(I) - pointer to packet information */ 1322 /* */ 1323 /* TCP header sanity checking. Look for bad combinations of TCP flags, */ 1324 /* and make some checks with how they interact with other fields. */ 1325 /* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is */ 1326 /* valid and mark the packet as bad if not. */ 1327 /* ------------------------------------------------------------------------ */ 1328 static INLINE int 1329 ipf_pr_tcpcommon(fr_info_t *fin) 1330 { 1331 ipf_main_softc_t *softc = fin->fin_main_soft; 1332 int flags, tlen; 1333 tcphdr_t *tcp; 1334 1335 fin->fin_flx |= FI_TCPUDP; 1336 if (fin->fin_off != 0) { 1337 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_frag); 1338 return 0; 1339 } 1340 1341 if (ipf_pr_pullup(fin, sizeof(*tcp)) == -1) { 1342 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup); 1343 return -1; 1344 } 1345 1346 tcp = fin->fin_dp; 1347 if (fin->fin_dlen > 3) { 1348 fin->fin_sport = ntohs(tcp->th_sport); 1349 fin->fin_dport = ntohs(tcp->th_dport); 1350 } 1351 1352 if ((fin->fin_flx & FI_SHORT) != 0) { 1353 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_short); 1354 return 1; 1355 } 1356 1357 /* 1358 * Use of the TCP data offset *must* result in a value that is at 1359 * least the same size as the TCP header. 1360 */ 1361 tlen = TCP_OFF(tcp) << 2; 1362 if (tlen < sizeof(tcphdr_t)) { 1363 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_small); 1364 fin->fin_flx |= FI_BAD; 1365 DT3(ipf_fi_bad_tlen, fr_info_t, fin, u_int, tlen, u_int, sizeof(tcphdr_t)); 1366 return 1; 1367 } 1368 1369 flags = tcp->th_flags; 1370 fin->fin_tcpf = tcp->th_flags; 1371 1372 /* 1373 * If the urgent flag is set, then the urgent pointer must 1374 * also be set and vice versa. Good TCP packets do not have 1375 * just one of these set. 1376 */ 1377 if ((flags & TH_URG) != 0 && (tcp->th_urp == 0)) { 1378 fin->fin_flx |= FI_BAD; 1379 DT3(ipf_fi_bad_th_urg, fr_info_t*, fin, u_int, (flags & TH_URG), u_int, tcp->th_urp); 1380 #if 0 1381 } else if ((flags & TH_URG) == 0 && (tcp->th_urp != 0)) { 1382 /* 1383 * Ignore this case (#if 0) as it shows up in "real" 1384 * traffic with bogus values in the urgent pointer field. 1385 */ 1386 fin->fin_flx |= FI_BAD; 1387 DT3(ipf_fi_bad_th_urg0, fr_info_t *, fin, u_int, (flags & TH_URG), u_int, tcp->th_urp); 1388 #endif 1389 } else if (((flags & (TH_SYN|TH_FIN)) != 0) && 1390 ((flags & (TH_RST|TH_ACK)) == TH_RST)) { 1391 /* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */ 1392 fin->fin_flx |= FI_BAD; 1393 DT1(ipf_fi_bad_th_fin_rst_ack, fr_info_t, fin); 1394 #if 1 1395 } else if (((flags & TH_SYN) != 0) && 1396 ((flags & (TH_URG|TH_PUSH)) != 0)) { 1397 /* 1398 * SYN with URG and PUSH set is not for normal TCP but it is 1399 * possible(?) with T/TCP...but who uses T/TCP? 1400 */ 1401 fin->fin_flx |= FI_BAD; 1402 DT1(ipf_fi_bad_th_syn_urg_psh, fr_info_t *, fin); 1403 #endif 1404 } else if (!(flags & TH_ACK)) { 1405 /* 1406 * If the ack bit isn't set, then either the SYN or 1407 * RST bit must be set. If the SYN bit is set, then 1408 * we expect the ACK field to be 0. If the ACK is 1409 * not set and if URG, PSH or FIN are set, consdier 1410 * that to indicate a bad TCP packet. 1411 */ 1412 if ((flags == TH_SYN) && (tcp->th_ack != 0)) { 1413 /* 1414 * Cisco PIX sets the ACK field to a random value. 1415 * In light of this, do not set FI_BAD until a patch 1416 * is available from Cisco to ensure that 1417 * interoperability between existing systems is 1418 * achieved. 1419 */ 1420 /*fin->fin_flx |= FI_BAD*/; 1421 /*DT1(ipf_fi_bad_th_syn_ack, fr_info_t *, fin);*/ 1422 } else if (!(flags & (TH_RST|TH_SYN))) { 1423 fin->fin_flx |= FI_BAD; 1424 DT1(ipf_fi_bad_th_rst_syn, fr_info_t *, fin); 1425 } else if ((flags & (TH_URG|TH_PUSH|TH_FIN)) != 0) { 1426 fin->fin_flx |= FI_BAD; 1427 DT1(ipf_fi_bad_th_urg_push_fin, fr_info_t *, fin); 1428 } 1429 } 1430 if (fin->fin_flx & FI_BAD) { 1431 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_bad_flags); 1432 return 1; 1433 } 1434 1435 /* 1436 * At this point, it's not exactly clear what is to be gained by 1437 * marking up which TCP options are and are not present. The one we 1438 * are most interested in is the TCP window scale. This is only in 1439 * a SYN packet [RFC1323] so we don't need this here...? 1440 * Now if we were to analyse the header for passive fingerprinting, 1441 * then that might add some weight to adding this... 1442 */ 1443 if (tlen == sizeof(tcphdr_t)) { 1444 return 0; 1445 } 1446 1447 if (ipf_pr_pullup(fin, tlen) == -1) { 1448 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup); 1449 return -1; 1450 } 1451 1452 #if 0 1453 tcp = fin->fin_dp; 1454 ip = fin->fin_ip; 1455 s = (u_char *)(tcp + 1); 1456 off = IP_HL(ip) << 2; 1457 # ifdef _KERNEL 1458 if (fin->fin_mp != NULL) { 1459 mb_t *m = *fin->fin_mp; 1460 1461 if (off + tlen > M_LEN(m)) 1462 return; 1463 } 1464 # endif 1465 for (tlen -= (int)sizeof(*tcp); tlen > 0; ) { 1466 opt = *s; 1467 if (opt == '\0') 1468 break; 1469 else if (opt == TCPOPT_NOP) 1470 ol = 1; 1471 else { 1472 if (tlen < 2) 1473 break; 1474 ol = (int)*(s + 1); 1475 if (ol < 2 || ol > tlen) 1476 break; 1477 } 1478 1479 for (i = 9, mv = 4; mv >= 0; ) { 1480 op = ipopts + i; 1481 if (opt == (u_char)op->ol_val) { 1482 optmsk |= op->ol_bit; 1483 break; 1484 } 1485 } 1486 tlen -= ol; 1487 s += ol; 1488 } 1489 #endif /* 0 */ 1490 1491 return 0; 1492 } 1493 1494 1495 1496 /* ------------------------------------------------------------------------ */ 1497 /* Function: ipf_pr_udpcommon */ 1498 /* Returns: int - 0 = header ok, 1 = bad packet */ 1499 /* Parameters: fin(I) - pointer to packet information */ 1500 /* */ 1501 /* Extract the UDP source and destination ports, if present. If compiled */ 1502 /* with IPFILTER_CKSUM, check to see if the UDP checksum is valid. */ 1503 /* ------------------------------------------------------------------------ */ 1504 static INLINE int 1505 ipf_pr_udpcommon(fr_info_t *fin) 1506 { 1507 udphdr_t *udp; 1508 1509 fin->fin_flx |= FI_TCPUDP; 1510 1511 if (!fin->fin_off && (fin->fin_dlen > 3)) { 1512 if (ipf_pr_pullup(fin, sizeof(*udp)) == -1) { 1513 ipf_main_softc_t *softc = fin->fin_main_soft; 1514 1515 fin->fin_flx |= FI_SHORT; 1516 LBUMPD(ipf_stats[fin->fin_out], fr_udp_pullup); 1517 return 1; 1518 } 1519 1520 udp = fin->fin_dp; 1521 1522 fin->fin_sport = ntohs(udp->uh_sport); 1523 fin->fin_dport = ntohs(udp->uh_dport); 1524 } 1525 1526 return 0; 1527 } 1528 1529 1530 /* ------------------------------------------------------------------------ */ 1531 /* Function: ipf_pr_tcp */ 1532 /* Returns: void */ 1533 /* Parameters: fin(I) - pointer to packet information */ 1534 /* */ 1535 /* IPv4 Only */ 1536 /* Analyse the packet for IPv4/TCP properties. */ 1537 /* ------------------------------------------------------------------------ */ 1538 static INLINE void 1539 ipf_pr_tcp(fr_info_t *fin) 1540 { 1541 1542 ipf_pr_short(fin, sizeof(tcphdr_t)); 1543 1544 if (ipf_pr_tcpcommon(fin) == 0) 1545 ipf_checkv4sum(fin); 1546 } 1547 1548 1549 /* ------------------------------------------------------------------------ */ 1550 /* Function: ipf_pr_udp */ 1551 /* Returns: void */ 1552 /* Parameters: fin(I) - pointer to packet information */ 1553 /* */ 1554 /* IPv4 Only */ 1555 /* Analyse the packet for IPv4/UDP properties. */ 1556 /* ------------------------------------------------------------------------ */ 1557 static INLINE void 1558 ipf_pr_udp(fr_info_t *fin) 1559 { 1560 1561 ipf_pr_short(fin, sizeof(udphdr_t)); 1562 1563 if (ipf_pr_udpcommon(fin) == 0) 1564 ipf_checkv4sum(fin); 1565 } 1566 1567 1568 /* ------------------------------------------------------------------------ */ 1569 /* Function: ipf_pr_esp */ 1570 /* Returns: void */ 1571 /* Parameters: fin(I) - pointer to packet information */ 1572 /* */ 1573 /* Analyse the packet for ESP properties. */ 1574 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ 1575 /* even though the newer ESP packets must also have a sequence number that */ 1576 /* is 32bits as well, it is not possible(?) to determine the version from a */ 1577 /* simple packet header. */ 1578 /* ------------------------------------------------------------------------ */ 1579 static INLINE void 1580 ipf_pr_esp(fr_info_t *fin) 1581 { 1582 1583 if (fin->fin_off == 0) { 1584 ipf_pr_short(fin, 8); 1585 if (ipf_pr_pullup(fin, 8) == -1) { 1586 ipf_main_softc_t *softc = fin->fin_main_soft; 1587 1588 LBUMPD(ipf_stats[fin->fin_out], fr_v4_esp_pullup); 1589 } 1590 } 1591 } 1592 1593 1594 /* ------------------------------------------------------------------------ */ 1595 /* Function: ipf_pr_ah */ 1596 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 1597 /* Parameters: fin(I) - pointer to packet information */ 1598 /* */ 1599 /* Analyse the packet for AH properties. */ 1600 /* The minimum length is taken to be the combination of all fields in the */ 1601 /* header being present and no authentication data (null algorithm used.) */ 1602 /* ------------------------------------------------------------------------ */ 1603 static INLINE int 1604 ipf_pr_ah(fr_info_t *fin) 1605 { 1606 ipf_main_softc_t *softc = fin->fin_main_soft; 1607 authhdr_t *ah; 1608 int len; 1609 1610 fin->fin_flx |= FI_AH; 1611 ipf_pr_short(fin, sizeof(*ah)); 1612 1613 if (((fin->fin_flx & FI_SHORT) != 0) || (fin->fin_off != 0)) { 1614 LBUMPD(ipf_stats[fin->fin_out], fr_v4_ah_bad); 1615 return IPPROTO_NONE; 1616 } 1617 1618 if (ipf_pr_pullup(fin, sizeof(*ah)) == -1) { 1619 DT(fr_v4_ah_pullup_1); 1620 LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup); 1621 return IPPROTO_NONE; 1622 } 1623 1624 ah = (authhdr_t *)fin->fin_dp; 1625 1626 len = (ah->ah_plen + 2) << 2; 1627 ipf_pr_short(fin, len); 1628 if (ipf_pr_pullup(fin, len) == -1) { 1629 DT(fr_v4_ah_pullup_2); 1630 LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup); 1631 return IPPROTO_NONE; 1632 } 1633 1634 /* 1635 * Adjust fin_dp and fin_dlen for skipping over the authentication 1636 * header. 1637 */ 1638 fin->fin_dp = (char *)fin->fin_dp + len; 1639 fin->fin_dlen -= len; 1640 return ah->ah_next; 1641 } 1642 1643 1644 /* ------------------------------------------------------------------------ */ 1645 /* Function: ipf_pr_gre */ 1646 /* Returns: void */ 1647 /* Parameters: fin(I) - pointer to packet information */ 1648 /* */ 1649 /* Analyse the packet for GRE properties. */ 1650 /* ------------------------------------------------------------------------ */ 1651 static INLINE void 1652 ipf_pr_gre(fr_info_t *fin) 1653 { 1654 ipf_main_softc_t *softc = fin->fin_main_soft; 1655 grehdr_t *gre; 1656 1657 ipf_pr_short(fin, sizeof(grehdr_t)); 1658 1659 if (fin->fin_off != 0) { 1660 LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_frag); 1661 return; 1662 } 1663 1664 if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) { 1665 LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_pullup); 1666 return; 1667 } 1668 1669 gre = fin->fin_dp; 1670 if (GRE_REV(gre->gr_flags) == 1) 1671 fin->fin_data[0] = gre->gr_call; 1672 } 1673 1674 1675 /* ------------------------------------------------------------------------ */ 1676 /* Function: ipf_pr_ipv4hdr */ 1677 /* Returns: void */ 1678 /* Parameters: fin(I) - pointer to packet information */ 1679 /* */ 1680 /* IPv4 Only */ 1681 /* Analyze the IPv4 header and set fields in the fr_info_t structure. */ 1682 /* Check all options present and flag their presence if any exist. */ 1683 /* ------------------------------------------------------------------------ */ 1684 static INLINE void 1685 ipf_pr_ipv4hdr(fr_info_t *fin) 1686 { 1687 u_short optmsk = 0, secmsk = 0, auth = 0; 1688 int hlen, ol, mv, p, i; 1689 const struct optlist *op; 1690 u_char *s, opt; 1691 u_short off; 1692 fr_ip_t *fi; 1693 ip_t *ip; 1694 1695 fi = &fin->fin_fi; 1696 hlen = fin->fin_hlen; 1697 1698 ip = fin->fin_ip; 1699 p = ip->ip_p; 1700 fi->fi_p = p; 1701 fin->fin_crc = p; 1702 fi->fi_tos = ip->ip_tos; 1703 fin->fin_id = ntohs(ip->ip_id); 1704 off = ntohs(ip->ip_off); 1705 1706 /* Get both TTL and protocol */ 1707 fi->fi_p = ip->ip_p; 1708 fi->fi_ttl = ip->ip_ttl; 1709 1710 /* Zero out bits not used in IPv6 address */ 1711 fi->fi_src.i6[1] = 0; 1712 fi->fi_src.i6[2] = 0; 1713 fi->fi_src.i6[3] = 0; 1714 fi->fi_dst.i6[1] = 0; 1715 fi->fi_dst.i6[2] = 0; 1716 fi->fi_dst.i6[3] = 0; 1717 1718 fi->fi_saddr = ip->ip_src.s_addr; 1719 fin->fin_crc += fi->fi_saddr; 1720 fi->fi_daddr = ip->ip_dst.s_addr; 1721 fin->fin_crc += fi->fi_daddr; 1722 if (IN_CLASSD(fi->fi_daddr)) 1723 fin->fin_flx |= FI_MULTICAST|FI_MBCAST; 1724 1725 /* 1726 * set packet attribute flags based on the offset and 1727 * calculate the byte offset that it represents. 1728 */ 1729 off &= IP_MF|IP_OFFMASK; 1730 if (off != 0) { 1731 int morefrag = off & IP_MF; 1732 fi->fi_flx |= FI_FRAG; 1733 off &= IP_OFFMASK; 1734 if (off != 0) { 1735 if (off == 1 && p == IPPROTO_TCP) { 1736 fin->fin_flx |= FI_SHORT; /* RFC 3128 */ 1737 DT1(ipf_fi_tcp_frag_off_1, fr_info_t *, fin); 1738 } 1739 1740 fin->fin_flx |= FI_FRAGBODY; 1741 off <<= 3; 1742 if ((off + fin->fin_dlen > 65535) || 1743 (fin->fin_dlen == 0) || 1744 ((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) { 1745 /* 1746 * The length of the packet, starting at its 1747 * offset cannot exceed 65535 (0xffff) as the 1748 * length of an IP packet is only 16 bits. 1749 * 1750 * Any fragment that isn't the last fragment 1751 * must have a length greater than 0 and it 1752 * must be an even multiple of 8. 1753 */ 1754 fi->fi_flx |= FI_BAD; 1755 DT1(ipf_fi_bad_fragbody_gt_65535, fr_info_t *, fin); 1756 } 1757 } 1758 } 1759 fin->fin_off = off; 1760 1761 /* 1762 * Call per-protocol setup and checking 1763 */ 1764 if (p == IPPROTO_AH) { 1765 /* 1766 * Treat AH differently because we expect there to be another 1767 * layer 4 header after it. 1768 */ 1769 p = ipf_pr_ah(fin); 1770 } 1771 1772 switch (p) 1773 { 1774 case IPPROTO_UDP : 1775 ipf_pr_udp(fin); 1776 break; 1777 case IPPROTO_TCP : 1778 ipf_pr_tcp(fin); 1779 break; 1780 case IPPROTO_ICMP : 1781 ipf_pr_icmp(fin); 1782 break; 1783 case IPPROTO_ESP : 1784 ipf_pr_esp(fin); 1785 break; 1786 case IPPROTO_GRE : 1787 ipf_pr_gre(fin); 1788 break; 1789 } 1790 1791 ip = fin->fin_ip; 1792 if (ip == NULL) 1793 return; 1794 1795 /* 1796 * If it is a standard IP header (no options), set the flag fields 1797 * which relate to options to 0. 1798 */ 1799 if (hlen == sizeof(*ip)) { 1800 fi->fi_optmsk = 0; 1801 fi->fi_secmsk = 0; 1802 fi->fi_auth = 0; 1803 return; 1804 } 1805 1806 /* 1807 * So the IP header has some IP options attached. Walk the entire 1808 * list of options present with this packet and set flags to indicate 1809 * which ones are here and which ones are not. For the somewhat out 1810 * of date and obscure security classification options, set a flag to 1811 * represent which classification is present. 1812 */ 1813 fi->fi_flx |= FI_OPTIONS; 1814 1815 for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) { 1816 opt = *s; 1817 if (opt == '\0') 1818 break; 1819 else if (opt == IPOPT_NOP) 1820 ol = 1; 1821 else { 1822 if (hlen < 2) 1823 break; 1824 ol = (int)*(s + 1); 1825 if (ol < 2 || ol > hlen) 1826 break; 1827 } 1828 for (i = 9, mv = 4; mv >= 0; ) { 1829 op = ipopts + i; 1830 1831 if ((opt == (u_char)op->ol_val) && (ol > 4)) { 1832 u_32_t doi; 1833 1834 switch (opt) 1835 { 1836 case IPOPT_SECURITY : 1837 if (optmsk & op->ol_bit) { 1838 fin->fin_flx |= FI_BAD; 1839 DT2(ipf_fi_bad_ipopt_security, fr_info_t *, fin, u_short, (optmsk & op->ol_bit)); 1840 } else { 1841 doi = ipf_checkripso(s); 1842 secmsk = doi >> 16; 1843 auth = doi & 0xffff; 1844 } 1845 break; 1846 1847 case IPOPT_CIPSO : 1848 1849 if (optmsk & op->ol_bit) { 1850 fin->fin_flx |= FI_BAD; 1851 DT2(ipf_fi_bad_ipopt_cipso, fr_info_t *, fin, u_short, (optmsk & op->ol_bit)); 1852 } else { 1853 doi = ipf_checkcipso(fin, 1854 s, ol); 1855 secmsk = doi >> 16; 1856 auth = doi & 0xffff; 1857 } 1858 break; 1859 } 1860 optmsk |= op->ol_bit; 1861 } 1862 1863 if (opt < op->ol_val) 1864 i -= mv; 1865 else 1866 i += mv; 1867 mv--; 1868 } 1869 hlen -= ol; 1870 s += ol; 1871 } 1872 1873 /* 1874 * 1875 */ 1876 if (auth && !(auth & 0x0100)) 1877 auth &= 0xff00; 1878 fi->fi_optmsk = optmsk; 1879 fi->fi_secmsk = secmsk; 1880 fi->fi_auth = auth; 1881 } 1882 1883 1884 /* ------------------------------------------------------------------------ */ 1885 /* Function: ipf_checkripso */ 1886 /* Returns: void */ 1887 /* Parameters: s(I) - pointer to start of RIPSO option */ 1888 /* */ 1889 /* ------------------------------------------------------------------------ */ 1890 static u_32_t 1891 ipf_checkripso(u_char *s) 1892 { 1893 const struct optlist *sp; 1894 u_short secmsk = 0, auth = 0; 1895 u_char sec; 1896 int j, m; 1897 1898 sec = *(s + 2); /* classification */ 1899 for (j = 3, m = 2; m >= 0; ) { 1900 sp = secopt + j; 1901 if (sec == sp->ol_val) { 1902 secmsk |= sp->ol_bit; 1903 auth = *(s + 3); 1904 auth *= 256; 1905 auth += *(s + 4); 1906 break; 1907 } 1908 if (sec < sp->ol_val) 1909 j -= m; 1910 else 1911 j += m; 1912 m--; 1913 } 1914 1915 return (secmsk << 16) | auth; 1916 } 1917 1918 1919 /* ------------------------------------------------------------------------ */ 1920 /* Function: ipf_checkcipso */ 1921 /* Returns: u_32_t - 0 = failure, else the doi from the header */ 1922 /* Parameters: fin(IO) - pointer to packet information */ 1923 /* s(I) - pointer to start of CIPSO option */ 1924 /* ol(I) - length of CIPSO option field */ 1925 /* */ 1926 /* This function returns the domain of integrity (DOI) field from the CIPSO */ 1927 /* header and returns that whilst also storing the highest sensitivity */ 1928 /* value found in the fr_info_t structure. */ 1929 /* */ 1930 /* No attempt is made to extract the category bitmaps as these are defined */ 1931 /* by the user (rather than the protocol) and can be rather numerous on the */ 1932 /* end nodes. */ 1933 /* ------------------------------------------------------------------------ */ 1934 static u_32_t 1935 ipf_checkcipso(fr_info_t *fin, u_char *s, int ol) 1936 { 1937 ipf_main_softc_t *softc = fin->fin_main_soft; 1938 fr_ip_t *fi; 1939 u_32_t doi; 1940 u_char *t, tag, tlen, sensitivity; 1941 int len; 1942 1943 if (ol < 6 || ol > 40) { 1944 LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_bad); 1945 fin->fin_flx |= FI_BAD; 1946 DT2(ipf_fi_bad_checkcipso_ol, fr_info_t *, fin, u_int, ol); 1947 return 0; 1948 } 1949 1950 fi = &fin->fin_fi; 1951 fi->fi_sensitivity = 0; 1952 /* 1953 * The DOI field MUST be there. 1954 */ 1955 bcopy(s + 2, &doi, sizeof(doi)); 1956 1957 t = (u_char *)s + 6; 1958 for (len = ol - 6; len >= 2; len -= tlen, t+= tlen) { 1959 tag = *t; 1960 tlen = *(t + 1); 1961 if (tlen > len || tlen < 4 || tlen > 34) { 1962 LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_tlen); 1963 fin->fin_flx |= FI_BAD; 1964 DT2(ipf_fi_bad_checkcipso_tlen, fr_info_t *, fin, u_int, tlen); 1965 return 0; 1966 } 1967 1968 sensitivity = 0; 1969 /* 1970 * Tag numbers 0, 1, 2, 5 are laid out in the CIPSO Internet 1971 * draft (16 July 1992) that has expired. 1972 */ 1973 if (tag == 0) { 1974 fin->fin_flx |= FI_BAD; 1975 DT2(ipf_fi_bad_checkcipso_tag, fr_info_t *, fin, u_int, tag); 1976 continue; 1977 } else if (tag == 1) { 1978 if (*(t + 2) != 0) { 1979 fin->fin_flx |= FI_BAD; 1980 DT2(ipf_fi_bad_checkcipso_tag1_t2, fr_info_t *, fin, u_int, (*t + 2)); 1981 continue; 1982 } 1983 sensitivity = *(t + 3); 1984 /* Category bitmap for categories 0-239 */ 1985 1986 } else if (tag == 4) { 1987 if (*(t + 2) != 0) { 1988 fin->fin_flx |= FI_BAD; 1989 DT2(ipf_fi_bad_checkcipso_tag4_t2, fr_info_t *, fin, u_int, (*t + 2)); 1990 continue; 1991 } 1992 sensitivity = *(t + 3); 1993 /* Enumerated categories, 16bits each, upto 15 */ 1994 1995 } else if (tag == 5) { 1996 if (*(t + 2) != 0) { 1997 fin->fin_flx |= FI_BAD; 1998 DT2(ipf_fi_bad_checkcipso_tag5_t2, fr_info_t *, fin, u_int, (*t + 2)); 1999 continue; 2000 } 2001 sensitivity = *(t + 3); 2002 /* Range of categories (2*16bits), up to 7 pairs */ 2003 2004 } else if (tag > 127) { 2005 /* Custom defined DOI */ 2006 ; 2007 } else { 2008 DT2(ipf_fi_bad_checkcipso_tag127, fr_info_t *, fin, u_int, tag); 2009 fin->fin_flx |= FI_BAD; 2010 continue; 2011 } 2012 2013 if (sensitivity > fi->fi_sensitivity) 2014 fi->fi_sensitivity = sensitivity; 2015 } 2016 2017 return doi; 2018 } 2019 2020 2021 /* ------------------------------------------------------------------------ */ 2022 /* Function: ipf_makefrip */ 2023 /* Returns: int - 0 == packet ok, -1 == packet freed */ 2024 /* Parameters: hlen(I) - length of IP packet header */ 2025 /* ip(I) - pointer to the IP header */ 2026 /* fin(IO) - pointer to packet information */ 2027 /* */ 2028 /* Compact the IP header into a structure which contains just the info. */ 2029 /* which is useful for comparing IP headers with and store this information */ 2030 /* in the fr_info_t structure pointer to by fin. At present, it is assumed */ 2031 /* this function will be called with either an IPv4 or IPv6 packet. */ 2032 /* ------------------------------------------------------------------------ */ 2033 int 2034 ipf_makefrip(int hlen, ip_t *ip, fr_info_t *fin) 2035 { 2036 ipf_main_softc_t *softc = fin->fin_main_soft; 2037 int v; 2038 2039 fin->fin_depth = 0; 2040 fin->fin_hlen = (u_short)hlen; 2041 fin->fin_ip = ip; 2042 fin->fin_rule = 0xffffffff; 2043 fin->fin_group[0] = -1; 2044 fin->fin_group[1] = '\0'; 2045 fin->fin_dp = (char *)ip + hlen; 2046 2047 v = fin->fin_v; 2048 if (v == 4) { 2049 fin->fin_plen = ntohs(ip->ip_len); 2050 fin->fin_dlen = fin->fin_plen - hlen; 2051 ipf_pr_ipv4hdr(fin); 2052 #ifdef USE_INET6 2053 } else if (v == 6) { 2054 fin->fin_plen = ntohs(((ip6_t *)ip)->ip6_plen); 2055 fin->fin_dlen = fin->fin_plen; 2056 fin->fin_plen += hlen; 2057 2058 ipf_pr_ipv6hdr(fin); 2059 #endif 2060 } 2061 if (fin->fin_ip == NULL) { 2062 LBUMP(ipf_stats[fin->fin_out].fr_ip_freed); 2063 return -1; 2064 } 2065 return 0; 2066 } 2067 2068 2069 /* ------------------------------------------------------------------------ */ 2070 /* Function: ipf_portcheck */ 2071 /* Returns: int - 1 == port matched, 0 == port match failed */ 2072 /* Parameters: frp(I) - pointer to port check `expression' */ 2073 /* pop(I) - port number to evaluate */ 2074 /* */ 2075 /* Perform a comparison of a port number against some other(s), using a */ 2076 /* structure with compare information stored in it. */ 2077 /* ------------------------------------------------------------------------ */ 2078 static INLINE int 2079 ipf_portcheck(frpcmp_t *frp, u_32_t pop) 2080 { 2081 int err = 1; 2082 u_32_t po; 2083 2084 po = frp->frp_port; 2085 2086 /* 2087 * Do opposite test to that required and continue if that succeeds. 2088 */ 2089 switch (frp->frp_cmp) 2090 { 2091 case FR_EQUAL : 2092 if (pop != po) /* EQUAL */ 2093 err = 0; 2094 break; 2095 case FR_NEQUAL : 2096 if (pop == po) /* NOTEQUAL */ 2097 err = 0; 2098 break; 2099 case FR_LESST : 2100 if (pop >= po) /* LESSTHAN */ 2101 err = 0; 2102 break; 2103 case FR_GREATERT : 2104 if (pop <= po) /* GREATERTHAN */ 2105 err = 0; 2106 break; 2107 case FR_LESSTE : 2108 if (pop > po) /* LT or EQ */ 2109 err = 0; 2110 break; 2111 case FR_GREATERTE : 2112 if (pop < po) /* GT or EQ */ 2113 err = 0; 2114 break; 2115 case FR_OUTRANGE : 2116 if (pop >= po && pop <= frp->frp_top) /* Out of range */ 2117 err = 0; 2118 break; 2119 case FR_INRANGE : 2120 if (pop <= po || pop >= frp->frp_top) /* In range */ 2121 err = 0; 2122 break; 2123 case FR_INCRANGE : 2124 if (pop < po || pop > frp->frp_top) /* Inclusive range */ 2125 err = 0; 2126 break; 2127 default : 2128 break; 2129 } 2130 return err; 2131 } 2132 2133 2134 /* ------------------------------------------------------------------------ */ 2135 /* Function: ipf_tcpudpchk */ 2136 /* Returns: int - 1 == protocol matched, 0 == check failed */ 2137 /* Parameters: fda(I) - pointer to packet information */ 2138 /* ft(I) - pointer to structure with comparison data */ 2139 /* */ 2140 /* Compares the current pcket (assuming it is TCP/UDP) information with a */ 2141 /* structure containing information that we want to match against. */ 2142 /* ------------------------------------------------------------------------ */ 2143 int 2144 ipf_tcpudpchk(fr_ip_t *fi, frtuc_t *ft) 2145 { 2146 int err = 1; 2147 2148 /* 2149 * Both ports should *always* be in the first fragment. 2150 * So far, I cannot find any cases where they can not be. 2151 * 2152 * compare destination ports 2153 */ 2154 if (ft->ftu_dcmp) 2155 err = ipf_portcheck(&ft->ftu_dst, fi->fi_ports[1]); 2156 2157 /* 2158 * compare source ports 2159 */ 2160 if (err && ft->ftu_scmp) 2161 err = ipf_portcheck(&ft->ftu_src, fi->fi_ports[0]); 2162 2163 /* 2164 * If we don't have all the TCP/UDP header, then how can we 2165 * expect to do any sort of match on it ? If we were looking for 2166 * TCP flags, then NO match. If not, then match (which should 2167 * satisfy the "short" class too). 2168 */ 2169 if (err && (fi->fi_p == IPPROTO_TCP)) { 2170 if (fi->fi_flx & FI_SHORT) 2171 return !(ft->ftu_tcpf | ft->ftu_tcpfm); 2172 /* 2173 * Match the flags ? If not, abort this match. 2174 */ 2175 if (ft->ftu_tcpfm && 2176 ft->ftu_tcpf != (fi->fi_tcpf & ft->ftu_tcpfm)) { 2177 FR_DEBUG(("f. %#x & %#x != %#x\n", fi->fi_tcpf, 2178 ft->ftu_tcpfm, ft->ftu_tcpf)); 2179 err = 0; 2180 } 2181 } 2182 return err; 2183 } 2184 2185 2186 /* ------------------------------------------------------------------------ */ 2187 /* Function: ipf_check_ipf */ 2188 /* Returns: int - 0 == match, else no match */ 2189 /* Parameters: fin(I) - pointer to packet information */ 2190 /* fr(I) - pointer to filter rule */ 2191 /* portcmp(I) - flag indicating whether to attempt matching on */ 2192 /* TCP/UDP port data. */ 2193 /* */ 2194 /* Check to see if a packet matches an IPFilter rule. Checks of addresses, */ 2195 /* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */ 2196 /* this function. */ 2197 /* ------------------------------------------------------------------------ */ 2198 static INLINE int 2199 ipf_check_ipf(fr_info_t *fin, frentry_t *fr, int portcmp) 2200 { 2201 u_32_t *ld, *lm, *lip; 2202 fripf_t *fri; 2203 fr_ip_t *fi; 2204 int i; 2205 2206 fi = &fin->fin_fi; 2207 fri = fr->fr_ipf; 2208 lip = (u_32_t *)fi; 2209 lm = (u_32_t *)&fri->fri_mip; 2210 ld = (u_32_t *)&fri->fri_ip; 2211 2212 /* 2213 * first 32 bits to check coversion: 2214 * IP version, TOS, TTL, protocol 2215 */ 2216 i = ((*lip & *lm) != *ld); 2217 FR_DEBUG(("0. %#08x & %#08x != %#08x\n", 2218 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2219 if (i) 2220 return 1; 2221 2222 /* 2223 * Next 32 bits is a constructed bitmask indicating which IP options 2224 * are present (if any) in this packet. 2225 */ 2226 lip++, lm++, ld++; 2227 i = ((*lip & *lm) != *ld); 2228 FR_DEBUG(("1. %#08x & %#08x != %#08x\n", 2229 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2230 if (i != 0) 2231 return 1; 2232 2233 lip++, lm++, ld++; 2234 /* 2235 * Unrolled loops (4 each, for 32 bits) for address checks. 2236 */ 2237 /* 2238 * Check the source address. 2239 */ 2240 if (fr->fr_satype == FRI_LOOKUP) { 2241 i = (*fr->fr_srcfunc)(fin->fin_main_soft, fr->fr_srcptr, 2242 fi->fi_v, lip, fin->fin_plen); 2243 if (i == -1) 2244 return 1; 2245 lip += 3; 2246 lm += 3; 2247 ld += 3; 2248 } else { 2249 i = ((*lip & *lm) != *ld); 2250 FR_DEBUG(("2a. %#08x & %#08x != %#08x\n", 2251 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2252 if (fi->fi_v == 6) { 2253 lip++, lm++, ld++; 2254 i |= ((*lip & *lm) != *ld); 2255 FR_DEBUG(("2b. %#08x & %#08x != %#08x\n", 2256 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2257 lip++, lm++, ld++; 2258 i |= ((*lip & *lm) != *ld); 2259 FR_DEBUG(("2c. %#08x & %#08x != %#08x\n", 2260 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2261 lip++, lm++, ld++; 2262 i |= ((*lip & *lm) != *ld); 2263 FR_DEBUG(("2d. %#08x & %#08x != %#08x\n", 2264 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2265 } else { 2266 lip += 3; 2267 lm += 3; 2268 ld += 3; 2269 } 2270 } 2271 i ^= (fr->fr_flags & FR_NOTSRCIP) >> 6; 2272 if (i != 0) 2273 return 1; 2274 2275 /* 2276 * Check the destination address. 2277 */ 2278 lip++, lm++, ld++; 2279 if (fr->fr_datype == FRI_LOOKUP) { 2280 i = (*fr->fr_dstfunc)(fin->fin_main_soft, fr->fr_dstptr, 2281 fi->fi_v, lip, fin->fin_plen); 2282 if (i == -1) 2283 return 1; 2284 lip += 3; 2285 lm += 3; 2286 ld += 3; 2287 } else { 2288 i = ((*lip & *lm) != *ld); 2289 FR_DEBUG(("3a. %#08x & %#08x != %#08x\n", 2290 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2291 if (fi->fi_v == 6) { 2292 lip++, lm++, ld++; 2293 i |= ((*lip & *lm) != *ld); 2294 FR_DEBUG(("3b. %#08x & %#08x != %#08x\n", 2295 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2296 lip++, lm++, ld++; 2297 i |= ((*lip & *lm) != *ld); 2298 FR_DEBUG(("3c. %#08x & %#08x != %#08x\n", 2299 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2300 lip++, lm++, ld++; 2301 i |= ((*lip & *lm) != *ld); 2302 FR_DEBUG(("3d. %#08x & %#08x != %#08x\n", 2303 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2304 } else { 2305 lip += 3; 2306 lm += 3; 2307 ld += 3; 2308 } 2309 } 2310 i ^= (fr->fr_flags & FR_NOTDSTIP) >> 7; 2311 if (i != 0) 2312 return 1; 2313 /* 2314 * IP addresses matched. The next 32bits contains: 2315 * mast of old IP header security & authentication bits. 2316 */ 2317 lip++, lm++, ld++; 2318 i = (*ld - (*lip & *lm)); 2319 FR_DEBUG(("4. %#08x & %#08x != %#08x\n", *lip, *lm, *ld)); 2320 2321 /* 2322 * Next we have 32 bits of packet flags. 2323 */ 2324 lip++, lm++, ld++; 2325 i |= (*ld - (*lip & *lm)); 2326 FR_DEBUG(("5. %#08x & %#08x != %#08x\n", *lip, *lm, *ld)); 2327 2328 if (i == 0) { 2329 /* 2330 * If a fragment, then only the first has what we're 2331 * looking for here... 2332 */ 2333 if (portcmp) { 2334 if (!ipf_tcpudpchk(&fin->fin_fi, &fr->fr_tuc)) 2335 i = 1; 2336 } else { 2337 if (fr->fr_dcmp || fr->fr_scmp || 2338 fr->fr_tcpf || fr->fr_tcpfm) 2339 i = 1; 2340 if (fr->fr_icmpm || fr->fr_icmp) { 2341 if (((fi->fi_p != IPPROTO_ICMP) && 2342 (fi->fi_p != IPPROTO_ICMPV6)) || 2343 fin->fin_off || (fin->fin_dlen < 2)) 2344 i = 1; 2345 else if ((fin->fin_data[0] & fr->fr_icmpm) != 2346 fr->fr_icmp) { 2347 FR_DEBUG(("i. %#x & %#x != %#x\n", 2348 fin->fin_data[0], 2349 fr->fr_icmpm, fr->fr_icmp)); 2350 i = 1; 2351 } 2352 } 2353 } 2354 } 2355 return i; 2356 } 2357 2358 2359 /* ------------------------------------------------------------------------ */ 2360 /* Function: ipf_scanlist */ 2361 /* Returns: int - result flags of scanning filter list */ 2362 /* Parameters: fin(I) - pointer to packet information */ 2363 /* pass(I) - default result to return for filtering */ 2364 /* */ 2365 /* Check the input/output list of rules for a match to the current packet. */ 2366 /* If a match is found, the value of fr_flags from the rule becomes the */ 2367 /* return value and fin->fin_fr points to the matched rule. */ 2368 /* */ 2369 /* This function may be called recursively upto 16 times (limit inbuilt.) */ 2370 /* When unwinding, it should finish up with fin_depth as 0. */ 2371 /* */ 2372 /* Could be per interface, but this gets real nasty when you don't have, */ 2373 /* or can't easily change, the kernel source code to . */ 2374 /* ------------------------------------------------------------------------ */ 2375 int 2376 ipf_scanlist(fr_info_t *fin, u_32_t pass) 2377 { 2378 ipf_main_softc_t *softc = fin->fin_main_soft; 2379 int rulen, portcmp, off, skip; 2380 struct frentry *fr, *fnext; 2381 u_32_t passt, passo; 2382 2383 /* 2384 * Do not allow nesting deeper than 16 levels. 2385 */ 2386 if (fin->fin_depth >= 16) 2387 return pass; 2388 2389 fr = fin->fin_fr; 2390 2391 /* 2392 * If there are no rules in this list, return now. 2393 */ 2394 if (fr == NULL) 2395 return pass; 2396 2397 skip = 0; 2398 portcmp = 0; 2399 fin->fin_depth++; 2400 fin->fin_fr = NULL; 2401 off = fin->fin_off; 2402 2403 if ((fin->fin_flx & FI_TCPUDP) && (fin->fin_dlen > 3) && !off) 2404 portcmp = 1; 2405 2406 for (rulen = 0; fr; fr = fnext, rulen++) { 2407 fnext = fr->fr_next; 2408 if (skip != 0) { 2409 FR_VERBOSE(("SKIP %d (%#x)\n", skip, fr->fr_flags)); 2410 skip--; 2411 continue; 2412 } 2413 2414 /* 2415 * In all checks below, a null (zero) value in the 2416 * filter struture is taken to mean a wildcard. 2417 * 2418 * check that we are working for the right interface 2419 */ 2420 #ifdef _KERNEL 2421 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) 2422 continue; 2423 #else 2424 if (opts & (OPT_VERBOSE|OPT_DEBUG)) 2425 printf("\n"); 2426 FR_VERBOSE(("%c", FR_ISSKIP(pass) ? 's' : 2427 FR_ISPASS(pass) ? 'p' : 2428 FR_ISACCOUNT(pass) ? 'A' : 2429 FR_ISAUTH(pass) ? 'a' : 2430 (pass & FR_NOMATCH) ? 'n' :'b')); 2431 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) 2432 continue; 2433 FR_VERBOSE((":i")); 2434 #endif 2435 2436 switch (fr->fr_type) 2437 { 2438 case FR_T_IPF : 2439 case FR_T_IPF_BUILTIN : 2440 if (ipf_check_ipf(fin, fr, portcmp)) 2441 continue; 2442 break; 2443 #if defined(IPFILTER_BPF) 2444 case FR_T_BPFOPC : 2445 case FR_T_BPFOPC_BUILTIN : 2446 { 2447 u_char *mc; 2448 int wlen; 2449 2450 if (*fin->fin_mp == NULL) 2451 continue; 2452 if (fin->fin_family != fr->fr_family) 2453 continue; 2454 mc = (u_char *)fin->fin_m; 2455 wlen = fin->fin_dlen + fin->fin_hlen; 2456 if (!bpf_filter(fr->fr_data, mc, wlen, 0)) 2457 continue; 2458 break; 2459 } 2460 #endif 2461 case FR_T_CALLFUNC_BUILTIN : 2462 { 2463 frentry_t *f; 2464 2465 f = (*fr->fr_func)(fin, &pass); 2466 if (f != NULL) 2467 fr = f; 2468 else 2469 continue; 2470 break; 2471 } 2472 2473 case FR_T_IPFEXPR : 2474 case FR_T_IPFEXPR_BUILTIN : 2475 if (fin->fin_family != fr->fr_family) 2476 continue; 2477 if (ipf_fr_matcharray(fin, fr->fr_data) == 0) 2478 continue; 2479 break; 2480 2481 default : 2482 break; 2483 } 2484 2485 if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) { 2486 if (fin->fin_nattag == NULL) 2487 continue; 2488 if (ipf_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0) 2489 continue; 2490 } 2491 FR_VERBOSE(("=%d/%d.%d *", fr->fr_grhead, fr->fr_group, rulen)); 2492 2493 passt = fr->fr_flags; 2494 2495 /* 2496 * If the rule is a "call now" rule, then call the function 2497 * in the rule, if it exists and use the results from that. 2498 * If the function pointer is bad, just make like we ignore 2499 * it, except for increasing the hit counter. 2500 */ 2501 if ((passt & FR_CALLNOW) != 0) { 2502 frentry_t *frs; 2503 2504 ATOMIC_INC64(fr->fr_hits); 2505 if ((fr->fr_func == NULL) || 2506 (fr->fr_func == (ipfunc_t)-1)) 2507 continue; 2508 2509 frs = fin->fin_fr; 2510 fin->fin_fr = fr; 2511 fr = (*fr->fr_func)(fin, &passt); 2512 if (fr == NULL) { 2513 fin->fin_fr = frs; 2514 continue; 2515 } 2516 passt = fr->fr_flags; 2517 } 2518 fin->fin_fr = fr; 2519 2520 #ifdef IPFILTER_LOG 2521 /* 2522 * Just log this packet... 2523 */ 2524 if ((passt & FR_LOGMASK) == FR_LOG) { 2525 if (ipf_log_pkt(fin, passt) == -1) { 2526 if (passt & FR_LOGORBLOCK) { 2527 DT(frb_logfail); 2528 passt &= ~FR_CMDMASK; 2529 passt |= FR_BLOCK|FR_QUICK; 2530 fin->fin_reason = FRB_LOGFAIL; 2531 } 2532 } 2533 } 2534 #endif /* IPFILTER_LOG */ 2535 2536 MUTEX_ENTER(&fr->fr_lock); 2537 fr->fr_bytes += (U_QUAD_T)fin->fin_plen; 2538 fr->fr_hits++; 2539 MUTEX_EXIT(&fr->fr_lock); 2540 fin->fin_rule = rulen; 2541 2542 passo = pass; 2543 if (FR_ISSKIP(passt)) { 2544 skip = fr->fr_arg; 2545 continue; 2546 } else if (((passt & FR_LOGMASK) != FR_LOG) && 2547 ((passt & FR_LOGMASK) != FR_DECAPSULATE)) { 2548 pass = passt; 2549 } 2550 2551 if (passt & (FR_RETICMP|FR_FAKEICMP)) 2552 fin->fin_icode = fr->fr_icode; 2553 2554 if (fr->fr_group != -1) { 2555 (void) strncpy(fin->fin_group, 2556 FR_NAME(fr, fr_group), 2557 strlen(FR_NAME(fr, fr_group))); 2558 } else { 2559 fin->fin_group[0] = '\0'; 2560 } 2561 2562 FR_DEBUG(("pass %#x/%#x/%x\n", passo, pass, passt)); 2563 2564 if (fr->fr_grphead != NULL) { 2565 fin->fin_fr = fr->fr_grphead->fg_start; 2566 FR_VERBOSE(("group %s\n", FR_NAME(fr, fr_grhead))); 2567 2568 if (FR_ISDECAPS(passt)) 2569 passt = ipf_decaps(fin, pass, fr->fr_icode); 2570 else 2571 passt = ipf_scanlist(fin, pass); 2572 2573 if (fin->fin_fr == NULL) { 2574 fin->fin_rule = rulen; 2575 if (fr->fr_group != -1) 2576 (void) strncpy(fin->fin_group, 2577 fr->fr_names + 2578 fr->fr_group, 2579 strlen(fr->fr_names + 2580 fr->fr_group)); 2581 fin->fin_fr = fr; 2582 passt = pass; 2583 } 2584 pass = passt; 2585 } 2586 2587 if (pass & FR_QUICK) { 2588 /* 2589 * Finally, if we've asked to track state for this 2590 * packet, set it up. Add state for "quick" rules 2591 * here so that if the action fails we can consider 2592 * the rule to "not match" and keep on processing 2593 * filter rules. 2594 */ 2595 if ((pass & FR_KEEPSTATE) && !FR_ISAUTH(pass) && 2596 !(fin->fin_flx & FI_STATE)) { 2597 int out = fin->fin_out; 2598 2599 fin->fin_fr = fr; 2600 if (ipf_state_add(softc, fin, NULL, 0) == 0) { 2601 LBUMPD(ipf_stats[out], fr_ads); 2602 } else { 2603 LBUMPD(ipf_stats[out], fr_bads); 2604 pass = passo; 2605 continue; 2606 } 2607 } 2608 break; 2609 } 2610 } 2611 fin->fin_depth--; 2612 return pass; 2613 } 2614 2615 2616 /* ------------------------------------------------------------------------ */ 2617 /* Function: ipf_acctpkt */ 2618 /* Returns: frentry_t* - always returns NULL */ 2619 /* Parameters: fin(I) - pointer to packet information */ 2620 /* passp(IO) - pointer to current/new filter decision (unused) */ 2621 /* */ 2622 /* Checks a packet against accounting rules, if there are any for the given */ 2623 /* IP protocol version. */ 2624 /* */ 2625 /* N.B.: this function returns NULL to match the prototype used by other */ 2626 /* functions called from the IPFilter "mainline" in ipf_check(). */ 2627 /* ------------------------------------------------------------------------ */ 2628 frentry_t * 2629 ipf_acctpkt(fr_info_t *fin, u_32_t *passp) 2630 { 2631 ipf_main_softc_t *softc = fin->fin_main_soft; 2632 char group[FR_GROUPLEN]; 2633 frentry_t *fr, *frsave; 2634 u_32_t pass, rulen; 2635 2636 passp = passp; 2637 fr = softc->ipf_acct[fin->fin_out][softc->ipf_active]; 2638 2639 if (fr != NULL) { 2640 frsave = fin->fin_fr; 2641 bcopy(fin->fin_group, group, FR_GROUPLEN); 2642 rulen = fin->fin_rule; 2643 fin->fin_fr = fr; 2644 pass = ipf_scanlist(fin, FR_NOMATCH); 2645 if (FR_ISACCOUNT(pass)) { 2646 LBUMPD(ipf_stats[0], fr_acct); 2647 } 2648 fin->fin_fr = frsave; 2649 bcopy(group, fin->fin_group, FR_GROUPLEN); 2650 fin->fin_rule = rulen; 2651 } 2652 return NULL; 2653 } 2654 2655 2656 /* ------------------------------------------------------------------------ */ 2657 /* Function: ipf_firewall */ 2658 /* Returns: frentry_t* - returns pointer to matched rule, if no matches */ 2659 /* were found, returns NULL. */ 2660 /* Parameters: fin(I) - pointer to packet information */ 2661 /* passp(IO) - pointer to current/new filter decision (unused) */ 2662 /* */ 2663 /* Applies an appropriate set of firewall rules to the packet, to see if */ 2664 /* there are any matches. The first check is to see if a match can be seen */ 2665 /* in the cache. If not, then search an appropriate list of rules. Once a */ 2666 /* matching rule is found, take any appropriate actions as defined by the */ 2667 /* rule - except logging. */ 2668 /* ------------------------------------------------------------------------ */ 2669 static frentry_t * 2670 ipf_firewall(fr_info_t *fin, u_32_t *passp) 2671 { 2672 ipf_main_softc_t *softc = fin->fin_main_soft; 2673 frentry_t *fr; 2674 u_32_t pass; 2675 int out; 2676 2677 out = fin->fin_out; 2678 pass = *passp; 2679 2680 /* 2681 * This rule cache will only affect packets that are not being 2682 * statefully filtered. 2683 */ 2684 fin->fin_fr = softc->ipf_rules[out][softc->ipf_active]; 2685 if (fin->fin_fr != NULL) 2686 pass = ipf_scanlist(fin, softc->ipf_pass); 2687 2688 if ((pass & FR_NOMATCH)) { 2689 LBUMPD(ipf_stats[out], fr_nom); 2690 } 2691 fr = fin->fin_fr; 2692 2693 /* 2694 * Apply packets per second rate-limiting to a rule as required. 2695 */ 2696 if ((fr != NULL) && (fr->fr_pps != 0) && 2697 !ppsratecheck(&fr->fr_lastpkt, &fr->fr_curpps, fr->fr_pps)) { 2698 DT2(frb_ppsrate, fr_info_t *, fin, frentry_t *, fr); 2699 pass &= ~(FR_CMDMASK|FR_RETICMP|FR_RETRST); 2700 pass |= FR_BLOCK; 2701 LBUMPD(ipf_stats[out], fr_ppshit); 2702 fin->fin_reason = FRB_PPSRATE; 2703 } 2704 2705 /* 2706 * If we fail to add a packet to the authorization queue, then we 2707 * drop the packet later. However, if it was added then pretend 2708 * we've dropped it already. 2709 */ 2710 if (FR_ISAUTH(pass)) { 2711 if (ipf_auth_new(fin->fin_m, fin) != 0) { 2712 DT1(frb_authnew, fr_info_t *, fin); 2713 fin->fin_m = *fin->fin_mp = NULL; 2714 fin->fin_reason = FRB_AUTHNEW; 2715 fin->fin_error = 0; 2716 } else { 2717 IPFERROR(1); 2718 fin->fin_error = ENOSPC; 2719 } 2720 } 2721 2722 if ((fr != NULL) && (fr->fr_func != NULL) && 2723 (fr->fr_func != (ipfunc_t)-1) && !(pass & FR_CALLNOW)) 2724 (void) (*fr->fr_func)(fin, &pass); 2725 2726 /* 2727 * If a rule is a pre-auth rule, check again in the list of rules 2728 * loaded for authenticated use. It does not particulary matter 2729 * if this search fails because a "preauth" result, from a rule, 2730 * is treated as "not a pass", hence the packet is blocked. 2731 */ 2732 if (FR_ISPREAUTH(pass)) { 2733 pass = ipf_auth_pre_scanlist(softc, fin, pass); 2734 } 2735 2736 /* 2737 * If the rule has "keep frag" and the packet is actually a fragment, 2738 * then create a fragment state entry. 2739 */ 2740 if (pass & FR_KEEPFRAG) { 2741 if (fin->fin_flx & FI_FRAG) { 2742 if (ipf_frag_new(softc, fin, pass) == -1) { 2743 LBUMP(ipf_stats[out].fr_bnfr); 2744 } else { 2745 LBUMP(ipf_stats[out].fr_nfr); 2746 } 2747 } else { 2748 LBUMP(ipf_stats[out].fr_cfr); 2749 } 2750 } 2751 2752 fr = fin->fin_fr; 2753 *passp = pass; 2754 2755 return fr; 2756 } 2757 2758 2759 /* ------------------------------------------------------------------------ */ 2760 /* Function: ipf_check */ 2761 /* Returns: int - 0 == packet allowed through, */ 2762 /* User space: */ 2763 /* -1 == packet blocked */ 2764 /* 1 == packet not matched */ 2765 /* -2 == requires authentication */ 2766 /* Kernel: */ 2767 /* > 0 == filter error # for packet */ 2768 /* Parameters: ip(I) - pointer to start of IPv4/6 packet */ 2769 /* hlen(I) - length of header */ 2770 /* ifp(I) - pointer to interface this packet is on */ 2771 /* out(I) - 0 == packet going in, 1 == packet going out */ 2772 /* mp(IO) - pointer to caller's buffer pointer that holds this */ 2773 /* IP packet. */ 2774 /* Solaris & HP-UX ONLY : */ 2775 /* qpi(I) - pointer to STREAMS queue information for this */ 2776 /* interface & direction. */ 2777 /* */ 2778 /* ipf_check() is the master function for all IPFilter packet processing. */ 2779 /* It orchestrates: Network Address Translation (NAT), checking for packet */ 2780 /* authorisation (or pre-authorisation), presence of related state info., */ 2781 /* generating log entries, IP packet accounting, routing of packets as */ 2782 /* directed by firewall rules and of course whether or not to allow the */ 2783 /* packet to be further processed by the kernel. */ 2784 /* */ 2785 /* For packets blocked, the contents of "mp" will be NULL'd and the buffer */ 2786 /* freed. Packets passed may be returned with the pointer pointed to by */ 2787 /* by "mp" changed to a new buffer. */ 2788 /* ------------------------------------------------------------------------ */ 2789 int 2790 ipf_check(void *ctx, ip_t *ip, int hlen, void *ifp, int out, 2791 #if defined(_KERNEL) && defined(MENTAT) 2792 void *qif, 2793 #endif 2794 mb_t **mp) 2795 { 2796 /* 2797 * The above really sucks, but short of writing a diff 2798 */ 2799 ipf_main_softc_t *softc = ctx; 2800 fr_info_t frinfo; 2801 fr_info_t *fin = &frinfo; 2802 u_32_t pass = softc->ipf_pass; 2803 frentry_t *fr = NULL; 2804 int v = IP_V(ip); 2805 mb_t *mc = NULL; 2806 mb_t *m; 2807 /* 2808 * The first part of ipf_check() deals with making sure that what goes 2809 * into the filtering engine makes some sense. Information about the 2810 * the packet is distilled, collected into a fr_info_t structure and 2811 * the an attempt to ensure the buffer the packet is in is big enough 2812 * to hold all the required packet headers. 2813 */ 2814 #ifdef _KERNEL 2815 # ifdef MENTAT 2816 qpktinfo_t *qpi = qif; 2817 2818 # ifdef __sparc 2819 if ((u_int)ip & 0x3) 2820 return 2; 2821 # endif 2822 # else 2823 SPL_INT(s); 2824 # endif 2825 2826 if (softc->ipf_running <= 0) { 2827 return 0; 2828 } 2829 2830 bzero((char *)fin, sizeof(*fin)); 2831 2832 # ifdef MENTAT 2833 if (qpi->qpi_flags & QF_BROADCAST) 2834 fin->fin_flx |= FI_MBCAST|FI_BROADCAST; 2835 if (qpi->qpi_flags & QF_MULTICAST) 2836 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2837 m = qpi->qpi_m; 2838 fin->fin_qfm = m; 2839 fin->fin_qpi = qpi; 2840 # else /* MENTAT */ 2841 2842 m = *mp; 2843 2844 # if defined(M_MCAST) 2845 if ((m->m_flags & M_MCAST) != 0) 2846 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2847 # endif 2848 # if defined(M_MLOOP) 2849 if ((m->m_flags & M_MLOOP) != 0) 2850 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2851 # endif 2852 # if defined(M_BCAST) 2853 if ((m->m_flags & M_BCAST) != 0) 2854 fin->fin_flx |= FI_MBCAST|FI_BROADCAST; 2855 # endif 2856 # ifdef M_CANFASTFWD 2857 /* 2858 * XXX For now, IP Filter and fast-forwarding of cached flows 2859 * XXX are mutually exclusive. Eventually, IP Filter should 2860 * XXX get a "can-fast-forward" filter rule. 2861 */ 2862 m->m_flags &= ~M_CANFASTFWD; 2863 # endif /* M_CANFASTFWD */ 2864 # if defined(CSUM_DELAY_DATA) && (!defined(__FreeBSD_version) || \ 2865 (__FreeBSD_version < 501108)) 2866 /* 2867 * disable delayed checksums. 2868 */ 2869 if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 2870 in_undefer_cksum_tcpudp(m); 2871 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 2872 } 2873 # endif /* CSUM_DELAY_DATA */ 2874 # endif /* MENTAT */ 2875 #else 2876 bzero((char *)fin, sizeof(*fin)); 2877 m = *mp; 2878 # if defined(M_MCAST) 2879 if ((m->m_flags & M_MCAST) != 0) 2880 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2881 # endif 2882 # if defined(M_MLOOP) 2883 if ((m->m_flags & M_MLOOP) != 0) 2884 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2885 # endif 2886 # if defined(M_BCAST) 2887 if ((m->m_flags & M_BCAST) != 0) 2888 fin->fin_flx |= FI_MBCAST|FI_BROADCAST; 2889 # endif 2890 #endif /* _KERNEL */ 2891 2892 fin->fin_v = v; 2893 fin->fin_m = m; 2894 fin->fin_ip = ip; 2895 fin->fin_mp = mp; 2896 fin->fin_out = out; 2897 fin->fin_ifp = ifp; 2898 fin->fin_error = ENETUNREACH; 2899 fin->fin_hlen = (u_short)hlen; 2900 fin->fin_dp = (char *)ip + hlen; 2901 fin->fin_main_soft = softc; 2902 2903 fin->fin_ipoff = (char *)ip - MTOD(m, char *); 2904 2905 SPL_NET(s); 2906 2907 #ifdef USE_INET6 2908 if (v == 6) { 2909 LBUMP(ipf_stats[out].fr_ipv6); 2910 /* 2911 * Jumbo grams are quite likely too big for internal buffer 2912 * structures to handle comfortably, for now, so just drop 2913 * them. 2914 */ 2915 if (((ip6_t *)ip)->ip6_plen == 0) { 2916 DT1(frb_jumbo, ip6_t *, (ip6_t *)ip); 2917 pass = FR_BLOCK|FR_NOMATCH; 2918 fin->fin_reason = FRB_JUMBO; 2919 goto finished; 2920 } 2921 fin->fin_family = AF_INET6; 2922 } else 2923 #endif 2924 { 2925 fin->fin_family = AF_INET; 2926 } 2927 2928 if (ipf_makefrip(hlen, ip, fin) == -1) { 2929 DT1(frb_makefrip, fr_info_t *, fin); 2930 pass = FR_BLOCK|FR_NOMATCH; 2931 fin->fin_reason = FRB_MAKEFRIP; 2932 goto finished; 2933 } 2934 2935 /* 2936 * For at least IPv6 packets, if a m_pullup() fails then this pointer 2937 * becomes NULL and so we have no packet to free. 2938 */ 2939 if (*fin->fin_mp == NULL) 2940 goto finished; 2941 2942 if (!out) { 2943 if (v == 4) { 2944 if (softc->ipf_chksrc && !ipf_verifysrc(fin)) { 2945 LBUMPD(ipf_stats[0], fr_v4_badsrc); 2946 fin->fin_flx |= FI_BADSRC; 2947 } 2948 if (fin->fin_ip->ip_ttl < softc->ipf_minttl) { 2949 LBUMPD(ipf_stats[0], fr_v4_badttl); 2950 fin->fin_flx |= FI_LOWTTL; 2951 } 2952 } 2953 #ifdef USE_INET6 2954 else if (v == 6) { 2955 if (((ip6_t *)ip)->ip6_hlim < softc->ipf_minttl) { 2956 LBUMPD(ipf_stats[0], fr_v6_badttl); 2957 fin->fin_flx |= FI_LOWTTL; 2958 } 2959 } 2960 #endif 2961 } 2962 2963 if (fin->fin_flx & FI_SHORT) { 2964 LBUMPD(ipf_stats[out], fr_short); 2965 } 2966 2967 READ_ENTER(&softc->ipf_mutex); 2968 2969 if (!out) { 2970 switch (fin->fin_v) 2971 { 2972 case 4 : 2973 if (ipf_nat_checkin(fin, &pass) == -1) { 2974 goto filterdone; 2975 } 2976 break; 2977 #ifdef USE_INET6 2978 case 6 : 2979 if (ipf_nat6_checkin(fin, &pass) == -1) { 2980 goto filterdone; 2981 } 2982 break; 2983 #endif 2984 default : 2985 break; 2986 } 2987 } 2988 /* 2989 * Check auth now. 2990 * If a packet is found in the auth table, then skip checking 2991 * the access lists for permission but we do need to consider 2992 * the result as if it were from the ACL's. In addition, being 2993 * found in the auth table means it has been seen before, so do 2994 * not pass it through accounting (again), lest it be counted twice. 2995 */ 2996 fr = ipf_auth_check(fin, &pass); 2997 if (!out && (fr == NULL)) 2998 (void) ipf_acctpkt(fin, NULL); 2999 3000 if (fr == NULL) { 3001 if ((fin->fin_flx & FI_FRAG) != 0) 3002 fr = ipf_frag_known(fin, &pass); 3003 3004 if (fr == NULL) 3005 fr = ipf_state_check(fin, &pass); 3006 } 3007 3008 if ((pass & FR_NOMATCH) || (fr == NULL)) 3009 fr = ipf_firewall(fin, &pass); 3010 3011 /* 3012 * If we've asked to track state for this packet, set it up. 3013 * Here rather than ipf_firewall because ipf_checkauth may decide 3014 * to return a packet for "keep state" 3015 */ 3016 if ((pass & FR_KEEPSTATE) && (fin->fin_m != NULL) && 3017 !(fin->fin_flx & FI_STATE)) { 3018 if (ipf_state_add(softc, fin, NULL, 0) == 0) { 3019 LBUMP(ipf_stats[out].fr_ads); 3020 } else { 3021 LBUMP(ipf_stats[out].fr_bads); 3022 if (FR_ISPASS(pass)) { 3023 DT(frb_stateadd); 3024 pass &= ~FR_CMDMASK; 3025 pass |= FR_BLOCK; 3026 fin->fin_reason = FRB_STATEADD; 3027 } 3028 } 3029 } 3030 3031 fin->fin_fr = fr; 3032 if ((fr != NULL) && !(fin->fin_flx & FI_STATE)) { 3033 fin->fin_dif = &fr->fr_dif; 3034 fin->fin_tif = &fr->fr_tifs[fin->fin_rev]; 3035 } 3036 3037 /* 3038 * Only count/translate packets which will be passed on, out the 3039 * interface. 3040 */ 3041 if (out && FR_ISPASS(pass)) { 3042 (void) ipf_acctpkt(fin, NULL); 3043 3044 switch (fin->fin_v) 3045 { 3046 case 4 : 3047 if (ipf_nat_checkout(fin, &pass) == -1) { 3048 ; 3049 } else if ((softc->ipf_update_ipid != 0) && (v == 4)) { 3050 if (ipf_updateipid(fin) == -1) { 3051 DT(frb_updateipid); 3052 LBUMP(ipf_stats[1].fr_ipud); 3053 pass &= ~FR_CMDMASK; 3054 pass |= FR_BLOCK; 3055 fin->fin_reason = FRB_UPDATEIPID; 3056 } else { 3057 LBUMP(ipf_stats[0].fr_ipud); 3058 } 3059 } 3060 break; 3061 #ifdef USE_INET6 3062 case 6 : 3063 (void) ipf_nat6_checkout(fin, &pass); 3064 break; 3065 #endif 3066 default : 3067 break; 3068 } 3069 } 3070 3071 filterdone: 3072 #ifdef IPFILTER_LOG 3073 if ((softc->ipf_flags & FF_LOGGING) || (pass & FR_LOGMASK)) { 3074 (void) ipf_dolog(fin, &pass); 3075 } 3076 #endif 3077 3078 /* 3079 * The FI_STATE flag is cleared here so that calling ipf_state_check 3080 * will work when called from inside of fr_fastroute. Although 3081 * there is a similar flag, FI_NATED, for NAT, it does have the same 3082 * impact on code execution. 3083 */ 3084 fin->fin_flx &= ~FI_STATE; 3085 3086 #if defined(FASTROUTE_RECURSION) 3087 /* 3088 * Up the reference on fr_lock and exit ipf_mutex. The generation of 3089 * a packet below can sometimes cause a recursive call into IPFilter. 3090 * On those platforms where that does happen, we need to hang onto 3091 * the filter rule just in case someone decides to remove or flush it 3092 * in the meantime. 3093 */ 3094 if (fr != NULL) { 3095 MUTEX_ENTER(&fr->fr_lock); 3096 fr->fr_ref++; 3097 MUTEX_EXIT(&fr->fr_lock); 3098 } 3099 3100 RWLOCK_EXIT(&softc->ipf_mutex); 3101 #endif 3102 3103 if ((pass & FR_RETMASK) != 0) { 3104 /* 3105 * Should we return an ICMP packet to indicate error 3106 * status passing through the packet filter ? 3107 * WARNING: ICMP error packets AND TCP RST packets should 3108 * ONLY be sent in repsonse to incoming packets. Sending 3109 * them in response to outbound packets can result in a 3110 * panic on some operating systems. 3111 */ 3112 if (!out) { 3113 if (pass & FR_RETICMP) { 3114 int dst; 3115 3116 if ((pass & FR_RETMASK) == FR_FAKEICMP) 3117 dst = 1; 3118 else 3119 dst = 0; 3120 (void) ipf_send_icmp_err(ICMP_UNREACH, fin, 3121 dst); 3122 LBUMP(ipf_stats[0].fr_ret); 3123 } else if (((pass & FR_RETMASK) == FR_RETRST) && 3124 !(fin->fin_flx & FI_SHORT)) { 3125 if (((fin->fin_flx & FI_OOW) != 0) || 3126 (ipf_send_reset(fin) == 0)) { 3127 LBUMP(ipf_stats[1].fr_ret); 3128 } 3129 } 3130 3131 /* 3132 * When using return-* with auth rules, the auth code 3133 * takes over disposing of this packet. 3134 */ 3135 if (FR_ISAUTH(pass) && (fin->fin_m != NULL)) { 3136 DT1(frb_authcapture, fr_info_t *, fin); 3137 fin->fin_m = *fin->fin_mp = NULL; 3138 fin->fin_reason = FRB_AUTHCAPTURE; 3139 m = NULL; 3140 } 3141 } else { 3142 if (pass & FR_RETRST) { 3143 fin->fin_error = ECONNRESET; 3144 } 3145 } 3146 } 3147 3148 /* 3149 * After the above so that ICMP unreachables and TCP RSTs get 3150 * created properly. 3151 */ 3152 if (FR_ISBLOCK(pass) && (fin->fin_flx & FI_NEWNAT)) 3153 ipf_nat_uncreate(fin); 3154 3155 /* 3156 * If we didn't drop off the bottom of the list of rules (and thus 3157 * the 'current' rule fr is not NULL), then we may have some extra 3158 * instructions about what to do with a packet. 3159 * Once we're finished return to our caller, freeing the packet if 3160 * we are dropping it. 3161 */ 3162 if (fr != NULL) { 3163 frdest_t *fdp; 3164 3165 /* 3166 * Generate a duplicated packet first because ipf_fastroute 3167 * can lead to fin_m being free'd... not good. 3168 */ 3169 fdp = fin->fin_dif; 3170 if ((fdp != NULL) && (fdp->fd_ptr != NULL) && 3171 (fdp->fd_ptr != (void *)-1) && (fin->fin_m != NULL)) { 3172 mc = M_COPY(fin->fin_m); 3173 if (mc != NULL) 3174 ipf_fastroute(mc, &mc, fin, fdp); 3175 } 3176 3177 fdp = fin->fin_tif; 3178 if (!out && (pass & FR_FASTROUTE)) { 3179 /* 3180 * For fastroute rule, no destination interface defined 3181 * so pass NULL as the frdest_t parameter 3182 */ 3183 (void) ipf_fastroute(fin->fin_m, mp, fin, NULL); 3184 m = *mp = NULL; 3185 } else if ((fdp != NULL) && (fdp->fd_ptr != NULL) && 3186 (fdp->fd_ptr != (struct ifnet *)-1)) { 3187 /* this is for to rules: */ 3188 ipf_fastroute(fin->fin_m, mp, fin, fdp); 3189 m = *mp = NULL; 3190 } 3191 3192 #if defined(FASTROUTE_RECURSION) 3193 (void) ipf_derefrule(softc, &fr); 3194 #endif 3195 } 3196 #if !defined(FASTROUTE_RECURSION) 3197 RWLOCK_EXIT(&softc->ipf_mutex); 3198 #endif 3199 3200 finished: 3201 if (!FR_ISPASS(pass)) { 3202 LBUMP(ipf_stats[out].fr_block); 3203 if (*mp != NULL) { 3204 #ifdef _KERNEL 3205 FREE_MB_T(*mp); 3206 #endif 3207 m = *mp = NULL; 3208 } 3209 } else { 3210 LBUMP(ipf_stats[out].fr_pass); 3211 #if defined(_KERNEL) && defined(__sgi) 3212 if ((fin->fin_hbuf != NULL) && 3213 (mtod(fin->fin_m, struct ip *) != fin->fin_ip)) { 3214 COPYBACK(fin->fin_m, 0, fin->fin_plen, fin->fin_hbuf); 3215 } 3216 #endif 3217 } 3218 3219 SPL_X(s); 3220 3221 if (fin->fin_m == NULL && fin->fin_flx & FI_BAD && 3222 fin->fin_reason == FRB_PULLUP) { 3223 /* m_pullup() has freed the mbuf */ 3224 LBUMP(ipf_stats[out].fr_blocked[fin->fin_reason]); 3225 return (-1); 3226 } 3227 3228 #ifdef _KERNEL 3229 if (FR_ISPASS(pass)) 3230 return 0; 3231 LBUMP(ipf_stats[out].fr_blocked[fin->fin_reason]); 3232 return fin->fin_error; 3233 #else /* _KERNEL */ 3234 if (*mp != NULL) 3235 (*mp)->mb_ifp = fin->fin_ifp; 3236 blockreason = fin->fin_reason; 3237 FR_VERBOSE(("fin_flx %#x pass %#x ", fin->fin_flx, pass)); 3238 /*if ((pass & FR_CMDMASK) == (softc->ipf_pass & FR_CMDMASK))*/ 3239 if ((pass & FR_NOMATCH) != 0) 3240 return 1; 3241 3242 if ((pass & FR_RETMASK) != 0) 3243 switch (pass & FR_RETMASK) 3244 { 3245 case FR_RETRST : 3246 return 3; 3247 case FR_RETICMP : 3248 return 4; 3249 case FR_FAKEICMP : 3250 return 5; 3251 } 3252 3253 switch (pass & FR_CMDMASK) 3254 { 3255 case FR_PASS : 3256 return 0; 3257 case FR_BLOCK : 3258 return -1; 3259 case FR_AUTH : 3260 return -2; 3261 case FR_ACCOUNT : 3262 return -3; 3263 case FR_PREAUTH : 3264 return -4; 3265 } 3266 return 2; 3267 #endif /* _KERNEL */ 3268 } 3269 3270 3271 #ifdef IPFILTER_LOG 3272 /* ------------------------------------------------------------------------ */ 3273 /* Function: ipf_dolog */ 3274 /* Returns: frentry_t* - returns contents of fin_fr (no change made) */ 3275 /* Parameters: fin(I) - pointer to packet information */ 3276 /* passp(IO) - pointer to current/new filter decision (unused) */ 3277 /* */ 3278 /* Checks flags set to see how a packet should be logged, if it is to be */ 3279 /* logged. Adjust statistics based on its success or not. */ 3280 /* ------------------------------------------------------------------------ */ 3281 frentry_t * 3282 ipf_dolog(fr_info_t *fin, u_32_t *passp) 3283 { 3284 ipf_main_softc_t *softc = fin->fin_main_soft; 3285 u_32_t pass; 3286 int out; 3287 3288 out = fin->fin_out; 3289 pass = *passp; 3290 3291 if ((softc->ipf_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) { 3292 pass |= FF_LOGNOMATCH; 3293 LBUMPD(ipf_stats[out], fr_npkl); 3294 goto logit; 3295 3296 } else if (((pass & FR_LOGMASK) == FR_LOGP) || 3297 (FR_ISPASS(pass) && (softc->ipf_flags & FF_LOGPASS))) { 3298 if ((pass & FR_LOGMASK) != FR_LOGP) 3299 pass |= FF_LOGPASS; 3300 LBUMPD(ipf_stats[out], fr_ppkl); 3301 goto logit; 3302 3303 } else if (((pass & FR_LOGMASK) == FR_LOGB) || 3304 (FR_ISBLOCK(pass) && (softc->ipf_flags & FF_LOGBLOCK))) { 3305 if ((pass & FR_LOGMASK) != FR_LOGB) 3306 pass |= FF_LOGBLOCK; 3307 LBUMPD(ipf_stats[out], fr_bpkl); 3308 3309 logit: 3310 if (ipf_log_pkt(fin, pass) == -1) { 3311 /* 3312 * If the "or-block" option has been used then 3313 * block the packet if we failed to log it. 3314 */ 3315 if ((pass & FR_LOGORBLOCK) && FR_ISPASS(pass)) { 3316 DT1(frb_logfail2, u_int, pass); 3317 pass &= ~FR_CMDMASK; 3318 pass |= FR_BLOCK; 3319 fin->fin_reason = FRB_LOGFAIL2; 3320 } 3321 } 3322 *passp = pass; 3323 } 3324 3325 return fin->fin_fr; 3326 } 3327 #endif /* IPFILTER_LOG */ 3328 3329 3330 /* ------------------------------------------------------------------------ */ 3331 /* Function: ipf_cksum */ 3332 /* Returns: u_short - IP header checksum */ 3333 /* Parameters: addr(I) - pointer to start of buffer to checksum */ 3334 /* len(I) - length of buffer in bytes */ 3335 /* */ 3336 /* Calculate the two's complement 16 bit checksum of the buffer passed. */ 3337 /* */ 3338 /* N.B.: addr should be 16bit aligned. */ 3339 /* ------------------------------------------------------------------------ */ 3340 u_short 3341 ipf_cksum(u_short *addr, int len) 3342 { 3343 u_32_t sum = 0; 3344 3345 for (sum = 0; len > 1; len -= 2) 3346 sum += *addr++; 3347 3348 /* mop up an odd byte, if necessary */ 3349 if (len == 1) 3350 sum += *(u_char *)addr; 3351 3352 /* 3353 * add back carry outs from top 16 bits to low 16 bits 3354 */ 3355 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 3356 sum += (sum >> 16); /* add carry */ 3357 return (u_short)(~sum); 3358 } 3359 3360 3361 /* ------------------------------------------------------------------------ */ 3362 /* Function: fr_cksum */ 3363 /* Returns: u_short - layer 4 checksum */ 3364 /* Parameters: fin(I) - pointer to packet information */ 3365 /* ip(I) - pointer to IP header */ 3366 /* l4proto(I) - protocol to caclulate checksum for */ 3367 /* l4hdr(I) - pointer to layer 4 header */ 3368 /* */ 3369 /* Calculates the TCP checksum for the packet held in "m", using the data */ 3370 /* in the IP header "ip" to seed it. */ 3371 /* */ 3372 /* NB: This function assumes we've pullup'd enough for all of the IP header */ 3373 /* and the TCP header. We also assume that data blocks aren't allocated in */ 3374 /* odd sizes. */ 3375 /* */ 3376 /* Expects ip_len and ip_off to be in network byte order when called. */ 3377 /* ------------------------------------------------------------------------ */ 3378 u_short 3379 fr_cksum(fr_info_t *fin, ip_t *ip, int l4proto, void *l4hdr) 3380 { 3381 u_short *sp, slen, sumsave, *csump; 3382 u_int sum, sum2; 3383 int hlen; 3384 int off; 3385 #ifdef USE_INET6 3386 ip6_t *ip6; 3387 #endif 3388 3389 csump = NULL; 3390 sumsave = 0; 3391 sp = NULL; 3392 slen = 0; 3393 hlen = 0; 3394 sum = 0; 3395 3396 sum = htons((u_short)l4proto); 3397 /* 3398 * Add up IP Header portion 3399 */ 3400 #ifdef USE_INET6 3401 if (IP_V(ip) == 4) { 3402 #endif 3403 hlen = IP_HL(ip) << 2; 3404 off = hlen; 3405 sp = (u_short *)&ip->ip_src; 3406 sum += *sp++; /* ip_src */ 3407 sum += *sp++; 3408 sum += *sp++; /* ip_dst */ 3409 sum += *sp++; 3410 #ifdef USE_INET6 3411 } else if (IP_V(ip) == 6) { 3412 ip6 = (ip6_t *)ip; 3413 hlen = sizeof(*ip6); 3414 off = ((char *)fin->fin_dp - (char *)fin->fin_ip); 3415 sp = (u_short *)&ip6->ip6_src; 3416 sum += *sp++; /* ip6_src */ 3417 sum += *sp++; 3418 sum += *sp++; 3419 sum += *sp++; 3420 sum += *sp++; 3421 sum += *sp++; 3422 sum += *sp++; 3423 sum += *sp++; 3424 /* This needs to be routing header aware. */ 3425 sum += *sp++; /* ip6_dst */ 3426 sum += *sp++; 3427 sum += *sp++; 3428 sum += *sp++; 3429 sum += *sp++; 3430 sum += *sp++; 3431 sum += *sp++; 3432 sum += *sp++; 3433 } else { 3434 return 0xffff; 3435 } 3436 #endif 3437 slen = fin->fin_plen - off; 3438 sum += htons(slen); 3439 3440 switch (l4proto) 3441 { 3442 case IPPROTO_UDP : 3443 csump = &((udphdr_t *)l4hdr)->uh_sum; 3444 break; 3445 3446 case IPPROTO_TCP : 3447 csump = &((tcphdr_t *)l4hdr)->th_sum; 3448 break; 3449 case IPPROTO_ICMP : 3450 csump = &((icmphdr_t *)l4hdr)->icmp_cksum; 3451 sum = 0; /* Pseudo-checksum is not included */ 3452 break; 3453 #ifdef USE_INET6 3454 case IPPROTO_ICMPV6 : 3455 csump = &((struct icmp6_hdr *)l4hdr)->icmp6_cksum; 3456 break; 3457 #endif 3458 default : 3459 break; 3460 } 3461 3462 if (csump != NULL) { 3463 sumsave = *csump; 3464 *csump = 0; 3465 } 3466 3467 sum2 = ipf_pcksum(fin, off, sum); 3468 if (csump != NULL) 3469 *csump = sumsave; 3470 return sum2; 3471 } 3472 3473 3474 /* ------------------------------------------------------------------------ */ 3475 /* Function: ipf_findgroup */ 3476 /* Returns: frgroup_t * - NULL = group not found, else pointer to group */ 3477 /* Parameters: softc(I) - pointer to soft context main structure */ 3478 /* group(I) - group name to search for */ 3479 /* unit(I) - device to which this group belongs */ 3480 /* set(I) - which set of rules (inactive/inactive) this is */ 3481 /* fgpp(O) - pointer to place to store pointer to the pointer */ 3482 /* to where to add the next (last) group or where */ 3483 /* to delete group from. */ 3484 /* */ 3485 /* Search amongst the defined groups for a particular group number. */ 3486 /* ------------------------------------------------------------------------ */ 3487 frgroup_t * 3488 ipf_findgroup(ipf_main_softc_t *softc, char *group, minor_t unit, int set, 3489 frgroup_t ***fgpp) 3490 { 3491 frgroup_t *fg, **fgp; 3492 3493 /* 3494 * Which list of groups to search in is dependent on which list of 3495 * rules are being operated on. 3496 */ 3497 fgp = &softc->ipf_groups[unit][set]; 3498 3499 while ((fg = *fgp) != NULL) { 3500 if (strncmp(group, fg->fg_name, FR_GROUPLEN) == 0) 3501 break; 3502 else 3503 fgp = &fg->fg_next; 3504 } 3505 if (fgpp != NULL) 3506 *fgpp = fgp; 3507 return fg; 3508 } 3509 3510 3511 /* ------------------------------------------------------------------------ */ 3512 /* Function: ipf_group_add */ 3513 /* Returns: frgroup_t * - NULL == did not create group, */ 3514 /* != NULL == pointer to the group */ 3515 /* Parameters: softc(I) - pointer to soft context main structure */ 3516 /* num(I) - group number to add */ 3517 /* head(I) - rule pointer that is using this as the head */ 3518 /* flags(I) - rule flags which describe the type of rule it is */ 3519 /* unit(I) - device to which this group will belong to */ 3520 /* set(I) - which set of rules (inactive/inactive) this is */ 3521 /* Write Locks: ipf_mutex */ 3522 /* */ 3523 /* Add a new group head, or if it already exists, increase the reference */ 3524 /* count to it. */ 3525 /* ------------------------------------------------------------------------ */ 3526 frgroup_t * 3527 ipf_group_add(ipf_main_softc_t *softc, char *group, void *head, u_32_t flags, 3528 minor_t unit, int set) 3529 { 3530 frgroup_t *fg, **fgp; 3531 u_32_t gflags; 3532 3533 if (group == NULL) 3534 return NULL; 3535 3536 if (unit == IPL_LOGIPF && *group == '\0') 3537 return NULL; 3538 3539 fgp = NULL; 3540 gflags = flags & FR_INOUT; 3541 3542 fg = ipf_findgroup(softc, group, unit, set, &fgp); 3543 if (fg != NULL) { 3544 if (fg->fg_head == NULL && head != NULL) 3545 fg->fg_head = head; 3546 if (fg->fg_flags == 0) 3547 fg->fg_flags = gflags; 3548 else if (gflags != fg->fg_flags) 3549 return NULL; 3550 fg->fg_ref++; 3551 return fg; 3552 } 3553 3554 KMALLOC(fg, frgroup_t *); 3555 if (fg != NULL) { 3556 fg->fg_head = head; 3557 fg->fg_start = NULL; 3558 fg->fg_next = *fgp; 3559 bcopy(group, fg->fg_name, strlen(group) + 1); 3560 fg->fg_flags = gflags; 3561 fg->fg_ref = 1; 3562 fg->fg_set = &softc->ipf_groups[unit][set]; 3563 *fgp = fg; 3564 } 3565 return fg; 3566 } 3567 3568 3569 /* ------------------------------------------------------------------------ */ 3570 /* Function: ipf_group_del */ 3571 /* Returns: int - number of rules deleted */ 3572 /* Parameters: softc(I) - pointer to soft context main structure */ 3573 /* group(I) - group name to delete */ 3574 /* fr(I) - filter rule from which group is referenced */ 3575 /* Write Locks: ipf_mutex */ 3576 /* */ 3577 /* This function is called whenever a reference to a group is to be dropped */ 3578 /* and thus its reference count needs to be lowered and the group free'd if */ 3579 /* the reference count reaches zero. Passing in fr is really for the sole */ 3580 /* purpose of knowing when the head rule is being deleted. */ 3581 /* ------------------------------------------------------------------------ */ 3582 void 3583 ipf_group_del(ipf_main_softc_t *softc, frgroup_t *group, frentry_t *fr) 3584 { 3585 3586 if (group->fg_head == fr) 3587 group->fg_head = NULL; 3588 3589 group->fg_ref--; 3590 if ((group->fg_ref == 0) && (group->fg_start == NULL)) 3591 ipf_group_free(group); 3592 } 3593 3594 3595 /* ------------------------------------------------------------------------ */ 3596 /* Function: ipf_group_free */ 3597 /* Returns: Nil */ 3598 /* Parameters: group(I) - pointer to filter rule group */ 3599 /* */ 3600 /* Remove the group from the list of groups and free it. */ 3601 /* ------------------------------------------------------------------------ */ 3602 static void 3603 ipf_group_free(frgroup_t *group) 3604 { 3605 frgroup_t **gp; 3606 3607 for (gp = group->fg_set; *gp != NULL; gp = &(*gp)->fg_next) { 3608 if (*gp == group) { 3609 *gp = group->fg_next; 3610 break; 3611 } 3612 } 3613 KFREE(group); 3614 } 3615 3616 3617 /* ------------------------------------------------------------------------ */ 3618 /* Function: ipf_group_flush */ 3619 /* Returns: int - number of rules flush from group */ 3620 /* Parameters: softc(I) - pointer to soft context main structure */ 3621 /* Parameters: group(I) - pointer to filter rule group */ 3622 /* */ 3623 /* Remove all of the rules that currently are listed under the given group. */ 3624 /* ------------------------------------------------------------------------ */ 3625 static int 3626 ipf_group_flush(ipf_main_softc_t *softc, frgroup_t *group) 3627 { 3628 int gone = 0; 3629 3630 (void) ipf_flushlist(softc, &gone, &group->fg_start); 3631 3632 return gone; 3633 } 3634 3635 3636 /* ------------------------------------------------------------------------ */ 3637 /* Function: ipf_getrulen */ 3638 /* Returns: frentry_t * - NULL == not found, else pointer to rule n */ 3639 /* Parameters: softc(I) - pointer to soft context main structure */ 3640 /* Parameters: unit(I) - device for which to count the rule's number */ 3641 /* flags(I) - which set of rules to find the rule in */ 3642 /* group(I) - group name */ 3643 /* n(I) - rule number to find */ 3644 /* */ 3645 /* Find rule # n in group # g and return a pointer to it. Return NULl if */ 3646 /* group # g doesn't exist or there are less than n rules in the group. */ 3647 /* ------------------------------------------------------------------------ */ 3648 frentry_t * 3649 ipf_getrulen(ipf_main_softc_t *softc, int unit, char *group, u_32_t n) 3650 { 3651 frentry_t *fr; 3652 frgroup_t *fg; 3653 3654 fg = ipf_findgroup(softc, group, unit, softc->ipf_active, NULL); 3655 if (fg == NULL) 3656 return NULL; 3657 for (fr = fg->fg_start; fr && n; fr = fr->fr_next, n--) 3658 ; 3659 if (n != 0) 3660 return NULL; 3661 return fr; 3662 } 3663 3664 3665 /* ------------------------------------------------------------------------ */ 3666 /* Function: ipf_flushlist */ 3667 /* Returns: int - >= 0 - number of flushed rules */ 3668 /* Parameters: softc(I) - pointer to soft context main structure */ 3669 /* nfreedp(O) - pointer to int where flush count is stored */ 3670 /* listp(I) - pointer to list to flush pointer */ 3671 /* Write Locks: ipf_mutex */ 3672 /* */ 3673 /* Recursively flush rules from the list, descending groups as they are */ 3674 /* encountered. if a rule is the head of a group and it has lost all its */ 3675 /* group members, then also delete the group reference. nfreedp is needed */ 3676 /* to store the accumulating count of rules removed, whereas the returned */ 3677 /* value is just the number removed from the current list. The latter is */ 3678 /* needed to correctly adjust reference counts on rules that define groups. */ 3679 /* */ 3680 /* NOTE: Rules not loaded from user space cannot be flushed. */ 3681 /* ------------------------------------------------------------------------ */ 3682 static int 3683 ipf_flushlist(ipf_main_softc_t *softc, int *nfreedp, frentry_t **listp) 3684 { 3685 int freed = 0; 3686 frentry_t *fp; 3687 3688 while ((fp = *listp) != NULL) { 3689 if ((fp->fr_type & FR_T_BUILTIN) || 3690 !(fp->fr_flags & FR_COPIED)) { 3691 listp = &fp->fr_next; 3692 continue; 3693 } 3694 *listp = fp->fr_next; 3695 if (fp->fr_next != NULL) 3696 fp->fr_next->fr_pnext = fp->fr_pnext; 3697 fp->fr_pnext = NULL; 3698 3699 if (fp->fr_grphead != NULL) { 3700 freed += ipf_group_flush(softc, fp->fr_grphead); 3701 fp->fr_names[fp->fr_grhead] = '\0'; 3702 } 3703 3704 if (fp->fr_icmpgrp != NULL) { 3705 freed += ipf_group_flush(softc, fp->fr_icmpgrp); 3706 fp->fr_names[fp->fr_icmphead] = '\0'; 3707 } 3708 3709 if (fp->fr_srctrack.ht_max_nodes) 3710 ipf_rb_ht_flush(&fp->fr_srctrack); 3711 3712 fp->fr_next = NULL; 3713 3714 ASSERT(fp->fr_ref > 0); 3715 if (ipf_derefrule(softc, &fp) == 0) 3716 freed++; 3717 } 3718 *nfreedp += freed; 3719 return freed; 3720 } 3721 3722 3723 /* ------------------------------------------------------------------------ */ 3724 /* Function: ipf_flush */ 3725 /* Returns: int - >= 0 - number of flushed rules */ 3726 /* Parameters: softc(I) - pointer to soft context main structure */ 3727 /* unit(I) - device for which to flush rules */ 3728 /* flags(I) - which set of rules to flush */ 3729 /* */ 3730 /* Calls flushlist() for all filter rules (accounting, firewall - both IPv4 */ 3731 /* and IPv6) as defined by the value of flags. */ 3732 /* ------------------------------------------------------------------------ */ 3733 int 3734 ipf_flush(ipf_main_softc_t *softc, minor_t unit, int flags) 3735 { 3736 int flushed = 0, set; 3737 3738 WRITE_ENTER(&softc->ipf_mutex); 3739 3740 set = softc->ipf_active; 3741 if ((flags & FR_INACTIVE) == FR_INACTIVE) 3742 set = 1 - set; 3743 3744 if (flags & FR_OUTQUE) { 3745 ipf_flushlist(softc, &flushed, &softc->ipf_rules[1][set]); 3746 ipf_flushlist(softc, &flushed, &softc->ipf_acct[1][set]); 3747 } 3748 if (flags & FR_INQUE) { 3749 ipf_flushlist(softc, &flushed, &softc->ipf_rules[0][set]); 3750 ipf_flushlist(softc, &flushed, &softc->ipf_acct[0][set]); 3751 } 3752 3753 flushed += ipf_flush_groups(softc, &softc->ipf_groups[unit][set], 3754 flags & (FR_INQUE|FR_OUTQUE)); 3755 3756 RWLOCK_EXIT(&softc->ipf_mutex); 3757 3758 if (unit == IPL_LOGIPF) { 3759 int tmp; 3760 3761 tmp = ipf_flush(softc, IPL_LOGCOUNT, flags); 3762 if (tmp >= 0) 3763 flushed += tmp; 3764 } 3765 return flushed; 3766 } 3767 3768 3769 /* ------------------------------------------------------------------------ */ 3770 /* Function: ipf_flush_groups */ 3771 /* Returns: int - >= 0 - number of flushed rules */ 3772 /* Parameters: softc(I) - soft context pointerto work with */ 3773 /* grhead(I) - pointer to the start of the group list to flush */ 3774 /* flags(I) - which set of rules to flush */ 3775 /* */ 3776 /* Walk through all of the groups under the given group head and remove all */ 3777 /* of those that match the flags passed in. The for loop here is bit more */ 3778 /* complicated than usual because the removal of a rule with ipf_derefrule */ 3779 /* may end up removing not only the structure pointed to by "fg" but also */ 3780 /* what is fg_next and fg_next after that. So if a filter rule is actually */ 3781 /* removed from the group then it is necessary to start again. */ 3782 /* ------------------------------------------------------------------------ */ 3783 static int 3784 ipf_flush_groups( ipf_main_softc_t *softc, frgroup_t **grhead, int flags) 3785 { 3786 frentry_t *fr, **frp; 3787 frgroup_t *fg, **fgp; 3788 int flushed = 0; 3789 int removed = 0; 3790 3791 for (fgp = grhead; (fg = *fgp) != NULL; ) { 3792 while ((fg != NULL) && ((fg->fg_flags & flags) == 0)) 3793 fg = fg->fg_next; 3794 if (fg == NULL) 3795 break; 3796 removed = 0; 3797 frp = &fg->fg_start; 3798 while ((removed == 0) && ((fr = *frp) != NULL)) { 3799 if ((fr->fr_flags & flags) == 0) { 3800 frp = &fr->fr_next; 3801 } else { 3802 if (fr->fr_next != NULL) 3803 fr->fr_next->fr_pnext = fr->fr_pnext; 3804 *frp = fr->fr_next; 3805 fr->fr_pnext = NULL; 3806 fr->fr_next = NULL; 3807 (void) ipf_derefrule(softc, &fr); 3808 flushed++; 3809 removed++; 3810 } 3811 } 3812 if (removed == 0) 3813 fgp = &fg->fg_next; 3814 } 3815 return flushed; 3816 } 3817 3818 3819 /* ------------------------------------------------------------------------ */ 3820 /* Function: memstr */ 3821 /* Returns: char * - NULL if failed, != NULL pointer to matching bytes */ 3822 /* Parameters: src(I) - pointer to byte sequence to match */ 3823 /* dst(I) - pointer to byte sequence to search */ 3824 /* slen(I) - match length */ 3825 /* dlen(I) - length available to search in */ 3826 /* */ 3827 /* Search dst for a sequence of bytes matching those at src and extend for */ 3828 /* slen bytes. */ 3829 /* ------------------------------------------------------------------------ */ 3830 char * 3831 memstr(const char *src, char *dst, size_t slen, size_t dlen) 3832 { 3833 char *s = NULL; 3834 3835 while (dlen >= slen) { 3836 if (memcmp(src, dst, slen) == 0) { 3837 s = dst; 3838 break; 3839 } 3840 dst++; 3841 dlen--; 3842 } 3843 return s; 3844 } 3845 3846 3847 /* ------------------------------------------------------------------------ */ 3848 /* Function: ipf_fixskip */ 3849 /* Returns: Nil */ 3850 /* Parameters: listp(IO) - pointer to start of list with skip rule */ 3851 /* rp(I) - rule added/removed with skip in it. */ 3852 /* addremove(I) - adjustment (-1/+1) to make to skip count, */ 3853 /* depending on whether a rule was just added */ 3854 /* or removed. */ 3855 /* */ 3856 /* Adjust all the rules in a list which would have skip'd past the position */ 3857 /* where we are inserting to skip to the right place given the change. */ 3858 /* ------------------------------------------------------------------------ */ 3859 void 3860 ipf_fixskip(frentry_t **listp, frentry_t *rp, int addremove) 3861 { 3862 int rules, rn; 3863 frentry_t *fp; 3864 3865 rules = 0; 3866 for (fp = *listp; (fp != NULL) && (fp != rp); fp = fp->fr_next) 3867 rules++; 3868 3869 if (!fp) 3870 return; 3871 3872 for (rn = 0, fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++) 3873 if (FR_ISSKIP(fp->fr_flags) && (rn + fp->fr_arg >= rules)) 3874 fp->fr_arg += addremove; 3875 } 3876 3877 3878 #ifdef _KERNEL 3879 /* ------------------------------------------------------------------------ */ 3880 /* Function: count4bits */ 3881 /* Returns: int - >= 0 - number of consecutive bits in input */ 3882 /* Parameters: ip(I) - 32bit IP address */ 3883 /* */ 3884 /* IPv4 ONLY */ 3885 /* count consecutive 1's in bit mask. If the mask generated by counting */ 3886 /* consecutive 1's is different to that passed, return -1, else return # */ 3887 /* of bits. */ 3888 /* ------------------------------------------------------------------------ */ 3889 int 3890 count4bits(u_32_t ip) 3891 { 3892 u_32_t ipn; 3893 int cnt = 0, i, j; 3894 3895 ip = ipn = ntohl(ip); 3896 for (i = 32; i; i--, ipn *= 2) 3897 if (ipn & 0x80000000) 3898 cnt++; 3899 else 3900 break; 3901 ipn = 0; 3902 for (i = 32, j = cnt; i; i--, j--) { 3903 ipn *= 2; 3904 if (j > 0) 3905 ipn++; 3906 } 3907 if (ipn == ip) 3908 return cnt; 3909 return -1; 3910 } 3911 3912 3913 /* ------------------------------------------------------------------------ */ 3914 /* Function: count6bits */ 3915 /* Returns: int - >= 0 - number of consecutive bits in input */ 3916 /* Parameters: msk(I) - pointer to start of IPv6 bitmask */ 3917 /* */ 3918 /* IPv6 ONLY */ 3919 /* count consecutive 1's in bit mask. */ 3920 /* ------------------------------------------------------------------------ */ 3921 # ifdef USE_INET6 3922 int 3923 count6bits(u_32_t *msk) 3924 { 3925 int i = 0, k; 3926 u_32_t j; 3927 3928 for (k = 3; k >= 0; k--) 3929 if (msk[k] == 0xffffffff) 3930 i += 32; 3931 else { 3932 for (j = msk[k]; j; j <<= 1) 3933 if (j & 0x80000000) 3934 i++; 3935 } 3936 return i; 3937 } 3938 # endif 3939 #endif /* _KERNEL */ 3940 3941 3942 /* ------------------------------------------------------------------------ */ 3943 /* Function: ipf_synclist */ 3944 /* Returns: int - 0 = no failures, else indication of first failure */ 3945 /* Parameters: fr(I) - start of filter list to sync interface names for */ 3946 /* ifp(I) - interface pointer for limiting sync lookups */ 3947 /* Write Locks: ipf_mutex */ 3948 /* */ 3949 /* Walk through a list of filter rules and resolve any interface names into */ 3950 /* pointers. Where dynamic addresses are used, also update the IP address */ 3951 /* used in the rule. The interface pointer is used to limit the lookups to */ 3952 /* a specific set of matching names if it is non-NULL. */ 3953 /* Errors can occur when resolving the destination name of to/dup-to fields */ 3954 /* when the name points to a pool and that pool doest not exist. If this */ 3955 /* does happen then it is necessary to check if there are any lookup refs */ 3956 /* that need to be dropped before returning with an error. */ 3957 /* ------------------------------------------------------------------------ */ 3958 static int 3959 ipf_synclist(ipf_main_softc_t *softc, frentry_t *fr, void *ifp) 3960 { 3961 frentry_t *frt, *start = fr; 3962 frdest_t *fdp; 3963 char *name; 3964 int error; 3965 void *ifa; 3966 int v, i; 3967 3968 error = 0; 3969 3970 for (; fr; fr = fr->fr_next) { 3971 if (fr->fr_family == AF_INET) 3972 v = 4; 3973 else if (fr->fr_family == AF_INET6) 3974 v = 6; 3975 else 3976 v = 0; 3977 3978 /* 3979 * Lookup all the interface names that are part of the rule. 3980 */ 3981 for (i = 0; i < 4; i++) { 3982 if ((ifp != NULL) && (fr->fr_ifas[i] != ifp)) 3983 continue; 3984 if (fr->fr_ifnames[i] == -1) 3985 continue; 3986 name = FR_NAME(fr, fr_ifnames[i]); 3987 fr->fr_ifas[i] = ipf_resolvenic(softc, name, v); 3988 } 3989 3990 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) { 3991 if (fr->fr_satype != FRI_NORMAL && 3992 fr->fr_satype != FRI_LOOKUP) { 3993 ifa = ipf_resolvenic(softc, fr->fr_names + 3994 fr->fr_sifpidx, v); 3995 ipf_ifpaddr(softc, v, fr->fr_satype, ifa, 3996 &fr->fr_src6, &fr->fr_smsk6); 3997 } 3998 if (fr->fr_datype != FRI_NORMAL && 3999 fr->fr_datype != FRI_LOOKUP) { 4000 ifa = ipf_resolvenic(softc, fr->fr_names + 4001 fr->fr_sifpidx, v); 4002 ipf_ifpaddr(softc, v, fr->fr_datype, ifa, 4003 &fr->fr_dst6, &fr->fr_dmsk6); 4004 } 4005 } 4006 4007 fdp = &fr->fr_tifs[0]; 4008 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) { 4009 error = ipf_resolvedest(softc, fr->fr_names, fdp, v); 4010 if (error != 0) 4011 goto unwind; 4012 } 4013 4014 fdp = &fr->fr_tifs[1]; 4015 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) { 4016 error = ipf_resolvedest(softc, fr->fr_names, fdp, v); 4017 if (error != 0) 4018 goto unwind; 4019 } 4020 4021 fdp = &fr->fr_dif; 4022 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) { 4023 error = ipf_resolvedest(softc, fr->fr_names, fdp, v); 4024 if (error != 0) 4025 goto unwind; 4026 } 4027 4028 if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 4029 (fr->fr_satype == FRI_LOOKUP) && (fr->fr_srcptr == NULL)) { 4030 fr->fr_srcptr = ipf_lookup_res_num(softc, 4031 fr->fr_srctype, 4032 IPL_LOGIPF, 4033 fr->fr_srcnum, 4034 &fr->fr_srcfunc); 4035 } 4036 if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 4037 (fr->fr_datype == FRI_LOOKUP) && (fr->fr_dstptr == NULL)) { 4038 fr->fr_dstptr = ipf_lookup_res_num(softc, 4039 fr->fr_dsttype, 4040 IPL_LOGIPF, 4041 fr->fr_dstnum, 4042 &fr->fr_dstfunc); 4043 } 4044 } 4045 return 0; 4046 4047 unwind: 4048 for (frt = start; frt != fr; fr = fr->fr_next) { 4049 if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 4050 (frt->fr_satype == FRI_LOOKUP) && (frt->fr_srcptr != NULL)) 4051 ipf_lookup_deref(softc, frt->fr_srctype, 4052 frt->fr_srcptr); 4053 if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 4054 (frt->fr_datype == FRI_LOOKUP) && (frt->fr_dstptr != NULL)) 4055 ipf_lookup_deref(softc, frt->fr_dsttype, 4056 frt->fr_dstptr); 4057 } 4058 return error; 4059 } 4060 4061 4062 /* ------------------------------------------------------------------------ */ 4063 /* Function: ipf_sync */ 4064 /* Returns: void */ 4065 /* Parameters: Nil */ 4066 /* */ 4067 /* ipf_sync() is called when we suspect that the interface list or */ 4068 /* information about interfaces (like IP#) has changed. Go through all */ 4069 /* filter rules, NAT entries and the state table and check if anything */ 4070 /* needs to be changed/updated. */ 4071 /* ------------------------------------------------------------------------ */ 4072 int 4073 ipf_sync(ipf_main_softc_t *softc, void *ifp) 4074 { 4075 int i; 4076 4077 # if !SOLARIS 4078 ipf_nat_sync(softc, ifp); 4079 ipf_state_sync(softc, ifp); 4080 ipf_lookup_sync(softc, ifp); 4081 # endif 4082 4083 WRITE_ENTER(&softc->ipf_mutex); 4084 (void) ipf_synclist(softc, softc->ipf_acct[0][softc->ipf_active], ifp); 4085 (void) ipf_synclist(softc, softc->ipf_acct[1][softc->ipf_active], ifp); 4086 (void) ipf_synclist(softc, softc->ipf_rules[0][softc->ipf_active], ifp); 4087 (void) ipf_synclist(softc, softc->ipf_rules[1][softc->ipf_active], ifp); 4088 4089 for (i = 0; i < IPL_LOGSIZE; i++) { 4090 frgroup_t *g; 4091 4092 for (g = softc->ipf_groups[i][0]; g != NULL; g = g->fg_next) 4093 (void) ipf_synclist(softc, g->fg_start, ifp); 4094 for (g = softc->ipf_groups[i][1]; g != NULL; g = g->fg_next) 4095 (void) ipf_synclist(softc, g->fg_start, ifp); 4096 } 4097 RWLOCK_EXIT(&softc->ipf_mutex); 4098 4099 return 0; 4100 } 4101 4102 4103 /* 4104 * In the functions below, bcopy() is called because the pointer being 4105 * copied _from_ in this instance is a pointer to a char buf (which could 4106 * end up being unaligned) and on the kernel's local stack. 4107 */ 4108 /* ------------------------------------------------------------------------ */ 4109 /* Function: copyinptr */ 4110 /* Returns: int - 0 = success, else failure */ 4111 /* Parameters: src(I) - pointer to the source address */ 4112 /* dst(I) - destination address */ 4113 /* size(I) - number of bytes to copy */ 4114 /* */ 4115 /* Copy a block of data in from user space, given a pointer to the pointer */ 4116 /* to start copying from (src) and a pointer to where to store it (dst). */ 4117 /* NB: src - pointer to user space pointer, dst - kernel space pointer */ 4118 /* ------------------------------------------------------------------------ */ 4119 int 4120 copyinptr(ipf_main_softc_t *softc, void *src, void *dst, size_t size) 4121 { 4122 void *ca; 4123 int error; 4124 4125 # if SOLARIS 4126 error = COPYIN(src, &ca, sizeof(ca)); 4127 if (error != 0) 4128 return error; 4129 # else 4130 bcopy(src, (void *)&ca, sizeof(ca)); 4131 # endif 4132 error = COPYIN(ca, dst, size); 4133 if (error != 0) { 4134 IPFERROR(3); 4135 error = EFAULT; 4136 } 4137 return error; 4138 } 4139 4140 4141 /* ------------------------------------------------------------------------ */ 4142 /* Function: copyoutptr */ 4143 /* Returns: int - 0 = success, else failure */ 4144 /* Parameters: src(I) - pointer to the source address */ 4145 /* dst(I) - destination address */ 4146 /* size(I) - number of bytes to copy */ 4147 /* */ 4148 /* Copy a block of data out to user space, given a pointer to the pointer */ 4149 /* to start copying from (src) and a pointer to where to store it (dst). */ 4150 /* NB: src - kernel space pointer, dst - pointer to user space pointer. */ 4151 /* ------------------------------------------------------------------------ */ 4152 int 4153 copyoutptr(ipf_main_softc_t *softc, void *src, void *dst, size_t size) 4154 { 4155 void *ca; 4156 int error; 4157 4158 bcopy(dst, &ca, sizeof(ca)); 4159 error = COPYOUT(src, ca, size); 4160 if (error != 0) { 4161 IPFERROR(4); 4162 error = EFAULT; 4163 } 4164 return error; 4165 } 4166 #ifdef _KERNEL 4167 #endif 4168 4169 4170 /* ------------------------------------------------------------------------ */ 4171 /* Function: ipf_lock */ 4172 /* Returns: int - 0 = success, else error */ 4173 /* Parameters: data(I) - pointer to lock value to set */ 4174 /* lockp(O) - pointer to location to store old lock value */ 4175 /* */ 4176 /* Get the new value for the lock integer, set it and return the old value */ 4177 /* in *lockp. */ 4178 /* ------------------------------------------------------------------------ */ 4179 int 4180 ipf_lock(void *data, int *lockp) 4181 { 4182 int arg, err; 4183 4184 err = BCOPYIN(data, &arg, sizeof(arg)); 4185 if (err != 0) 4186 return EFAULT; 4187 err = BCOPYOUT(lockp, data, sizeof(*lockp)); 4188 if (err != 0) 4189 return EFAULT; 4190 *lockp = arg; 4191 return 0; 4192 } 4193 4194 4195 /* ------------------------------------------------------------------------ */ 4196 /* Function: ipf_getstat */ 4197 /* Returns: Nil */ 4198 /* Parameters: softc(I) - pointer to soft context main structure */ 4199 /* fiop(I) - pointer to ipfilter stats structure */ 4200 /* rev(I) - version claim by program doing ioctl */ 4201 /* */ 4202 /* Stores a copy of current pointers, counters, etc, in the friostat */ 4203 /* structure. */ 4204 /* If IPFILTER_COMPAT is compiled, we pretend to be whatever version the */ 4205 /* program is looking for. This ensure that validation of the version it */ 4206 /* expects will always succeed. Thus kernels with IPFILTER_COMPAT will */ 4207 /* allow older binaries to work but kernels without it will not. */ 4208 /* ------------------------------------------------------------------------ */ 4209 /*ARGSUSED*/ 4210 static void 4211 ipf_getstat(ipf_main_softc_t *softc, friostat_t *fiop, int rev) 4212 { 4213 int i; 4214 4215 bcopy((char *)softc->ipf_stats, (char *)fiop->f_st, 4216 sizeof(ipf_statistics_t) * 2); 4217 fiop->f_locks[IPL_LOGSTATE] = -1; 4218 fiop->f_locks[IPL_LOGNAT] = -1; 4219 fiop->f_locks[IPL_LOGIPF] = -1; 4220 fiop->f_locks[IPL_LOGAUTH] = -1; 4221 4222 fiop->f_ipf[0][0] = softc->ipf_rules[0][0]; 4223 fiop->f_acct[0][0] = softc->ipf_acct[0][0]; 4224 fiop->f_ipf[0][1] = softc->ipf_rules[0][1]; 4225 fiop->f_acct[0][1] = softc->ipf_acct[0][1]; 4226 fiop->f_ipf[1][0] = softc->ipf_rules[1][0]; 4227 fiop->f_acct[1][0] = softc->ipf_acct[1][0]; 4228 fiop->f_ipf[1][1] = softc->ipf_rules[1][1]; 4229 fiop->f_acct[1][1] = softc->ipf_acct[1][1]; 4230 4231 fiop->f_ticks = softc->ipf_ticks; 4232 fiop->f_active = softc->ipf_active; 4233 fiop->f_froute[0] = softc->ipf_frouteok[0]; 4234 fiop->f_froute[1] = softc->ipf_frouteok[1]; 4235 fiop->f_rb_no_mem = softc->ipf_rb_no_mem; 4236 fiop->f_rb_node_max = softc->ipf_rb_node_max; 4237 4238 fiop->f_running = softc->ipf_running; 4239 for (i = 0; i < IPL_LOGSIZE; i++) { 4240 fiop->f_groups[i][0] = softc->ipf_groups[i][0]; 4241 fiop->f_groups[i][1] = softc->ipf_groups[i][1]; 4242 } 4243 #ifdef IPFILTER_LOG 4244 fiop->f_log_ok = ipf_log_logok(softc, IPL_LOGIPF); 4245 fiop->f_log_fail = ipf_log_failures(softc, IPL_LOGIPF); 4246 fiop->f_logging = 1; 4247 #else 4248 fiop->f_log_ok = 0; 4249 fiop->f_log_fail = 0; 4250 fiop->f_logging = 0; 4251 #endif 4252 fiop->f_defpass = softc->ipf_pass; 4253 fiop->f_features = ipf_features; 4254 4255 #ifdef IPFILTER_COMPAT 4256 snprintf(fiop->f_version, sizeof(fiop->f_version), 4257 "IP Filter: v%d.%d.%d", (rev / 1000000) % 100, 4258 (rev / 10000) % 100, (rev / 100) % 100); 4259 #else 4260 rev = rev; 4261 (void) strncpy(fiop->f_version, ipfilter_version, 4262 sizeof(fiop->f_version)); 4263 fiop->f_version[sizeof(fiop->f_version) - 1] = '\0'; 4264 #endif 4265 } 4266 4267 4268 #ifdef USE_INET6 4269 int icmptoicmp6types[ICMP_MAXTYPE+1] = { 4270 ICMP6_ECHO_REPLY, /* 0: ICMP_ECHOREPLY */ 4271 -1, /* 1: UNUSED */ 4272 -1, /* 2: UNUSED */ 4273 ICMP6_DST_UNREACH, /* 3: ICMP_UNREACH */ 4274 -1, /* 4: ICMP_SOURCEQUENCH */ 4275 ND_REDIRECT, /* 5: ICMP_REDIRECT */ 4276 -1, /* 6: UNUSED */ 4277 -1, /* 7: UNUSED */ 4278 ICMP6_ECHO_REQUEST, /* 8: ICMP_ECHO */ 4279 -1, /* 9: UNUSED */ 4280 -1, /* 10: UNUSED */ 4281 ICMP6_TIME_EXCEEDED, /* 11: ICMP_TIMXCEED */ 4282 ICMP6_PARAM_PROB, /* 12: ICMP_PARAMPROB */ 4283 -1, /* 13: ICMP_TSTAMP */ 4284 -1, /* 14: ICMP_TSTAMPREPLY */ 4285 -1, /* 15: ICMP_IREQ */ 4286 -1, /* 16: ICMP_IREQREPLY */ 4287 -1, /* 17: ICMP_MASKREQ */ 4288 -1, /* 18: ICMP_MASKREPLY */ 4289 }; 4290 4291 4292 int icmptoicmp6unreach[ICMP_MAX_UNREACH] = { 4293 ICMP6_DST_UNREACH_ADDR, /* 0: ICMP_UNREACH_NET */ 4294 ICMP6_DST_UNREACH_ADDR, /* 1: ICMP_UNREACH_HOST */ 4295 -1, /* 2: ICMP_UNREACH_PROTOCOL */ 4296 ICMP6_DST_UNREACH_NOPORT, /* 3: ICMP_UNREACH_PORT */ 4297 -1, /* 4: ICMP_UNREACH_NEEDFRAG */ 4298 ICMP6_DST_UNREACH_NOTNEIGHBOR, /* 5: ICMP_UNREACH_SRCFAIL */ 4299 ICMP6_DST_UNREACH_ADDR, /* 6: ICMP_UNREACH_NET_UNKNOWN */ 4300 ICMP6_DST_UNREACH_ADDR, /* 7: ICMP_UNREACH_HOST_UNKNOWN */ 4301 -1, /* 8: ICMP_UNREACH_ISOLATED */ 4302 ICMP6_DST_UNREACH_ADMIN, /* 9: ICMP_UNREACH_NET_PROHIB */ 4303 ICMP6_DST_UNREACH_ADMIN, /* 10: ICMP_UNREACH_HOST_PROHIB */ 4304 -1, /* 11: ICMP_UNREACH_TOSNET */ 4305 -1, /* 12: ICMP_UNREACH_TOSHOST */ 4306 ICMP6_DST_UNREACH_ADMIN, /* 13: ICMP_UNREACH_ADMIN_PROHIBIT */ 4307 }; 4308 int icmpreplytype6[ICMP6_MAXTYPE + 1]; 4309 #endif 4310 4311 int icmpreplytype4[ICMP_MAXTYPE + 1]; 4312 4313 4314 /* ------------------------------------------------------------------------ */ 4315 /* Function: ipf_matchicmpqueryreply */ 4316 /* Returns: int - 1 if "icmp" is a valid reply to "ic" else 0. */ 4317 /* Parameters: v(I) - IP protocol version (4 or 6) */ 4318 /* ic(I) - ICMP information */ 4319 /* icmp(I) - ICMP packet header */ 4320 /* rev(I) - direction (0 = forward/1 = reverse) of packet */ 4321 /* */ 4322 /* Check if the ICMP packet defined by the header pointed to by icmp is a */ 4323 /* reply to one as described by what's in ic. If it is a match, return 1, */ 4324 /* else return 0 for no match. */ 4325 /* ------------------------------------------------------------------------ */ 4326 int 4327 ipf_matchicmpqueryreply(int v, icmpinfo_t *ic, icmphdr_t *icmp, int rev) 4328 { 4329 int ictype; 4330 4331 ictype = ic->ici_type; 4332 4333 if (v == 4) { 4334 /* 4335 * If we matched its type on the way in, then when going out 4336 * it will still be the same type. 4337 */ 4338 if ((!rev && (icmp->icmp_type == ictype)) || 4339 (rev && (icmpreplytype4[ictype] == icmp->icmp_type))) { 4340 if (icmp->icmp_type != ICMP_ECHOREPLY) 4341 return 1; 4342 if (icmp->icmp_id == ic->ici_id) 4343 return 1; 4344 } 4345 } 4346 #ifdef USE_INET6 4347 else if (v == 6) { 4348 if ((!rev && (icmp->icmp_type == ictype)) || 4349 (rev && (icmpreplytype6[ictype] == icmp->icmp_type))) { 4350 if (icmp->icmp_type != ICMP6_ECHO_REPLY) 4351 return 1; 4352 if (icmp->icmp_id == ic->ici_id) 4353 return 1; 4354 } 4355 } 4356 #endif 4357 return 0; 4358 } 4359 4360 /* ------------------------------------------------------------------------ */ 4361 /* Function: ipf_rule_compare */ 4362 /* Parameters: fr1(I) - first rule structure to compare */ 4363 /* fr2(I) - second rule structure to compare */ 4364 /* Returns: int - 0 == rules are the same, else mismatch */ 4365 /* */ 4366 /* Compare two rules and return 0 if they match or a number indicating */ 4367 /* which of the individual checks failed. */ 4368 /* ------------------------------------------------------------------------ */ 4369 static int 4370 ipf_rule_compare(frentry_t *fr1, frentry_t *fr2) 4371 { 4372 if (fr1->fr_cksum != fr2->fr_cksum) 4373 return 1; 4374 if (fr1->fr_size != fr2->fr_size) 4375 return 2; 4376 if (fr1->fr_dsize != fr2->fr_dsize) 4377 return 3; 4378 if (memcmp(&fr1->fr_func, &fr2->fr_func, 4379 fr1->fr_size - offsetof(struct frentry, fr_func)) != 0) 4380 return 4; 4381 if (fr1->fr_data && !fr2->fr_data) 4382 return 5; 4383 if (!fr1->fr_data && fr2->fr_data) 4384 return 6; 4385 if (fr1->fr_data) { 4386 if (memcmp(fr1->fr_caddr, fr2->fr_caddr, fr1->fr_dsize)) 4387 return 7; 4388 } 4389 return 0; 4390 } 4391 4392 4393 /* ------------------------------------------------------------------------ */ 4394 /* Function: frrequest */ 4395 /* Returns: int - 0 == success, > 0 == errno value */ 4396 /* Parameters: unit(I) - device for which this is for */ 4397 /* req(I) - ioctl command (SIOC*) */ 4398 /* data(I) - pointer to ioctl data */ 4399 /* set(I) - 1 or 0 (filter set) */ 4400 /* makecopy(I) - flag indicating whether data points to a rule */ 4401 /* in kernel space & hence doesn't need copying. */ 4402 /* */ 4403 /* This function handles all the requests which operate on the list of */ 4404 /* filter rules. This includes adding, deleting, insertion. It is also */ 4405 /* responsible for creating groups when a "head" rule is loaded. Interface */ 4406 /* names are resolved here and other sanity checks are made on the content */ 4407 /* of the rule structure being loaded. If a rule has user defined timeouts */ 4408 /* then make sure they are created and initialised before exiting. */ 4409 /* ------------------------------------------------------------------------ */ 4410 int 4411 frrequest(ipf_main_softc_t *softc, int unit, ioctlcmd_t req, void *data, 4412 int set, int makecopy) 4413 { 4414 int error = 0, in, family, addrem, need_free = 0; 4415 frentry_t frd, *fp, *f, **fprev, **ftail; 4416 void *ptr, *uptr; 4417 u_int *p, *pp; 4418 frgroup_t *fg; 4419 char *group; 4420 4421 ptr = NULL; 4422 fg = NULL; 4423 fp = &frd; 4424 if (makecopy != 0) { 4425 bzero(fp, sizeof(frd)); 4426 error = ipf_inobj(softc, data, NULL, fp, IPFOBJ_FRENTRY); 4427 if (error) { 4428 return error; 4429 } 4430 if ((fp->fr_type & FR_T_BUILTIN) != 0) { 4431 IPFERROR(6); 4432 return EINVAL; 4433 } 4434 KMALLOCS(f, frentry_t *, fp->fr_size); 4435 if (f == NULL) { 4436 IPFERROR(131); 4437 return ENOMEM; 4438 } 4439 bzero(f, fp->fr_size); 4440 error = ipf_inobjsz(softc, data, f, IPFOBJ_FRENTRY, 4441 fp->fr_size); 4442 if (error) { 4443 KFREES(f, fp->fr_size); 4444 return error; 4445 } 4446 4447 fp = f; 4448 f = NULL; 4449 fp->fr_next = NULL; 4450 fp->fr_dnext = NULL; 4451 fp->fr_pnext = NULL; 4452 fp->fr_pdnext = NULL; 4453 fp->fr_grp = NULL; 4454 fp->fr_grphead = NULL; 4455 fp->fr_icmpgrp = NULL; 4456 fp->fr_isc = (void *)-1; 4457 fp->fr_ptr = NULL; 4458 fp->fr_ref = 0; 4459 fp->fr_flags |= FR_COPIED; 4460 } else { 4461 fp = (frentry_t *)data; 4462 if ((fp->fr_type & FR_T_BUILTIN) == 0) { 4463 IPFERROR(7); 4464 return EINVAL; 4465 } 4466 fp->fr_flags &= ~FR_COPIED; 4467 } 4468 4469 if (((fp->fr_dsize == 0) && (fp->fr_data != NULL)) || 4470 ((fp->fr_dsize != 0) && (fp->fr_data == NULL))) { 4471 IPFERROR(8); 4472 error = EINVAL; 4473 goto donenolock; 4474 } 4475 4476 family = fp->fr_family; 4477 uptr = fp->fr_data; 4478 4479 if (req == (ioctlcmd_t)SIOCINAFR || req == (ioctlcmd_t)SIOCINIFR || 4480 req == (ioctlcmd_t)SIOCADAFR || req == (ioctlcmd_t)SIOCADIFR) 4481 addrem = 0; 4482 else if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR) 4483 addrem = 1; 4484 else if (req == (ioctlcmd_t)SIOCZRLST) 4485 addrem = 2; 4486 else { 4487 IPFERROR(9); 4488 error = EINVAL; 4489 goto donenolock; 4490 } 4491 4492 /* 4493 * Only filter rules for IPv4 or IPv6 are accepted. 4494 */ 4495 if (family == AF_INET) { 4496 /*EMPTY*/; 4497 #ifdef USE_INET6 4498 } else if (family == AF_INET6) { 4499 /*EMPTY*/; 4500 #endif 4501 } else if (family != 0) { 4502 IPFERROR(10); 4503 error = EINVAL; 4504 goto donenolock; 4505 } 4506 4507 /* 4508 * If the rule is being loaded from user space, i.e. we had to copy it 4509 * into kernel space, then do not trust the function pointer in the 4510 * rule. 4511 */ 4512 if ((makecopy == 1) && (fp->fr_func != NULL)) { 4513 if (ipf_findfunc(fp->fr_func) == NULL) { 4514 IPFERROR(11); 4515 error = ESRCH; 4516 goto donenolock; 4517 } 4518 4519 if (addrem == 0) { 4520 error = ipf_funcinit(softc, fp); 4521 if (error != 0) 4522 goto donenolock; 4523 } 4524 } 4525 if ((fp->fr_flags & FR_CALLNOW) && 4526 ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) { 4527 IPFERROR(142); 4528 error = ESRCH; 4529 goto donenolock; 4530 } 4531 if (((fp->fr_flags & FR_CMDMASK) == FR_CALL) && 4532 ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) { 4533 IPFERROR(143); 4534 error = ESRCH; 4535 goto donenolock; 4536 } 4537 4538 ptr = NULL; 4539 4540 if (FR_ISACCOUNT(fp->fr_flags)) 4541 unit = IPL_LOGCOUNT; 4542 4543 /* 4544 * Check that each group name in the rule has a start index that 4545 * is valid. 4546 */ 4547 if (fp->fr_icmphead != -1) { 4548 if ((fp->fr_icmphead < 0) || 4549 (fp->fr_icmphead >= fp->fr_namelen)) { 4550 IPFERROR(136); 4551 error = EINVAL; 4552 goto donenolock; 4553 } 4554 if (!strcmp(FR_NAME(fp, fr_icmphead), "0")) 4555 fp->fr_names[fp->fr_icmphead] = '\0'; 4556 } 4557 4558 if (fp->fr_grhead != -1) { 4559 if ((fp->fr_grhead < 0) || 4560 (fp->fr_grhead >= fp->fr_namelen)) { 4561 IPFERROR(137); 4562 error = EINVAL; 4563 goto donenolock; 4564 } 4565 if (!strcmp(FR_NAME(fp, fr_grhead), "0")) 4566 fp->fr_names[fp->fr_grhead] = '\0'; 4567 } 4568 4569 if (fp->fr_group != -1) { 4570 if ((fp->fr_group < 0) || 4571 (fp->fr_group >= fp->fr_namelen)) { 4572 IPFERROR(138); 4573 error = EINVAL; 4574 goto donenolock; 4575 } 4576 if ((req != (int)SIOCZRLST) && (fp->fr_group != -1)) { 4577 /* 4578 * Allow loading rules that are in groups to cause 4579 * them to be created if they don't already exit. 4580 */ 4581 group = FR_NAME(fp, fr_group); 4582 if (addrem == 0) { 4583 fg = ipf_group_add(softc, group, NULL, 4584 fp->fr_flags, unit, set); 4585 if (fg == NULL) { 4586 IPFERROR(152); 4587 error = ESRCH; 4588 goto donenolock; 4589 } 4590 fp->fr_grp = fg; 4591 } else { 4592 fg = ipf_findgroup(softc, group, unit, 4593 set, NULL); 4594 if (fg == NULL) { 4595 IPFERROR(12); 4596 error = ESRCH; 4597 goto donenolock; 4598 } 4599 } 4600 4601 if (fg->fg_flags == 0) { 4602 fg->fg_flags = fp->fr_flags & FR_INOUT; 4603 } else if (fg->fg_flags != (fp->fr_flags & FR_INOUT)) { 4604 IPFERROR(13); 4605 error = ESRCH; 4606 goto donenolock; 4607 } 4608 } 4609 } else { 4610 /* 4611 * If a rule is going to be part of a group then it does 4612 * not matter whether it is an in or out rule, but if it 4613 * isn't in a group, then it does... 4614 */ 4615 if ((fp->fr_flags & (FR_INQUE|FR_OUTQUE)) == 0) { 4616 IPFERROR(14); 4617 error = EINVAL; 4618 goto donenolock; 4619 } 4620 } 4621 in = (fp->fr_flags & FR_INQUE) ? 0 : 1; 4622 4623 /* 4624 * Work out which rule list this change is being applied to. 4625 */ 4626 ftail = NULL; 4627 fprev = NULL; 4628 if (unit == IPL_LOGAUTH) { 4629 if ((fp->fr_tifs[0].fd_ptr != NULL) || 4630 (fp->fr_tifs[1].fd_ptr != NULL) || 4631 (fp->fr_dif.fd_ptr != NULL) || 4632 (fp->fr_flags & FR_FASTROUTE)) { 4633 IPFERROR(145); 4634 error = EINVAL; 4635 goto donenolock; 4636 } 4637 fprev = ipf_auth_rulehead(softc); 4638 } else { 4639 if (FR_ISACCOUNT(fp->fr_flags)) 4640 fprev = &softc->ipf_acct[in][set]; 4641 else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0) 4642 fprev = &softc->ipf_rules[in][set]; 4643 } 4644 if (fprev == NULL) { 4645 IPFERROR(15); 4646 error = ESRCH; 4647 goto donenolock; 4648 } 4649 4650 if (fg != NULL) 4651 fprev = &fg->fg_start; 4652 4653 /* 4654 * Copy in extra data for the rule. 4655 */ 4656 if (fp->fr_dsize != 0) { 4657 if (makecopy != 0) { 4658 KMALLOCS(ptr, void *, fp->fr_dsize); 4659 if (ptr == NULL) { 4660 IPFERROR(16); 4661 error = ENOMEM; 4662 goto donenolock; 4663 } 4664 4665 /* 4666 * The bcopy case is for when the data is appended 4667 * to the rule by ipf_in_compat(). 4668 */ 4669 if (uptr >= (void *)fp && 4670 uptr < (void *)((char *)fp + fp->fr_size)) { 4671 bcopy(uptr, ptr, fp->fr_dsize); 4672 error = 0; 4673 } else { 4674 error = COPYIN(uptr, ptr, fp->fr_dsize); 4675 if (error != 0) { 4676 IPFERROR(17); 4677 error = EFAULT; 4678 goto donenolock; 4679 } 4680 } 4681 } else { 4682 ptr = uptr; 4683 } 4684 fp->fr_data = ptr; 4685 } else { 4686 fp->fr_data = NULL; 4687 } 4688 4689 /* 4690 * Perform per-rule type sanity checks of their members. 4691 * All code after this needs to be aware that allocated memory 4692 * may need to be free'd before exiting. 4693 */ 4694 switch (fp->fr_type & ~FR_T_BUILTIN) 4695 { 4696 #if defined(IPFILTER_BPF) 4697 case FR_T_BPFOPC : 4698 if (fp->fr_dsize == 0) { 4699 IPFERROR(19); 4700 error = EINVAL; 4701 break; 4702 } 4703 if (!bpf_validate(ptr, fp->fr_dsize/sizeof(struct bpf_insn))) { 4704 IPFERROR(20); 4705 error = EINVAL; 4706 break; 4707 } 4708 break; 4709 #endif 4710 case FR_T_IPF : 4711 /* 4712 * Preparation for error case at the bottom of this function. 4713 */ 4714 if (fp->fr_datype == FRI_LOOKUP) 4715 fp->fr_dstptr = NULL; 4716 if (fp->fr_satype == FRI_LOOKUP) 4717 fp->fr_srcptr = NULL; 4718 4719 if (fp->fr_dsize != sizeof(fripf_t)) { 4720 IPFERROR(21); 4721 error = EINVAL; 4722 break; 4723 } 4724 4725 /* 4726 * Allowing a rule with both "keep state" and "with oow" is 4727 * pointless because adding a state entry to the table will 4728 * fail with the out of window (oow) flag set. 4729 */ 4730 if ((fp->fr_flags & FR_KEEPSTATE) && (fp->fr_flx & FI_OOW)) { 4731 IPFERROR(22); 4732 error = EINVAL; 4733 break; 4734 } 4735 4736 switch (fp->fr_satype) 4737 { 4738 case FRI_BROADCAST : 4739 case FRI_DYNAMIC : 4740 case FRI_NETWORK : 4741 case FRI_NETMASKED : 4742 case FRI_PEERADDR : 4743 if (fp->fr_sifpidx < 0) { 4744 IPFERROR(23); 4745 error = EINVAL; 4746 } 4747 break; 4748 case FRI_LOOKUP : 4749 fp->fr_srcptr = ipf_findlookup(softc, unit, fp, 4750 &fp->fr_src6, 4751 &fp->fr_smsk6); 4752 if (fp->fr_srcfunc == NULL) { 4753 IPFERROR(132); 4754 error = ESRCH; 4755 break; 4756 } 4757 break; 4758 case FRI_NORMAL : 4759 break; 4760 default : 4761 IPFERROR(133); 4762 error = EINVAL; 4763 break; 4764 } 4765 if (error != 0) 4766 break; 4767 4768 switch (fp->fr_datype) 4769 { 4770 case FRI_BROADCAST : 4771 case FRI_DYNAMIC : 4772 case FRI_NETWORK : 4773 case FRI_NETMASKED : 4774 case FRI_PEERADDR : 4775 if (fp->fr_difpidx < 0) { 4776 IPFERROR(24); 4777 error = EINVAL; 4778 } 4779 break; 4780 case FRI_LOOKUP : 4781 fp->fr_dstptr = ipf_findlookup(softc, unit, fp, 4782 &fp->fr_dst6, 4783 &fp->fr_dmsk6); 4784 if (fp->fr_dstfunc == NULL) { 4785 IPFERROR(134); 4786 error = ESRCH; 4787 } 4788 break; 4789 case FRI_NORMAL : 4790 break; 4791 default : 4792 IPFERROR(135); 4793 error = EINVAL; 4794 } 4795 break; 4796 4797 case FR_T_NONE : 4798 case FR_T_CALLFUNC : 4799 case FR_T_COMPIPF : 4800 break; 4801 4802 case FR_T_IPFEXPR : 4803 if (ipf_matcharray_verify(fp->fr_data, fp->fr_dsize) == -1) { 4804 IPFERROR(25); 4805 error = EINVAL; 4806 } 4807 break; 4808 4809 default : 4810 IPFERROR(26); 4811 error = EINVAL; 4812 break; 4813 } 4814 if (error != 0) 4815 goto donenolock; 4816 4817 if (fp->fr_tif.fd_name != -1) { 4818 if ((fp->fr_tif.fd_name < 0) || 4819 (fp->fr_tif.fd_name >= fp->fr_namelen)) { 4820 IPFERROR(139); 4821 error = EINVAL; 4822 goto donenolock; 4823 } 4824 } 4825 4826 if (fp->fr_dif.fd_name != -1) { 4827 if ((fp->fr_dif.fd_name < 0) || 4828 (fp->fr_dif.fd_name >= fp->fr_namelen)) { 4829 IPFERROR(140); 4830 error = EINVAL; 4831 goto donenolock; 4832 } 4833 } 4834 4835 if (fp->fr_rif.fd_name != -1) { 4836 if ((fp->fr_rif.fd_name < 0) || 4837 (fp->fr_rif.fd_name >= fp->fr_namelen)) { 4838 IPFERROR(141); 4839 error = EINVAL; 4840 goto donenolock; 4841 } 4842 } 4843 4844 /* 4845 * Lookup all the interface names that are part of the rule. 4846 */ 4847 error = ipf_synclist(softc, fp, NULL); 4848 if (error != 0) 4849 goto donenolock; 4850 fp->fr_statecnt = 0; 4851 if (fp->fr_srctrack.ht_max_nodes != 0) 4852 ipf_rb_ht_init(&fp->fr_srctrack); 4853 4854 /* 4855 * Look for an existing matching filter rule, but don't include the 4856 * next or interface pointer in the comparison (fr_next, fr_ifa). 4857 * This elminates rules which are indentical being loaded. Checksum 4858 * the constant part of the filter rule to make comparisons quicker 4859 * (this meaning no pointers are included). 4860 */ 4861 for (fp->fr_cksum = 0, p = (u_int *)&fp->fr_func, pp = &fp->fr_cksum; 4862 p < pp; p++) 4863 fp->fr_cksum += *p; 4864 pp = (u_int *)((char *)fp->fr_caddr + fp->fr_dsize); 4865 for (p = (u_int *)fp->fr_data; p < pp; p++) 4866 fp->fr_cksum += *p; 4867 4868 WRITE_ENTER(&softc->ipf_mutex); 4869 4870 /* 4871 * Now that the filter rule lists are locked, we can walk the 4872 * chain of them without fear. 4873 */ 4874 ftail = fprev; 4875 for (f = *ftail; (f = *ftail) != NULL; ftail = &f->fr_next) { 4876 if (fp->fr_collect <= f->fr_collect) { 4877 ftail = fprev; 4878 f = NULL; 4879 break; 4880 } 4881 fprev = ftail; 4882 } 4883 4884 for (; (f = *ftail) != NULL; ftail = &f->fr_next) { 4885 DT2(rule_cmp, frentry_t *, fp, frentry_t *, f); 4886 if (ipf_rule_compare(fp, f) == 0) 4887 break; 4888 } 4889 4890 /* 4891 * If zero'ing statistics, copy current to caller and zero. 4892 */ 4893 if (addrem == 2) { 4894 if (f == NULL) { 4895 IPFERROR(27); 4896 error = ESRCH; 4897 } else { 4898 /* 4899 * Copy and reduce lock because of impending copyout. 4900 * Well we should, but if we do then the atomicity of 4901 * this call and the correctness of fr_hits and 4902 * fr_bytes cannot be guaranteed. As it is, this code 4903 * only resets them to 0 if they are successfully 4904 * copied out into user space. 4905 */ 4906 bcopy((char *)f, (char *)fp, f->fr_size); 4907 /* MUTEX_DOWNGRADE(&softc->ipf_mutex); */ 4908 4909 /* 4910 * When we copy this rule back out, set the data 4911 * pointer to be what it was in user space. 4912 */ 4913 fp->fr_data = uptr; 4914 error = ipf_outobj(softc, data, fp, IPFOBJ_FRENTRY); 4915 4916 if (error == 0) { 4917 if ((f->fr_dsize != 0) && (uptr != NULL)) { 4918 error = COPYOUT(f->fr_data, uptr, 4919 f->fr_dsize); 4920 if (error != 0) { 4921 IPFERROR(28); 4922 error = EFAULT; 4923 } 4924 } 4925 if (error == 0) { 4926 f->fr_hits = 0; 4927 f->fr_bytes = 0; 4928 } 4929 } 4930 } 4931 4932 if (makecopy != 0) { 4933 if (ptr != NULL) { 4934 KFREES(ptr, fp->fr_dsize); 4935 } 4936 KFREES(fp, fp->fr_size); 4937 } 4938 RWLOCK_EXIT(&softc->ipf_mutex); 4939 return error; 4940 } 4941 4942 if (!f) { 4943 /* 4944 * At the end of this, ftail must point to the place where the 4945 * new rule is to be saved/inserted/added. 4946 * For SIOCAD*FR, this should be the last rule in the group of 4947 * rules that have equal fr_collect fields. 4948 * For SIOCIN*FR, ... 4949 */ 4950 if (req == (ioctlcmd_t)SIOCADAFR || 4951 req == (ioctlcmd_t)SIOCADIFR) { 4952 4953 for (ftail = fprev; (f = *ftail) != NULL; ) { 4954 if (f->fr_collect > fp->fr_collect) 4955 break; 4956 ftail = &f->fr_next; 4957 fprev = ftail; 4958 } 4959 ftail = fprev; 4960 f = NULL; 4961 ptr = NULL; 4962 } else if (req == (ioctlcmd_t)SIOCINAFR || 4963 req == (ioctlcmd_t)SIOCINIFR) { 4964 while ((f = *fprev) != NULL) { 4965 if (f->fr_collect >= fp->fr_collect) 4966 break; 4967 fprev = &f->fr_next; 4968 } 4969 ftail = fprev; 4970 if (fp->fr_hits != 0) { 4971 while (fp->fr_hits && (f = *ftail)) { 4972 if (f->fr_collect != fp->fr_collect) 4973 break; 4974 fprev = ftail; 4975 ftail = &f->fr_next; 4976 fp->fr_hits--; 4977 } 4978 } 4979 f = NULL; 4980 ptr = NULL; 4981 } 4982 } 4983 4984 /* 4985 * Request to remove a rule. 4986 */ 4987 if (addrem == 1) { 4988 if (!f) { 4989 IPFERROR(29); 4990 error = ESRCH; 4991 } else { 4992 /* 4993 * Do not allow activity from user space to interfere 4994 * with rules not loaded that way. 4995 */ 4996 if ((makecopy == 1) && !(f->fr_flags & FR_COPIED)) { 4997 IPFERROR(30); 4998 error = EPERM; 4999 goto done; 5000 } 5001 5002 /* 5003 * Return EBUSY if the rule is being reference by 5004 * something else (eg state information.) 5005 */ 5006 if (f->fr_ref > 1) { 5007 IPFERROR(31); 5008 error = EBUSY; 5009 goto done; 5010 } 5011 #ifdef IPFILTER_SCAN 5012 if (f->fr_isctag != -1 && 5013 (f->fr_isc != (struct ipscan *)-1)) 5014 ipf_scan_detachfr(f); 5015 #endif 5016 5017 if (unit == IPL_LOGAUTH) { 5018 error = ipf_auth_precmd(softc, req, f, ftail); 5019 goto done; 5020 } 5021 5022 ipf_rule_delete(softc, f, unit, set); 5023 5024 need_free = makecopy; 5025 } 5026 } else { 5027 /* 5028 * Not removing, so we must be adding/inserting a rule. 5029 */ 5030 if (f != NULL) { 5031 IPFERROR(32); 5032 error = EEXIST; 5033 goto done; 5034 } 5035 if (unit == IPL_LOGAUTH) { 5036 error = ipf_auth_precmd(softc, req, fp, ftail); 5037 goto done; 5038 } 5039 5040 MUTEX_NUKE(&fp->fr_lock); 5041 MUTEX_INIT(&fp->fr_lock, "filter rule lock"); 5042 if (fp->fr_die != 0) 5043 ipf_rule_expire_insert(softc, fp, set); 5044 5045 fp->fr_hits = 0; 5046 if (makecopy != 0) 5047 fp->fr_ref = 1; 5048 fp->fr_pnext = ftail; 5049 fp->fr_next = *ftail; 5050 if (fp->fr_next != NULL) 5051 fp->fr_next->fr_pnext = &fp->fr_next; 5052 *ftail = fp; 5053 if (addrem == 0) 5054 ipf_fixskip(ftail, fp, 1); 5055 5056 fp->fr_icmpgrp = NULL; 5057 if (fp->fr_icmphead != -1) { 5058 group = FR_NAME(fp, fr_icmphead); 5059 fg = ipf_group_add(softc, group, fp, 0, unit, set); 5060 fp->fr_icmpgrp = fg; 5061 } 5062 5063 fp->fr_grphead = NULL; 5064 if (fp->fr_grhead != -1) { 5065 group = FR_NAME(fp, fr_grhead); 5066 fg = ipf_group_add(softc, group, fp, fp->fr_flags, 5067 unit, set); 5068 fp->fr_grphead = fg; 5069 } 5070 } 5071 done: 5072 RWLOCK_EXIT(&softc->ipf_mutex); 5073 donenolock: 5074 if (need_free || (error != 0)) { 5075 if ((fp->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) { 5076 if ((fp->fr_satype == FRI_LOOKUP) && 5077 (fp->fr_srcptr != NULL)) 5078 ipf_lookup_deref(softc, fp->fr_srctype, 5079 fp->fr_srcptr); 5080 if ((fp->fr_datype == FRI_LOOKUP) && 5081 (fp->fr_dstptr != NULL)) 5082 ipf_lookup_deref(softc, fp->fr_dsttype, 5083 fp->fr_dstptr); 5084 } 5085 if (fp->fr_grp != NULL) { 5086 WRITE_ENTER(&softc->ipf_mutex); 5087 ipf_group_del(softc, fp->fr_grp, fp); 5088 RWLOCK_EXIT(&softc->ipf_mutex); 5089 } 5090 if ((ptr != NULL) && (makecopy != 0)) { 5091 KFREES(ptr, fp->fr_dsize); 5092 } 5093 KFREES(fp, fp->fr_size); 5094 } 5095 return (error); 5096 } 5097 5098 5099 /* ------------------------------------------------------------------------ */ 5100 /* Function: ipf_rule_delete */ 5101 /* Returns: Nil */ 5102 /* Parameters: softc(I) - pointer to soft context main structure */ 5103 /* f(I) - pointer to the rule being deleted */ 5104 /* ftail(I) - pointer to the pointer to f */ 5105 /* unit(I) - device for which this is for */ 5106 /* set(I) - 1 or 0 (filter set) */ 5107 /* */ 5108 /* This function attempts to do what it can to delete a filter rule: remove */ 5109 /* it from any linked lists and remove any groups it is responsible for. */ 5110 /* But in the end, removing a rule can only drop the reference count - we */ 5111 /* must use that as the guide for whether or not it can be freed. */ 5112 /* ------------------------------------------------------------------------ */ 5113 static void 5114 ipf_rule_delete(ipf_main_softc_t *softc, frentry_t *f, int unit, int set) 5115 { 5116 5117 /* 5118 * If fr_pdnext is set, then the rule is on the expire list, so 5119 * remove it from there. 5120 */ 5121 if (f->fr_pdnext != NULL) { 5122 *f->fr_pdnext = f->fr_dnext; 5123 if (f->fr_dnext != NULL) 5124 f->fr_dnext->fr_pdnext = f->fr_pdnext; 5125 f->fr_pdnext = NULL; 5126 f->fr_dnext = NULL; 5127 } 5128 5129 ipf_fixskip(f->fr_pnext, f, -1); 5130 if (f->fr_pnext != NULL) 5131 *f->fr_pnext = f->fr_next; 5132 if (f->fr_next != NULL) 5133 f->fr_next->fr_pnext = f->fr_pnext; 5134 f->fr_pnext = NULL; 5135 f->fr_next = NULL; 5136 5137 (void) ipf_derefrule(softc, &f); 5138 } 5139 5140 /* ------------------------------------------------------------------------ */ 5141 /* Function: ipf_rule_expire_insert */ 5142 /* Returns: Nil */ 5143 /* Parameters: softc(I) - pointer to soft context main structure */ 5144 /* f(I) - pointer to rule to be added to expire list */ 5145 /* set(I) - 1 or 0 (filter set) */ 5146 /* */ 5147 /* If the new rule has a given expiration time, insert it into the list of */ 5148 /* expiring rules with the ones to be removed first added to the front of */ 5149 /* the list. The insertion is O(n) but it is kept sorted for quick scans at */ 5150 /* expiration interval checks. */ 5151 /* ------------------------------------------------------------------------ */ 5152 static void 5153 ipf_rule_expire_insert(ipf_main_softc_t *softc, frentry_t *f, int set) 5154 { 5155 frentry_t *fr; 5156 5157 /* 5158 */ 5159 5160 f->fr_die = softc->ipf_ticks + IPF_TTLVAL(f->fr_die); 5161 for (fr = softc->ipf_rule_explist[set]; fr != NULL; 5162 fr = fr->fr_dnext) { 5163 if (f->fr_die < fr->fr_die) 5164 break; 5165 if (fr->fr_dnext == NULL) { 5166 /* 5167 * We've got to the last rule and everything 5168 * wanted to be expired before this new node, 5169 * so we have to tack it on the end... 5170 */ 5171 fr->fr_dnext = f; 5172 f->fr_pdnext = &fr->fr_dnext; 5173 fr = NULL; 5174 break; 5175 } 5176 } 5177 5178 if (softc->ipf_rule_explist[set] == NULL) { 5179 softc->ipf_rule_explist[set] = f; 5180 f->fr_pdnext = &softc->ipf_rule_explist[set]; 5181 } else if (fr != NULL) { 5182 f->fr_dnext = fr; 5183 f->fr_pdnext = fr->fr_pdnext; 5184 fr->fr_pdnext = &f->fr_dnext; 5185 } 5186 } 5187 5188 5189 /* ------------------------------------------------------------------------ */ 5190 /* Function: ipf_findlookup */ 5191 /* Returns: NULL = failure, else success */ 5192 /* Parameters: softc(I) - pointer to soft context main structure */ 5193 /* unit(I) - ipf device we want to find match for */ 5194 /* fp(I) - rule for which lookup is for */ 5195 /* addrp(I) - pointer to lookup information in address struct */ 5196 /* maskp(O) - pointer to lookup information for storage */ 5197 /* */ 5198 /* When using pools and hash tables to store addresses for matching in */ 5199 /* rules, it is necessary to resolve both the object referred to by the */ 5200 /* name or address (and return that pointer) and also provide the means by */ 5201 /* which to determine if an address belongs to that object to make the */ 5202 /* packet matching quicker. */ 5203 /* ------------------------------------------------------------------------ */ 5204 static void * 5205 ipf_findlookup(ipf_main_softc_t *softc, int unit, frentry_t *fr, 5206 i6addr_t *addrp, i6addr_t *maskp) 5207 { 5208 void *ptr = NULL; 5209 5210 switch (addrp->iplookupsubtype) 5211 { 5212 case 0 : 5213 ptr = ipf_lookup_res_num(softc, unit, addrp->iplookuptype, 5214 addrp->iplookupnum, 5215 &maskp->iplookupfunc); 5216 break; 5217 case 1 : 5218 if (addrp->iplookupname < 0) 5219 break; 5220 if (addrp->iplookupname >= fr->fr_namelen) 5221 break; 5222 ptr = ipf_lookup_res_name(softc, unit, addrp->iplookuptype, 5223 fr->fr_names + addrp->iplookupname, 5224 &maskp->iplookupfunc); 5225 break; 5226 default : 5227 break; 5228 } 5229 5230 return ptr; 5231 } 5232 5233 5234 /* ------------------------------------------------------------------------ */ 5235 /* Function: ipf_funcinit */ 5236 /* Returns: int - 0 == success, else ESRCH: cannot resolve rule details */ 5237 /* Parameters: softc(I) - pointer to soft context main structure */ 5238 /* fr(I) - pointer to filter rule */ 5239 /* */ 5240 /* If a rule is a call rule, then check if the function it points to needs */ 5241 /* an init function to be called now the rule has been loaded. */ 5242 /* ------------------------------------------------------------------------ */ 5243 static int 5244 ipf_funcinit(ipf_main_softc_t *softc, frentry_t *fr) 5245 { 5246 ipfunc_resolve_t *ft; 5247 int err; 5248 5249 IPFERROR(34); 5250 err = ESRCH; 5251 5252 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5253 if (ft->ipfu_addr == fr->fr_func) { 5254 err = 0; 5255 if (ft->ipfu_init != NULL) 5256 err = (*ft->ipfu_init)(softc, fr); 5257 break; 5258 } 5259 return err; 5260 } 5261 5262 5263 /* ------------------------------------------------------------------------ */ 5264 /* Function: ipf_funcfini */ 5265 /* Returns: Nil */ 5266 /* Parameters: softc(I) - pointer to soft context main structure */ 5267 /* fr(I) - pointer to filter rule */ 5268 /* */ 5269 /* For a given filter rule, call the matching "fini" function if the rule */ 5270 /* is using a known function that would have resulted in the "init" being */ 5271 /* called for ealier. */ 5272 /* ------------------------------------------------------------------------ */ 5273 static void 5274 ipf_funcfini(ipf_main_softc_t *softc, frentry_t *fr) 5275 { 5276 ipfunc_resolve_t *ft; 5277 5278 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5279 if (ft->ipfu_addr == fr->fr_func) { 5280 if (ft->ipfu_fini != NULL) 5281 (void) (*ft->ipfu_fini)(softc, fr); 5282 break; 5283 } 5284 } 5285 5286 5287 /* ------------------------------------------------------------------------ */ 5288 /* Function: ipf_findfunc */ 5289 /* Returns: ipfunc_t - pointer to function if found, else NULL */ 5290 /* Parameters: funcptr(I) - function pointer to lookup */ 5291 /* */ 5292 /* Look for a function in the table of known functions. */ 5293 /* ------------------------------------------------------------------------ */ 5294 static ipfunc_t 5295 ipf_findfunc(ipfunc_t funcptr) 5296 { 5297 ipfunc_resolve_t *ft; 5298 5299 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5300 if (ft->ipfu_addr == funcptr) 5301 return funcptr; 5302 return NULL; 5303 } 5304 5305 5306 /* ------------------------------------------------------------------------ */ 5307 /* Function: ipf_resolvefunc */ 5308 /* Returns: int - 0 == success, else error */ 5309 /* Parameters: data(IO) - ioctl data pointer to ipfunc_resolve_t struct */ 5310 /* */ 5311 /* Copy in a ipfunc_resolve_t structure and then fill in the missing field. */ 5312 /* This will either be the function name (if the pointer is set) or the */ 5313 /* function pointer if the name is set. When found, fill in the other one */ 5314 /* so that the entire, complete, structure can be copied back to user space.*/ 5315 /* ------------------------------------------------------------------------ */ 5316 int 5317 ipf_resolvefunc(ipf_main_softc_t *softc, void *data) 5318 { 5319 ipfunc_resolve_t res, *ft; 5320 int error; 5321 5322 error = BCOPYIN(data, &res, sizeof(res)); 5323 if (error != 0) { 5324 IPFERROR(123); 5325 return EFAULT; 5326 } 5327 5328 if (res.ipfu_addr == NULL && res.ipfu_name[0] != '\0') { 5329 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5330 if (strncmp(res.ipfu_name, ft->ipfu_name, 5331 sizeof(res.ipfu_name)) == 0) { 5332 res.ipfu_addr = ft->ipfu_addr; 5333 res.ipfu_init = ft->ipfu_init; 5334 if (COPYOUT(&res, data, sizeof(res)) != 0) { 5335 IPFERROR(35); 5336 return EFAULT; 5337 } 5338 return 0; 5339 } 5340 } 5341 if (res.ipfu_addr != NULL && res.ipfu_name[0] == '\0') { 5342 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5343 if (ft->ipfu_addr == res.ipfu_addr) { 5344 (void) strncpy(res.ipfu_name, ft->ipfu_name, 5345 sizeof(res.ipfu_name)); 5346 res.ipfu_init = ft->ipfu_init; 5347 if (COPYOUT(&res, data, sizeof(res)) != 0) { 5348 IPFERROR(36); 5349 return EFAULT; 5350 } 5351 return 0; 5352 } 5353 } 5354 IPFERROR(37); 5355 return ESRCH; 5356 } 5357 5358 5359 #if !defined(_KERNEL) || (!defined(__NetBSD__) && !defined(__OpenBSD__) && \ 5360 !defined(__FreeBSD__)) || \ 5361 FREEBSD_LT_REV(501000) || NETBSD_LT_REV(105000000) || \ 5362 OPENBSD_LT_REV(200006) 5363 /* 5364 * From: NetBSD 5365 * ppsratecheck(): packets (or events) per second limitation. 5366 */ 5367 int 5368 ppsratecheck(lasttime, curpps, maxpps) 5369 struct timeval *lasttime; 5370 int *curpps; 5371 int maxpps; /* maximum pps allowed */ 5372 { 5373 struct timeval tv, delta; 5374 int rv; 5375 5376 GETKTIME(&tv); 5377 5378 delta.tv_sec = tv.tv_sec - lasttime->tv_sec; 5379 delta.tv_usec = tv.tv_usec - lasttime->tv_usec; 5380 if (delta.tv_usec < 0) { 5381 delta.tv_sec--; 5382 delta.tv_usec += 1000000; 5383 } 5384 5385 /* 5386 * check for 0,0 is so that the message will be seen at least once. 5387 * if more than one second have passed since the last update of 5388 * lasttime, reset the counter. 5389 * 5390 * we do increment *curpps even in *curpps < maxpps case, as some may 5391 * try to use *curpps for stat purposes as well. 5392 */ 5393 if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) || 5394 delta.tv_sec >= 1) { 5395 *lasttime = tv; 5396 *curpps = 0; 5397 rv = 1; 5398 } else if (maxpps < 0) 5399 rv = 1; 5400 else if (*curpps < maxpps) 5401 rv = 1; 5402 else 5403 rv = 0; 5404 *curpps = *curpps + 1; 5405 5406 return (rv); 5407 } 5408 #endif 5409 5410 5411 /* ------------------------------------------------------------------------ */ 5412 /* Function: ipf_derefrule */ 5413 /* Returns: int - 0 == rule freed up, else rule not freed */ 5414 /* Parameters: fr(I) - pointer to filter rule */ 5415 /* */ 5416 /* Decrement the reference counter to a rule by one. If it reaches zero, */ 5417 /* free it and any associated storage space being used by it. */ 5418 /* ------------------------------------------------------------------------ */ 5419 int 5420 ipf_derefrule(ipf_main_softc_t *softc, frentry_t **frp) 5421 { 5422 frentry_t *fr; 5423 frdest_t *fdp; 5424 5425 fr = *frp; 5426 *frp = NULL; 5427 5428 MUTEX_ENTER(&fr->fr_lock); 5429 fr->fr_ref--; 5430 if (fr->fr_ref == 0) { 5431 MUTEX_EXIT(&fr->fr_lock); 5432 MUTEX_DESTROY(&fr->fr_lock); 5433 5434 ipf_funcfini(softc, fr); 5435 5436 fdp = &fr->fr_tif; 5437 if (fdp->fd_type == FRD_DSTLIST) 5438 ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr); 5439 5440 fdp = &fr->fr_rif; 5441 if (fdp->fd_type == FRD_DSTLIST) 5442 ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr); 5443 5444 fdp = &fr->fr_dif; 5445 if (fdp->fd_type == FRD_DSTLIST) 5446 ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr); 5447 5448 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF && 5449 fr->fr_satype == FRI_LOOKUP) 5450 ipf_lookup_deref(softc, fr->fr_srctype, fr->fr_srcptr); 5451 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF && 5452 fr->fr_datype == FRI_LOOKUP) 5453 ipf_lookup_deref(softc, fr->fr_dsttype, fr->fr_dstptr); 5454 5455 if (fr->fr_grp != NULL) 5456 ipf_group_del(softc, fr->fr_grp, fr); 5457 5458 if (fr->fr_grphead != NULL) 5459 ipf_group_del(softc, fr->fr_grphead, fr); 5460 5461 if (fr->fr_icmpgrp != NULL) 5462 ipf_group_del(softc, fr->fr_icmpgrp, fr); 5463 5464 if ((fr->fr_flags & FR_COPIED) != 0) { 5465 if (fr->fr_dsize) { 5466 KFREES(fr->fr_data, fr->fr_dsize); 5467 } 5468 KFREES(fr, fr->fr_size); 5469 return 0; 5470 } 5471 return 1; 5472 } else { 5473 MUTEX_EXIT(&fr->fr_lock); 5474 } 5475 return -1; 5476 } 5477 5478 5479 /* ------------------------------------------------------------------------ */ 5480 /* Function: ipf_grpmapinit */ 5481 /* Returns: int - 0 == success, else ESRCH because table entry not found*/ 5482 /* Parameters: fr(I) - pointer to rule to find hash table for */ 5483 /* */ 5484 /* Looks for group hash table fr_arg and stores a pointer to it in fr_ptr. */ 5485 /* fr_ptr is later used by ipf_srcgrpmap and ipf_dstgrpmap. */ 5486 /* ------------------------------------------------------------------------ */ 5487 static int 5488 ipf_grpmapinit(ipf_main_softc_t *softc, frentry_t *fr) 5489 { 5490 char name[FR_GROUPLEN]; 5491 iphtable_t *iph; 5492 5493 (void) snprintf(name, sizeof(name), "%d", fr->fr_arg); 5494 iph = ipf_lookup_find_htable(softc, IPL_LOGIPF, name); 5495 if (iph == NULL) { 5496 IPFERROR(38); 5497 return ESRCH; 5498 } 5499 if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT)) { 5500 IPFERROR(39); 5501 return ESRCH; 5502 } 5503 iph->iph_ref++; 5504 fr->fr_ptr = iph; 5505 return 0; 5506 } 5507 5508 5509 /* ------------------------------------------------------------------------ */ 5510 /* Function: ipf_grpmapfini */ 5511 /* Returns: int - 0 == success, else ESRCH because table entry not found*/ 5512 /* Parameters: softc(I) - pointer to soft context main structure */ 5513 /* fr(I) - pointer to rule to release hash table for */ 5514 /* */ 5515 /* For rules that have had ipf_grpmapinit called, ipf_lookup_deref needs to */ 5516 /* be called to undo what ipf_grpmapinit caused to be done. */ 5517 /* ------------------------------------------------------------------------ */ 5518 static int 5519 ipf_grpmapfini(ipf_main_softc_t *softc, frentry_t *fr) 5520 { 5521 iphtable_t *iph; 5522 iph = fr->fr_ptr; 5523 if (iph != NULL) 5524 ipf_lookup_deref(softc, IPLT_HASH, iph); 5525 return 0; 5526 } 5527 5528 5529 /* ------------------------------------------------------------------------ */ 5530 /* Function: ipf_srcgrpmap */ 5531 /* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ 5532 /* Parameters: fin(I) - pointer to packet information */ 5533 /* passp(IO) - pointer to current/new filter decision (unused) */ 5534 /* */ 5535 /* Look for a rule group head in a hash table, using the source address as */ 5536 /* the key, and descend into that group and continue matching rules against */ 5537 /* the packet. */ 5538 /* ------------------------------------------------------------------------ */ 5539 frentry_t * 5540 ipf_srcgrpmap(fr_info_t *fin, u_32_t *passp) 5541 { 5542 frgroup_t *fg; 5543 void *rval; 5544 5545 rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr, 5546 &fin->fin_src); 5547 if (rval == NULL) 5548 return NULL; 5549 5550 fg = rval; 5551 fin->fin_fr = fg->fg_start; 5552 (void) ipf_scanlist(fin, *passp); 5553 return fin->fin_fr; 5554 } 5555 5556 5557 /* ------------------------------------------------------------------------ */ 5558 /* Function: ipf_dstgrpmap */ 5559 /* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ 5560 /* Parameters: fin(I) - pointer to packet information */ 5561 /* passp(IO) - pointer to current/new filter decision (unused) */ 5562 /* */ 5563 /* Look for a rule group head in a hash table, using the destination */ 5564 /* address as the key, and descend into that group and continue matching */ 5565 /* rules against the packet. */ 5566 /* ------------------------------------------------------------------------ */ 5567 frentry_t * 5568 ipf_dstgrpmap(fr_info_t *fin, u_32_t *passp) 5569 { 5570 frgroup_t *fg; 5571 void *rval; 5572 5573 rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr, 5574 &fin->fin_dst); 5575 if (rval == NULL) 5576 return NULL; 5577 5578 fg = rval; 5579 fin->fin_fr = fg->fg_start; 5580 (void) ipf_scanlist(fin, *passp); 5581 return fin->fin_fr; 5582 } 5583 5584 /* 5585 * Queue functions 5586 * =============== 5587 * These functions manage objects on queues for efficient timeouts. There 5588 * are a number of system defined queues as well as user defined timeouts. 5589 * It is expected that a lock is held in the domain in which the queue 5590 * belongs (i.e. either state or NAT) when calling any of these functions 5591 * that prevents ipf_freetimeoutqueue() from being called at the same time 5592 * as any other. 5593 */ 5594 5595 5596 /* ------------------------------------------------------------------------ */ 5597 /* Function: ipf_addtimeoutqueue */ 5598 /* Returns: struct ifqtq * - NULL if malloc fails, else pointer to */ 5599 /* timeout queue with given interval. */ 5600 /* Parameters: parent(I) - pointer to pointer to parent node of this list */ 5601 /* of interface queues. */ 5602 /* seconds(I) - timeout value in seconds for this queue. */ 5603 /* */ 5604 /* This routine first looks for a timeout queue that matches the interval */ 5605 /* being requested. If it finds one, increments the reference counter and */ 5606 /* returns a pointer to it. If none are found, it allocates a new one and */ 5607 /* inserts it at the top of the list. */ 5608 /* */ 5609 /* Locking. */ 5610 /* It is assumed that the caller of this function has an appropriate lock */ 5611 /* held (exclusively) in the domain that encompases 'parent'. */ 5612 /* ------------------------------------------------------------------------ */ 5613 ipftq_t * 5614 ipf_addtimeoutqueue(ipf_main_softc_t *softc, ipftq_t **parent, u_int seconds) 5615 { 5616 ipftq_t *ifq; 5617 u_int period; 5618 5619 period = seconds * IPF_HZ_DIVIDE; 5620 5621 MUTEX_ENTER(&softc->ipf_timeoutlock); 5622 for (ifq = *parent; ifq != NULL; ifq = ifq->ifq_next) { 5623 if (ifq->ifq_ttl == period) { 5624 /* 5625 * Reset the delete flag, if set, so the structure 5626 * gets reused rather than freed and reallocated. 5627 */ 5628 MUTEX_ENTER(&ifq->ifq_lock); 5629 ifq->ifq_flags &= ~IFQF_DELETE; 5630 ifq->ifq_ref++; 5631 MUTEX_EXIT(&ifq->ifq_lock); 5632 MUTEX_EXIT(&softc->ipf_timeoutlock); 5633 5634 return ifq; 5635 } 5636 } 5637 5638 KMALLOC(ifq, ipftq_t *); 5639 if (ifq != NULL) { 5640 MUTEX_NUKE(&ifq->ifq_lock); 5641 IPFTQ_INIT(ifq, period, "ipftq mutex"); 5642 ifq->ifq_next = *parent; 5643 ifq->ifq_pnext = parent; 5644 ifq->ifq_flags = IFQF_USER; 5645 ifq->ifq_ref++; 5646 *parent = ifq; 5647 softc->ipf_userifqs++; 5648 } 5649 MUTEX_EXIT(&softc->ipf_timeoutlock); 5650 return ifq; 5651 } 5652 5653 5654 /* ------------------------------------------------------------------------ */ 5655 /* Function: ipf_deletetimeoutqueue */ 5656 /* Returns: int - new reference count value of the timeout queue */ 5657 /* Parameters: ifq(I) - timeout queue which is losing a reference. */ 5658 /* Locks: ifq->ifq_lock */ 5659 /* */ 5660 /* This routine must be called when we're discarding a pointer to a timeout */ 5661 /* queue object, taking care of the reference counter. */ 5662 /* */ 5663 /* Now that this just sets a DELETE flag, it requires the expire code to */ 5664 /* check the list of user defined timeout queues and call the free function */ 5665 /* below (currently commented out) to stop memory leaking. It is done this */ 5666 /* way because the locking may not be sufficient to safely do a free when */ 5667 /* this function is called. */ 5668 /* ------------------------------------------------------------------------ */ 5669 int 5670 ipf_deletetimeoutqueue(ipftq_t *ifq) 5671 { 5672 5673 ifq->ifq_ref--; 5674 if ((ifq->ifq_ref == 0) && ((ifq->ifq_flags & IFQF_USER) != 0)) { 5675 ifq->ifq_flags |= IFQF_DELETE; 5676 } 5677 5678 return ifq->ifq_ref; 5679 } 5680 5681 5682 /* ------------------------------------------------------------------------ */ 5683 /* Function: ipf_freetimeoutqueue */ 5684 /* Parameters: ifq(I) - timeout queue which is losing a reference. */ 5685 /* Returns: Nil */ 5686 /* */ 5687 /* Locking: */ 5688 /* It is assumed that the caller of this function has an appropriate lock */ 5689 /* held (exclusively) in the domain that encompases the callers "domain". */ 5690 /* The ifq_lock for this structure should not be held. */ 5691 /* */ 5692 /* Remove a user defined timeout queue from the list of queues it is in and */ 5693 /* tidy up after this is done. */ 5694 /* ------------------------------------------------------------------------ */ 5695 void 5696 ipf_freetimeoutqueue(ipf_main_softc_t *softc, ipftq_t *ifq) 5697 { 5698 5699 if (((ifq->ifq_flags & IFQF_DELETE) == 0) || (ifq->ifq_ref != 0) || 5700 ((ifq->ifq_flags & IFQF_USER) == 0)) { 5701 printf("ipf_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n", 5702 (u_long)ifq, ifq->ifq_flags, ifq->ifq_ttl, 5703 ifq->ifq_ref); 5704 return; 5705 } 5706 5707 /* 5708 * Remove from its position in the list. 5709 */ 5710 *ifq->ifq_pnext = ifq->ifq_next; 5711 if (ifq->ifq_next != NULL) 5712 ifq->ifq_next->ifq_pnext = ifq->ifq_pnext; 5713 ifq->ifq_next = NULL; 5714 ifq->ifq_pnext = NULL; 5715 5716 MUTEX_DESTROY(&ifq->ifq_lock); 5717 ATOMIC_DEC(softc->ipf_userifqs); 5718 KFREE(ifq); 5719 } 5720 5721 5722 /* ------------------------------------------------------------------------ */ 5723 /* Function: ipf_deletequeueentry */ 5724 /* Returns: Nil */ 5725 /* Parameters: tqe(I) - timeout queue entry to delete */ 5726 /* */ 5727 /* Remove a tail queue entry from its queue and make it an orphan. */ 5728 /* ipf_deletetimeoutqueue is called to make sure the reference count on the */ 5729 /* queue is correct. We can't, however, call ipf_freetimeoutqueue because */ 5730 /* the correct lock(s) may not be held that would make it safe to do so. */ 5731 /* ------------------------------------------------------------------------ */ 5732 void 5733 ipf_deletequeueentry(ipftqent_t *tqe) 5734 { 5735 ipftq_t *ifq; 5736 5737 ifq = tqe->tqe_ifq; 5738 5739 MUTEX_ENTER(&ifq->ifq_lock); 5740 5741 if (tqe->tqe_pnext != NULL) { 5742 *tqe->tqe_pnext = tqe->tqe_next; 5743 if (tqe->tqe_next != NULL) 5744 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5745 else /* we must be the tail anyway */ 5746 ifq->ifq_tail = tqe->tqe_pnext; 5747 5748 tqe->tqe_pnext = NULL; 5749 tqe->tqe_ifq = NULL; 5750 } 5751 5752 (void) ipf_deletetimeoutqueue(ifq); 5753 ASSERT(ifq->ifq_ref > 0); 5754 5755 MUTEX_EXIT(&ifq->ifq_lock); 5756 } 5757 5758 5759 /* ------------------------------------------------------------------------ */ 5760 /* Function: ipf_queuefront */ 5761 /* Returns: Nil */ 5762 /* Parameters: tqe(I) - pointer to timeout queue entry */ 5763 /* */ 5764 /* Move a queue entry to the front of the queue, if it isn't already there. */ 5765 /* ------------------------------------------------------------------------ */ 5766 void 5767 ipf_queuefront(ipftqent_t *tqe) 5768 { 5769 ipftq_t *ifq; 5770 5771 ifq = tqe->tqe_ifq; 5772 if (ifq == NULL) 5773 return; 5774 5775 MUTEX_ENTER(&ifq->ifq_lock); 5776 if (ifq->ifq_head != tqe) { 5777 *tqe->tqe_pnext = tqe->tqe_next; 5778 if (tqe->tqe_next) 5779 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5780 else 5781 ifq->ifq_tail = tqe->tqe_pnext; 5782 5783 tqe->tqe_next = ifq->ifq_head; 5784 ifq->ifq_head->tqe_pnext = &tqe->tqe_next; 5785 ifq->ifq_head = tqe; 5786 tqe->tqe_pnext = &ifq->ifq_head; 5787 } 5788 MUTEX_EXIT(&ifq->ifq_lock); 5789 } 5790 5791 5792 /* ------------------------------------------------------------------------ */ 5793 /* Function: ipf_queueback */ 5794 /* Returns: Nil */ 5795 /* Parameters: ticks(I) - ipf tick time to use with this call */ 5796 /* tqe(I) - pointer to timeout queue entry */ 5797 /* */ 5798 /* Move a queue entry to the back of the queue, if it isn't already there. */ 5799 /* We use use ticks to calculate the expiration and mark for when we last */ 5800 /* touched the structure. */ 5801 /* ------------------------------------------------------------------------ */ 5802 void 5803 ipf_queueback(u_long ticks, ipftqent_t *tqe) 5804 { 5805 ipftq_t *ifq; 5806 5807 ifq = tqe->tqe_ifq; 5808 if (ifq == NULL) 5809 return; 5810 tqe->tqe_die = ticks + ifq->ifq_ttl; 5811 tqe->tqe_touched = ticks; 5812 5813 MUTEX_ENTER(&ifq->ifq_lock); 5814 if (tqe->tqe_next != NULL) { /* at the end already ? */ 5815 /* 5816 * Remove from list 5817 */ 5818 *tqe->tqe_pnext = tqe->tqe_next; 5819 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5820 5821 /* 5822 * Make it the last entry. 5823 */ 5824 tqe->tqe_next = NULL; 5825 tqe->tqe_pnext = ifq->ifq_tail; 5826 *ifq->ifq_tail = tqe; 5827 ifq->ifq_tail = &tqe->tqe_next; 5828 } 5829 MUTEX_EXIT(&ifq->ifq_lock); 5830 } 5831 5832 5833 /* ------------------------------------------------------------------------ */ 5834 /* Function: ipf_queueappend */ 5835 /* Returns: Nil */ 5836 /* Parameters: ticks(I) - ipf tick time to use with this call */ 5837 /* tqe(I) - pointer to timeout queue entry */ 5838 /* ifq(I) - pointer to timeout queue */ 5839 /* parent(I) - owing object pointer */ 5840 /* */ 5841 /* Add a new item to this queue and put it on the very end. */ 5842 /* We use use ticks to calculate the expiration and mark for when we last */ 5843 /* touched the structure. */ 5844 /* ------------------------------------------------------------------------ */ 5845 void 5846 ipf_queueappend(u_long ticks, ipftqent_t *tqe, ipftq_t *ifq, void *parent) 5847 { 5848 5849 MUTEX_ENTER(&ifq->ifq_lock); 5850 tqe->tqe_parent = parent; 5851 tqe->tqe_pnext = ifq->ifq_tail; 5852 *ifq->ifq_tail = tqe; 5853 ifq->ifq_tail = &tqe->tqe_next; 5854 tqe->tqe_next = NULL; 5855 tqe->tqe_ifq = ifq; 5856 tqe->tqe_die = ticks + ifq->ifq_ttl; 5857 tqe->tqe_touched = ticks; 5858 ifq->ifq_ref++; 5859 MUTEX_EXIT(&ifq->ifq_lock); 5860 } 5861 5862 5863 /* ------------------------------------------------------------------------ */ 5864 /* Function: ipf_movequeue */ 5865 /* Returns: Nil */ 5866 /* Parameters: tq(I) - pointer to timeout queue information */ 5867 /* oifp(I) - old timeout queue entry was on */ 5868 /* nifp(I) - new timeout queue to put entry on */ 5869 /* */ 5870 /* Move a queue entry from one timeout queue to another timeout queue. */ 5871 /* If it notices that the current entry is already last and does not need */ 5872 /* to move queue, the return. */ 5873 /* ------------------------------------------------------------------------ */ 5874 void 5875 ipf_movequeue(u_long ticks, ipftqent_t *tqe, ipftq_t *oifq, ipftq_t *nifq) 5876 { 5877 5878 /* 5879 * If the queue hasn't changed and we last touched this entry at the 5880 * same ipf time, then we're not going to achieve anything by either 5881 * changing the ttl or moving it on the queue. 5882 */ 5883 if (oifq == nifq && tqe->tqe_touched == ticks) 5884 return; 5885 5886 /* 5887 * For any of this to be outside the lock, there is a risk that two 5888 * packets entering simultaneously, with one changing to a different 5889 * queue and one not, could end up with things in a bizarre state. 5890 */ 5891 MUTEX_ENTER(&oifq->ifq_lock); 5892 5893 tqe->tqe_touched = ticks; 5894 tqe->tqe_die = ticks + nifq->ifq_ttl; 5895 /* 5896 * Is the operation here going to be a no-op ? 5897 */ 5898 if (oifq == nifq) { 5899 if ((tqe->tqe_next == NULL) || 5900 (tqe->tqe_next->tqe_die == tqe->tqe_die)) { 5901 MUTEX_EXIT(&oifq->ifq_lock); 5902 return; 5903 } 5904 } 5905 5906 /* 5907 * Remove from the old queue 5908 */ 5909 *tqe->tqe_pnext = tqe->tqe_next; 5910 if (tqe->tqe_next) 5911 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5912 else 5913 oifq->ifq_tail = tqe->tqe_pnext; 5914 tqe->tqe_next = NULL; 5915 5916 /* 5917 * If we're moving from one queue to another, release the 5918 * lock on the old queue and get a lock on the new queue. 5919 * For user defined queues, if we're moving off it, call 5920 * delete in case it can now be freed. 5921 */ 5922 if (oifq != nifq) { 5923 tqe->tqe_ifq = NULL; 5924 5925 (void) ipf_deletetimeoutqueue(oifq); 5926 5927 MUTEX_EXIT(&oifq->ifq_lock); 5928 5929 MUTEX_ENTER(&nifq->ifq_lock); 5930 5931 tqe->tqe_ifq = nifq; 5932 nifq->ifq_ref++; 5933 } 5934 5935 /* 5936 * Add to the bottom of the new queue 5937 */ 5938 tqe->tqe_pnext = nifq->ifq_tail; 5939 *nifq->ifq_tail = tqe; 5940 nifq->ifq_tail = &tqe->tqe_next; 5941 MUTEX_EXIT(&nifq->ifq_lock); 5942 } 5943 5944 5945 /* ------------------------------------------------------------------------ */ 5946 /* Function: ipf_updateipid */ 5947 /* Returns: int - 0 == success, -1 == error (packet should be dropped) */ 5948 /* Parameters: fin(I) - pointer to packet information */ 5949 /* */ 5950 /* When we are doing NAT, change the IP of every packet to represent a */ 5951 /* single sequence of packets coming from the host, hiding any host */ 5952 /* specific sequencing that might otherwise be revealed. If the packet is */ 5953 /* a fragment, then store the 'new' IPid in the fragment cache and look up */ 5954 /* the fragment cache for non-leading fragments. If a non-leading fragment */ 5955 /* has no match in the cache, return an error. */ 5956 /* ------------------------------------------------------------------------ */ 5957 static int 5958 ipf_updateipid(fr_info_t *fin) 5959 { 5960 u_short id, ido, sums; 5961 u_32_t sumd, sum; 5962 ip_t *ip; 5963 5964 if (fin->fin_off != 0) { 5965 sum = ipf_frag_ipidknown(fin); 5966 if (sum == 0xffffffff) 5967 return -1; 5968 sum &= 0xffff; 5969 id = (u_short)sum; 5970 } else { 5971 id = ipf_nextipid(fin); 5972 if (fin->fin_off == 0 && (fin->fin_flx & FI_FRAG) != 0) 5973 (void) ipf_frag_ipidnew(fin, (u_32_t)id); 5974 } 5975 5976 ip = fin->fin_ip; 5977 ido = ntohs(ip->ip_id); 5978 if (id == ido) 5979 return 0; 5980 ip->ip_id = htons(id); 5981 CALC_SUMD(ido, id, sumd); /* DESTRUCTIVE MACRO! id,ido change */ 5982 sum = (~ntohs(ip->ip_sum)) & 0xffff; 5983 sum += sumd; 5984 sum = (sum >> 16) + (sum & 0xffff); 5985 sum = (sum >> 16) + (sum & 0xffff); 5986 sums = ~(u_short)sum; 5987 ip->ip_sum = htons(sums); 5988 return 0; 5989 } 5990 5991 5992 #ifdef NEED_FRGETIFNAME 5993 /* ------------------------------------------------------------------------ */ 5994 /* Function: ipf_getifname */ 5995 /* Returns: char * - pointer to interface name */ 5996 /* Parameters: ifp(I) - pointer to network interface */ 5997 /* buffer(O) - pointer to where to store interface name */ 5998 /* */ 5999 /* Constructs an interface name in the buffer passed. The buffer passed is */ 6000 /* expected to be at least LIFNAMSIZ in bytes big. If buffer is passed in */ 6001 /* as a NULL pointer then return a pointer to a static array. */ 6002 /* ------------------------------------------------------------------------ */ 6003 char * 6004 ipf_getifname(ifp, buffer) 6005 struct ifnet *ifp; 6006 char *buffer; 6007 { 6008 static char namebuf[LIFNAMSIZ]; 6009 # if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \ 6010 defined(__sgi) || defined(linux) || defined(_AIX51) || \ 6011 (defined(sun) && !defined(__SVR4) && !defined(__svr4__)) 6012 int unit, space; 6013 char temp[20]; 6014 char *s; 6015 # endif 6016 6017 if (buffer == NULL) 6018 buffer = namebuf; 6019 (void) strncpy(buffer, ifp->if_name, LIFNAMSIZ); 6020 buffer[LIFNAMSIZ - 1] = '\0'; 6021 # if defined(MENTAT) || defined(__FreeBSD__) || defined(__osf__) || \ 6022 defined(__sgi) || defined(_AIX51) || \ 6023 (defined(sun) && !defined(__SVR4) && !defined(__svr4__)) 6024 for (s = buffer; *s; s++) 6025 ; 6026 unit = ifp->if_unit; 6027 space = LIFNAMSIZ - (s - buffer); 6028 if ((space > 0) && (unit >= 0)) { 6029 snprintf(temp, sizeof(temp), "%d", unit); 6030 (void) strncpy(s, temp, space); 6031 s[space - 1] = '\0'; 6032 } 6033 # endif 6034 return buffer; 6035 } 6036 #endif 6037 6038 6039 /* ------------------------------------------------------------------------ */ 6040 /* Function: ipf_ioctlswitch */ 6041 /* Returns: int - -1 continue processing, else ioctl return value */ 6042 /* Parameters: unit(I) - device unit opened */ 6043 /* data(I) - pointer to ioctl data */ 6044 /* cmd(I) - ioctl command */ 6045 /* mode(I) - mode value */ 6046 /* uid(I) - uid making the ioctl call */ 6047 /* ctx(I) - pointer to context data */ 6048 /* */ 6049 /* Based on the value of unit, call the appropriate ioctl handler or return */ 6050 /* EIO if ipfilter is not running. Also checks if write perms are req'd */ 6051 /* for the device in order to execute the ioctl. A special case is made */ 6052 /* SIOCIPFINTERROR so that the same code isn't required in every handler. */ 6053 /* The context data pointer is passed through as this is used as the key */ 6054 /* for locating a matching token for continued access for walking lists, */ 6055 /* etc. */ 6056 /* ------------------------------------------------------------------------ */ 6057 int 6058 ipf_ioctlswitch(ipf_main_softc_t *softc, int unit, void *data, ioctlcmd_t cmd, 6059 int mode, int uid, void *ctx) 6060 { 6061 int error = 0; 6062 6063 switch (cmd) 6064 { 6065 case SIOCIPFINTERROR : 6066 error = BCOPYOUT(&softc->ipf_interror, data, 6067 sizeof(softc->ipf_interror)); 6068 if (error != 0) { 6069 IPFERROR(40); 6070 error = EFAULT; 6071 } 6072 return error; 6073 default : 6074 break; 6075 } 6076 6077 switch (unit) 6078 { 6079 case IPL_LOGIPF : 6080 error = ipf_ipf_ioctl(softc, data, cmd, mode, uid, ctx); 6081 break; 6082 case IPL_LOGNAT : 6083 if (softc->ipf_running > 0) { 6084 error = ipf_nat_ioctl(softc, data, cmd, mode, 6085 uid, ctx); 6086 } else { 6087 IPFERROR(42); 6088 error = EIO; 6089 } 6090 break; 6091 case IPL_LOGSTATE : 6092 if (softc->ipf_running > 0) { 6093 error = ipf_state_ioctl(softc, data, cmd, mode, 6094 uid, ctx); 6095 } else { 6096 IPFERROR(43); 6097 error = EIO; 6098 } 6099 break; 6100 case IPL_LOGAUTH : 6101 if (softc->ipf_running > 0) { 6102 error = ipf_auth_ioctl(softc, data, cmd, mode, 6103 uid, ctx); 6104 } else { 6105 IPFERROR(44); 6106 error = EIO; 6107 } 6108 break; 6109 case IPL_LOGSYNC : 6110 if (softc->ipf_running > 0) { 6111 error = ipf_sync_ioctl(softc, data, cmd, mode, 6112 uid, ctx); 6113 } else { 6114 error = EIO; 6115 IPFERROR(45); 6116 } 6117 break; 6118 case IPL_LOGSCAN : 6119 #ifdef IPFILTER_SCAN 6120 if (softc->ipf_running > 0) 6121 error = ipf_scan_ioctl(softc, data, cmd, mode, 6122 uid, ctx); 6123 else 6124 #endif 6125 { 6126 error = EIO; 6127 IPFERROR(46); 6128 } 6129 break; 6130 case IPL_LOGLOOKUP : 6131 if (softc->ipf_running > 0) { 6132 error = ipf_lookup_ioctl(softc, data, cmd, mode, 6133 uid, ctx); 6134 } else { 6135 error = EIO; 6136 IPFERROR(47); 6137 } 6138 break; 6139 default : 6140 IPFERROR(48); 6141 error = EIO; 6142 break; 6143 } 6144 6145 return error; 6146 } 6147 6148 6149 /* 6150 * This array defines the expected size of objects coming into the kernel 6151 * for the various recognised object types. The first column is flags (see 6152 * below), 2nd column is current size, 3rd column is the version number of 6153 * when the current size became current. 6154 * Flags: 6155 * 1 = minimum size, not absolute size 6156 */ 6157 static int ipf_objbytes[IPFOBJ_COUNT][3] = { 6158 { 1, sizeof(struct frentry), 5010000 }, /* 0 */ 6159 { 1, sizeof(struct friostat), 5010000 }, 6160 { 0, sizeof(struct fr_info), 5010000 }, 6161 { 0, sizeof(struct ipf_authstat), 4010100 }, 6162 { 0, sizeof(struct ipfrstat), 5010000 }, 6163 { 1, sizeof(struct ipnat), 5010000 }, /* 5 */ 6164 { 0, sizeof(struct natstat), 5010000 }, 6165 { 0, sizeof(struct ipstate_save), 5010000 }, 6166 { 1, sizeof(struct nat_save), 5010000 }, 6167 { 0, sizeof(struct natlookup), 5010000 }, 6168 { 1, sizeof(struct ipstate), 5010000 }, /* 10 */ 6169 { 0, sizeof(struct ips_stat), 5010000 }, 6170 { 0, sizeof(struct frauth), 5010000 }, 6171 { 0, sizeof(struct ipftune), 4010100 }, 6172 { 0, sizeof(struct nat), 5010000 }, 6173 { 0, sizeof(struct ipfruleiter), 4011400 }, /* 15 */ 6174 { 0, sizeof(struct ipfgeniter), 4011400 }, 6175 { 0, sizeof(struct ipftable), 4011400 }, 6176 { 0, sizeof(struct ipflookupiter), 4011400 }, 6177 { 0, sizeof(struct ipftq) * IPF_TCP_NSTATES }, 6178 { 1, 0, 0 }, /* IPFEXPR */ 6179 { 0, 0, 0 }, /* PROXYCTL */ 6180 { 0, sizeof (struct fripf), 5010000 } 6181 }; 6182 6183 6184 /* ------------------------------------------------------------------------ */ 6185 /* Function: ipf_inobj */ 6186 /* Returns: int - 0 = success, else failure */ 6187 /* Parameters: softc(I) - soft context pointerto work with */ 6188 /* data(I) - pointer to ioctl data */ 6189 /* objp(O) - where to store ipfobj structure */ 6190 /* ptr(I) - pointer to data to copy out */ 6191 /* type(I) - type of structure being moved */ 6192 /* */ 6193 /* Copy in the contents of what the ipfobj_t points to. In future, we */ 6194 /* add things to check for version numbers, sizes, etc, to make it backward */ 6195 /* compatible at the ABI for user land. */ 6196 /* If objp is not NULL then we assume that the caller wants to see what is */ 6197 /* in the ipfobj_t structure being copied in. As an example, this can tell */ 6198 /* the caller what version of ipfilter the ioctl program was written to. */ 6199 /* ------------------------------------------------------------------------ */ 6200 int 6201 ipf_inobj(ipf_main_softc_t *softc, void *data, ipfobj_t *objp, void *ptr, 6202 int type) 6203 { 6204 ipfobj_t obj; 6205 int error; 6206 int size; 6207 6208 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6209 IPFERROR(49); 6210 return EINVAL; 6211 } 6212 6213 if (objp == NULL) 6214 objp = &obj; 6215 error = BCOPYIN(data, objp, sizeof(*objp)); 6216 if (error != 0) { 6217 IPFERROR(124); 6218 return EFAULT; 6219 } 6220 6221 if (objp->ipfo_type != type) { 6222 IPFERROR(50); 6223 return EINVAL; 6224 } 6225 6226 if (objp->ipfo_rev >= ipf_objbytes[type][2]) { 6227 if ((ipf_objbytes[type][0] & 1) != 0) { 6228 if (objp->ipfo_size < ipf_objbytes[type][1]) { 6229 IPFERROR(51); 6230 return EINVAL; 6231 } 6232 size = ipf_objbytes[type][1]; 6233 } else if (objp->ipfo_size == ipf_objbytes[type][1]) { 6234 size = objp->ipfo_size; 6235 } else { 6236 IPFERROR(52); 6237 return EINVAL; 6238 } 6239 error = COPYIN(objp->ipfo_ptr, ptr, size); 6240 if (error != 0) { 6241 IPFERROR(55); 6242 error = EFAULT; 6243 } 6244 } else { 6245 #ifdef IPFILTER_COMPAT 6246 error = ipf_in_compat(softc, objp, ptr, 0); 6247 #else 6248 IPFERROR(54); 6249 error = EINVAL; 6250 #endif 6251 } 6252 return error; 6253 } 6254 6255 6256 /* ------------------------------------------------------------------------ */ 6257 /* Function: ipf_inobjsz */ 6258 /* Returns: int - 0 = success, else failure */ 6259 /* Parameters: softc(I) - soft context pointerto work with */ 6260 /* data(I) - pointer to ioctl data */ 6261 /* ptr(I) - pointer to store real data in */ 6262 /* type(I) - type of structure being moved */ 6263 /* sz(I) - size of data to copy */ 6264 /* */ 6265 /* As per ipf_inobj, except the size of the object to copy in is passed in */ 6266 /* but it must not be smaller than the size defined for the type and the */ 6267 /* type must allow for varied sized objects. The extra requirement here is */ 6268 /* that sz must match the size of the object being passed in - this is not */ 6269 /* not possible nor required in ipf_inobj(). */ 6270 /* ------------------------------------------------------------------------ */ 6271 int 6272 ipf_inobjsz(ipf_main_softc_t *softc, void *data, void *ptr, int type, int sz) 6273 { 6274 ipfobj_t obj; 6275 int error; 6276 6277 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6278 IPFERROR(56); 6279 return EINVAL; 6280 } 6281 6282 error = BCOPYIN(data, &obj, sizeof(obj)); 6283 if (error != 0) { 6284 IPFERROR(125); 6285 return EFAULT; 6286 } 6287 6288 if (obj.ipfo_type != type) { 6289 IPFERROR(58); 6290 return EINVAL; 6291 } 6292 6293 if (obj.ipfo_rev >= ipf_objbytes[type][2]) { 6294 if (((ipf_objbytes[type][0] & 1) == 0) || 6295 (sz < ipf_objbytes[type][1])) { 6296 IPFERROR(57); 6297 return EINVAL; 6298 } 6299 error = COPYIN(obj.ipfo_ptr, ptr, sz); 6300 if (error != 0) { 6301 IPFERROR(61); 6302 error = EFAULT; 6303 } 6304 } else { 6305 #ifdef IPFILTER_COMPAT 6306 error = ipf_in_compat(softc, &obj, ptr, sz); 6307 #else 6308 IPFERROR(60); 6309 error = EINVAL; 6310 #endif 6311 } 6312 return error; 6313 } 6314 6315 6316 /* ------------------------------------------------------------------------ */ 6317 /* Function: ipf_outobjsz */ 6318 /* Returns: int - 0 = success, else failure */ 6319 /* Parameters: data(I) - pointer to ioctl data */ 6320 /* ptr(I) - pointer to store real data in */ 6321 /* type(I) - type of structure being moved */ 6322 /* sz(I) - size of data to copy */ 6323 /* */ 6324 /* As per ipf_outobj, except the size of the object to copy out is passed in*/ 6325 /* but it must not be smaller than the size defined for the type and the */ 6326 /* type must allow for varied sized objects. The extra requirement here is */ 6327 /* that sz must match the size of the object being passed in - this is not */ 6328 /* not possible nor required in ipf_outobj(). */ 6329 /* ------------------------------------------------------------------------ */ 6330 int 6331 ipf_outobjsz(ipf_main_softc_t *softc, void *data, void *ptr, int type, int sz) 6332 { 6333 ipfobj_t obj; 6334 int error; 6335 6336 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6337 IPFERROR(62); 6338 return EINVAL; 6339 } 6340 6341 error = BCOPYIN(data, &obj, sizeof(obj)); 6342 if (error != 0) { 6343 IPFERROR(127); 6344 return EFAULT; 6345 } 6346 6347 if (obj.ipfo_type != type) { 6348 IPFERROR(63); 6349 return EINVAL; 6350 } 6351 6352 if (obj.ipfo_rev >= ipf_objbytes[type][2]) { 6353 if (((ipf_objbytes[type][0] & 1) == 0) || 6354 (sz < ipf_objbytes[type][1])) { 6355 IPFERROR(146); 6356 return EINVAL; 6357 } 6358 error = COPYOUT(ptr, obj.ipfo_ptr, sz); 6359 if (error != 0) { 6360 IPFERROR(66); 6361 error = EFAULT; 6362 } 6363 } else { 6364 #ifdef IPFILTER_COMPAT 6365 error = ipf_out_compat(softc, &obj, ptr); 6366 #else 6367 IPFERROR(65); 6368 error = EINVAL; 6369 #endif 6370 } 6371 return error; 6372 } 6373 6374 6375 /* ------------------------------------------------------------------------ */ 6376 /* Function: ipf_outobj */ 6377 /* Returns: int - 0 = success, else failure */ 6378 /* Parameters: data(I) - pointer to ioctl data */ 6379 /* ptr(I) - pointer to store real data in */ 6380 /* type(I) - type of structure being moved */ 6381 /* */ 6382 /* Copy out the contents of what ptr is to where ipfobj points to. In */ 6383 /* future, we add things to check for version numbers, sizes, etc, to make */ 6384 /* it backward compatible at the ABI for user land. */ 6385 /* ------------------------------------------------------------------------ */ 6386 int 6387 ipf_outobj(ipf_main_softc_t *softc, void *data, void *ptr, int type) 6388 { 6389 ipfobj_t obj; 6390 int error; 6391 6392 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6393 IPFERROR(67); 6394 return EINVAL; 6395 } 6396 6397 error = BCOPYIN(data, &obj, sizeof(obj)); 6398 if (error != 0) { 6399 IPFERROR(126); 6400 return EFAULT; 6401 } 6402 6403 if (obj.ipfo_type != type) { 6404 IPFERROR(68); 6405 return EINVAL; 6406 } 6407 6408 if (obj.ipfo_rev >= ipf_objbytes[type][2]) { 6409 if ((ipf_objbytes[type][0] & 1) != 0) { 6410 if (obj.ipfo_size < ipf_objbytes[type][1]) { 6411 IPFERROR(69); 6412 return EINVAL; 6413 } 6414 } else if (obj.ipfo_size != ipf_objbytes[type][1]) { 6415 IPFERROR(70); 6416 return EINVAL; 6417 } 6418 6419 error = COPYOUT(ptr, obj.ipfo_ptr, obj.ipfo_size); 6420 if (error != 0) { 6421 IPFERROR(73); 6422 error = EFAULT; 6423 } 6424 } else { 6425 #ifdef IPFILTER_COMPAT 6426 error = ipf_out_compat(softc, &obj, ptr); 6427 #else 6428 IPFERROR(72); 6429 error = EINVAL; 6430 #endif 6431 } 6432 return error; 6433 } 6434 6435 6436 /* ------------------------------------------------------------------------ */ 6437 /* Function: ipf_outobjk */ 6438 /* Returns: int - 0 = success, else failure */ 6439 /* Parameters: obj(I) - pointer to data description structure */ 6440 /* ptr(I) - pointer to kernel data to copy out */ 6441 /* */ 6442 /* In the above functions, the ipfobj_t structure is copied into the kernel,*/ 6443 /* telling ipfilter how to copy out data. In this instance, the ipfobj_t is */ 6444 /* already populated with information and now we just need to use it. */ 6445 /* There is no need for this function to have a "type" parameter as there */ 6446 /* is no point in validating information that comes from the kernel with */ 6447 /* itself. */ 6448 /* ------------------------------------------------------------------------ */ 6449 int 6450 ipf_outobjk(ipf_main_softc_t *softc, ipfobj_t *obj, void *ptr) 6451 { 6452 int type = obj->ipfo_type; 6453 int error; 6454 6455 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6456 IPFERROR(147); 6457 return EINVAL; 6458 } 6459 6460 if (obj->ipfo_rev >= ipf_objbytes[type][2]) { 6461 if ((ipf_objbytes[type][0] & 1) != 0) { 6462 if (obj->ipfo_size < ipf_objbytes[type][1]) { 6463 IPFERROR(148); 6464 return EINVAL; 6465 } 6466 6467 } else if (obj->ipfo_size != ipf_objbytes[type][1]) { 6468 IPFERROR(149); 6469 return EINVAL; 6470 } 6471 6472 error = COPYOUT(ptr, obj->ipfo_ptr, obj->ipfo_size); 6473 if (error != 0) { 6474 IPFERROR(150); 6475 error = EFAULT; 6476 } 6477 } else { 6478 #ifdef IPFILTER_COMPAT 6479 error = ipf_out_compat(softc, obj, ptr); 6480 #else 6481 IPFERROR(151); 6482 error = EINVAL; 6483 #endif 6484 } 6485 return error; 6486 } 6487 6488 6489 /* ------------------------------------------------------------------------ */ 6490 /* Function: ipf_checkl4sum */ 6491 /* Returns: int - 0 = good, -1 = bad, 1 = cannot check */ 6492 /* Parameters: fin(I) - pointer to packet information */ 6493 /* */ 6494 /* If possible, calculate the layer 4 checksum for the packet. If this is */ 6495 /* not possible, return without indicating a failure or success but in a */ 6496 /* way that is ditinguishable. This function should only be called by the */ 6497 /* ipf_checkv6sum() for each platform. */ 6498 /* ------------------------------------------------------------------------ */ 6499 int 6500 ipf_checkl4sum(fr_info_t *fin) 6501 { 6502 u_short sum, hdrsum, *csump; 6503 udphdr_t *udp; 6504 int dosum; 6505 6506 /* 6507 * If the TCP packet isn't a fragment, isn't too short and otherwise 6508 * isn't already considered "bad", then validate the checksum. If 6509 * this check fails then considered the packet to be "bad". 6510 */ 6511 if ((fin->fin_flx & (FI_FRAG|FI_SHORT|FI_BAD)) != 0) 6512 return 1; 6513 6514 csump = NULL; 6515 hdrsum = 0; 6516 dosum = 0; 6517 sum = 0; 6518 6519 switch (fin->fin_p) 6520 { 6521 case IPPROTO_TCP : 6522 csump = &((tcphdr_t *)fin->fin_dp)->th_sum; 6523 dosum = 1; 6524 break; 6525 6526 case IPPROTO_UDP : 6527 udp = fin->fin_dp; 6528 if (udp->uh_sum != 0) { 6529 csump = &udp->uh_sum; 6530 dosum = 1; 6531 } 6532 break; 6533 6534 #ifdef USE_INET6 6535 case IPPROTO_ICMPV6 : 6536 csump = &((struct icmp6_hdr *)fin->fin_dp)->icmp6_cksum; 6537 dosum = 1; 6538 break; 6539 #endif 6540 6541 case IPPROTO_ICMP : 6542 csump = &((struct icmp *)fin->fin_dp)->icmp_cksum; 6543 dosum = 1; 6544 break; 6545 6546 default : 6547 return 1; 6548 /*NOTREACHED*/ 6549 } 6550 6551 if (csump != NULL) { 6552 hdrsum = *csump; 6553 if (fin->fin_p == IPPROTO_UDP && hdrsum == 0xffff) 6554 hdrsum = 0x0000; 6555 } 6556 6557 if (dosum) { 6558 sum = fr_cksum(fin, fin->fin_ip, fin->fin_p, fin->fin_dp); 6559 } 6560 #if !defined(_KERNEL) 6561 if (sum == hdrsum) { 6562 FR_DEBUG(("checkl4sum: %hx == %hx\n", sum, hdrsum)); 6563 } else { 6564 FR_DEBUG(("checkl4sum: %hx != %hx\n", sum, hdrsum)); 6565 } 6566 #endif 6567 DT2(l4sums, u_short, hdrsum, u_short, sum); 6568 if (hdrsum == sum) { 6569 fin->fin_cksum = FI_CK_SUMOK; 6570 return 0; 6571 } 6572 fin->fin_cksum = FI_CK_BAD; 6573 return -1; 6574 } 6575 6576 6577 /* ------------------------------------------------------------------------ */ 6578 /* Function: ipf_ifpfillv4addr */ 6579 /* Returns: int - 0 = address update, -1 = address not updated */ 6580 /* Parameters: atype(I) - type of network address update to perform */ 6581 /* sin(I) - pointer to source of address information */ 6582 /* mask(I) - pointer to source of netmask information */ 6583 /* inp(I) - pointer to destination address store */ 6584 /* inpmask(I) - pointer to destination netmask store */ 6585 /* */ 6586 /* Given a type of network address update (atype) to perform, copy */ 6587 /* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ 6588 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ 6589 /* which case the operation fails. For all values of atype other than */ 6590 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ 6591 /* value. */ 6592 /* ------------------------------------------------------------------------ */ 6593 int 6594 ipf_ifpfillv4addr(int atype, struct sockaddr_in *sin, struct sockaddr_in *mask, 6595 struct in_addr *inp, struct in_addr *inpmask) 6596 { 6597 if (inpmask != NULL && atype != FRI_NETMASKED) 6598 inpmask->s_addr = 0xffffffff; 6599 6600 if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { 6601 if (atype == FRI_NETMASKED) { 6602 if (inpmask == NULL) 6603 return -1; 6604 inpmask->s_addr = mask->sin_addr.s_addr; 6605 } 6606 inp->s_addr = sin->sin_addr.s_addr & mask->sin_addr.s_addr; 6607 } else { 6608 inp->s_addr = sin->sin_addr.s_addr; 6609 } 6610 return 0; 6611 } 6612 6613 6614 #ifdef USE_INET6 6615 /* ------------------------------------------------------------------------ */ 6616 /* Function: ipf_ifpfillv6addr */ 6617 /* Returns: int - 0 = address update, -1 = address not updated */ 6618 /* Parameters: atype(I) - type of network address update to perform */ 6619 /* sin(I) - pointer to source of address information */ 6620 /* mask(I) - pointer to source of netmask information */ 6621 /* inp(I) - pointer to destination address store */ 6622 /* inpmask(I) - pointer to destination netmask store */ 6623 /* */ 6624 /* Given a type of network address update (atype) to perform, copy */ 6625 /* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ 6626 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ 6627 /* which case the operation fails. For all values of atype other than */ 6628 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ 6629 /* value. */ 6630 /* ------------------------------------------------------------------------ */ 6631 int 6632 ipf_ifpfillv6addr(int atype, struct sockaddr_in6 *sin, 6633 struct sockaddr_in6 *mask, i6addr_t *inp, i6addr_t *inpmask) 6634 { 6635 i6addr_t *src, *and; 6636 6637 src = (i6addr_t *)&sin->sin6_addr; 6638 and = (i6addr_t *)&mask->sin6_addr; 6639 6640 if (inpmask != NULL && atype != FRI_NETMASKED) { 6641 inpmask->i6[0] = 0xffffffff; 6642 inpmask->i6[1] = 0xffffffff; 6643 inpmask->i6[2] = 0xffffffff; 6644 inpmask->i6[3] = 0xffffffff; 6645 } 6646 6647 if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { 6648 if (atype == FRI_NETMASKED) { 6649 if (inpmask == NULL) 6650 return -1; 6651 inpmask->i6[0] = and->i6[0]; 6652 inpmask->i6[1] = and->i6[1]; 6653 inpmask->i6[2] = and->i6[2]; 6654 inpmask->i6[3] = and->i6[3]; 6655 } 6656 6657 inp->i6[0] = src->i6[0] & and->i6[0]; 6658 inp->i6[1] = src->i6[1] & and->i6[1]; 6659 inp->i6[2] = src->i6[2] & and->i6[2]; 6660 inp->i6[3] = src->i6[3] & and->i6[3]; 6661 } else { 6662 inp->i6[0] = src->i6[0]; 6663 inp->i6[1] = src->i6[1]; 6664 inp->i6[2] = src->i6[2]; 6665 inp->i6[3] = src->i6[3]; 6666 } 6667 return 0; 6668 } 6669 #endif 6670 6671 6672 /* ------------------------------------------------------------------------ */ 6673 /* Function: ipf_matchtag */ 6674 /* Returns: 0 == mismatch, 1 == match. */ 6675 /* Parameters: tag1(I) - pointer to first tag to compare */ 6676 /* tag2(I) - pointer to second tag to compare */ 6677 /* */ 6678 /* Returns true (non-zero) or false(0) if the two tag structures can be */ 6679 /* considered to be a match or not match, respectively. The tag is 16 */ 6680 /* bytes long (16 characters) but that is overlayed with 4 32bit ints so */ 6681 /* compare the ints instead, for speed. tag1 is the master of the */ 6682 /* comparison. This function should only be called with both tag1 and tag2 */ 6683 /* as non-NULL pointers. */ 6684 /* ------------------------------------------------------------------------ */ 6685 int 6686 ipf_matchtag(ipftag_t *tag1, ipftag_t *tag2) 6687 { 6688 if (tag1 == tag2) 6689 return 1; 6690 6691 if ((tag1->ipt_num[0] == 0) && (tag2->ipt_num[0] == 0)) 6692 return 1; 6693 6694 if ((tag1->ipt_num[0] == tag2->ipt_num[0]) && 6695 (tag1->ipt_num[1] == tag2->ipt_num[1]) && 6696 (tag1->ipt_num[2] == tag2->ipt_num[2]) && 6697 (tag1->ipt_num[3] == tag2->ipt_num[3])) 6698 return 1; 6699 return 0; 6700 } 6701 6702 6703 /* ------------------------------------------------------------------------ */ 6704 /* Function: ipf_coalesce */ 6705 /* Returns: 1 == success, -1 == failure, 0 == no change */ 6706 /* Parameters: fin(I) - pointer to packet information */ 6707 /* */ 6708 /* Attempt to get all of the packet data into a single, contiguous buffer. */ 6709 /* If this call returns a failure then the buffers have also been freed. */ 6710 /* ------------------------------------------------------------------------ */ 6711 int 6712 ipf_coalesce(fr_info_t *fin) 6713 { 6714 6715 if ((fin->fin_flx & FI_COALESCE) != 0) 6716 return 1; 6717 6718 /* 6719 * If the mbuf pointers indicate that there is no mbuf to work with, 6720 * return but do not indicate success or failure. 6721 */ 6722 if (fin->fin_m == NULL || fin->fin_mp == NULL) 6723 return 0; 6724 6725 #if defined(_KERNEL) 6726 if (ipf_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) { 6727 ipf_main_softc_t *softc = fin->fin_main_soft; 6728 6729 DT1(frb_coalesce, fr_info_t *, fin); 6730 LBUMP(ipf_stats[fin->fin_out].fr_badcoalesces); 6731 # ifdef MENTAT 6732 FREE_MB_T(*fin->fin_mp); 6733 # endif 6734 fin->fin_reason = FRB_COALESCE; 6735 *fin->fin_mp = NULL; 6736 fin->fin_m = NULL; 6737 return -1; 6738 } 6739 #else 6740 fin = fin; /* LINT */ 6741 #endif 6742 return 1; 6743 } 6744 6745 6746 /* 6747 * The following table lists all of the tunable variables that can be 6748 * accessed via SIOCIPFGET/SIOCIPFSET/SIOCIPFGETNEXt. The format of each row 6749 * in the table below is as follows: 6750 * 6751 * pointer to value, name of value, minimum, maximum, size of the value's 6752 * container, value attribute flags 6753 * 6754 * For convienience, IPFT_RDONLY means the value is read-only, IPFT_WRDISABLED 6755 * means the value can only be written to when IPFilter is loaded but disabled. 6756 * The obvious implication is if neither of these are set then the value can be 6757 * changed at any time without harm. 6758 */ 6759 6760 6761 /* ------------------------------------------------------------------------ */ 6762 /* Function: ipf_tune_findbycookie */ 6763 /* Returns: NULL = search failed, else pointer to tune struct */ 6764 /* Parameters: cookie(I) - cookie value to search for amongst tuneables */ 6765 /* next(O) - pointer to place to store the cookie for the */ 6766 /* "next" tuneable, if it is desired. */ 6767 /* */ 6768 /* This function is used to walk through all of the existing tunables with */ 6769 /* successive calls. It searches the known tunables for the one which has */ 6770 /* a matching value for "cookie" - ie its address. When returning a match, */ 6771 /* the next one to be found may be returned inside next. */ 6772 /* ------------------------------------------------------------------------ */ 6773 static ipftuneable_t * 6774 ipf_tune_findbycookie(ipftuneable_t **ptop, void *cookie, void **next) 6775 { 6776 ipftuneable_t *ta, **tap; 6777 6778 for (ta = *ptop; ta->ipft_name != NULL; ta++) 6779 if (ta == cookie) { 6780 if (next != NULL) { 6781 /* 6782 * If the next entry in the array has a name 6783 * present, then return a pointer to it for 6784 * where to go next, else return a pointer to 6785 * the dynaminc list as a key to search there 6786 * next. This facilitates a weak linking of 6787 * the two "lists" together. 6788 */ 6789 if ((ta + 1)->ipft_name != NULL) 6790 *next = ta + 1; 6791 else 6792 *next = ptop; 6793 } 6794 return ta; 6795 } 6796 6797 for (tap = ptop; (ta = *tap) != NULL; tap = &ta->ipft_next) 6798 if (tap == cookie) { 6799 if (next != NULL) 6800 *next = &ta->ipft_next; 6801 return ta; 6802 } 6803 6804 if (next != NULL) 6805 *next = NULL; 6806 return NULL; 6807 } 6808 6809 6810 /* ------------------------------------------------------------------------ */ 6811 /* Function: ipf_tune_findbyname */ 6812 /* Returns: NULL = search failed, else pointer to tune struct */ 6813 /* Parameters: name(I) - name of the tuneable entry to find. */ 6814 /* */ 6815 /* Search the static array of tuneables and the list of dynamic tuneables */ 6816 /* for an entry with a matching name. If we can find one, return a pointer */ 6817 /* to the matching structure. */ 6818 /* ------------------------------------------------------------------------ */ 6819 static ipftuneable_t * 6820 ipf_tune_findbyname(ipftuneable_t *top, const char *name) 6821 { 6822 ipftuneable_t *ta; 6823 6824 for (ta = top; ta != NULL; ta = ta->ipft_next) 6825 if (!strcmp(ta->ipft_name, name)) { 6826 return ta; 6827 } 6828 6829 return NULL; 6830 } 6831 6832 6833 /* ------------------------------------------------------------------------ */ 6834 /* Function: ipf_tune_add_array */ 6835 /* Returns: int - 0 == success, else failure */ 6836 /* Parameters: newtune - pointer to new tune array to add to tuneables */ 6837 /* */ 6838 /* Appends tune structures from the array passed in (newtune) to the end of */ 6839 /* the current list of "dynamic" tuneable parameters. */ 6840 /* If any entry to be added is already present (by name) then the operation */ 6841 /* is aborted - entries that have been added are removed before returning. */ 6842 /* An entry with no name (NULL) is used as the indication that the end of */ 6843 /* the array has been reached. */ 6844 /* ------------------------------------------------------------------------ */ 6845 int 6846 ipf_tune_add_array(ipf_main_softc_t *softc, ipftuneable_t *newtune) 6847 { 6848 ipftuneable_t *nt, *dt; 6849 int error = 0; 6850 6851 for (nt = newtune; nt->ipft_name != NULL; nt++) { 6852 error = ipf_tune_add(softc, nt); 6853 if (error != 0) { 6854 for (dt = newtune; dt != nt; dt++) { 6855 (void) ipf_tune_del(softc, dt); 6856 } 6857 } 6858 } 6859 6860 return error; 6861 } 6862 6863 6864 /* ------------------------------------------------------------------------ */ 6865 /* Function: ipf_tune_array_link */ 6866 /* Returns: 0 == success, -1 == failure */ 6867 /* Parameters: softc(I) - soft context pointerto work with */ 6868 /* array(I) - pointer to an array of tuneables */ 6869 /* */ 6870 /* Given an array of tunables (array), append them to the current list of */ 6871 /* tuneables for this context (softc->ipf_tuners.) To properly prepare the */ 6872 /* the array for being appended to the list, initialise all of the next */ 6873 /* pointers so we don't need to walk parts of it with ++ and others with */ 6874 /* next. The array is expected to have an entry with a NULL name as the */ 6875 /* terminator. Trying to add an array with no non-NULL names will return as */ 6876 /* a failure. */ 6877 /* ------------------------------------------------------------------------ */ 6878 int 6879 ipf_tune_array_link(ipf_main_softc_t *softc, ipftuneable_t *array) 6880 { 6881 ipftuneable_t *t, **p; 6882 6883 t = array; 6884 if (t->ipft_name == NULL) 6885 return -1; 6886 6887 for (; t[1].ipft_name != NULL; t++) 6888 t[0].ipft_next = &t[1]; 6889 t->ipft_next = NULL; 6890 6891 /* 6892 * Since a pointer to the last entry isn't kept, we need to find it 6893 * each time we want to add new variables to the list. 6894 */ 6895 for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next) 6896 if (t->ipft_name == NULL) 6897 break; 6898 *p = array; 6899 6900 return 0; 6901 } 6902 6903 6904 /* ------------------------------------------------------------------------ */ 6905 /* Function: ipf_tune_array_unlink */ 6906 /* Returns: 0 == success, -1 == failure */ 6907 /* Parameters: softc(I) - soft context pointerto work with */ 6908 /* array(I) - pointer to an array of tuneables */ 6909 /* */ 6910 /* ------------------------------------------------------------------------ */ 6911 int 6912 ipf_tune_array_unlink(ipf_main_softc_t *softc, ipftuneable_t *array) 6913 { 6914 ipftuneable_t *t, **p; 6915 6916 for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next) 6917 if (t == array) 6918 break; 6919 if (t == NULL) 6920 return -1; 6921 6922 for (; t[1].ipft_name != NULL; t++) 6923 ; 6924 6925 *p = t->ipft_next; 6926 6927 return 0; 6928 } 6929 6930 6931 /* ------------------------------------------------------------------------ */ 6932 /* Function: ipf_tune_array_copy */ 6933 /* Returns: NULL = failure, else pointer to new array */ 6934 /* Parameters: base(I) - pointer to structure base */ 6935 /* size(I) - size of the array at template */ 6936 /* template(I) - original array to copy */ 6937 /* */ 6938 /* Allocate memory for a new set of tuneable values and copy everything */ 6939 /* from template into the new region of memory. The new region is full of */ 6940 /* uninitialised pointers (ipft_next) so set them up. Now, ipftp_offset... */ 6941 /* */ 6942 /* NOTE: the following assumes that sizeof(long) == sizeof(void *) */ 6943 /* In the array template, ipftp_offset is the offset (in bytes) of the */ 6944 /* location of the tuneable value inside the structure pointed to by base. */ 6945 /* As ipftp_offset is a union over the pointers to the tuneable values, if */ 6946 /* we add base to the copy's ipftp_offset, copy ends up with a pointer in */ 6947 /* ipftp_void that points to the stored value. */ 6948 /* ------------------------------------------------------------------------ */ 6949 ipftuneable_t * 6950 ipf_tune_array_copy(void *base, size_t size, const ipftuneable_t *template) 6951 { 6952 ipftuneable_t *copy; 6953 int i; 6954 6955 6956 KMALLOCS(copy, ipftuneable_t *, size); 6957 if (copy == NULL) { 6958 return NULL; 6959 } 6960 bcopy(template, copy, size); 6961 6962 for (i = 0; copy[i].ipft_name; i++) { 6963 copy[i].ipft_una.ipftp_offset += (u_long)base; 6964 copy[i].ipft_next = copy + i + 1; 6965 } 6966 6967 return copy; 6968 } 6969 6970 6971 /* ------------------------------------------------------------------------ */ 6972 /* Function: ipf_tune_add */ 6973 /* Returns: int - 0 == success, else failure */ 6974 /* Parameters: newtune - pointer to new tune entry to add to tuneables */ 6975 /* */ 6976 /* Appends tune structures from the array passed in (newtune) to the end of */ 6977 /* the current list of "dynamic" tuneable parameters. Once added, the */ 6978 /* owner of the object is not expected to ever change "ipft_next". */ 6979 /* ------------------------------------------------------------------------ */ 6980 int 6981 ipf_tune_add(ipf_main_softc_t *softc, ipftuneable_t *newtune) 6982 { 6983 ipftuneable_t *ta, **tap; 6984 6985 ta = ipf_tune_findbyname(softc->ipf_tuners, newtune->ipft_name); 6986 if (ta != NULL) { 6987 IPFERROR(74); 6988 return EEXIST; 6989 } 6990 6991 for (tap = &softc->ipf_tuners; *tap != NULL; tap = &(*tap)->ipft_next) 6992 ; 6993 6994 newtune->ipft_next = NULL; 6995 *tap = newtune; 6996 return 0; 6997 } 6998 6999 7000 /* ------------------------------------------------------------------------ */ 7001 /* Function: ipf_tune_del */ 7002 /* Returns: int - 0 == success, else failure */ 7003 /* Parameters: oldtune - pointer to tune entry to remove from the list of */ 7004 /* current dynamic tuneables */ 7005 /* */ 7006 /* Search for the tune structure, by pointer, in the list of those that are */ 7007 /* dynamically added at run time. If found, adjust the list so that this */ 7008 /* structure is no longer part of it. */ 7009 /* ------------------------------------------------------------------------ */ 7010 int 7011 ipf_tune_del(ipf_main_softc_t *softc, ipftuneable_t *oldtune) 7012 { 7013 ipftuneable_t *ta, **tap; 7014 int error = 0; 7015 7016 for (tap = &softc->ipf_tuners; (ta = *tap) != NULL; 7017 tap = &ta->ipft_next) { 7018 if (ta == oldtune) { 7019 *tap = oldtune->ipft_next; 7020 oldtune->ipft_next = NULL; 7021 break; 7022 } 7023 } 7024 7025 if (ta == NULL) { 7026 error = ESRCH; 7027 IPFERROR(75); 7028 } 7029 return error; 7030 } 7031 7032 7033 /* ------------------------------------------------------------------------ */ 7034 /* Function: ipf_tune_del_array */ 7035 /* Returns: int - 0 == success, else failure */ 7036 /* Parameters: oldtune - pointer to tuneables array */ 7037 /* */ 7038 /* Remove each tuneable entry in the array from the list of "dynamic" */ 7039 /* tunables. If one entry should fail to be found, an error will be */ 7040 /* returned and no further ones removed. */ 7041 /* An entry with a NULL name is used as the indicator of the last entry in */ 7042 /* the array. */ 7043 /* ------------------------------------------------------------------------ */ 7044 int 7045 ipf_tune_del_array(ipf_main_softc_t *softc, ipftuneable_t *oldtune) 7046 { 7047 ipftuneable_t *ot; 7048 int error = 0; 7049 7050 for (ot = oldtune; ot->ipft_name != NULL; ot++) { 7051 error = ipf_tune_del(softc, ot); 7052 if (error != 0) 7053 break; 7054 } 7055 7056 return error; 7057 7058 } 7059 7060 7061 /* ------------------------------------------------------------------------ */ 7062 /* Function: ipf_tune */ 7063 /* Returns: int - 0 == success, else failure */ 7064 /* Parameters: cmd(I) - ioctl command number */ 7065 /* data(I) - pointer to ioctl data structure */ 7066 /* */ 7067 /* Implement handling of SIOCIPFGETNEXT, SIOCIPFGET and SIOCIPFSET. These */ 7068 /* three ioctls provide the means to access and control global variables */ 7069 /* within IPFilter, allowing (for example) timeouts and table sizes to be */ 7070 /* changed without rebooting, reloading or recompiling. The initialisation */ 7071 /* and 'destruction' routines of the various components of ipfilter are all */ 7072 /* each responsible for handling their own values being too big. */ 7073 /* ------------------------------------------------------------------------ */ 7074 int 7075 ipf_ipftune(ipf_main_softc_t *softc, ioctlcmd_t cmd, void *data) 7076 { 7077 ipftuneable_t *ta; 7078 ipftune_t tu; 7079 void *cookie; 7080 int error; 7081 7082 error = ipf_inobj(softc, data, NULL, &tu, IPFOBJ_TUNEABLE); 7083 if (error != 0) 7084 return error; 7085 7086 tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0'; 7087 cookie = tu.ipft_cookie; 7088 ta = NULL; 7089 7090 switch (cmd) 7091 { 7092 case SIOCIPFGETNEXT : 7093 /* 7094 * If cookie is non-NULL, assume it to be a pointer to the last 7095 * entry we looked at, so find it (if possible) and return a 7096 * pointer to the next one after it. The last entry in the 7097 * the table is a NULL entry, so when we get to it, set cookie 7098 * to NULL and return that, indicating end of list, erstwhile 7099 * if we come in with cookie set to NULL, we are starting anew 7100 * at the front of the list. 7101 */ 7102 if (cookie != NULL) { 7103 ta = ipf_tune_findbycookie(&softc->ipf_tuners, 7104 cookie, &tu.ipft_cookie); 7105 } else { 7106 ta = softc->ipf_tuners; 7107 tu.ipft_cookie = ta + 1; 7108 } 7109 if (ta != NULL) { 7110 /* 7111 * Entry found, but does the data pointed to by that 7112 * row fit in what we can return? 7113 */ 7114 if (ta->ipft_sz > sizeof(tu.ipft_un)) { 7115 IPFERROR(76); 7116 return EINVAL; 7117 } 7118 7119 tu.ipft_vlong = 0; 7120 if (ta->ipft_sz == sizeof(u_long)) 7121 tu.ipft_vlong = *ta->ipft_plong; 7122 else if (ta->ipft_sz == sizeof(u_int)) 7123 tu.ipft_vint = *ta->ipft_pint; 7124 else if (ta->ipft_sz == sizeof(u_short)) 7125 tu.ipft_vshort = *ta->ipft_pshort; 7126 else if (ta->ipft_sz == sizeof(u_char)) 7127 tu.ipft_vchar = *ta->ipft_pchar; 7128 7129 tu.ipft_sz = ta->ipft_sz; 7130 tu.ipft_min = ta->ipft_min; 7131 tu.ipft_max = ta->ipft_max; 7132 tu.ipft_flags = ta->ipft_flags; 7133 bcopy(ta->ipft_name, tu.ipft_name, 7134 MIN(sizeof(tu.ipft_name), 7135 strlen(ta->ipft_name) + 1)); 7136 } 7137 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE); 7138 break; 7139 7140 case SIOCIPFGET : 7141 case SIOCIPFSET : 7142 /* 7143 * Search by name or by cookie value for a particular entry 7144 * in the tuning paramter table. 7145 */ 7146 IPFERROR(77); 7147 error = ESRCH; 7148 if (cookie != NULL) { 7149 ta = ipf_tune_findbycookie(&softc->ipf_tuners, 7150 cookie, NULL); 7151 if (ta != NULL) 7152 error = 0; 7153 } else if (tu.ipft_name[0] != '\0') { 7154 ta = ipf_tune_findbyname(softc->ipf_tuners, 7155 tu.ipft_name); 7156 if (ta != NULL) 7157 error = 0; 7158 } 7159 if (error != 0) 7160 break; 7161 7162 if (cmd == (ioctlcmd_t)SIOCIPFGET) { 7163 /* 7164 * Fetch the tuning parameters for a particular value 7165 */ 7166 tu.ipft_vlong = 0; 7167 if (ta->ipft_sz == sizeof(u_long)) 7168 tu.ipft_vlong = *ta->ipft_plong; 7169 else if (ta->ipft_sz == sizeof(u_int)) 7170 tu.ipft_vint = *ta->ipft_pint; 7171 else if (ta->ipft_sz == sizeof(u_short)) 7172 tu.ipft_vshort = *ta->ipft_pshort; 7173 else if (ta->ipft_sz == sizeof(u_char)) 7174 tu.ipft_vchar = *ta->ipft_pchar; 7175 tu.ipft_cookie = ta; 7176 tu.ipft_sz = ta->ipft_sz; 7177 tu.ipft_min = ta->ipft_min; 7178 tu.ipft_max = ta->ipft_max; 7179 tu.ipft_flags = ta->ipft_flags; 7180 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE); 7181 7182 } else if (cmd == (ioctlcmd_t)SIOCIPFSET) { 7183 /* 7184 * Set an internal parameter. The hard part here is 7185 * getting the new value safely and correctly out of 7186 * the kernel (given we only know its size, not type.) 7187 */ 7188 u_long in; 7189 7190 if (((ta->ipft_flags & IPFT_WRDISABLED) != 0) && 7191 (softc->ipf_running > 0)) { 7192 IPFERROR(78); 7193 error = EBUSY; 7194 break; 7195 } 7196 7197 in = tu.ipft_vlong; 7198 if (in < ta->ipft_min || in > ta->ipft_max) { 7199 IPFERROR(79); 7200 error = EINVAL; 7201 break; 7202 } 7203 7204 if (ta->ipft_func != NULL) { 7205 SPL_INT(s); 7206 7207 SPL_NET(s); 7208 error = (*ta->ipft_func)(softc, ta, 7209 &tu.ipft_un); 7210 SPL_X(s); 7211 7212 } else if (ta->ipft_sz == sizeof(u_long)) { 7213 tu.ipft_vlong = *ta->ipft_plong; 7214 *ta->ipft_plong = in; 7215 7216 } else if (ta->ipft_sz == sizeof(u_int)) { 7217 tu.ipft_vint = *ta->ipft_pint; 7218 *ta->ipft_pint = (u_int)(in & 0xffffffff); 7219 7220 } else if (ta->ipft_sz == sizeof(u_short)) { 7221 tu.ipft_vshort = *ta->ipft_pshort; 7222 *ta->ipft_pshort = (u_short)(in & 0xffff); 7223 7224 } else if (ta->ipft_sz == sizeof(u_char)) { 7225 tu.ipft_vchar = *ta->ipft_pchar; 7226 *ta->ipft_pchar = (u_char)(in & 0xff); 7227 } 7228 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE); 7229 } 7230 break; 7231 7232 default : 7233 IPFERROR(80); 7234 error = EINVAL; 7235 break; 7236 } 7237 7238 return error; 7239 } 7240 7241 7242 /* ------------------------------------------------------------------------ */ 7243 /* Function: ipf_zerostats */ 7244 /* Returns: int - 0 = success, else failure */ 7245 /* Parameters: data(O) - pointer to pointer for copying data back to */ 7246 /* */ 7247 /* Copies the current statistics out to userspace and then zero's the */ 7248 /* current ones in the kernel. The lock is only held across the bzero() as */ 7249 /* the copyout may result in paging (ie network activity.) */ 7250 /* ------------------------------------------------------------------------ */ 7251 int 7252 ipf_zerostats(ipf_main_softc_t *softc, void *data) 7253 { 7254 friostat_t fio; 7255 ipfobj_t obj; 7256 int error; 7257 7258 error = ipf_inobj(softc, data, &obj, &fio, IPFOBJ_IPFSTAT); 7259 if (error != 0) 7260 return error; 7261 ipf_getstat(softc, &fio, obj.ipfo_rev); 7262 error = ipf_outobj(softc, data, &fio, IPFOBJ_IPFSTAT); 7263 if (error != 0) 7264 return error; 7265 7266 WRITE_ENTER(&softc->ipf_mutex); 7267 bzero(&softc->ipf_stats, sizeof(softc->ipf_stats)); 7268 RWLOCK_EXIT(&softc->ipf_mutex); 7269 7270 return 0; 7271 } 7272 7273 7274 /* ------------------------------------------------------------------------ */ 7275 /* Function: ipf_resolvedest */ 7276 /* Returns: Nil */ 7277 /* Parameters: softc(I) - pointer to soft context main structure */ 7278 /* base(I) - where strings are stored */ 7279 /* fdp(IO) - pointer to destination information to resolve */ 7280 /* v(I) - IP protocol version to match */ 7281 /* */ 7282 /* Looks up an interface name in the frdest structure pointed to by fdp and */ 7283 /* if a matching name can be found for the particular IP protocol version */ 7284 /* then store the interface pointer in the frdest struct. If no match is */ 7285 /* found, then set the interface pointer to be -1 as NULL is considered to */ 7286 /* indicate there is no information at all in the structure. */ 7287 /* ------------------------------------------------------------------------ */ 7288 int 7289 ipf_resolvedest(ipf_main_softc_t *softc, char *base, frdest_t *fdp, int v) 7290 { 7291 int errval = 0; 7292 void *ifp; 7293 7294 ifp = NULL; 7295 7296 if (fdp->fd_name != -1) { 7297 if (fdp->fd_type == FRD_DSTLIST) { 7298 ifp = ipf_lookup_res_name(softc, IPL_LOGIPF, 7299 IPLT_DSTLIST, 7300 base + fdp->fd_name, 7301 NULL); 7302 if (ifp == NULL) { 7303 IPFERROR(144); 7304 errval = ESRCH; 7305 } 7306 } else { 7307 ifp = GETIFP(base + fdp->fd_name, v); 7308 } 7309 } 7310 fdp->fd_ptr = ifp; 7311 7312 return errval; 7313 } 7314 7315 7316 /* ------------------------------------------------------------------------ */ 7317 /* Function: ipf_resolvenic */ 7318 /* Returns: void* - NULL = wildcard name, -1 = failed to find NIC, else */ 7319 /* pointer to interface structure for NIC */ 7320 /* Parameters: softc(I)- pointer to soft context main structure */ 7321 /* name(I) - complete interface name */ 7322 /* v(I) - IP protocol version */ 7323 /* */ 7324 /* Look for a network interface structure that firstly has a matching name */ 7325 /* to that passed in and that is also being used for that IP protocol */ 7326 /* version (necessary on some platforms where there are separate listings */ 7327 /* for both IPv4 and IPv6 on the same physical NIC. */ 7328 /* */ 7329 /* ------------------------------------------------------------------------ */ 7330 void * 7331 ipf_resolvenic(ipf_main_softc_t *softc, char *name, int v) 7332 { 7333 void *nic; 7334 7335 softc = softc; /* gcc -Wextra */ 7336 if (name[0] == '\0') 7337 return NULL; 7338 7339 if ((name[1] == '\0') && ((name[0] == '-') || (name[0] == '*'))) { 7340 return NULL; 7341 } 7342 7343 nic = GETIFP(name, v); 7344 if (nic == NULL) 7345 nic = (void *)-1; 7346 return nic; 7347 } 7348 7349 7350 /* ------------------------------------------------------------------------ */ 7351 /* Function: ipf_token_expire */ 7352 /* Returns: None. */ 7353 /* Parameters: softc(I) - pointer to soft context main structure */ 7354 /* */ 7355 /* This function is run every ipf tick to see if there are any tokens that */ 7356 /* have been held for too long and need to be freed up. */ 7357 /* ------------------------------------------------------------------------ */ 7358 void 7359 ipf_token_expire(ipf_main_softc_t *softc) 7360 { 7361 ipftoken_t *it; 7362 7363 WRITE_ENTER(&softc->ipf_tokens); 7364 while ((it = softc->ipf_token_head) != NULL) { 7365 if (it->ipt_die > softc->ipf_ticks) 7366 break; 7367 7368 ipf_token_deref(softc, it); 7369 } 7370 RWLOCK_EXIT(&softc->ipf_tokens); 7371 } 7372 7373 7374 /* ------------------------------------------------------------------------ */ 7375 /* Function: ipf_token_flush */ 7376 /* Returns: None. */ 7377 /* Parameters: softc(I) - pointer to soft context main structure */ 7378 /* */ 7379 /* Loop through all of the existing tokens and call deref to see if they */ 7380 /* can be freed. Normally a function like this might just loop on */ 7381 /* ipf_token_head but there is a chance that a token might have a ref count */ 7382 /* of greater than one and in that case the the reference would drop twice */ 7383 /* by code that is only entitled to drop it once. */ 7384 /* ------------------------------------------------------------------------ */ 7385 static void 7386 ipf_token_flush(ipf_main_softc_t *softc) 7387 { 7388 ipftoken_t *it, *next; 7389 7390 WRITE_ENTER(&softc->ipf_tokens); 7391 for (it = softc->ipf_token_head; it != NULL; it = next) { 7392 next = it->ipt_next; 7393 (void) ipf_token_deref(softc, it); 7394 } 7395 RWLOCK_EXIT(&softc->ipf_tokens); 7396 } 7397 7398 7399 /* ------------------------------------------------------------------------ */ 7400 /* Function: ipf_token_del */ 7401 /* Returns: int - 0 = success, else error */ 7402 /* Parameters: softc(I)- pointer to soft context main structure */ 7403 /* type(I) - the token type to match */ 7404 /* uid(I) - uid owning the token */ 7405 /* ptr(I) - context pointer for the token */ 7406 /* */ 7407 /* This function looks for a a token in the current list that matches up */ 7408 /* the fields (type, uid, ptr). If none is found, ESRCH is returned, else */ 7409 /* call ipf_token_dewref() to remove it from the list. In the event that */ 7410 /* the token has a reference held elsewhere, setting ipt_complete to 2 */ 7411 /* enables debugging to distinguish between the two paths that ultimately */ 7412 /* lead to a token to be deleted. */ 7413 /* ------------------------------------------------------------------------ */ 7414 int 7415 ipf_token_del(ipf_main_softc_t *softc, int type, int uid, void *ptr) 7416 { 7417 ipftoken_t *it; 7418 int error; 7419 7420 IPFERROR(82); 7421 error = ESRCH; 7422 7423 WRITE_ENTER(&softc->ipf_tokens); 7424 for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) { 7425 if (ptr == it->ipt_ctx && type == it->ipt_type && 7426 uid == it->ipt_uid) { 7427 it->ipt_complete = 2; 7428 ipf_token_deref(softc, it); 7429 error = 0; 7430 break; 7431 } 7432 } 7433 RWLOCK_EXIT(&softc->ipf_tokens); 7434 7435 return error; 7436 } 7437 7438 7439 /* ------------------------------------------------------------------------ */ 7440 /* Function: ipf_token_mark_complete */ 7441 /* Returns: None. */ 7442 /* Parameters: token(I) - pointer to token structure */ 7443 /* */ 7444 /* Mark a token as being ineligable for being found with ipf_token_find. */ 7445 /* ------------------------------------------------------------------------ */ 7446 void 7447 ipf_token_mark_complete(ipftoken_t *token) 7448 { 7449 if (token->ipt_complete == 0) 7450 token->ipt_complete = 1; 7451 } 7452 7453 7454 /* ------------------------------------------------------------------------ */ 7455 /* Function: ipf_token_find */ 7456 /* Returns: ipftoken_t * - NULL if no memory, else pointer to token */ 7457 /* Parameters: softc(I)- pointer to soft context main structure */ 7458 /* type(I) - the token type to match */ 7459 /* uid(I) - uid owning the token */ 7460 /* ptr(I) - context pointer for the token */ 7461 /* */ 7462 /* This function looks for a live token in the list of current tokens that */ 7463 /* matches the tuple (type, uid, ptr). If one cannot be found then one is */ 7464 /* allocated. If one is found then it is moved to the top of the list of */ 7465 /* currently active tokens. */ 7466 /* ------------------------------------------------------------------------ */ 7467 ipftoken_t * 7468 ipf_token_find(ipf_main_softc_t *softc, int type, int uid, void *ptr) 7469 { 7470 ipftoken_t *it, *new; 7471 7472 KMALLOC(new, ipftoken_t *); 7473 if (new != NULL) 7474 bzero((char *)new, sizeof(*new)); 7475 7476 WRITE_ENTER(&softc->ipf_tokens); 7477 for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) { 7478 if ((ptr == it->ipt_ctx) && (type == it->ipt_type) && 7479 (uid == it->ipt_uid) && (it->ipt_complete < 2)) 7480 break; 7481 } 7482 7483 if (it == NULL) { 7484 it = new; 7485 new = NULL; 7486 if (it == NULL) { 7487 RWLOCK_EXIT(&softc->ipf_tokens); 7488 return NULL; 7489 } 7490 it->ipt_ctx = ptr; 7491 it->ipt_uid = uid; 7492 it->ipt_type = type; 7493 it->ipt_ref = 1; 7494 } else { 7495 if (new != NULL) { 7496 KFREE(new); 7497 new = NULL; 7498 } 7499 7500 if (it->ipt_complete > 0) 7501 it = NULL; 7502 else 7503 ipf_token_unlink(softc, it); 7504 } 7505 7506 if (it != NULL) { 7507 it->ipt_pnext = softc->ipf_token_tail; 7508 *softc->ipf_token_tail = it; 7509 softc->ipf_token_tail = &it->ipt_next; 7510 it->ipt_next = NULL; 7511 it->ipt_ref++; 7512 7513 it->ipt_die = softc->ipf_ticks + 20; 7514 } 7515 7516 RWLOCK_EXIT(&softc->ipf_tokens); 7517 7518 return it; 7519 } 7520 7521 7522 /* ------------------------------------------------------------------------ */ 7523 /* Function: ipf_token_unlink */ 7524 /* Returns: None. */ 7525 /* Parameters: softc(I) - pointer to soft context main structure */ 7526 /* token(I) - pointer to token structure */ 7527 /* Write Locks: ipf_tokens */ 7528 /* */ 7529 /* This function unlinks a token structure from the linked list of tokens */ 7530 /* that "own" it. The head pointer never needs to be explicitly adjusted */ 7531 /* but the tail does due to the linked list implementation. */ 7532 /* ------------------------------------------------------------------------ */ 7533 static void 7534 ipf_token_unlink(ipf_main_softc_t *softc, ipftoken_t *token) 7535 { 7536 7537 if (softc->ipf_token_tail == &token->ipt_next) 7538 softc->ipf_token_tail = token->ipt_pnext; 7539 7540 *token->ipt_pnext = token->ipt_next; 7541 if (token->ipt_next != NULL) 7542 token->ipt_next->ipt_pnext = token->ipt_pnext; 7543 token->ipt_next = NULL; 7544 token->ipt_pnext = NULL; 7545 } 7546 7547 7548 /* ------------------------------------------------------------------------ */ 7549 /* Function: ipf_token_deref */ 7550 /* Returns: int - 0 == token freed, else reference count */ 7551 /* Parameters: softc(I) - pointer to soft context main structure */ 7552 /* token(I) - pointer to token structure */ 7553 /* Write Locks: ipf_tokens */ 7554 /* */ 7555 /* Drop the reference count on the token structure and if it drops to zero, */ 7556 /* call the dereference function for the token type because it is then */ 7557 /* possible to free the token data structure. */ 7558 /* ------------------------------------------------------------------------ */ 7559 int 7560 ipf_token_deref(ipf_main_softc_t *softc, ipftoken_t *token) 7561 { 7562 void *data, **datap; 7563 7564 ASSERT(token->ipt_ref > 0); 7565 token->ipt_ref--; 7566 if (token->ipt_ref > 0) 7567 return token->ipt_ref; 7568 7569 data = token->ipt_data; 7570 datap = &data; 7571 7572 if ((data != NULL) && (data != (void *)-1)) { 7573 switch (token->ipt_type) 7574 { 7575 case IPFGENITER_IPF : 7576 (void) ipf_derefrule(softc, (frentry_t **)datap); 7577 break; 7578 case IPFGENITER_IPNAT : 7579 WRITE_ENTER(&softc->ipf_nat); 7580 ipf_nat_rule_deref(softc, (ipnat_t **)datap); 7581 RWLOCK_EXIT(&softc->ipf_nat); 7582 break; 7583 case IPFGENITER_NAT : 7584 ipf_nat_deref(softc, (nat_t **)datap); 7585 break; 7586 case IPFGENITER_STATE : 7587 ipf_state_deref(softc, (ipstate_t **)datap); 7588 break; 7589 case IPFGENITER_FRAG : 7590 ipf_frag_pkt_deref(softc, (ipfr_t **)datap); 7591 break; 7592 case IPFGENITER_NATFRAG : 7593 ipf_frag_nat_deref(softc, (ipfr_t **)datap); 7594 break; 7595 case IPFGENITER_HOSTMAP : 7596 WRITE_ENTER(&softc->ipf_nat); 7597 ipf_nat_hostmapdel(softc, (hostmap_t **)datap); 7598 RWLOCK_EXIT(&softc->ipf_nat); 7599 break; 7600 default : 7601 ipf_lookup_iterderef(softc, token->ipt_type, data); 7602 break; 7603 } 7604 } 7605 7606 ipf_token_unlink(softc, token); 7607 KFREE(token); 7608 return 0; 7609 } 7610 7611 7612 /* ------------------------------------------------------------------------ */ 7613 /* Function: ipf_nextrule */ 7614 /* Returns: frentry_t * - NULL == no more rules, else pointer to next */ 7615 /* Parameters: softc(I) - pointer to soft context main structure */ 7616 /* fr(I) - pointer to filter rule */ 7617 /* out(I) - 1 == out rules, 0 == input rules */ 7618 /* */ 7619 /* Starting with "fr", find the next rule to visit. This includes visiting */ 7620 /* the list of rule groups if either fr is NULL (empty list) or it is the */ 7621 /* last rule in the list. When walking rule lists, it is either input or */ 7622 /* output rules that are returned, never both. */ 7623 /* ------------------------------------------------------------------------ */ 7624 static frentry_t * 7625 ipf_nextrule(ipf_main_softc_t *softc, int active, int unit, 7626 frentry_t *fr, int out) 7627 { 7628 frentry_t *next; 7629 frgroup_t *fg; 7630 7631 if (fr != NULL && fr->fr_group != -1) { 7632 fg = ipf_findgroup(softc, fr->fr_names + fr->fr_group, 7633 unit, active, NULL); 7634 if (fg != NULL) 7635 fg = fg->fg_next; 7636 } else { 7637 fg = softc->ipf_groups[unit][active]; 7638 } 7639 7640 while (fg != NULL) { 7641 next = fg->fg_start; 7642 while (next != NULL) { 7643 if (out) { 7644 if (next->fr_flags & FR_OUTQUE) 7645 return next; 7646 } else if (next->fr_flags & FR_INQUE) { 7647 return next; 7648 } 7649 next = next->fr_next; 7650 } 7651 if (next == NULL) 7652 fg = fg->fg_next; 7653 } 7654 7655 return NULL; 7656 } 7657 7658 /* ------------------------------------------------------------------------ */ 7659 /* Function: ipf_getnextrule */ 7660 /* Returns: int - 0 = success, else error */ 7661 /* Parameters: softc(I)- pointer to soft context main structure */ 7662 /* t(I) - pointer to destination information to resolve */ 7663 /* ptr(I) - pointer to ipfobj_t to copyin from user space */ 7664 /* */ 7665 /* This function's first job is to bring in the ipfruleiter_t structure via */ 7666 /* the ipfobj_t structure to determine what should be the next rule to */ 7667 /* return. Once the ipfruleiter_t has been brought in, it then tries to */ 7668 /* find the 'next rule'. This may include searching rule group lists or */ 7669 /* just be as simple as looking at the 'next' field in the rule structure. */ 7670 /* When we have found the rule to return, increase its reference count and */ 7671 /* if we used an existing rule to get here, decrease its reference count. */ 7672 /* ------------------------------------------------------------------------ */ 7673 int 7674 ipf_getnextrule(ipf_main_softc_t *softc, ipftoken_t *t, void *ptr) 7675 { 7676 frentry_t *fr, *next, zero; 7677 ipfruleiter_t it; 7678 int error, out; 7679 frgroup_t *fg; 7680 ipfobj_t obj; 7681 int predict; 7682 char *dst; 7683 int unit; 7684 7685 if (t == NULL || ptr == NULL) { 7686 IPFERROR(84); 7687 return EFAULT; 7688 } 7689 7690 error = ipf_inobj(softc, ptr, &obj, &it, IPFOBJ_IPFITER); 7691 if (error != 0) 7692 return error; 7693 7694 if ((it.iri_inout < 0) || (it.iri_inout > 3)) { 7695 IPFERROR(85); 7696 return EINVAL; 7697 } 7698 if ((it.iri_active != 0) && (it.iri_active != 1)) { 7699 IPFERROR(86); 7700 return EINVAL; 7701 } 7702 if (it.iri_nrules == 0) { 7703 IPFERROR(87); 7704 return ENOSPC; 7705 } 7706 if (it.iri_rule == NULL) { 7707 IPFERROR(88); 7708 return EFAULT; 7709 } 7710 7711 fg = NULL; 7712 fr = t->ipt_data; 7713 if ((it.iri_inout & F_OUT) != 0) 7714 out = 1; 7715 else 7716 out = 0; 7717 if ((it.iri_inout & F_ACIN) != 0) 7718 unit = IPL_LOGCOUNT; 7719 else 7720 unit = IPL_LOGIPF; 7721 7722 READ_ENTER(&softc->ipf_mutex); 7723 if (fr == NULL) { 7724 if (*it.iri_group == '\0') { 7725 if (unit == IPL_LOGCOUNT) { 7726 next = softc->ipf_acct[out][it.iri_active]; 7727 } else { 7728 next = softc->ipf_rules[out][it.iri_active]; 7729 } 7730 if (next == NULL) 7731 next = ipf_nextrule(softc, it.iri_active, 7732 unit, NULL, out); 7733 } else { 7734 fg = ipf_findgroup(softc, it.iri_group, unit, 7735 it.iri_active, NULL); 7736 if (fg != NULL) 7737 next = fg->fg_start; 7738 else 7739 next = NULL; 7740 } 7741 } else { 7742 next = fr->fr_next; 7743 if (next == NULL) 7744 next = ipf_nextrule(softc, it.iri_active, unit, 7745 fr, out); 7746 } 7747 7748 if (next != NULL && next->fr_next != NULL) 7749 predict = 1; 7750 else if (ipf_nextrule(softc, it.iri_active, unit, next, out) != NULL) 7751 predict = 1; 7752 else 7753 predict = 0; 7754 7755 if (fr != NULL) 7756 (void) ipf_derefrule(softc, &fr); 7757 7758 obj.ipfo_type = IPFOBJ_FRENTRY; 7759 dst = (char *)it.iri_rule; 7760 7761 if (next != NULL) { 7762 obj.ipfo_size = next->fr_size; 7763 MUTEX_ENTER(&next->fr_lock); 7764 next->fr_ref++; 7765 MUTEX_EXIT(&next->fr_lock); 7766 t->ipt_data = next; 7767 } else { 7768 obj.ipfo_size = sizeof(frentry_t); 7769 bzero(&zero, sizeof(zero)); 7770 next = &zero; 7771 t->ipt_data = NULL; 7772 } 7773 it.iri_rule = predict ? next : NULL; 7774 if (predict == 0) 7775 ipf_token_mark_complete(t); 7776 7777 RWLOCK_EXIT(&softc->ipf_mutex); 7778 7779 obj.ipfo_ptr = dst; 7780 error = ipf_outobjk(softc, &obj, next); 7781 if (error == 0 && t->ipt_data != NULL) { 7782 dst += obj.ipfo_size; 7783 if (next->fr_data != NULL) { 7784 ipfobj_t dobj; 7785 7786 if (next->fr_type == FR_T_IPFEXPR) 7787 dobj.ipfo_type = IPFOBJ_IPFEXPR; 7788 else 7789 dobj.ipfo_type = IPFOBJ_FRIPF; 7790 dobj.ipfo_size = next->fr_dsize; 7791 dobj.ipfo_rev = obj.ipfo_rev; 7792 dobj.ipfo_ptr = dst; 7793 error = ipf_outobjk(softc, &dobj, next->fr_data); 7794 } 7795 } 7796 7797 if ((fr != NULL) && (next == &zero)) 7798 (void) ipf_derefrule(softc, &fr); 7799 7800 return error; 7801 } 7802 7803 7804 /* ------------------------------------------------------------------------ */ 7805 /* Function: ipf_frruleiter */ 7806 /* Returns: int - 0 = success, else error */ 7807 /* Parameters: softc(I)- pointer to soft context main structure */ 7808 /* data(I) - the token type to match */ 7809 /* uid(I) - uid owning the token */ 7810 /* ptr(I) - context pointer for the token */ 7811 /* */ 7812 /* This function serves as a stepping stone between ipf_ipf_ioctl and */ 7813 /* ipf_getnextrule. It's role is to find the right token in the kernel for */ 7814 /* the process doing the ioctl and use that to ask for the next rule. */ 7815 /* ------------------------------------------------------------------------ */ 7816 static int 7817 ipf_frruleiter(ipf_main_softc_t *softc, void *data, int uid, void *ctx) 7818 { 7819 ipftoken_t *token; 7820 ipfruleiter_t it; 7821 ipfobj_t obj; 7822 int error; 7823 7824 token = ipf_token_find(softc, IPFGENITER_IPF, uid, ctx); 7825 if (token != NULL) { 7826 error = ipf_getnextrule(softc, token, data); 7827 WRITE_ENTER(&softc->ipf_tokens); 7828 ipf_token_deref(softc, token); 7829 RWLOCK_EXIT(&softc->ipf_tokens); 7830 } else { 7831 error = ipf_inobj(softc, data, &obj, &it, IPFOBJ_IPFITER); 7832 if (error != 0) 7833 return error; 7834 it.iri_rule = NULL; 7835 error = ipf_outobj(softc, data, &it, IPFOBJ_IPFITER); 7836 } 7837 7838 return error; 7839 } 7840 7841 7842 /* ------------------------------------------------------------------------ */ 7843 /* Function: ipf_geniter */ 7844 /* Returns: int - 0 = success, else error */ 7845 /* Parameters: softc(I) - pointer to soft context main structure */ 7846 /* token(I) - pointer to ipftoken_t structure */ 7847 /* itp(I) - pointer to iterator data */ 7848 /* */ 7849 /* Decide which iterator function to call using information passed through */ 7850 /* the ipfgeniter_t structure at itp. */ 7851 /* ------------------------------------------------------------------------ */ 7852 static int 7853 ipf_geniter(ipf_main_softc_t *softc, ipftoken_t *token, ipfgeniter_t *itp) 7854 { 7855 int error; 7856 7857 switch (itp->igi_type) 7858 { 7859 case IPFGENITER_FRAG : 7860 error = ipf_frag_pkt_next(softc, token, itp); 7861 break; 7862 default : 7863 IPFERROR(92); 7864 error = EINVAL; 7865 break; 7866 } 7867 7868 return error; 7869 } 7870 7871 7872 /* ------------------------------------------------------------------------ */ 7873 /* Function: ipf_genericiter */ 7874 /* Returns: int - 0 = success, else error */ 7875 /* Parameters: softc(I)- pointer to soft context main structure */ 7876 /* data(I) - the token type to match */ 7877 /* uid(I) - uid owning the token */ 7878 /* ptr(I) - context pointer for the token */ 7879 /* */ 7880 /* Handle the SIOCGENITER ioctl for the ipfilter device. The primary role */ 7881 /* ------------------------------------------------------------------------ */ 7882 int 7883 ipf_genericiter(ipf_main_softc_t *softc, void *data, int uid, void *ctx) 7884 { 7885 ipftoken_t *token; 7886 ipfgeniter_t iter; 7887 int error; 7888 7889 error = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_GENITER); 7890 if (error != 0) 7891 return error; 7892 7893 token = ipf_token_find(softc, iter.igi_type, uid, ctx); 7894 if (token != NULL) { 7895 token->ipt_subtype = iter.igi_type; 7896 error = ipf_geniter(softc, token, &iter); 7897 WRITE_ENTER(&softc->ipf_tokens); 7898 ipf_token_deref(softc, token); 7899 RWLOCK_EXIT(&softc->ipf_tokens); 7900 } else { 7901 IPFERROR(93); 7902 error = 0; 7903 } 7904 7905 return error; 7906 } 7907 7908 7909 /* ------------------------------------------------------------------------ */ 7910 /* Function: ipf_ipf_ioctl */ 7911 /* Returns: int - 0 = success, else error */ 7912 /* Parameters: softc(I)- pointer to soft context main structure */ 7913 /* data(I) - the token type to match */ 7914 /* cmd(I) - the ioctl command number */ 7915 /* mode(I) - mode flags for the ioctl */ 7916 /* uid(I) - uid owning the token */ 7917 /* ptr(I) - context pointer for the token */ 7918 /* */ 7919 /* This function handles all of the ioctl command that are actually isssued */ 7920 /* to the /dev/ipl device. */ 7921 /* ------------------------------------------------------------------------ */ 7922 int 7923 ipf_ipf_ioctl(ipf_main_softc_t *softc, void *data, ioctlcmd_t cmd, int mode, 7924 int uid, void *ctx) 7925 { 7926 friostat_t fio; 7927 int error, tmp; 7928 ipfobj_t obj; 7929 SPL_INT(s); 7930 7931 switch (cmd) 7932 { 7933 case SIOCFRENB : 7934 if (!(mode & FWRITE)) { 7935 IPFERROR(94); 7936 error = EPERM; 7937 } else { 7938 error = BCOPYIN(data, &tmp, sizeof(tmp)); 7939 if (error != 0) { 7940 IPFERROR(95); 7941 error = EFAULT; 7942 break; 7943 } 7944 7945 WRITE_ENTER(&softc->ipf_global); 7946 if (tmp) { 7947 if (softc->ipf_running > 0) 7948 error = 0; 7949 else 7950 error = ipfattach(softc); 7951 if (error == 0) 7952 softc->ipf_running = 1; 7953 else 7954 (void) ipfdetach(softc); 7955 } else { 7956 if (softc->ipf_running == 1) 7957 error = ipfdetach(softc); 7958 else 7959 error = 0; 7960 if (error == 0) 7961 softc->ipf_running = -1; 7962 } 7963 RWLOCK_EXIT(&softc->ipf_global); 7964 } 7965 break; 7966 7967 case SIOCIPFSET : 7968 if (!(mode & FWRITE)) { 7969 IPFERROR(96); 7970 error = EPERM; 7971 break; 7972 } 7973 /* FALLTHRU */ 7974 case SIOCIPFGETNEXT : 7975 case SIOCIPFGET : 7976 error = ipf_ipftune(softc, cmd, (void *)data); 7977 break; 7978 7979 case SIOCSETFF : 7980 if (!(mode & FWRITE)) { 7981 IPFERROR(97); 7982 error = EPERM; 7983 } else { 7984 error = BCOPYIN(data, &softc->ipf_flags, 7985 sizeof(softc->ipf_flags)); 7986 if (error != 0) { 7987 IPFERROR(98); 7988 error = EFAULT; 7989 } 7990 } 7991 break; 7992 7993 case SIOCGETFF : 7994 error = BCOPYOUT(&softc->ipf_flags, data, 7995 sizeof(softc->ipf_flags)); 7996 if (error != 0) { 7997 IPFERROR(99); 7998 error = EFAULT; 7999 } 8000 break; 8001 8002 case SIOCFUNCL : 8003 error = ipf_resolvefunc(softc, (void *)data); 8004 break; 8005 8006 case SIOCINAFR : 8007 case SIOCRMAFR : 8008 case SIOCADAFR : 8009 case SIOCZRLST : 8010 if (!(mode & FWRITE)) { 8011 IPFERROR(100); 8012 error = EPERM; 8013 } else { 8014 error = frrequest(softc, IPL_LOGIPF, cmd, data, 8015 softc->ipf_active, 1); 8016 } 8017 break; 8018 8019 case SIOCINIFR : 8020 case SIOCRMIFR : 8021 case SIOCADIFR : 8022 if (!(mode & FWRITE)) { 8023 IPFERROR(101); 8024 error = EPERM; 8025 } else { 8026 error = frrequest(softc, IPL_LOGIPF, cmd, data, 8027 1 - softc->ipf_active, 1); 8028 } 8029 break; 8030 8031 case SIOCSWAPA : 8032 if (!(mode & FWRITE)) { 8033 IPFERROR(102); 8034 error = EPERM; 8035 } else { 8036 WRITE_ENTER(&softc->ipf_mutex); 8037 error = BCOPYOUT(&softc->ipf_active, data, 8038 sizeof(softc->ipf_active)); 8039 if (error != 0) { 8040 IPFERROR(103); 8041 error = EFAULT; 8042 } else { 8043 softc->ipf_active = 1 - softc->ipf_active; 8044 } 8045 RWLOCK_EXIT(&softc->ipf_mutex); 8046 } 8047 break; 8048 8049 case SIOCGETFS : 8050 error = ipf_inobj(softc, (void *)data, &obj, &fio, 8051 IPFOBJ_IPFSTAT); 8052 if (error != 0) 8053 break; 8054 ipf_getstat(softc, &fio, obj.ipfo_rev); 8055 error = ipf_outobj(softc, (void *)data, &fio, IPFOBJ_IPFSTAT); 8056 break; 8057 8058 case SIOCFRZST : 8059 if (!(mode & FWRITE)) { 8060 IPFERROR(104); 8061 error = EPERM; 8062 } else 8063 error = ipf_zerostats(softc, data); 8064 break; 8065 8066 case SIOCIPFFL : 8067 if (!(mode & FWRITE)) { 8068 IPFERROR(105); 8069 error = EPERM; 8070 } else { 8071 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8072 if (!error) { 8073 tmp = ipf_flush(softc, IPL_LOGIPF, tmp); 8074 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8075 if (error != 0) { 8076 IPFERROR(106); 8077 error = EFAULT; 8078 } 8079 } else { 8080 IPFERROR(107); 8081 error = EFAULT; 8082 } 8083 } 8084 break; 8085 8086 #ifdef USE_INET6 8087 case SIOCIPFL6 : 8088 if (!(mode & FWRITE)) { 8089 IPFERROR(108); 8090 error = EPERM; 8091 } else { 8092 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8093 if (!error) { 8094 tmp = ipf_flush(softc, IPL_LOGIPF, tmp); 8095 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8096 if (error != 0) { 8097 IPFERROR(109); 8098 error = EFAULT; 8099 } 8100 } else { 8101 IPFERROR(110); 8102 error = EFAULT; 8103 } 8104 } 8105 break; 8106 #endif 8107 8108 case SIOCSTLCK : 8109 if (!(mode & FWRITE)) { 8110 IPFERROR(122); 8111 error = EPERM; 8112 } else { 8113 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8114 if (error == 0) { 8115 ipf_state_setlock(softc->ipf_state_soft, tmp); 8116 ipf_nat_setlock(softc->ipf_nat_soft, tmp); 8117 ipf_frag_setlock(softc->ipf_frag_soft, tmp); 8118 ipf_auth_setlock(softc->ipf_auth_soft, tmp); 8119 } else { 8120 IPFERROR(111); 8121 error = EFAULT; 8122 } 8123 } 8124 break; 8125 8126 #ifdef IPFILTER_LOG 8127 case SIOCIPFFB : 8128 if (!(mode & FWRITE)) { 8129 IPFERROR(112); 8130 error = EPERM; 8131 } else { 8132 tmp = ipf_log_clear(softc, IPL_LOGIPF); 8133 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8134 if (error) { 8135 IPFERROR(113); 8136 error = EFAULT; 8137 } 8138 } 8139 break; 8140 #endif /* IPFILTER_LOG */ 8141 8142 case SIOCFRSYN : 8143 if (!(mode & FWRITE)) { 8144 IPFERROR(114); 8145 error = EPERM; 8146 } else { 8147 WRITE_ENTER(&softc->ipf_global); 8148 #if (defined(MENTAT) && defined(_KERNEL)) && !defined(INSTANCES) 8149 error = ipfsync(); 8150 #else 8151 ipf_sync(softc, NULL); 8152 error = 0; 8153 #endif 8154 RWLOCK_EXIT(&softc->ipf_global); 8155 8156 } 8157 break; 8158 8159 case SIOCGFRST : 8160 error = ipf_outobj(softc, (void *)data, 8161 ipf_frag_stats(softc->ipf_frag_soft), 8162 IPFOBJ_FRAGSTAT); 8163 break; 8164 8165 #ifdef IPFILTER_LOG 8166 case FIONREAD : 8167 tmp = ipf_log_bytesused(softc, IPL_LOGIPF); 8168 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8169 break; 8170 #endif 8171 8172 case SIOCIPFITER : 8173 SPL_SCHED(s); 8174 error = ipf_frruleiter(softc, data, uid, ctx); 8175 SPL_X(s); 8176 break; 8177 8178 case SIOCGENITER : 8179 SPL_SCHED(s); 8180 error = ipf_genericiter(softc, data, uid, ctx); 8181 SPL_X(s); 8182 break; 8183 8184 case SIOCIPFDELTOK : 8185 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8186 if (error == 0) { 8187 SPL_SCHED(s); 8188 error = ipf_token_del(softc, tmp, uid, ctx); 8189 SPL_X(s); 8190 } 8191 break; 8192 8193 default : 8194 IPFERROR(115); 8195 error = EINVAL; 8196 break; 8197 } 8198 8199 return error; 8200 } 8201 8202 8203 /* ------------------------------------------------------------------------ */ 8204 /* Function: ipf_decaps */ 8205 /* Returns: int - -1 == decapsulation failed, else bit mask of */ 8206 /* flags indicating packet filtering decision. */ 8207 /* Parameters: fin(I) - pointer to packet information */ 8208 /* pass(I) - IP protocol version to match */ 8209 /* l5proto(I) - layer 5 protocol to decode UDP data as. */ 8210 /* */ 8211 /* This function is called for packets that are wrapt up in other packets, */ 8212 /* for example, an IP packet that is the entire data segment for another IP */ 8213 /* packet. If the basic constraints for this are satisfied, change the */ 8214 /* buffer to point to the start of the inner packet and start processing */ 8215 /* rules belonging to the head group this rule specifies. */ 8216 /* ------------------------------------------------------------------------ */ 8217 u_32_t 8218 ipf_decaps(fr_info_t *fin, u_32_t pass, int l5proto) 8219 { 8220 fr_info_t fin2, *fino = NULL; 8221 int elen, hlen, nh; 8222 grehdr_t gre; 8223 ip_t *ip; 8224 mb_t *m; 8225 8226 if ((fin->fin_flx & FI_COALESCE) == 0) 8227 if (ipf_coalesce(fin) == -1) 8228 goto cantdecaps; 8229 8230 m = fin->fin_m; 8231 hlen = fin->fin_hlen; 8232 8233 switch (fin->fin_p) 8234 { 8235 case IPPROTO_UDP : 8236 /* 8237 * In this case, the specific protocol being decapsulated 8238 * inside UDP frames comes from the rule. 8239 */ 8240 nh = fin->fin_fr->fr_icode; 8241 break; 8242 8243 case IPPROTO_GRE : /* 47 */ 8244 bcopy(fin->fin_dp, (char *)&gre, sizeof(gre)); 8245 hlen += sizeof(grehdr_t); 8246 if (gre.gr_R|gre.gr_s) 8247 goto cantdecaps; 8248 if (gre.gr_C) 8249 hlen += 4; 8250 if (gre.gr_K) 8251 hlen += 4; 8252 if (gre.gr_S) 8253 hlen += 4; 8254 8255 nh = IPPROTO_IP; 8256 8257 /* 8258 * If the routing options flag is set, validate that it is 8259 * there and bounce over it. 8260 */ 8261 #if 0 8262 /* This is really heavy weight and lots of room for error, */ 8263 /* so for now, put it off and get the simple stuff right. */ 8264 if (gre.gr_R) { 8265 u_char off, len, *s; 8266 u_short af; 8267 int end; 8268 8269 end = 0; 8270 s = fin->fin_dp; 8271 s += hlen; 8272 aplen = fin->fin_plen - hlen; 8273 while (aplen > 3) { 8274 af = (s[0] << 8) | s[1]; 8275 off = s[2]; 8276 len = s[3]; 8277 aplen -= 4; 8278 s += 4; 8279 if (af == 0 && len == 0) { 8280 end = 1; 8281 break; 8282 } 8283 if (aplen < len) 8284 break; 8285 s += len; 8286 aplen -= len; 8287 } 8288 if (end != 1) 8289 goto cantdecaps; 8290 hlen = s - (u_char *)fin->fin_dp; 8291 } 8292 #endif 8293 break; 8294 8295 #ifdef IPPROTO_IPIP 8296 case IPPROTO_IPIP : /* 4 */ 8297 #endif 8298 nh = IPPROTO_IP; 8299 break; 8300 8301 default : /* Includes ESP, AH is special for IPv4 */ 8302 goto cantdecaps; 8303 } 8304 8305 switch (nh) 8306 { 8307 case IPPROTO_IP : 8308 case IPPROTO_IPV6 : 8309 break; 8310 default : 8311 goto cantdecaps; 8312 } 8313 8314 bcopy((char *)fin, (char *)&fin2, sizeof(fin2)); 8315 fino = fin; 8316 fin = &fin2; 8317 elen = hlen; 8318 #if defined(MENTAT) && defined(_KERNEL) 8319 m->b_rptr += elen; 8320 #else 8321 m->m_data += elen; 8322 m->m_len -= elen; 8323 #endif 8324 fin->fin_plen -= elen; 8325 8326 ip = (ip_t *)((char *)fin->fin_ip + elen); 8327 8328 /* 8329 * Make sure we have at least enough data for the network layer 8330 * header. 8331 */ 8332 if (IP_V(ip) == 4) 8333 hlen = IP_HL(ip) << 2; 8334 #ifdef USE_INET6 8335 else if (IP_V(ip) == 6) 8336 hlen = sizeof(ip6_t); 8337 #endif 8338 else 8339 goto cantdecaps2; 8340 8341 if (fin->fin_plen < hlen) 8342 goto cantdecaps2; 8343 8344 fin->fin_dp = (char *)ip + hlen; 8345 8346 if (IP_V(ip) == 4) { 8347 /* 8348 * Perform IPv4 header checksum validation. 8349 */ 8350 if (ipf_cksum((u_short *)ip, hlen)) 8351 goto cantdecaps2; 8352 } 8353 8354 if (ipf_makefrip(hlen, ip, fin) == -1) { 8355 cantdecaps2: 8356 if (m != NULL) { 8357 #if defined(MENTAT) && defined(_KERNEL) 8358 m->b_rptr -= elen; 8359 #else 8360 m->m_data -= elen; 8361 m->m_len += elen; 8362 #endif 8363 } 8364 cantdecaps: 8365 DT1(frb_decapfrip, fr_info_t *, fin); 8366 pass &= ~FR_CMDMASK; 8367 pass |= FR_BLOCK|FR_QUICK; 8368 fin->fin_reason = FRB_DECAPFRIP; 8369 return -1; 8370 } 8371 8372 pass = ipf_scanlist(fin, pass); 8373 8374 /* 8375 * Copy the packet filter "result" fields out of the fr_info_t struct 8376 * that is local to the decapsulation processing and back into the 8377 * one we were called with. 8378 */ 8379 fino->fin_flx = fin->fin_flx; 8380 fino->fin_rev = fin->fin_rev; 8381 fino->fin_icode = fin->fin_icode; 8382 fino->fin_rule = fin->fin_rule; 8383 (void) strncpy(fino->fin_group, fin->fin_group, FR_GROUPLEN); 8384 fino->fin_fr = fin->fin_fr; 8385 fino->fin_error = fin->fin_error; 8386 fino->fin_mp = fin->fin_mp; 8387 fino->fin_m = fin->fin_m; 8388 m = fin->fin_m; 8389 if (m != NULL) { 8390 #if defined(MENTAT) && defined(_KERNEL) 8391 m->b_rptr -= elen; 8392 #else 8393 m->m_data -= elen; 8394 m->m_len += elen; 8395 #endif 8396 } 8397 return pass; 8398 } 8399 8400 8401 /* ------------------------------------------------------------------------ */ 8402 /* Function: ipf_matcharray_load */ 8403 /* Returns: int - 0 = success, else error */ 8404 /* Parameters: softc(I) - pointer to soft context main structure */ 8405 /* data(I) - pointer to ioctl data */ 8406 /* objp(I) - ipfobj_t structure to load data into */ 8407 /* arrayptr(I) - pointer to location to store array pointer */ 8408 /* */ 8409 /* This function loads in a mathing array through the ipfobj_t struct that */ 8410 /* describes it. Sanity checking and array size limitations are enforced */ 8411 /* in this function to prevent userspace from trying to load in something */ 8412 /* that is insanely big. Once the size of the array is known, the memory */ 8413 /* required is malloc'd and returned through changing *arrayptr. The */ 8414 /* contents of the array are verified before returning. Only in the event */ 8415 /* of a successful call is the caller required to free up the malloc area. */ 8416 /* ------------------------------------------------------------------------ */ 8417 int 8418 ipf_matcharray_load(ipf_main_softc_t *softc, void *data, ipfobj_t *objp, 8419 int **arrayptr) 8420 { 8421 int arraysize, *array, error; 8422 8423 *arrayptr = NULL; 8424 8425 error = BCOPYIN(data, objp, sizeof(*objp)); 8426 if (error != 0) { 8427 IPFERROR(116); 8428 return EFAULT; 8429 } 8430 8431 if (objp->ipfo_type != IPFOBJ_IPFEXPR) { 8432 IPFERROR(117); 8433 return EINVAL; 8434 } 8435 8436 if (((objp->ipfo_size & 3) != 0) || (objp->ipfo_size == 0) || 8437 (objp->ipfo_size > 1024)) { 8438 IPFERROR(118); 8439 return EINVAL; 8440 } 8441 8442 arraysize = objp->ipfo_size * sizeof(*array); 8443 KMALLOCS(array, int *, arraysize); 8444 if (array == NULL) { 8445 IPFERROR(119); 8446 return ENOMEM; 8447 } 8448 8449 error = COPYIN(objp->ipfo_ptr, array, arraysize); 8450 if (error != 0) { 8451 KFREES(array, arraysize); 8452 IPFERROR(120); 8453 return EFAULT; 8454 } 8455 8456 if (ipf_matcharray_verify(array, arraysize) != 0) { 8457 KFREES(array, arraysize); 8458 IPFERROR(121); 8459 return EINVAL; 8460 } 8461 8462 *arrayptr = array; 8463 return 0; 8464 } 8465 8466 8467 /* ------------------------------------------------------------------------ */ 8468 /* Function: ipf_matcharray_verify */ 8469 /* Returns: Nil */ 8470 /* Parameters: array(I) - pointer to matching array */ 8471 /* arraysize(I) - number of elements in the array */ 8472 /* */ 8473 /* Verify the contents of a matching array by stepping through each element */ 8474 /* in it. The actual commands in the array are not verified for */ 8475 /* correctness, only that all of the sizes are correctly within limits. */ 8476 /* ------------------------------------------------------------------------ */ 8477 int 8478 ipf_matcharray_verify(int *array, int arraysize) 8479 { 8480 int i, nelem, maxidx; 8481 ipfexp_t *e; 8482 8483 nelem = arraysize / sizeof(*array); 8484 8485 /* 8486 * Currently, it makes no sense to have an array less than 6 8487 * elements long - the initial size at the from, a single operation 8488 * (minimum 4 in length) and a trailer, for a total of 6. 8489 */ 8490 if ((array[0] < 6) || (arraysize < 24) || (arraysize > 4096)) { 8491 return -1; 8492 } 8493 8494 /* 8495 * Verify the size of data pointed to by array with how long 8496 * the array claims to be itself. 8497 */ 8498 if (array[0] * sizeof(*array) != arraysize) { 8499 return -1; 8500 } 8501 8502 maxidx = nelem - 1; 8503 /* 8504 * The last opcode in this array should be an IPF_EXP_END. 8505 */ 8506 if (array[maxidx] != IPF_EXP_END) { 8507 return -1; 8508 } 8509 8510 for (i = 1; i < maxidx; ) { 8511 e = (ipfexp_t *)(array + i); 8512 8513 /* 8514 * The length of the bits to check must be at least 1 8515 * (or else there is nothing to comapre with!) and it 8516 * cannot exceed the length of the data present. 8517 */ 8518 if ((e->ipfe_size < 1 ) || 8519 (e->ipfe_size + i > maxidx)) { 8520 return -1; 8521 } 8522 i += e->ipfe_size; 8523 } 8524 return 0; 8525 } 8526 8527 8528 /* ------------------------------------------------------------------------ */ 8529 /* Function: ipf_fr_matcharray */ 8530 /* Returns: int - 0 = match failed, else positive match */ 8531 /* Parameters: fin(I) - pointer to packet information */ 8532 /* array(I) - pointer to matching array */ 8533 /* */ 8534 /* This function is used to apply a matching array against a packet and */ 8535 /* return an indication of whether or not the packet successfully matches */ 8536 /* all of the commands in it. */ 8537 /* ------------------------------------------------------------------------ */ 8538 static int 8539 ipf_fr_matcharray(fr_info_t *fin, int *array) 8540 { 8541 int i, n, *x, rv, p; 8542 ipfexp_t *e; 8543 8544 rv = 0; 8545 n = array[0]; 8546 x = array + 1; 8547 8548 for (; n > 0; x += 3 + x[3], rv = 0) { 8549 e = (ipfexp_t *)x; 8550 if (e->ipfe_cmd == IPF_EXP_END) 8551 break; 8552 n -= e->ipfe_size; 8553 8554 /* 8555 * The upper 16 bits currently store the protocol value. 8556 * This is currently used with TCP and UDP port compares and 8557 * allows "tcp.port = 80" without requiring an explicit 8558 " "ip.pr = tcp" first. 8559 */ 8560 p = e->ipfe_cmd >> 16; 8561 if ((p != 0) && (p != fin->fin_p)) 8562 break; 8563 8564 switch (e->ipfe_cmd) 8565 { 8566 case IPF_EXP_IP_PR : 8567 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8568 rv |= (fin->fin_p == e->ipfe_arg0[i]); 8569 } 8570 break; 8571 8572 case IPF_EXP_IP_SRCADDR : 8573 if (fin->fin_v != 4) 8574 break; 8575 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8576 rv |= ((fin->fin_saddr & 8577 e->ipfe_arg0[i * 2 + 1]) == 8578 e->ipfe_arg0[i * 2]); 8579 } 8580 break; 8581 8582 case IPF_EXP_IP_DSTADDR : 8583 if (fin->fin_v != 4) 8584 break; 8585 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8586 rv |= ((fin->fin_daddr & 8587 e->ipfe_arg0[i * 2 + 1]) == 8588 e->ipfe_arg0[i * 2]); 8589 } 8590 break; 8591 8592 case IPF_EXP_IP_ADDR : 8593 if (fin->fin_v != 4) 8594 break; 8595 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8596 rv |= ((fin->fin_saddr & 8597 e->ipfe_arg0[i * 2 + 1]) == 8598 e->ipfe_arg0[i * 2]) || 8599 ((fin->fin_daddr & 8600 e->ipfe_arg0[i * 2 + 1]) == 8601 e->ipfe_arg0[i * 2]); 8602 } 8603 break; 8604 8605 #ifdef USE_INET6 8606 case IPF_EXP_IP6_SRCADDR : 8607 if (fin->fin_v != 6) 8608 break; 8609 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8610 rv |= IP6_MASKEQ(&fin->fin_src6, 8611 &e->ipfe_arg0[i * 8 + 4], 8612 &e->ipfe_arg0[i * 8]); 8613 } 8614 break; 8615 8616 case IPF_EXP_IP6_DSTADDR : 8617 if (fin->fin_v != 6) 8618 break; 8619 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8620 rv |= IP6_MASKEQ(&fin->fin_dst6, 8621 &e->ipfe_arg0[i * 8 + 4], 8622 &e->ipfe_arg0[i * 8]); 8623 } 8624 break; 8625 8626 case IPF_EXP_IP6_ADDR : 8627 if (fin->fin_v != 6) 8628 break; 8629 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8630 rv |= IP6_MASKEQ(&fin->fin_src6, 8631 &e->ipfe_arg0[i * 8 + 4], 8632 &e->ipfe_arg0[i * 8]) || 8633 IP6_MASKEQ(&fin->fin_dst6, 8634 &e->ipfe_arg0[i * 8 + 4], 8635 &e->ipfe_arg0[i * 8]); 8636 } 8637 break; 8638 #endif 8639 8640 case IPF_EXP_UDP_PORT : 8641 case IPF_EXP_TCP_PORT : 8642 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8643 rv |= (fin->fin_sport == e->ipfe_arg0[i]) || 8644 (fin->fin_dport == e->ipfe_arg0[i]); 8645 } 8646 break; 8647 8648 case IPF_EXP_UDP_SPORT : 8649 case IPF_EXP_TCP_SPORT : 8650 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8651 rv |= (fin->fin_sport == e->ipfe_arg0[i]); 8652 } 8653 break; 8654 8655 case IPF_EXP_UDP_DPORT : 8656 case IPF_EXP_TCP_DPORT : 8657 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8658 rv |= (fin->fin_dport == e->ipfe_arg0[i]); 8659 } 8660 break; 8661 8662 case IPF_EXP_TCP_FLAGS : 8663 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8664 rv |= ((fin->fin_tcpf & 8665 e->ipfe_arg0[i * 2 + 1]) == 8666 e->ipfe_arg0[i * 2]); 8667 } 8668 break; 8669 } 8670 rv ^= e->ipfe_not; 8671 8672 if (rv == 0) 8673 break; 8674 } 8675 8676 return rv; 8677 } 8678 8679 8680 /* ------------------------------------------------------------------------ */ 8681 /* Function: ipf_queueflush */ 8682 /* Returns: int - number of entries flushed (0 = none) */ 8683 /* Parameters: softc(I) - pointer to soft context main structure */ 8684 /* deletefn(I) - function to call to delete entry */ 8685 /* ipfqs(I) - top of the list of ipf internal queues */ 8686 /* userqs(I) - top of the list of user defined timeouts */ 8687 /* */ 8688 /* This fucntion gets called when the state/NAT hash tables fill up and we */ 8689 /* need to try a bit harder to free up some space. The algorithm used here */ 8690 /* split into two parts but both halves have the same goal: to reduce the */ 8691 /* number of connections considered to be "active" to the low watermark. */ 8692 /* There are two steps in doing this: */ 8693 /* 1) Remove any TCP connections that are already considered to be "closed" */ 8694 /* but have not yet been removed from the state table. The two states */ 8695 /* TCPS_TIME_WAIT and TCPS_CLOSED are considered to be the perfect */ 8696 /* candidates for this style of removal. If freeing up entries in */ 8697 /* CLOSED or both CLOSED and TIME_WAIT brings us to the low watermark, */ 8698 /* we do not go on to step 2. */ 8699 /* */ 8700 /* 2) Look for the oldest entries on each timeout queue and free them if */ 8701 /* they are within the given window we are considering. Where the */ 8702 /* window starts and the steps taken to increase its size depend upon */ 8703 /* how long ipf has been running (ipf_ticks.) Anything modified in the */ 8704 /* last 30 seconds is not touched. */ 8705 /* touched */ 8706 /* die ipf_ticks 30*1.5 1800*1.5 | 43200*1.5 */ 8707 /* | | | | | | */ 8708 /* future <--+----------+--------+-----------+-----+-----+-----------> past */ 8709 /* now \_int=30s_/ \_int=1hr_/ \_int=12hr */ 8710 /* */ 8711 /* Points to note: */ 8712 /* - tqe_die is the time, in the future, when entries die. */ 8713 /* - tqe_die - ipf_ticks is how long left the connection has to live in ipf */ 8714 /* ticks. */ 8715 /* - tqe_touched is when the entry was last used by NAT/state */ 8716 /* - the closer tqe_touched is to ipf_ticks, the further tqe_die will be */ 8717 /* ipf_ticks any given timeout queue and vice versa. */ 8718 /* - both tqe_die and tqe_touched increase over time */ 8719 /* - timeout queues are sorted with the highest value of tqe_die at the */ 8720 /* bottom and therefore the smallest values of each are at the top */ 8721 /* - the pointer passed in as ipfqs should point to an array of timeout */ 8722 /* queues representing each of the TCP states */ 8723 /* */ 8724 /* We start by setting up a maximum range to scan for things to move of */ 8725 /* iend (newest) to istart (oldest) in chunks of "interval". If nothing is */ 8726 /* found in that range, "interval" is adjusted (so long as it isn't 30) and */ 8727 /* we start again with a new value for "iend" and "istart". This is */ 8728 /* continued until we either finish the scan of 30 second intervals or the */ 8729 /* low water mark is reached. */ 8730 /* ------------------------------------------------------------------------ */ 8731 int 8732 ipf_queueflush(ipf_main_softc_t *softc, ipftq_delete_fn_t deletefn, 8733 ipftq_t *ipfqs, ipftq_t *userqs, u_int *activep, int size, int low) 8734 { 8735 u_long interval, istart, iend; 8736 ipftq_t *ifq, *ifqnext; 8737 ipftqent_t *tqe, *tqn; 8738 int removed = 0; 8739 8740 for (tqn = ipfqs[IPF_TCPS_CLOSED].ifq_head; ((tqe = tqn) != NULL); ) { 8741 tqn = tqe->tqe_next; 8742 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8743 removed++; 8744 } 8745 if ((*activep * 100 / size) > low) { 8746 for (tqn = ipfqs[IPF_TCPS_TIME_WAIT].ifq_head; 8747 ((tqe = tqn) != NULL); ) { 8748 tqn = tqe->tqe_next; 8749 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8750 removed++; 8751 } 8752 } 8753 8754 if ((*activep * 100 / size) <= low) { 8755 return removed; 8756 } 8757 8758 /* 8759 * NOTE: Use of "* 15 / 10" is required here because if "* 1.5" is 8760 * used then the operations are upgraded to floating point 8761 * and kernels don't like floating point... 8762 */ 8763 if (softc->ipf_ticks > IPF_TTLVAL(43200 * 15 / 10)) { 8764 istart = IPF_TTLVAL(86400 * 4); 8765 interval = IPF_TTLVAL(43200); 8766 } else if (softc->ipf_ticks > IPF_TTLVAL(1800 * 15 / 10)) { 8767 istart = IPF_TTLVAL(43200); 8768 interval = IPF_TTLVAL(1800); 8769 } else if (softc->ipf_ticks > IPF_TTLVAL(30 * 15 / 10)) { 8770 istart = IPF_TTLVAL(1800); 8771 interval = IPF_TTLVAL(30); 8772 } else { 8773 return 0; 8774 } 8775 if (istart > softc->ipf_ticks) { 8776 if (softc->ipf_ticks - interval < interval) 8777 istart = interval; 8778 else 8779 istart = (softc->ipf_ticks / interval) * interval; 8780 } 8781 8782 iend = softc->ipf_ticks - interval; 8783 8784 while ((*activep * 100 / size) > low) { 8785 u_long try; 8786 8787 try = softc->ipf_ticks - istart; 8788 8789 for (ifq = ipfqs; ifq != NULL; ifq = ifq->ifq_next) { 8790 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { 8791 if (try < tqe->tqe_touched) 8792 break; 8793 tqn = tqe->tqe_next; 8794 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8795 removed++; 8796 } 8797 } 8798 8799 for (ifq = userqs; ifq != NULL; ifq = ifqnext) { 8800 ifqnext = ifq->ifq_next; 8801 8802 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { 8803 if (try < tqe->tqe_touched) 8804 break; 8805 tqn = tqe->tqe_next; 8806 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8807 removed++; 8808 } 8809 } 8810 8811 if (try >= iend) { 8812 if (interval == IPF_TTLVAL(43200)) { 8813 interval = IPF_TTLVAL(1800); 8814 } else if (interval == IPF_TTLVAL(1800)) { 8815 interval = IPF_TTLVAL(30); 8816 } else { 8817 break; 8818 } 8819 if (interval >= softc->ipf_ticks) 8820 break; 8821 8822 iend = softc->ipf_ticks - interval; 8823 } 8824 istart -= interval; 8825 } 8826 8827 return removed; 8828 } 8829 8830 8831 /* ------------------------------------------------------------------------ */ 8832 /* Function: ipf_deliverlocal */ 8833 /* Returns: int - 1 = local address, 0 = non-local address */ 8834 /* Parameters: softc(I) - pointer to soft context main structure */ 8835 /* ipversion(I) - IP protocol version (4 or 6) */ 8836 /* ifp(I) - network interface pointer */ 8837 /* ipaddr(I) - IPv4/6 destination address */ 8838 /* */ 8839 /* This fucntion is used to determine in the address "ipaddr" belongs to */ 8840 /* the network interface represented by ifp. */ 8841 /* ------------------------------------------------------------------------ */ 8842 int 8843 ipf_deliverlocal(ipf_main_softc_t *softc, int ipversion, void *ifp, 8844 i6addr_t *ipaddr) 8845 { 8846 i6addr_t addr; 8847 int islocal = 0; 8848 8849 if (ipversion == 4) { 8850 if (ipf_ifpaddr(softc, 4, FRI_NORMAL, ifp, &addr, NULL) == 0) { 8851 if (addr.in4.s_addr == ipaddr->in4.s_addr) 8852 islocal = 1; 8853 } 8854 8855 #ifdef USE_INET6 8856 } else if (ipversion == 6) { 8857 if (ipf_ifpaddr(softc, 6, FRI_NORMAL, ifp, &addr, NULL) == 0) { 8858 if (IP6_EQ(&addr, ipaddr)) 8859 islocal = 1; 8860 } 8861 #endif 8862 } 8863 8864 return islocal; 8865 } 8866 8867 8868 /* ------------------------------------------------------------------------ */ 8869 /* Function: ipf_settimeout */ 8870 /* Returns: int - 0 = success, -1 = failure */ 8871 /* Parameters: softc(I) - pointer to soft context main structure */ 8872 /* t(I) - pointer to tuneable array entry */ 8873 /* p(I) - pointer to values passed in to apply */ 8874 /* */ 8875 /* This function is called to set the timeout values for each distinct */ 8876 /* queue timeout that is available. When called, it calls into both the */ 8877 /* state and NAT code, telling them to update their timeout queues. */ 8878 /* ------------------------------------------------------------------------ */ 8879 static int 8880 ipf_settimeout(struct ipf_main_softc_s *softc, ipftuneable_t *t, 8881 ipftuneval_t *p) 8882 { 8883 8884 /* 8885 * ipf_interror should be set by the functions called here, not 8886 * by this function - it's just a middle man. 8887 */ 8888 if (ipf_state_settimeout(softc, t, p) == -1) 8889 return -1; 8890 if (ipf_nat_settimeout(softc, t, p) == -1) 8891 return -1; 8892 return 0; 8893 } 8894 8895 8896 /* ------------------------------------------------------------------------ */ 8897 /* Function: ipf_apply_timeout */ 8898 /* Returns: int - 0 = success, -1 = failure */ 8899 /* Parameters: head(I) - pointer to tuneable array entry */ 8900 /* seconds(I) - pointer to values passed in to apply */ 8901 /* */ 8902 /* This function applies a timeout of "seconds" to the timeout queue that */ 8903 /* is pointed to by "head". All entries on this list have an expiration */ 8904 /* set to be the current tick value of ipf plus the ttl. Given that this */ 8905 /* function should only be called when the delta is non-zero, the task is */ 8906 /* to walk the entire list and apply the change. The sort order will not */ 8907 /* change. The only catch is that this is O(n) across the list, so if the */ 8908 /* queue has lots of entries (10s of thousands or 100s of thousands), it */ 8909 /* could take a relatively long time to work through them all. */ 8910 /* ------------------------------------------------------------------------ */ 8911 void 8912 ipf_apply_timeout(ipftq_t *head, u_int seconds) 8913 { 8914 u_int oldtimeout, newtimeout; 8915 ipftqent_t *tqe; 8916 int delta; 8917 8918 MUTEX_ENTER(&head->ifq_lock); 8919 oldtimeout = head->ifq_ttl; 8920 newtimeout = IPF_TTLVAL(seconds); 8921 delta = oldtimeout - newtimeout; 8922 8923 head->ifq_ttl = newtimeout; 8924 8925 for (tqe = head->ifq_head; tqe != NULL; tqe = tqe->tqe_next) { 8926 tqe->tqe_die += delta; 8927 } 8928 MUTEX_EXIT(&head->ifq_lock); 8929 } 8930 8931 8932 /* ------------------------------------------------------------------------ */ 8933 /* Function: ipf_settimeout_tcp */ 8934 /* Returns: int - 0 = successfully applied, -1 = failed */ 8935 /* Parameters: t(I) - pointer to tuneable to change */ 8936 /* p(I) - pointer to new timeout information */ 8937 /* tab(I) - pointer to table of TCP queues */ 8938 /* */ 8939 /* This function applies the new timeout (p) to the TCP tunable (t) and */ 8940 /* updates all of the entries on the relevant timeout queue by calling */ 8941 /* ipf_apply_timeout(). */ 8942 /* ------------------------------------------------------------------------ */ 8943 int 8944 ipf_settimeout_tcp(ipftuneable_t *t, ipftuneval_t *p, ipftq_t *tab) 8945 { 8946 if (!strcmp(t->ipft_name, "tcp_idle_timeout") || 8947 !strcmp(t->ipft_name, "tcp_established")) { 8948 ipf_apply_timeout(&tab[IPF_TCPS_ESTABLISHED], p->ipftu_int); 8949 } else if (!strcmp(t->ipft_name, "tcp_close_wait")) { 8950 ipf_apply_timeout(&tab[IPF_TCPS_CLOSE_WAIT], p->ipftu_int); 8951 } else if (!strcmp(t->ipft_name, "tcp_last_ack")) { 8952 ipf_apply_timeout(&tab[IPF_TCPS_LAST_ACK], p->ipftu_int); 8953 } else if (!strcmp(t->ipft_name, "tcp_timeout")) { 8954 ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int); 8955 ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int); 8956 ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int); 8957 } else if (!strcmp(t->ipft_name, "tcp_listen")) { 8958 ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int); 8959 } else if (!strcmp(t->ipft_name, "tcp_half_established")) { 8960 ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int); 8961 } else if (!strcmp(t->ipft_name, "tcp_closing")) { 8962 ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int); 8963 } else if (!strcmp(t->ipft_name, "tcp_syn_received")) { 8964 ipf_apply_timeout(&tab[IPF_TCPS_SYN_RECEIVED], p->ipftu_int); 8965 } else if (!strcmp(t->ipft_name, "tcp_syn_sent")) { 8966 ipf_apply_timeout(&tab[IPF_TCPS_SYN_SENT], p->ipftu_int); 8967 } else if (!strcmp(t->ipft_name, "tcp_closed")) { 8968 ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int); 8969 } else if (!strcmp(t->ipft_name, "tcp_half_closed")) { 8970 ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int); 8971 } else if (!strcmp(t->ipft_name, "tcp_time_wait")) { 8972 ipf_apply_timeout(&tab[IPF_TCPS_TIME_WAIT], p->ipftu_int); 8973 } else { 8974 /* 8975 * ipf_interror isn't set here because it should be set 8976 * by whatever called this function. 8977 */ 8978 return -1; 8979 } 8980 return 0; 8981 } 8982 8983 8984 /* ------------------------------------------------------------------------ */ 8985 /* Function: ipf_main_soft_create */ 8986 /* Returns: NULL = failure, else success */ 8987 /* Parameters: arg(I) - pointer to soft context structure if already allocd */ 8988 /* */ 8989 /* Create the foundation soft context structure. In circumstances where it */ 8990 /* is not required to dynamically allocate the context, a pointer can be */ 8991 /* passed in (rather than NULL) to a structure to be initialised. */ 8992 /* The main thing of interest is that a number of locks are initialised */ 8993 /* here instead of in the where might be expected - in the relevant create */ 8994 /* function elsewhere. This is done because the current locking design has */ 8995 /* some areas where these locks are used outside of their module. */ 8996 /* Possibly the most important exercise that is done here is setting of all */ 8997 /* the timeout values, allowing them to be changed before init(). */ 8998 /* ------------------------------------------------------------------------ */ 8999 void * 9000 ipf_main_soft_create(void *arg) 9001 { 9002 ipf_main_softc_t *softc; 9003 9004 if (arg == NULL) { 9005 KMALLOC(softc, ipf_main_softc_t *); 9006 if (softc == NULL) 9007 return NULL; 9008 } else { 9009 softc = arg; 9010 } 9011 9012 bzero((char *)softc, sizeof(*softc)); 9013 9014 /* 9015 * This serves as a flag as to whether or not the softc should be 9016 * free'd when _destroy is called. 9017 */ 9018 softc->ipf_dynamic_softc = (arg == NULL) ? 1 : 0; 9019 9020 softc->ipf_tuners = ipf_tune_array_copy(softc, 9021 sizeof(ipf_main_tuneables), 9022 ipf_main_tuneables); 9023 if (softc->ipf_tuners == NULL) { 9024 ipf_main_soft_destroy(softc); 9025 return NULL; 9026 } 9027 9028 MUTEX_INIT(&softc->ipf_rw, "ipf rw mutex"); 9029 MUTEX_INIT(&softc->ipf_timeoutlock, "ipf timeout lock"); 9030 RWLOCK_INIT(&softc->ipf_global, "ipf filter load/unload mutex"); 9031 RWLOCK_INIT(&softc->ipf_mutex, "ipf filter rwlock"); 9032 RWLOCK_INIT(&softc->ipf_tokens, "ipf token rwlock"); 9033 RWLOCK_INIT(&softc->ipf_state, "ipf state rwlock"); 9034 RWLOCK_INIT(&softc->ipf_nat, "ipf IP NAT rwlock"); 9035 RWLOCK_INIT(&softc->ipf_poolrw, "ipf pool rwlock"); 9036 RWLOCK_INIT(&softc->ipf_frag, "ipf frag rwlock"); 9037 9038 softc->ipf_token_head = NULL; 9039 softc->ipf_token_tail = &softc->ipf_token_head; 9040 9041 softc->ipf_tcpidletimeout = FIVE_DAYS; 9042 softc->ipf_tcpclosewait = IPF_TTLVAL(2 * TCP_MSL); 9043 softc->ipf_tcplastack = IPF_TTLVAL(30); 9044 softc->ipf_tcptimewait = IPF_TTLVAL(2 * TCP_MSL); 9045 softc->ipf_tcptimeout = IPF_TTLVAL(2 * TCP_MSL); 9046 softc->ipf_tcpsynsent = IPF_TTLVAL(2 * TCP_MSL); 9047 softc->ipf_tcpsynrecv = IPF_TTLVAL(2 * TCP_MSL); 9048 softc->ipf_tcpclosed = IPF_TTLVAL(30); 9049 softc->ipf_tcphalfclosed = IPF_TTLVAL(2 * 3600); 9050 softc->ipf_udptimeout = IPF_TTLVAL(120); 9051 softc->ipf_udpacktimeout = IPF_TTLVAL(12); 9052 softc->ipf_icmptimeout = IPF_TTLVAL(60); 9053 softc->ipf_icmpacktimeout = IPF_TTLVAL(6); 9054 softc->ipf_iptimeout = IPF_TTLVAL(60); 9055 9056 #if defined(IPFILTER_DEFAULT_BLOCK) 9057 softc->ipf_pass = FR_BLOCK|FR_NOMATCH; 9058 #else 9059 softc->ipf_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH; 9060 #endif 9061 softc->ipf_minttl = 4; 9062 softc->ipf_icmpminfragmtu = 68; 9063 softc->ipf_flags = IPF_LOGGING; 9064 9065 return softc; 9066 } 9067 9068 /* ------------------------------------------------------------------------ */ 9069 /* Function: ipf_main_soft_init */ 9070 /* Returns: 0 = success, -1 = failure */ 9071 /* Parameters: softc(I) - pointer to soft context main structure */ 9072 /* */ 9073 /* A null-op function that exists as a placeholder so that the flow in */ 9074 /* other functions is obvious. */ 9075 /* ------------------------------------------------------------------------ */ 9076 /*ARGSUSED*/ 9077 int 9078 ipf_main_soft_init(ipf_main_softc_t *softc) 9079 { 9080 return 0; 9081 } 9082 9083 9084 /* ------------------------------------------------------------------------ */ 9085 /* Function: ipf_main_soft_destroy */ 9086 /* Returns: void */ 9087 /* Parameters: softc(I) - pointer to soft context main structure */ 9088 /* */ 9089 /* Undo everything that we did in ipf_main_soft_create. */ 9090 /* */ 9091 /* The most important check that needs to be made here is whether or not */ 9092 /* the structure was allocated by ipf_main_soft_create() by checking what */ 9093 /* value is stored in ipf_dynamic_main. */ 9094 /* ------------------------------------------------------------------------ */ 9095 /*ARGSUSED*/ 9096 void 9097 ipf_main_soft_destroy(ipf_main_softc_t *softc) 9098 { 9099 9100 RW_DESTROY(&softc->ipf_frag); 9101 RW_DESTROY(&softc->ipf_poolrw); 9102 RW_DESTROY(&softc->ipf_nat); 9103 RW_DESTROY(&softc->ipf_state); 9104 RW_DESTROY(&softc->ipf_tokens); 9105 RW_DESTROY(&softc->ipf_mutex); 9106 RW_DESTROY(&softc->ipf_global); 9107 MUTEX_DESTROY(&softc->ipf_timeoutlock); 9108 MUTEX_DESTROY(&softc->ipf_rw); 9109 9110 if (softc->ipf_tuners != NULL) { 9111 KFREES(softc->ipf_tuners, sizeof(ipf_main_tuneables)); 9112 } 9113 if (softc->ipf_dynamic_softc == 1) { 9114 KFREE(softc); 9115 } 9116 } 9117 9118 9119 /* ------------------------------------------------------------------------ */ 9120 /* Function: ipf_main_soft_fini */ 9121 /* Returns: 0 = success, -1 = failure */ 9122 /* Parameters: softc(I) - pointer to soft context main structure */ 9123 /* */ 9124 /* Clean out the rules which have been added since _init was last called, */ 9125 /* the only dynamic part of the mainline. */ 9126 /* ------------------------------------------------------------------------ */ 9127 int 9128 ipf_main_soft_fini(ipf_main_softc_t *softc) 9129 { 9130 (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE|FR_INACTIVE); 9131 (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE); 9132 (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE|FR_INACTIVE); 9133 (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE); 9134 9135 return 0; 9136 } 9137 9138 9139 /* ------------------------------------------------------------------------ */ 9140 /* Function: ipf_main_load */ 9141 /* Returns: 0 = success, -1 = failure */ 9142 /* Parameters: none */ 9143 /* */ 9144 /* Handle global initialisation that needs to be done for the base part of */ 9145 /* IPFilter. At present this just amounts to initialising some ICMP lookup */ 9146 /* arrays that get used by the state/NAT code. */ 9147 /* ------------------------------------------------------------------------ */ 9148 int 9149 ipf_main_load(void) 9150 { 9151 int i; 9152 9153 /* fill icmp reply type table */ 9154 for (i = 0; i <= ICMP_MAXTYPE; i++) 9155 icmpreplytype4[i] = -1; 9156 icmpreplytype4[ICMP_ECHO] = ICMP_ECHOREPLY; 9157 icmpreplytype4[ICMP_TSTAMP] = ICMP_TSTAMPREPLY; 9158 icmpreplytype4[ICMP_IREQ] = ICMP_IREQREPLY; 9159 icmpreplytype4[ICMP_MASKREQ] = ICMP_MASKREPLY; 9160 9161 #ifdef USE_INET6 9162 /* fill icmp reply type table */ 9163 for (i = 0; i <= ICMP6_MAXTYPE; i++) 9164 icmpreplytype6[i] = -1; 9165 icmpreplytype6[ICMP6_ECHO_REQUEST] = ICMP6_ECHO_REPLY; 9166 icmpreplytype6[ICMP6_MEMBERSHIP_QUERY] = ICMP6_MEMBERSHIP_REPORT; 9167 icmpreplytype6[ICMP6_NI_QUERY] = ICMP6_NI_REPLY; 9168 icmpreplytype6[ND_ROUTER_SOLICIT] = ND_ROUTER_ADVERT; 9169 icmpreplytype6[ND_NEIGHBOR_SOLICIT] = ND_NEIGHBOR_ADVERT; 9170 #endif 9171 9172 return 0; 9173 } 9174 9175 9176 /* ------------------------------------------------------------------------ */ 9177 /* Function: ipf_main_unload */ 9178 /* Returns: 0 = success, -1 = failure */ 9179 /* Parameters: none */ 9180 /* */ 9181 /* A null-op function that exists as a placeholder so that the flow in */ 9182 /* other functions is obvious. */ 9183 /* ------------------------------------------------------------------------ */ 9184 int 9185 ipf_main_unload(void) 9186 { 9187 return 0; 9188 } 9189 9190 9191 /* ------------------------------------------------------------------------ */ 9192 /* Function: ipf_load_all */ 9193 /* Returns: 0 = success, -1 = failure */ 9194 /* Parameters: none */ 9195 /* */ 9196 /* Work through all of the subsystems inside IPFilter and call the load */ 9197 /* function for each in an order that won't lead to a crash :) */ 9198 /* ------------------------------------------------------------------------ */ 9199 int 9200 ipf_load_all(void) 9201 { 9202 if (ipf_main_load() == -1) 9203 return -1; 9204 9205 if (ipf_state_main_load() == -1) 9206 return -1; 9207 9208 if (ipf_nat_main_load() == -1) 9209 return -1; 9210 9211 if (ipf_frag_main_load() == -1) 9212 return -1; 9213 9214 if (ipf_auth_main_load() == -1) 9215 return -1; 9216 9217 if (ipf_proxy_main_load() == -1) 9218 return -1; 9219 9220 return 0; 9221 } 9222 9223 9224 /* ------------------------------------------------------------------------ */ 9225 /* Function: ipf_unload_all */ 9226 /* Returns: 0 = success, -1 = failure */ 9227 /* Parameters: none */ 9228 /* */ 9229 /* Work through all of the subsystems inside IPFilter and call the unload */ 9230 /* function for each in an order that won't lead to a crash :) */ 9231 /* ------------------------------------------------------------------------ */ 9232 int 9233 ipf_unload_all(void) 9234 { 9235 if (ipf_proxy_main_unload() == -1) 9236 return -1; 9237 9238 if (ipf_auth_main_unload() == -1) 9239 return -1; 9240 9241 if (ipf_frag_main_unload() == -1) 9242 return -1; 9243 9244 if (ipf_nat_main_unload() == -1) 9245 return -1; 9246 9247 if (ipf_state_main_unload() == -1) 9248 return -1; 9249 9250 if (ipf_main_unload() == -1) 9251 return -1; 9252 9253 return 0; 9254 } 9255 9256 9257 /* ------------------------------------------------------------------------ */ 9258 /* Function: ipf_create_all */ 9259 /* Returns: NULL = failure, else success */ 9260 /* Parameters: arg(I) - pointer to soft context main structure */ 9261 /* */ 9262 /* Work through all of the subsystems inside IPFilter and call the create */ 9263 /* function for each in an order that won't lead to a crash :) */ 9264 /* ------------------------------------------------------------------------ */ 9265 ipf_main_softc_t * 9266 ipf_create_all(void *arg) 9267 { 9268 ipf_main_softc_t *softc; 9269 9270 softc = ipf_main_soft_create(arg); 9271 if (softc == NULL) 9272 return NULL; 9273 9274 #ifdef IPFILTER_LOG 9275 softc->ipf_log_soft = ipf_log_soft_create(softc); 9276 if (softc->ipf_log_soft == NULL) { 9277 ipf_destroy_all(softc); 9278 return NULL; 9279 } 9280 #endif 9281 9282 softc->ipf_lookup_soft = ipf_lookup_soft_create(softc); 9283 if (softc->ipf_lookup_soft == NULL) { 9284 ipf_destroy_all(softc); 9285 return NULL; 9286 } 9287 9288 softc->ipf_sync_soft = ipf_sync_soft_create(softc); 9289 if (softc->ipf_sync_soft == NULL) { 9290 ipf_destroy_all(softc); 9291 return NULL; 9292 } 9293 9294 softc->ipf_state_soft = ipf_state_soft_create(softc); 9295 if (softc->ipf_state_soft == NULL) { 9296 ipf_destroy_all(softc); 9297 return NULL; 9298 } 9299 9300 softc->ipf_nat_soft = ipf_nat_soft_create(softc); 9301 if (softc->ipf_nat_soft == NULL) { 9302 ipf_destroy_all(softc); 9303 return NULL; 9304 } 9305 9306 softc->ipf_frag_soft = ipf_frag_soft_create(softc); 9307 if (softc->ipf_frag_soft == NULL) { 9308 ipf_destroy_all(softc); 9309 return NULL; 9310 } 9311 9312 softc->ipf_auth_soft = ipf_auth_soft_create(softc); 9313 if (softc->ipf_auth_soft == NULL) { 9314 ipf_destroy_all(softc); 9315 return NULL; 9316 } 9317 9318 softc->ipf_proxy_soft = ipf_proxy_soft_create(softc); 9319 if (softc->ipf_proxy_soft == NULL) { 9320 ipf_destroy_all(softc); 9321 return NULL; 9322 } 9323 9324 return softc; 9325 } 9326 9327 9328 /* ------------------------------------------------------------------------ */ 9329 /* Function: ipf_destroy_all */ 9330 /* Returns: void */ 9331 /* Parameters: softc(I) - pointer to soft context main structure */ 9332 /* */ 9333 /* Work through all of the subsystems inside IPFilter and call the destroy */ 9334 /* function for each in an order that won't lead to a crash :) */ 9335 /* */ 9336 /* Every one of these functions is expected to succeed, so there is no */ 9337 /* checking of return values. */ 9338 /* ------------------------------------------------------------------------ */ 9339 void 9340 ipf_destroy_all(ipf_main_softc_t *softc) 9341 { 9342 9343 if (softc->ipf_state_soft != NULL) { 9344 ipf_state_soft_destroy(softc, softc->ipf_state_soft); 9345 softc->ipf_state_soft = NULL; 9346 } 9347 9348 if (softc->ipf_nat_soft != NULL) { 9349 ipf_nat_soft_destroy(softc, softc->ipf_nat_soft); 9350 softc->ipf_nat_soft = NULL; 9351 } 9352 9353 if (softc->ipf_frag_soft != NULL) { 9354 ipf_frag_soft_destroy(softc, softc->ipf_frag_soft); 9355 softc->ipf_frag_soft = NULL; 9356 } 9357 9358 if (softc->ipf_auth_soft != NULL) { 9359 ipf_auth_soft_destroy(softc, softc->ipf_auth_soft); 9360 softc->ipf_auth_soft = NULL; 9361 } 9362 9363 if (softc->ipf_proxy_soft != NULL) { 9364 ipf_proxy_soft_destroy(softc, softc->ipf_proxy_soft); 9365 softc->ipf_proxy_soft = NULL; 9366 } 9367 9368 if (softc->ipf_sync_soft != NULL) { 9369 ipf_sync_soft_destroy(softc, softc->ipf_sync_soft); 9370 softc->ipf_sync_soft = NULL; 9371 } 9372 9373 if (softc->ipf_lookup_soft != NULL) { 9374 ipf_lookup_soft_destroy(softc, softc->ipf_lookup_soft); 9375 softc->ipf_lookup_soft = NULL; 9376 } 9377 9378 #ifdef IPFILTER_LOG 9379 if (softc->ipf_log_soft != NULL) { 9380 ipf_log_soft_destroy(softc, softc->ipf_log_soft); 9381 softc->ipf_log_soft = NULL; 9382 } 9383 #endif 9384 9385 ipf_main_soft_destroy(softc); 9386 } 9387 9388 9389 /* ------------------------------------------------------------------------ */ 9390 /* Function: ipf_init_all */ 9391 /* Returns: 0 = success, -1 = failure */ 9392 /* Parameters: softc(I) - pointer to soft context main structure */ 9393 /* */ 9394 /* Work through all of the subsystems inside IPFilter and call the init */ 9395 /* function for each in an order that won't lead to a crash :) */ 9396 /* ------------------------------------------------------------------------ */ 9397 int 9398 ipf_init_all(ipf_main_softc_t *softc) 9399 { 9400 9401 if (ipf_main_soft_init(softc) == -1) 9402 return -1; 9403 9404 #ifdef IPFILTER_LOG 9405 if (ipf_log_soft_init(softc, softc->ipf_log_soft) == -1) 9406 return -1; 9407 #endif 9408 9409 if (ipf_lookup_soft_init(softc, softc->ipf_lookup_soft) == -1) 9410 return -1; 9411 9412 if (ipf_sync_soft_init(softc, softc->ipf_sync_soft) == -1) 9413 return -1; 9414 9415 if (ipf_state_soft_init(softc, softc->ipf_state_soft) == -1) 9416 return -1; 9417 9418 if (ipf_nat_soft_init(softc, softc->ipf_nat_soft) == -1) 9419 return -1; 9420 9421 if (ipf_frag_soft_init(softc, softc->ipf_frag_soft) == -1) 9422 return -1; 9423 9424 if (ipf_auth_soft_init(softc, softc->ipf_auth_soft) == -1) 9425 return -1; 9426 9427 if (ipf_proxy_soft_init(softc, softc->ipf_proxy_soft) == -1) 9428 return -1; 9429 9430 return 0; 9431 } 9432 9433 9434 /* ------------------------------------------------------------------------ */ 9435 /* Function: ipf_fini_all */ 9436 /* Returns: 0 = success, -1 = failure */ 9437 /* Parameters: softc(I) - pointer to soft context main structure */ 9438 /* */ 9439 /* Work through all of the subsystems inside IPFilter and call the fini */ 9440 /* function for each in an order that won't lead to a crash :) */ 9441 /* ------------------------------------------------------------------------ */ 9442 int 9443 ipf_fini_all(ipf_main_softc_t *softc) 9444 { 9445 9446 ipf_token_flush(softc); 9447 9448 if (ipf_proxy_soft_fini(softc, softc->ipf_proxy_soft) == -1) 9449 return -1; 9450 9451 if (ipf_auth_soft_fini(softc, softc->ipf_auth_soft) == -1) 9452 return -1; 9453 9454 if (ipf_frag_soft_fini(softc, softc->ipf_frag_soft) == -1) 9455 return -1; 9456 9457 if (ipf_nat_soft_fini(softc, softc->ipf_nat_soft) == -1) 9458 return -1; 9459 9460 if (ipf_state_soft_fini(softc, softc->ipf_state_soft) == -1) 9461 return -1; 9462 9463 if (ipf_sync_soft_fini(softc, softc->ipf_sync_soft) == -1) 9464 return -1; 9465 9466 if (ipf_lookup_soft_fini(softc, softc->ipf_lookup_soft) == -1) 9467 return -1; 9468 9469 #ifdef IPFILTER_LOG 9470 if (ipf_log_soft_fini(softc, softc->ipf_log_soft) == -1) 9471 return -1; 9472 #endif 9473 9474 if (ipf_main_soft_fini(softc) == -1) 9475 return -1; 9476 9477 return 0; 9478 } 9479 9480 9481 /* ------------------------------------------------------------------------ */ 9482 /* Function: ipf_rule_expire */ 9483 /* Returns: Nil */ 9484 /* Parameters: softc(I) - pointer to soft context main structure */ 9485 /* */ 9486 /* At present this function exists just to support temporary addition of */ 9487 /* firewall rules. Both inactive and active lists are scanned for items to */ 9488 /* purge, as by rights, the expiration is computed as soon as the rule is */ 9489 /* loaded in. */ 9490 /* ------------------------------------------------------------------------ */ 9491 void 9492 ipf_rule_expire(ipf_main_softc_t *softc) 9493 { 9494 frentry_t *fr; 9495 9496 if ((softc->ipf_rule_explist[0] == NULL) && 9497 (softc->ipf_rule_explist[1] == NULL)) 9498 return; 9499 9500 WRITE_ENTER(&softc->ipf_mutex); 9501 9502 while ((fr = softc->ipf_rule_explist[0]) != NULL) { 9503 /* 9504 * Because the list is kept sorted on insertion, the fist 9505 * one that dies in the future means no more work to do. 9506 */ 9507 if (fr->fr_die > softc->ipf_ticks) 9508 break; 9509 ipf_rule_delete(softc, fr, IPL_LOGIPF, 0); 9510 } 9511 9512 while ((fr = softc->ipf_rule_explist[1]) != NULL) { 9513 /* 9514 * Because the list is kept sorted on insertion, the fist 9515 * one that dies in the future means no more work to do. 9516 */ 9517 if (fr->fr_die > softc->ipf_ticks) 9518 break; 9519 ipf_rule_delete(softc, fr, IPL_LOGIPF, 1); 9520 } 9521 9522 RWLOCK_EXIT(&softc->ipf_mutex); 9523 } 9524 9525 9526 static int ipf_ht_node_cmp(const struct host_node_s *, const struct host_node_s *); 9527 static void ipf_ht_node_make_key(host_track_t *, host_node_t *, int, 9528 i6addr_t *); 9529 9530 RBI_CODE(ipf_rb, host_node_t, hn_entry, ipf_ht_node_cmp) 9531 9532 9533 /* ------------------------------------------------------------------------ */ 9534 /* Function: ipf_ht_node_cmp */ 9535 /* Returns: int - 0 == nodes are the same, .. */ 9536 /* Parameters: k1(I) - pointer to first key to compare */ 9537 /* k2(I) - pointer to second key to compare */ 9538 /* */ 9539 /* The "key" for the node is a combination of two fields: the address */ 9540 /* family and the address itself. */ 9541 /* */ 9542 /* Because we're not actually interpreting the address data, it isn't */ 9543 /* necessary to convert them to/from network/host byte order. The mask is */ 9544 /* just used to remove bits that aren't significant - it doesn't matter */ 9545 /* where they are, as long as they're always in the same place. */ 9546 /* */ 9547 /* As with IP6_EQ, comparing IPv6 addresses starts at the bottom because */ 9548 /* this is where individual ones will differ the most - but not true for */ 9549 /* for /48's, etc. */ 9550 /* ------------------------------------------------------------------------ */ 9551 static int 9552 ipf_ht_node_cmp(const struct host_node_s *k1, const struct host_node_s *k2) 9553 { 9554 int i; 9555 9556 i = (k2->hn_addr.adf_family - k1->hn_addr.adf_family); 9557 if (i != 0) 9558 return i; 9559 9560 if (k1->hn_addr.adf_family == AF_INET) 9561 return (k2->hn_addr.adf_addr.in4.s_addr - 9562 k1->hn_addr.adf_addr.in4.s_addr); 9563 9564 i = k2->hn_addr.adf_addr.i6[3] - k1->hn_addr.adf_addr.i6[3]; 9565 if (i != 0) 9566 return i; 9567 i = k2->hn_addr.adf_addr.i6[2] - k1->hn_addr.adf_addr.i6[2]; 9568 if (i != 0) 9569 return i; 9570 i = k2->hn_addr.adf_addr.i6[1] - k1->hn_addr.adf_addr.i6[1]; 9571 if (i != 0) 9572 return i; 9573 i = k2->hn_addr.adf_addr.i6[0] - k1->hn_addr.adf_addr.i6[0]; 9574 return i; 9575 } 9576 9577 9578 /* ------------------------------------------------------------------------ */ 9579 /* Function: ipf_ht_node_make_key */ 9580 /* Returns: Nil */ 9581 /* parameters: htp(I) - pointer to address tracking structure */ 9582 /* key(I) - where to store masked address for lookup */ 9583 /* family(I) - protocol family of address */ 9584 /* addr(I) - pointer to network address */ 9585 /* */ 9586 /* Using the "netmask" (number of bits) stored parent host tracking struct, */ 9587 /* copy the address passed in into the key structure whilst masking out the */ 9588 /* bits that we don't want. */ 9589 /* */ 9590 /* Because the parser will set ht_netmask to 128 if there is no protocol */ 9591 /* specified (the parser doesn't know if it should be a v4 or v6 rule), we */ 9592 /* have to be wary of that and not allow 32-128 to happen. */ 9593 /* ------------------------------------------------------------------------ */ 9594 static void 9595 ipf_ht_node_make_key(host_track_t *htp, host_node_t *key, int family, 9596 i6addr_t *addr) 9597 { 9598 key->hn_addr.adf_family = family; 9599 if (family == AF_INET) { 9600 u_32_t mask; 9601 int bits; 9602 9603 key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in4); 9604 bits = htp->ht_netmask; 9605 if (bits >= 32) { 9606 mask = 0xffffffff; 9607 } else { 9608 mask = htonl(0xffffffff << (32 - bits)); 9609 } 9610 key->hn_addr.adf_addr.in4.s_addr = addr->in4.s_addr & mask; 9611 #ifdef USE_INET6 9612 } else { 9613 int bits = htp->ht_netmask; 9614 9615 key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in6); 9616 if (bits > 96) { 9617 key->hn_addr.adf_addr.i6[3] = addr->i6[3] & 9618 htonl(0xffffffff << (128 - bits)); 9619 key->hn_addr.adf_addr.i6[2] = addr->i6[2]; 9620 key->hn_addr.adf_addr.i6[1] = addr->i6[2]; 9621 key->hn_addr.adf_addr.i6[0] = addr->i6[2]; 9622 } else if (bits > 64) { 9623 key->hn_addr.adf_addr.i6[3] = 0; 9624 key->hn_addr.adf_addr.i6[2] = addr->i6[2] & 9625 htonl(0xffffffff << (96 - bits)); 9626 key->hn_addr.adf_addr.i6[1] = addr->i6[1]; 9627 key->hn_addr.adf_addr.i6[0] = addr->i6[0]; 9628 } else if (bits > 32) { 9629 key->hn_addr.adf_addr.i6[3] = 0; 9630 key->hn_addr.adf_addr.i6[2] = 0; 9631 key->hn_addr.adf_addr.i6[1] = addr->i6[1] & 9632 htonl(0xffffffff << (64 - bits)); 9633 key->hn_addr.adf_addr.i6[0] = addr->i6[0]; 9634 } else { 9635 key->hn_addr.adf_addr.i6[3] = 0; 9636 key->hn_addr.adf_addr.i6[2] = 0; 9637 key->hn_addr.adf_addr.i6[1] = 0; 9638 key->hn_addr.adf_addr.i6[0] = addr->i6[0] & 9639 htonl(0xffffffff << (32 - bits)); 9640 } 9641 #endif 9642 } 9643 } 9644 9645 9646 /* ------------------------------------------------------------------------ */ 9647 /* Function: ipf_ht_node_add */ 9648 /* Returns: int - 0 == success, -1 == failure */ 9649 /* Parameters: softc(I) - pointer to soft context main structure */ 9650 /* htp(I) - pointer to address tracking structure */ 9651 /* family(I) - protocol family of address */ 9652 /* addr(I) - pointer to network address */ 9653 /* */ 9654 /* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS */ 9655 /* ipf_ht_node_del FROM RUNNING CONCURRENTLY ON THE SAME htp. */ 9656 /* */ 9657 /* After preparing the key with the address information to find, look in */ 9658 /* the red-black tree to see if the address is known. A successful call to */ 9659 /* this function can mean one of two things: a new node was added to the */ 9660 /* tree or a matching node exists and we're able to bump up its activity. */ 9661 /* ------------------------------------------------------------------------ */ 9662 int 9663 ipf_ht_node_add(ipf_main_softc_t *softc, host_track_t *htp, int family, 9664 i6addr_t *addr) 9665 { 9666 host_node_t *h; 9667 host_node_t k; 9668 9669 ipf_ht_node_make_key(htp, &k, family, addr); 9670 9671 h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k); 9672 if (h == NULL) { 9673 if (htp->ht_cur_nodes >= htp->ht_max_nodes) 9674 return -1; 9675 KMALLOC(h, host_node_t *); 9676 if (h == NULL) { 9677 DT(ipf_rb_no_mem); 9678 LBUMP(ipf_rb_no_mem); 9679 return -1; 9680 } 9681 9682 /* 9683 * If there was a macro to initialise the RB node then that 9684 * would get used here, but there isn't... 9685 */ 9686 bzero((char *)h, sizeof(*h)); 9687 h->hn_addr = k.hn_addr; 9688 h->hn_addr.adf_family = k.hn_addr.adf_family; 9689 RBI_INSERT(ipf_rb, &htp->ht_root, h); 9690 htp->ht_cur_nodes++; 9691 } else { 9692 if ((htp->ht_max_per_node != 0) && 9693 (h->hn_active >= htp->ht_max_per_node)) { 9694 DT(ipf_rb_node_max); 9695 LBUMP(ipf_rb_node_max); 9696 return -1; 9697 } 9698 } 9699 9700 h->hn_active++; 9701 9702 return 0; 9703 } 9704 9705 9706 /* ------------------------------------------------------------------------ */ 9707 /* Function: ipf_ht_node_del */ 9708 /* Returns: int - 0 == success, -1 == failure */ 9709 /* parameters: htp(I) - pointer to address tracking structure */ 9710 /* family(I) - protocol family of address */ 9711 /* addr(I) - pointer to network address */ 9712 /* */ 9713 /* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS */ 9714 /* ipf_ht_node_add FROM RUNNING CONCURRENTLY ON THE SAME htp. */ 9715 /* */ 9716 /* Try and find the address passed in amongst the leaves on this tree to */ 9717 /* be friend. If found then drop the active account for that node drops by */ 9718 /* one. If that count reaches 0, it is time to free it all up. */ 9719 /* ------------------------------------------------------------------------ */ 9720 int 9721 ipf_ht_node_del(host_track_t *htp, int family, i6addr_t *addr) 9722 { 9723 host_node_t *h; 9724 host_node_t k; 9725 9726 ipf_ht_node_make_key(htp, &k, family, addr); 9727 9728 h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k); 9729 if (h == NULL) { 9730 return -1; 9731 } else { 9732 h->hn_active--; 9733 if (h->hn_active == 0) { 9734 (void) RBI_DELETE(ipf_rb, &htp->ht_root, h); 9735 htp->ht_cur_nodes--; 9736 KFREE(h); 9737 } 9738 } 9739 9740 return 0; 9741 } 9742 9743 9744 /* ------------------------------------------------------------------------ */ 9745 /* Function: ipf_rb_ht_init */ 9746 /* Returns: Nil */ 9747 /* Parameters: head(I) - pointer to host tracking structure */ 9748 /* */ 9749 /* Initialise the host tracking structure to be ready for use above. */ 9750 /* ------------------------------------------------------------------------ */ 9751 void 9752 ipf_rb_ht_init(host_track_t *head) 9753 { 9754 memset(head, 0, sizeof(*head)); 9755 RBI_INIT(ipf_rb, &head->ht_root); 9756 } 9757 9758 9759 /* ------------------------------------------------------------------------ */ 9760 /* Function: ipf_rb_ht_freenode */ 9761 /* Returns: Nil */ 9762 /* Parameters: head(I) - pointer to host tracking structure */ 9763 /* arg(I) - additional argument from walk caller */ 9764 /* */ 9765 /* Free an actual host_node_t structure. */ 9766 /* ------------------------------------------------------------------------ */ 9767 void 9768 ipf_rb_ht_freenode(host_node_t *node, void *arg) 9769 { 9770 KFREE(node); 9771 } 9772 9773 9774 /* ------------------------------------------------------------------------ */ 9775 /* Function: ipf_rb_ht_flush */ 9776 /* Returns: Nil */ 9777 /* Parameters: head(I) - pointer to host tracking structure */ 9778 /* */ 9779 /* Remove all of the nodes in the tree tracking hosts by calling a walker */ 9780 /* and free'ing each one. */ 9781 /* ------------------------------------------------------------------------ */ 9782 void 9783 ipf_rb_ht_flush(host_track_t *head) 9784 { 9785 /* XXX - May use node members after freeing the node. */ 9786 RBI_WALK(ipf_rb, &head->ht_root, ipf_rb_ht_freenode, NULL); 9787 } 9788 9789 9790 /* ------------------------------------------------------------------------ */ 9791 /* Function: ipf_slowtimer */ 9792 /* Returns: Nil */ 9793 /* Parameters: ptr(I) - pointer to main ipf soft context structure */ 9794 /* */ 9795 /* Slowly expire held state for fragments. Timeouts are set * in */ 9796 /* expectation of this being called twice per second. */ 9797 /* ------------------------------------------------------------------------ */ 9798 void 9799 ipf_slowtimer(ipf_main_softc_t *softc) 9800 { 9801 9802 ipf_token_expire(softc); 9803 ipf_frag_expire(softc); 9804 ipf_state_expire(softc); 9805 ipf_nat_expire(softc); 9806 ipf_auth_expire(softc); 9807 ipf_lookup_expire(softc); 9808 ipf_rule_expire(softc); 9809 ipf_sync_expire(softc); 9810 softc->ipf_ticks++; 9811 # if defined(__OpenBSD__) 9812 timeout_add(&ipf_slowtimer_ch, hz/2); 9813 # endif 9814 } 9815 9816 9817 /* ------------------------------------------------------------------------ */ 9818 /* Function: ipf_inet_mask_add */ 9819 /* Returns: Nil */ 9820 /* Parameters: bits(I) - pointer to nat context information */ 9821 /* mtab(I) - pointer to mask hash table structure */ 9822 /* */ 9823 /* When called, bits represents the mask of a new NAT rule that has just */ 9824 /* been added. This function inserts a bitmask into the array of masks to */ 9825 /* search when searching for a matching NAT rule for a packet. */ 9826 /* Prevention of duplicate masks is achieved by checking the use count for */ 9827 /* a given netmask. */ 9828 /* ------------------------------------------------------------------------ */ 9829 void 9830 ipf_inet_mask_add(int bits, ipf_v4_masktab_t *mtab) 9831 { 9832 u_32_t mask; 9833 int i, j; 9834 9835 mtab->imt4_masks[bits]++; 9836 if (mtab->imt4_masks[bits] > 1) 9837 return; 9838 9839 if (bits == 0) 9840 mask = 0; 9841 else 9842 mask = 0xffffffff << (32 - bits); 9843 9844 for (i = 0; i < 33; i++) { 9845 if (ntohl(mtab->imt4_active[i]) < mask) { 9846 for (j = 32; j > i; j--) 9847 mtab->imt4_active[j] = mtab->imt4_active[j - 1]; 9848 mtab->imt4_active[i] = htonl(mask); 9849 break; 9850 } 9851 } 9852 mtab->imt4_max++; 9853 } 9854 9855 9856 /* ------------------------------------------------------------------------ */ 9857 /* Function: ipf_inet_mask_del */ 9858 /* Returns: Nil */ 9859 /* Parameters: bits(I) - number of bits set in the netmask */ 9860 /* mtab(I) - pointer to mask hash table structure */ 9861 /* */ 9862 /* Remove the 32bit bitmask represented by "bits" from the collection of */ 9863 /* netmasks stored inside of mtab. */ 9864 /* ------------------------------------------------------------------------ */ 9865 void 9866 ipf_inet_mask_del(int bits, ipf_v4_masktab_t *mtab) 9867 { 9868 u_32_t mask; 9869 int i, j; 9870 9871 mtab->imt4_masks[bits]--; 9872 if (mtab->imt4_masks[bits] > 0) 9873 return; 9874 9875 mask = htonl(0xffffffff << (32 - bits)); 9876 for (i = 0; i < 33; i++) { 9877 if (mtab->imt4_active[i] == mask) { 9878 for (j = i + 1; j < 33; j++) 9879 mtab->imt4_active[j - 1] = mtab->imt4_active[j]; 9880 break; 9881 } 9882 } 9883 mtab->imt4_max--; 9884 ASSERT(mtab->imt4_max >= 0); 9885 } 9886 9887 9888 #ifdef USE_INET6 9889 /* ------------------------------------------------------------------------ */ 9890 /* Function: ipf_inet6_mask_add */ 9891 /* Returns: Nil */ 9892 /* Parameters: bits(I) - number of bits set in mask */ 9893 /* mask(I) - pointer to mask to add */ 9894 /* mtab(I) - pointer to mask hash table structure */ 9895 /* */ 9896 /* When called, bitcount represents the mask of a IPv6 NAT map rule that */ 9897 /* has just been added. This function inserts a bitmask into the array of */ 9898 /* masks to search when searching for a matching NAT rule for a packet. */ 9899 /* Prevention of duplicate masks is achieved by checking the use count for */ 9900 /* a given netmask. */ 9901 /* ------------------------------------------------------------------------ */ 9902 void 9903 ipf_inet6_mask_add(int bits, i6addr_t *mask, ipf_v6_masktab_t *mtab) 9904 { 9905 i6addr_t zero; 9906 int i, j; 9907 9908 mtab->imt6_masks[bits]++; 9909 if (mtab->imt6_masks[bits] > 1) 9910 return; 9911 9912 if (bits == 0) { 9913 mask = &zero; 9914 zero.i6[0] = 0; 9915 zero.i6[1] = 0; 9916 zero.i6[2] = 0; 9917 zero.i6[3] = 0; 9918 } 9919 9920 for (i = 0; i < 129; i++) { 9921 if (IP6_LT(&mtab->imt6_active[i], mask)) { 9922 for (j = 128; j > i; j--) 9923 mtab->imt6_active[j] = mtab->imt6_active[j - 1]; 9924 mtab->imt6_active[i] = *mask; 9925 break; 9926 } 9927 } 9928 mtab->imt6_max++; 9929 } 9930 9931 9932 /* ------------------------------------------------------------------------ */ 9933 /* Function: ipf_inet6_mask_del */ 9934 /* Returns: Nil */ 9935 /* Parameters: bits(I) - number of bits set in mask */ 9936 /* mask(I) - pointer to mask to remove */ 9937 /* mtab(I) - pointer to mask hash table structure */ 9938 /* */ 9939 /* Remove the 128bit bitmask represented by "bits" from the collection of */ 9940 /* netmasks stored inside of mtab. */ 9941 /* ------------------------------------------------------------------------ */ 9942 void 9943 ipf_inet6_mask_del(int bits, i6addr_t *mask, ipf_v6_masktab_t *mtab) 9944 { 9945 i6addr_t zero; 9946 int i, j; 9947 9948 mtab->imt6_masks[bits]--; 9949 if (mtab->imt6_masks[bits] > 0) 9950 return; 9951 9952 if (bits == 0) 9953 mask = &zero; 9954 zero.i6[0] = 0; 9955 zero.i6[1] = 0; 9956 zero.i6[2] = 0; 9957 zero.i6[3] = 0; 9958 9959 for (i = 0; i < 129; i++) { 9960 if (IP6_EQ(&mtab->imt6_active[i], mask)) { 9961 for (j = i + 1; j < 129; j++) { 9962 mtab->imt6_active[j - 1] = mtab->imt6_active[j]; 9963 if (IP6_EQ(&mtab->imt6_active[j - 1], &zero)) 9964 break; 9965 } 9966 break; 9967 } 9968 } 9969 mtab->imt6_max--; 9970 ASSERT(mtab->imt6_max >= 0); 9971 } 9972 #endif 9973