1 /* $FreeBSD$ */ 2 3 /* 4 * Copyright (C) 2012 by Darren Reed. 5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 * 8 * Copyright 2008 Sun Microsystems. 9 * 10 * $Id$ 11 * 12 */ 13 #if defined(KERNEL) || defined(_KERNEL) 14 # undef KERNEL 15 # undef _KERNEL 16 # define KERNEL 1 17 # define _KERNEL 1 18 #endif 19 #include <sys/errno.h> 20 #include <sys/types.h> 21 #include <sys/param.h> 22 #include <sys/time.h> 23 #if defined(_KERNEL) && defined(__FreeBSD__) 24 # if !defined(IPFILTER_LKM) 25 # include "opt_inet6.h" 26 # endif 27 # include <sys/filio.h> 28 #else 29 # include <sys/ioctl.h> 30 #endif 31 #if defined(__SVR4) || defined(sun) /* SOLARIS */ 32 # include <sys/filio.h> 33 #endif 34 # include <sys/fcntl.h> 35 #if defined(_KERNEL) 36 # include <sys/systm.h> 37 # include <sys/file.h> 38 #else 39 # include <stdio.h> 40 # include <string.h> 41 # include <stdlib.h> 42 # include <stddef.h> 43 # include <sys/file.h> 44 # define _KERNEL 45 # include <sys/uio.h> 46 # undef _KERNEL 47 #endif 48 #if !defined(__SVR4) 49 # include <sys/mbuf.h> 50 #else 51 # include <sys/byteorder.h> 52 # if (SOLARIS2 < 5) && defined(sun) 53 # include <sys/dditypes.h> 54 # endif 55 #endif 56 # include <sys/protosw.h> 57 #include <sys/socket.h> 58 #include <net/if.h> 59 #ifdef sun 60 # include <net/af.h> 61 #endif 62 #include <netinet/in.h> 63 #include <netinet/in_systm.h> 64 #include <netinet/ip.h> 65 #include <netinet/tcp.h> 66 # include <netinet/udp.h> 67 # include <netinet/ip_icmp.h> 68 #include "netinet/ip_compat.h" 69 #ifdef USE_INET6 70 # include <netinet/icmp6.h> 71 # if !SOLARIS && defined(_KERNEL) 72 # include <netinet6/in6_var.h> 73 # endif 74 #endif 75 #include "netinet/ip_fil.h" 76 #include "netinet/ip_nat.h" 77 #include "netinet/ip_frag.h" 78 #include "netinet/ip_state.h" 79 #include "netinet/ip_proxy.h" 80 #include "netinet/ip_auth.h" 81 #ifdef IPFILTER_SCAN 82 # include "netinet/ip_scan.h" 83 #endif 84 #include "netinet/ip_sync.h" 85 #include "netinet/ip_lookup.h" 86 #include "netinet/ip_pool.h" 87 #include "netinet/ip_htable.h" 88 #ifdef IPFILTER_COMPILED 89 # include "netinet/ip_rules.h" 90 #endif 91 #if defined(IPFILTER_BPF) && defined(_KERNEL) 92 # include <net/bpf.h> 93 #endif 94 #if defined(__FreeBSD__) 95 # include <sys/malloc.h> 96 #endif 97 #include "netinet/ipl.h" 98 99 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) 100 # include <sys/callout.h> 101 extern struct callout ipf_slowtimer_ch; 102 #endif 103 /* END OF INCLUDES */ 104 105 #if !defined(lint) 106 static const char sccsid[] = "@(#)fil.c 1.36 6/5/96 (C) 1993-2000 Darren Reed"; 107 static const char rcsid[] = "@(#)$FreeBSD$"; 108 /* static const char rcsid[] = "@(#)$Id: fil.c,v 2.243.2.125 2007/10/10 09:27:20 darrenr Exp $"; */ 109 #endif 110 111 #ifndef _KERNEL 112 # include "ipf.h" 113 # include "ipt.h" 114 extern int opts; 115 extern int blockreason; 116 #endif /* _KERNEL */ 117 118 #define FASTROUTE_RECURSION 119 120 #define LBUMP(x) softc->x++ 121 #define LBUMPD(x, y) do { softc->x.y++; DT(y); } while (0) 122 123 static inline int ipf_check_ipf(fr_info_t *, frentry_t *, int); 124 static u_32_t ipf_checkcipso(fr_info_t *, u_char *, int); 125 static u_32_t ipf_checkripso(u_char *); 126 static u_32_t ipf_decaps(fr_info_t *, u_32_t, int); 127 #ifdef IPFILTER_LOG 128 static frentry_t *ipf_dolog(fr_info_t *, u_32_t *); 129 #endif 130 static int ipf_flushlist(ipf_main_softc_t *, int *, frentry_t **); 131 static int ipf_flush_groups(ipf_main_softc_t *, frgroup_t **, 132 int); 133 static ipfunc_t ipf_findfunc(ipfunc_t); 134 static void *ipf_findlookup(ipf_main_softc_t *, int, frentry_t *, 135 i6addr_t *, i6addr_t *); 136 static frentry_t *ipf_firewall(fr_info_t *, u_32_t *); 137 static int ipf_fr_matcharray(fr_info_t *, int *); 138 static int ipf_frruleiter(ipf_main_softc_t *, void *, int, 139 void *); 140 static void ipf_funcfini(ipf_main_softc_t *, frentry_t *); 141 static int ipf_funcinit(ipf_main_softc_t *, frentry_t *); 142 static int ipf_geniter(ipf_main_softc_t *, ipftoken_t *, 143 ipfgeniter_t *); 144 static void ipf_getstat(ipf_main_softc_t *, 145 struct friostat *, int); 146 static int ipf_group_flush(ipf_main_softc_t *, frgroup_t *); 147 static void ipf_group_free(frgroup_t *); 148 static int ipf_grpmapfini(struct ipf_main_softc_s *, 149 frentry_t *); 150 static int ipf_grpmapinit(struct ipf_main_softc_s *, 151 frentry_t *); 152 static frentry_t *ipf_nextrule(ipf_main_softc_t *, int, int, 153 frentry_t *, int); 154 static int ipf_portcheck(frpcmp_t *, u_32_t); 155 static inline int ipf_pr_ah(fr_info_t *); 156 static inline void ipf_pr_esp(fr_info_t *); 157 static inline void ipf_pr_gre(fr_info_t *); 158 static inline void ipf_pr_udp(fr_info_t *); 159 static inline void ipf_pr_tcp(fr_info_t *); 160 static inline void ipf_pr_icmp(fr_info_t *); 161 static inline void ipf_pr_ipv4hdr(fr_info_t *); 162 static inline void ipf_pr_short(fr_info_t *, int); 163 static inline int ipf_pr_tcpcommon(fr_info_t *); 164 static inline int ipf_pr_udpcommon(fr_info_t *); 165 static void ipf_rule_delete(ipf_main_softc_t *, frentry_t *f, 166 int, int); 167 static void ipf_rule_expire_insert(ipf_main_softc_t *, 168 frentry_t *, int); 169 static int ipf_synclist(ipf_main_softc_t *, frentry_t *, 170 void *); 171 static void ipf_token_flush(ipf_main_softc_t *); 172 static void ipf_token_unlink(ipf_main_softc_t *, 173 ipftoken_t *); 174 static ipftuneable_t *ipf_tune_findbyname(ipftuneable_t *, 175 const char *); 176 static ipftuneable_t *ipf_tune_findbycookie(ipftuneable_t **, void *, 177 void **); 178 static int ipf_updateipid(fr_info_t *); 179 static int ipf_settimeout(struct ipf_main_softc_s *, 180 struct ipftuneable *, 181 ipftuneval_t *); 182 #if !defined(_KERNEL) || SOLARIS 183 static int ppsratecheck(struct timeval *, int *, int); 184 #endif 185 186 187 /* 188 * bit values for identifying presence of individual IP options 189 * All of these tables should be ordered by increasing key value on the left 190 * hand side to allow for binary searching of the array and include a trailer 191 * with a 0 for the bitmask for linear searches to easily find the end with. 192 */ 193 static const struct optlist ipopts[] = { 194 { IPOPT_NOP, 0x000001 }, 195 { IPOPT_RR, 0x000002 }, 196 { IPOPT_ZSU, 0x000004 }, 197 { IPOPT_MTUP, 0x000008 }, 198 { IPOPT_MTUR, 0x000010 }, 199 { IPOPT_ENCODE, 0x000020 }, 200 { IPOPT_TS, 0x000040 }, 201 { IPOPT_TR, 0x000080 }, 202 { IPOPT_SECURITY, 0x000100 }, 203 { IPOPT_LSRR, 0x000200 }, 204 { IPOPT_E_SEC, 0x000400 }, 205 { IPOPT_CIPSO, 0x000800 }, 206 { IPOPT_SATID, 0x001000 }, 207 { IPOPT_SSRR, 0x002000 }, 208 { IPOPT_ADDEXT, 0x004000 }, 209 { IPOPT_VISA, 0x008000 }, 210 { IPOPT_IMITD, 0x010000 }, 211 { IPOPT_EIP, 0x020000 }, 212 { IPOPT_FINN, 0x040000 }, 213 { 0, 0x000000 } 214 }; 215 216 #ifdef USE_INET6 217 static const struct optlist ip6exthdr[] = { 218 { IPPROTO_HOPOPTS, 0x000001 }, 219 { IPPROTO_IPV6, 0x000002 }, 220 { IPPROTO_ROUTING, 0x000004 }, 221 { IPPROTO_FRAGMENT, 0x000008 }, 222 { IPPROTO_ESP, 0x000010 }, 223 { IPPROTO_AH, 0x000020 }, 224 { IPPROTO_NONE, 0x000040 }, 225 { IPPROTO_DSTOPTS, 0x000080 }, 226 { IPPROTO_MOBILITY, 0x000100 }, 227 { 0, 0 } 228 }; 229 #endif 230 231 /* 232 * bit values for identifying presence of individual IP security options 233 */ 234 static const struct optlist secopt[] = { 235 { IPSO_CLASS_RES4, 0x01 }, 236 { IPSO_CLASS_TOPS, 0x02 }, 237 { IPSO_CLASS_SECR, 0x04 }, 238 { IPSO_CLASS_RES3, 0x08 }, 239 { IPSO_CLASS_CONF, 0x10 }, 240 { IPSO_CLASS_UNCL, 0x20 }, 241 { IPSO_CLASS_RES2, 0x40 }, 242 { IPSO_CLASS_RES1, 0x80 } 243 }; 244 245 char ipfilter_version[] = IPL_VERSION; 246 247 int ipf_features = 0 248 #ifdef IPFILTER_LKM 249 | IPF_FEAT_LKM 250 #endif 251 #ifdef IPFILTER_LOG 252 | IPF_FEAT_LOG 253 #endif 254 | IPF_FEAT_LOOKUP 255 #ifdef IPFILTER_BPF 256 | IPF_FEAT_BPF 257 #endif 258 #ifdef IPFILTER_COMPILED 259 | IPF_FEAT_COMPILED 260 #endif 261 #ifdef IPFILTER_CKSUM 262 | IPF_FEAT_CKSUM 263 #endif 264 | IPF_FEAT_SYNC 265 #ifdef IPFILTER_SCAN 266 | IPF_FEAT_SCAN 267 #endif 268 #ifdef USE_INET6 269 | IPF_FEAT_IPV6 270 #endif 271 ; 272 273 274 /* 275 * Table of functions available for use with call rules. 276 */ 277 static ipfunc_resolve_t ipf_availfuncs[] = { 278 { "srcgrpmap", ipf_srcgrpmap, ipf_grpmapinit, ipf_grpmapfini }, 279 { "dstgrpmap", ipf_dstgrpmap, ipf_grpmapinit, ipf_grpmapfini }, 280 { "", NULL, NULL, NULL } 281 }; 282 283 static ipftuneable_t ipf_main_tuneables[] = { 284 { { (void *)offsetof(struct ipf_main_softc_s, ipf_flags) }, 285 "ipf_flags", 0, 0xffffffff, 286 stsizeof(ipf_main_softc_t, ipf_flags), 287 0, NULL, NULL }, 288 { { (void *)offsetof(struct ipf_main_softc_s, ipf_active) }, 289 "active", 0, 0, 290 stsizeof(ipf_main_softc_t, ipf_active), 291 IPFT_RDONLY, NULL, NULL }, 292 { { (void *)offsetof(ipf_main_softc_t, ipf_control_forwarding) }, 293 "control_forwarding", 0, 1, 294 stsizeof(ipf_main_softc_t, ipf_control_forwarding), 295 0, NULL, NULL }, 296 { { (void *)offsetof(ipf_main_softc_t, ipf_update_ipid) }, 297 "update_ipid", 0, 1, 298 stsizeof(ipf_main_softc_t, ipf_update_ipid), 299 0, NULL, NULL }, 300 { { (void *)offsetof(ipf_main_softc_t, ipf_chksrc) }, 301 "chksrc", 0, 1, 302 stsizeof(ipf_main_softc_t, ipf_chksrc), 303 0, NULL, NULL }, 304 { { (void *)offsetof(ipf_main_softc_t, ipf_minttl) }, 305 "min_ttl", 0, 1, 306 stsizeof(ipf_main_softc_t, ipf_minttl), 307 0, NULL, NULL }, 308 { { (void *)offsetof(ipf_main_softc_t, ipf_icmpminfragmtu) }, 309 "icmp_minfragmtu", 0, 1, 310 stsizeof(ipf_main_softc_t, ipf_icmpminfragmtu), 311 0, NULL, NULL }, 312 { { (void *)offsetof(ipf_main_softc_t, ipf_pass) }, 313 "default_pass", 0, 0xffffffff, 314 stsizeof(ipf_main_softc_t, ipf_pass), 315 0, NULL, NULL }, 316 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpidletimeout) }, 317 "tcp_idle_timeout", 1, 0x7fffffff, 318 stsizeof(ipf_main_softc_t, ipf_tcpidletimeout), 319 0, NULL, ipf_settimeout }, 320 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosewait) }, 321 "tcp_close_wait", 1, 0x7fffffff, 322 stsizeof(ipf_main_softc_t, ipf_tcpclosewait), 323 0, NULL, ipf_settimeout }, 324 { { (void *)offsetof(ipf_main_softc_t, ipf_tcplastack) }, 325 "tcp_last_ack", 1, 0x7fffffff, 326 stsizeof(ipf_main_softc_t, ipf_tcplastack), 327 0, NULL, ipf_settimeout }, 328 { { (void *)offsetof(ipf_main_softc_t, ipf_tcptimeout) }, 329 "tcp_timeout", 1, 0x7fffffff, 330 stsizeof(ipf_main_softc_t, ipf_tcptimeout), 331 0, NULL, ipf_settimeout }, 332 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynsent) }, 333 "tcp_syn_sent", 1, 0x7fffffff, 334 stsizeof(ipf_main_softc_t, ipf_tcpsynsent), 335 0, NULL, ipf_settimeout }, 336 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynrecv) }, 337 "tcp_syn_received", 1, 0x7fffffff, 338 stsizeof(ipf_main_softc_t, ipf_tcpsynrecv), 339 0, NULL, ipf_settimeout }, 340 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosed) }, 341 "tcp_closed", 1, 0x7fffffff, 342 stsizeof(ipf_main_softc_t, ipf_tcpclosed), 343 0, NULL, ipf_settimeout }, 344 { { (void *)offsetof(ipf_main_softc_t, ipf_tcphalfclosed) }, 345 "tcp_half_closed", 1, 0x7fffffff, 346 stsizeof(ipf_main_softc_t, ipf_tcphalfclosed), 347 0, NULL, ipf_settimeout }, 348 { { (void *)offsetof(ipf_main_softc_t, ipf_tcptimewait) }, 349 "tcp_time_wait", 1, 0x7fffffff, 350 stsizeof(ipf_main_softc_t, ipf_tcptimewait), 351 0, NULL, ipf_settimeout }, 352 { { (void *)offsetof(ipf_main_softc_t, ipf_udptimeout) }, 353 "udp_timeout", 1, 0x7fffffff, 354 stsizeof(ipf_main_softc_t, ipf_udptimeout), 355 0, NULL, ipf_settimeout }, 356 { { (void *)offsetof(ipf_main_softc_t, ipf_udpacktimeout) }, 357 "udp_ack_timeout", 1, 0x7fffffff, 358 stsizeof(ipf_main_softc_t, ipf_udpacktimeout), 359 0, NULL, ipf_settimeout }, 360 { { (void *)offsetof(ipf_main_softc_t, ipf_icmptimeout) }, 361 "icmp_timeout", 1, 0x7fffffff, 362 stsizeof(ipf_main_softc_t, ipf_icmptimeout), 363 0, NULL, ipf_settimeout }, 364 { { (void *)offsetof(ipf_main_softc_t, ipf_icmpacktimeout) }, 365 "icmp_ack_timeout", 1, 0x7fffffff, 366 stsizeof(ipf_main_softc_t, ipf_icmpacktimeout), 367 0, NULL, ipf_settimeout }, 368 { { (void *)offsetof(ipf_main_softc_t, ipf_iptimeout) }, 369 "ip_timeout", 1, 0x7fffffff, 370 stsizeof(ipf_main_softc_t, ipf_iptimeout), 371 0, NULL, ipf_settimeout }, 372 #if defined(INSTANCES) && defined(_KERNEL) 373 { { (void *)offsetof(ipf_main_softc_t, ipf_get_loopback) }, 374 "intercept_loopback", 0, 1, 375 stsizeof(ipf_main_softc_t, ipf_get_loopback), 376 0, NULL, ipf_set_loopback }, 377 #endif 378 { { 0 }, 379 NULL, 0, 0, 380 0, 381 0, NULL, NULL } 382 }; 383 384 385 /* 386 * The next section of code is a collection of small routines that set 387 * fields in the fr_info_t structure passed based on properties of the 388 * current packet. There are different routines for the same protocol 389 * for each of IPv4 and IPv6. Adding a new protocol, for which there 390 * will "special" inspection for setup, is now more easily done by adding 391 * a new routine and expanding the ipf_pr_ipinit*() function rather than by 392 * adding more code to a growing switch statement. 393 */ 394 #ifdef USE_INET6 395 static inline int ipf_pr_ah6(fr_info_t *); 396 static inline void ipf_pr_esp6(fr_info_t *); 397 static inline void ipf_pr_gre6(fr_info_t *); 398 static inline void ipf_pr_udp6(fr_info_t *); 399 static inline void ipf_pr_tcp6(fr_info_t *); 400 static inline void ipf_pr_icmp6(fr_info_t *); 401 static inline void ipf_pr_ipv6hdr(fr_info_t *); 402 static inline void ipf_pr_short6(fr_info_t *, int); 403 static inline int ipf_pr_hopopts6(fr_info_t *); 404 static inline int ipf_pr_mobility6(fr_info_t *); 405 static inline int ipf_pr_routing6(fr_info_t *); 406 static inline int ipf_pr_dstopts6(fr_info_t *); 407 static inline int ipf_pr_fragment6(fr_info_t *); 408 static inline struct ip6_ext *ipf_pr_ipv6exthdr(fr_info_t *, int, int); 409 410 411 /* ------------------------------------------------------------------------ */ 412 /* Function: ipf_pr_short6 */ 413 /* Returns: void */ 414 /* Parameters: fin(I) - pointer to packet information */ 415 /* xmin(I) - minimum header size */ 416 /* */ 417 /* IPv6 Only */ 418 /* This is function enforces the 'is a packet too short to be legit' rule */ 419 /* for IPv6 and marks the packet with FI_SHORT if so. See function comment */ 420 /* for ipf_pr_short() for more details. */ 421 /* ------------------------------------------------------------------------ */ 422 static inline void 423 ipf_pr_short6(fr_info_t *fin, int xmin) 424 { 425 426 if (fin->fin_dlen < xmin) 427 fin->fin_flx |= FI_SHORT; 428 } 429 430 431 /* ------------------------------------------------------------------------ */ 432 /* Function: ipf_pr_ipv6hdr */ 433 /* Returns: void */ 434 /* Parameters: fin(I) - pointer to packet information */ 435 /* */ 436 /* IPv6 Only */ 437 /* Copy values from the IPv6 header into the fr_info_t struct and call the */ 438 /* per-protocol analyzer if it exists. In validating the packet, a protocol*/ 439 /* analyzer may pullup or free the packet itself so we need to be vigiliant */ 440 /* of that possibility arising. */ 441 /* ------------------------------------------------------------------------ */ 442 static inline void 443 ipf_pr_ipv6hdr(fr_info_t *fin) 444 { 445 ip6_t *ip6 = (ip6_t *)fin->fin_ip; 446 int p, go = 1, i, hdrcount; 447 fr_ip_t *fi = &fin->fin_fi; 448 449 fin->fin_off = 0; 450 451 fi->fi_tos = 0; 452 fi->fi_optmsk = 0; 453 fi->fi_secmsk = 0; 454 fi->fi_auth = 0; 455 456 p = ip6->ip6_nxt; 457 fin->fin_crc = p; 458 fi->fi_ttl = ip6->ip6_hlim; 459 fi->fi_src.in6 = ip6->ip6_src; 460 fin->fin_crc += fi->fi_src.i6[0]; 461 fin->fin_crc += fi->fi_src.i6[1]; 462 fin->fin_crc += fi->fi_src.i6[2]; 463 fin->fin_crc += fi->fi_src.i6[3]; 464 fi->fi_dst.in6 = ip6->ip6_dst; 465 fin->fin_crc += fi->fi_dst.i6[0]; 466 fin->fin_crc += fi->fi_dst.i6[1]; 467 fin->fin_crc += fi->fi_dst.i6[2]; 468 fin->fin_crc += fi->fi_dst.i6[3]; 469 fin->fin_id = 0; 470 if (IN6_IS_ADDR_MULTICAST(&fi->fi_dst.in6)) 471 fin->fin_flx |= FI_MULTICAST|FI_MBCAST; 472 473 hdrcount = 0; 474 while (go && !(fin->fin_flx & FI_SHORT)) { 475 switch (p) 476 { 477 case IPPROTO_UDP : 478 ipf_pr_udp6(fin); 479 go = 0; 480 break; 481 482 case IPPROTO_TCP : 483 ipf_pr_tcp6(fin); 484 go = 0; 485 break; 486 487 case IPPROTO_ICMPV6 : 488 ipf_pr_icmp6(fin); 489 go = 0; 490 break; 491 492 case IPPROTO_GRE : 493 ipf_pr_gre6(fin); 494 go = 0; 495 break; 496 497 case IPPROTO_HOPOPTS : 498 p = ipf_pr_hopopts6(fin); 499 break; 500 501 case IPPROTO_MOBILITY : 502 p = ipf_pr_mobility6(fin); 503 break; 504 505 case IPPROTO_DSTOPTS : 506 p = ipf_pr_dstopts6(fin); 507 break; 508 509 case IPPROTO_ROUTING : 510 p = ipf_pr_routing6(fin); 511 break; 512 513 case IPPROTO_AH : 514 p = ipf_pr_ah6(fin); 515 break; 516 517 case IPPROTO_ESP : 518 ipf_pr_esp6(fin); 519 go = 0; 520 break; 521 522 case IPPROTO_IPV6 : 523 for (i = 0; ip6exthdr[i].ol_bit != 0; i++) 524 if (ip6exthdr[i].ol_val == p) { 525 fin->fin_flx |= ip6exthdr[i].ol_bit; 526 break; 527 } 528 go = 0; 529 break; 530 531 case IPPROTO_NONE : 532 go = 0; 533 break; 534 535 case IPPROTO_FRAGMENT : 536 p = ipf_pr_fragment6(fin); 537 /* 538 * Given that the only fragments we want to let through 539 * (where fin_off != 0) are those where the non-first 540 * fragments only have data, we can safely stop looking 541 * at headers if this is a non-leading fragment. 542 */ 543 if (fin->fin_off != 0) 544 go = 0; 545 break; 546 547 default : 548 go = 0; 549 break; 550 } 551 hdrcount++; 552 553 /* 554 * It is important to note that at this point, for the 555 * extension headers (go != 0), the entire header may not have 556 * been pulled up when the code gets to this point. This is 557 * only done for "go != 0" because the other header handlers 558 * will all pullup their complete header. The other indicator 559 * of an incomplete packet is that this was just an extension 560 * header. 561 */ 562 if ((go != 0) && (p != IPPROTO_NONE) && 563 (ipf_pr_pullup(fin, 0) == -1)) { 564 p = IPPROTO_NONE; 565 break; 566 } 567 } 568 569 /* 570 * Some of the above functions, like ipf_pr_esp6(), can call ipf_pullup 571 * and destroy whatever packet was here. The caller of this function 572 * expects us to return if there is a problem with ipf_pullup. 573 */ 574 if (fin->fin_m == NULL) { 575 ipf_main_softc_t *softc = fin->fin_main_soft; 576 577 LBUMPD(ipf_stats[fin->fin_out], fr_v6_bad); 578 return; 579 } 580 581 fi->fi_p = p; 582 583 /* 584 * IPv6 fragment case 1 - see comment for ipf_pr_fragment6(). 585 * "go != 0" implies the above loop hasn't arrived at a layer 4 header. 586 */ 587 if ((go != 0) && (fin->fin_flx & FI_FRAG) && (fin->fin_off == 0)) { 588 ipf_main_softc_t *softc = fin->fin_main_soft; 589 590 fin->fin_flx |= FI_BAD; 591 DT2(ipf_fi_bad_ipv6_frag_1, fr_info_t *, fin, int, go); 592 LBUMPD(ipf_stats[fin->fin_out], fr_v6_badfrag); 593 LBUMP(ipf_stats[fin->fin_out].fr_v6_bad); 594 } 595 } 596 597 598 /* ------------------------------------------------------------------------ */ 599 /* Function: ipf_pr_ipv6exthdr */ 600 /* Returns: struct ip6_ext * - pointer to the start of the next header */ 601 /* or NULL if there is a prolblem. */ 602 /* Parameters: fin(I) - pointer to packet information */ 603 /* multiple(I) - flag indicating yes/no if multiple occurances */ 604 /* of this extension header are allowed. */ 605 /* proto(I) - protocol number for this extension header */ 606 /* */ 607 /* IPv6 Only */ 608 /* This function embodies a number of common checks that all IPv6 extension */ 609 /* headers must be subjected to. For example, making sure the packet is */ 610 /* big enough for it to be in, checking if it is repeated and setting a */ 611 /* flag to indicate its presence. */ 612 /* ------------------------------------------------------------------------ */ 613 static inline struct ip6_ext * 614 ipf_pr_ipv6exthdr(fr_info_t *fin, int multiple, int proto) 615 { 616 ipf_main_softc_t *softc = fin->fin_main_soft; 617 struct ip6_ext *hdr; 618 u_short shift; 619 int i; 620 621 fin->fin_flx |= FI_V6EXTHDR; 622 623 /* 8 is default length of extension hdr */ 624 if ((fin->fin_dlen - 8) < 0) { 625 fin->fin_flx |= FI_SHORT; 626 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_short); 627 return (NULL); 628 } 629 630 if (ipf_pr_pullup(fin, 8) == -1) { 631 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_pullup); 632 return (NULL); 633 } 634 635 hdr = fin->fin_dp; 636 switch (proto) 637 { 638 case IPPROTO_FRAGMENT : 639 shift = 8; 640 break; 641 default : 642 shift = 8 + (hdr->ip6e_len << 3); 643 break; 644 } 645 646 if (shift > fin->fin_dlen) { /* Nasty extension header length? */ 647 fin->fin_flx |= FI_BAD; 648 DT3(ipf_fi_bad_pr_ipv6exthdr_len, fr_info_t *, fin, u_short, shift, u_short, fin->fin_dlen); 649 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_hlen); 650 return (NULL); 651 } 652 653 fin->fin_dp = (char *)fin->fin_dp + shift; 654 fin->fin_dlen -= shift; 655 656 /* 657 * If we have seen a fragment header, do not set any flags to indicate 658 * the presence of this extension header as it has no impact on the 659 * end result until after it has been defragmented. 660 */ 661 if (fin->fin_flx & FI_FRAG) 662 return (hdr); 663 664 for (i = 0; ip6exthdr[i].ol_bit != 0; i++) 665 if (ip6exthdr[i].ol_val == proto) { 666 /* 667 * Most IPv6 extension headers are only allowed once. 668 */ 669 if ((multiple == 0) && 670 ((fin->fin_optmsk & ip6exthdr[i].ol_bit) != 0)) { 671 fin->fin_flx |= FI_BAD; 672 DT2(ipf_fi_bad_ipv6exthdr_once, fr_info_t *, fin, u_int, (fin->fin_optmsk & ip6exthdr[i].ol_bit)); 673 } else 674 fin->fin_optmsk |= ip6exthdr[i].ol_bit; 675 break; 676 } 677 678 return (hdr); 679 } 680 681 682 /* ------------------------------------------------------------------------ */ 683 /* Function: ipf_pr_hopopts6 */ 684 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 685 /* Parameters: fin(I) - pointer to packet information */ 686 /* */ 687 /* IPv6 Only */ 688 /* This is function checks pending hop by hop options extension header */ 689 /* ------------------------------------------------------------------------ */ 690 static inline int 691 ipf_pr_hopopts6(fr_info_t *fin) 692 { 693 struct ip6_ext *hdr; 694 695 hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS); 696 if (hdr == NULL) 697 return (IPPROTO_NONE); 698 return (hdr->ip6e_nxt); 699 } 700 701 702 /* ------------------------------------------------------------------------ */ 703 /* Function: ipf_pr_mobility6 */ 704 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 705 /* Parameters: fin(I) - pointer to packet information */ 706 /* */ 707 /* IPv6 Only */ 708 /* This is function checks the IPv6 mobility extension header */ 709 /* ------------------------------------------------------------------------ */ 710 static inline int 711 ipf_pr_mobility6(fr_info_t *fin) 712 { 713 struct ip6_ext *hdr; 714 715 hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_MOBILITY); 716 if (hdr == NULL) 717 return (IPPROTO_NONE); 718 return (hdr->ip6e_nxt); 719 } 720 721 722 /* ------------------------------------------------------------------------ */ 723 /* Function: ipf_pr_routing6 */ 724 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 725 /* Parameters: fin(I) - pointer to packet information */ 726 /* */ 727 /* IPv6 Only */ 728 /* This is function checks pending routing extension header */ 729 /* ------------------------------------------------------------------------ */ 730 static inline int 731 ipf_pr_routing6(fr_info_t *fin) 732 { 733 struct ip6_routing *hdr; 734 735 hdr = (struct ip6_routing *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_ROUTING); 736 if (hdr == NULL) 737 return (IPPROTO_NONE); 738 739 switch (hdr->ip6r_type) 740 { 741 case 0 : 742 /* 743 * Nasty extension header length? 744 */ 745 if (((hdr->ip6r_len >> 1) < hdr->ip6r_segleft) || 746 (hdr->ip6r_segleft && (hdr->ip6r_len & 1))) { 747 ipf_main_softc_t *softc = fin->fin_main_soft; 748 749 fin->fin_flx |= FI_BAD; 750 DT1(ipf_fi_bad_routing6, fr_info_t *, fin); 751 LBUMPD(ipf_stats[fin->fin_out], fr_v6_rh_bad); 752 return (IPPROTO_NONE); 753 } 754 break; 755 756 default : 757 break; 758 } 759 760 return (hdr->ip6r_nxt); 761 } 762 763 764 /* ------------------------------------------------------------------------ */ 765 /* Function: ipf_pr_fragment6 */ 766 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 767 /* Parameters: fin(I) - pointer to packet information */ 768 /* */ 769 /* IPv6 Only */ 770 /* Examine the IPv6 fragment header and extract fragment offset information.*/ 771 /* */ 772 /* Fragments in IPv6 are extraordinarily difficult to deal with - much more */ 773 /* so than in IPv4. There are 5 cases of fragments with IPv6 that all */ 774 /* packets with a fragment header can fit into. They are as follows: */ 775 /* */ 776 /* 1. [IPv6][0-n EH][FH][0-n EH] (no L4HDR present) */ 777 /* 2. [IPV6][0-n EH][FH][0-n EH][L4HDR part] (short) */ 778 /* 3. [IPV6][0-n EH][FH][L4HDR part][0-n data] (short) */ 779 /* 4. [IPV6][0-n EH][FH][0-n EH][L4HDR][0-n data] */ 780 /* 5. [IPV6][0-n EH][FH][data] */ 781 /* */ 782 /* IPV6 = IPv6 header, FH = Fragment Header, */ 783 /* 0-n EH = 0 or more extension headers, 0-n data = 0 or more bytes of data */ 784 /* */ 785 /* Packets that match 1, 2, 3 will be dropped as the only reasonable */ 786 /* scenario in which they happen is in extreme circumstances that are most */ 787 /* likely to be an indication of an attack rather than normal traffic. */ 788 /* A type 3 packet may be sent by an attacked after a type 4 packet. There */ 789 /* are two rules that can be used to guard against type 3 packets: L4 */ 790 /* headers must always be in a packet that has the offset field set to 0 */ 791 /* and no packet is allowed to overlay that where offset = 0. */ 792 /* ------------------------------------------------------------------------ */ 793 static inline int 794 ipf_pr_fragment6(fr_info_t *fin) 795 { 796 ipf_main_softc_t *softc = fin->fin_main_soft; 797 struct ip6_frag *frag; 798 799 fin->fin_flx |= FI_FRAG; 800 801 frag = (struct ip6_frag *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT); 802 if (frag == NULL) { 803 LBUMPD(ipf_stats[fin->fin_out], fr_v6_frag_bad); 804 return (IPPROTO_NONE); 805 } 806 807 if ((frag->ip6f_offlg & IP6F_MORE_FRAG) != 0) { 808 /* 809 * Any fragment that isn't the last fragment must have its 810 * length as a multiple of 8. 811 */ 812 if ((fin->fin_plen & 7) != 0) { 813 fin->fin_flx |= FI_BAD; 814 DT2(ipf_fi_bad_frag_not_8, fr_info_t *, fin, u_int, (fin->fin_plen & 7)); 815 } 816 } 817 818 fin->fin_fraghdr = frag; 819 fin->fin_id = frag->ip6f_ident; 820 fin->fin_off = ntohs(frag->ip6f_offlg & IP6F_OFF_MASK); 821 if (fin->fin_off != 0) 822 fin->fin_flx |= FI_FRAGBODY; 823 824 /* 825 * Jumbograms aren't handled, so the max. length is 64k 826 */ 827 if ((fin->fin_off << 3) + fin->fin_dlen > 65535) { 828 fin->fin_flx |= FI_BAD; 829 DT2(ipf_fi_bad_jumbogram, fr_info_t *, fin, u_int, ((fin->fin_off << 3) + fin->fin_dlen)); 830 } 831 832 /* 833 * We don't know where the transport layer header (or whatever is next 834 * is), as it could be behind destination options (amongst others) so 835 * return the fragment header as the type of packet this is. Note that 836 * this effectively disables the fragment cache for > 1 protocol at a 837 * time. 838 */ 839 return (frag->ip6f_nxt); 840 } 841 842 843 /* ------------------------------------------------------------------------ */ 844 /* Function: ipf_pr_dstopts6 */ 845 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 846 /* Parameters: fin(I) - pointer to packet information */ 847 /* */ 848 /* IPv6 Only */ 849 /* This is function checks pending destination options extension header */ 850 /* ------------------------------------------------------------------------ */ 851 static inline int 852 ipf_pr_dstopts6(fr_info_t *fin) 853 { 854 ipf_main_softc_t *softc = fin->fin_main_soft; 855 struct ip6_ext *hdr; 856 857 hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_DSTOPTS); 858 if (hdr == NULL) { 859 LBUMPD(ipf_stats[fin->fin_out], fr_v6_dst_bad); 860 return (IPPROTO_NONE); 861 } 862 return (hdr->ip6e_nxt); 863 } 864 865 866 /* ------------------------------------------------------------------------ */ 867 /* Function: ipf_pr_icmp6 */ 868 /* Returns: void */ 869 /* Parameters: fin(I) - pointer to packet information */ 870 /* */ 871 /* IPv6 Only */ 872 /* This routine is mainly concerned with determining the minimum valid size */ 873 /* for an ICMPv6 packet. */ 874 /* ------------------------------------------------------------------------ */ 875 static inline void 876 ipf_pr_icmp6(fr_info_t *fin) 877 { 878 int minicmpsz = sizeof(struct icmp6_hdr); 879 struct icmp6_hdr *icmp6; 880 881 if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1) { 882 ipf_main_softc_t *softc = fin->fin_main_soft; 883 884 LBUMPD(ipf_stats[fin->fin_out], fr_v6_icmp6_pullup); 885 return; 886 } 887 888 if (fin->fin_dlen > 1) { 889 ip6_t *ip6; 890 891 icmp6 = fin->fin_dp; 892 893 fin->fin_data[0] = *(u_short *)icmp6; 894 895 if ((icmp6->icmp6_type & ICMP6_INFOMSG_MASK) != 0) 896 fin->fin_flx |= FI_ICMPQUERY; 897 898 switch (icmp6->icmp6_type) 899 { 900 case ICMP6_ECHO_REPLY : 901 case ICMP6_ECHO_REQUEST : 902 if (fin->fin_dlen >= 6) 903 fin->fin_data[1] = icmp6->icmp6_id; 904 minicmpsz = ICMP6ERR_MINPKTLEN - sizeof(ip6_t); 905 break; 906 907 case ICMP6_DST_UNREACH : 908 case ICMP6_PACKET_TOO_BIG : 909 case ICMP6_TIME_EXCEEDED : 910 case ICMP6_PARAM_PROB : 911 fin->fin_flx |= FI_ICMPERR; 912 minicmpsz = ICMP6ERR_IPICMPHLEN - sizeof(ip6_t); 913 if (fin->fin_plen < ICMP6ERR_IPICMPHLEN) 914 break; 915 916 if (M_LEN(fin->fin_m) < fin->fin_plen) { 917 if (ipf_coalesce(fin) != 1) 918 return; 919 } 920 921 if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN) == -1) 922 return; 923 924 /* 925 * If the destination of this packet doesn't match the 926 * source of the original packet then this packet is 927 * not correct. 928 */ 929 icmp6 = fin->fin_dp; 930 ip6 = (ip6_t *)((char *)icmp6 + ICMPERR_ICMPHLEN); 931 if (IP6_NEQ(&fin->fin_fi.fi_dst, 932 (i6addr_t *)&ip6->ip6_src)) { 933 fin->fin_flx |= FI_BAD; 934 DT1(ipf_fi_bad_icmp6, fr_info_t *, fin); 935 } 936 break; 937 default : 938 break; 939 } 940 } 941 942 ipf_pr_short6(fin, minicmpsz); 943 if ((fin->fin_flx & (FI_SHORT|FI_BAD)) == 0) { 944 u_char p = fin->fin_p; 945 946 fin->fin_p = IPPROTO_ICMPV6; 947 ipf_checkv6sum(fin); 948 fin->fin_p = p; 949 } 950 } 951 952 953 /* ------------------------------------------------------------------------ */ 954 /* Function: ipf_pr_udp6 */ 955 /* Returns: void */ 956 /* Parameters: fin(I) - pointer to packet information */ 957 /* */ 958 /* IPv6 Only */ 959 /* Analyse the packet for IPv6/UDP properties. */ 960 /* Is not expected to be called for fragmented packets. */ 961 /* ------------------------------------------------------------------------ */ 962 static inline void 963 ipf_pr_udp6(fr_info_t *fin) 964 { 965 966 if (ipf_pr_udpcommon(fin) == 0) { 967 u_char p = fin->fin_p; 968 969 fin->fin_p = IPPROTO_UDP; 970 ipf_checkv6sum(fin); 971 fin->fin_p = p; 972 } 973 } 974 975 976 /* ------------------------------------------------------------------------ */ 977 /* Function: ipf_pr_tcp6 */ 978 /* Returns: void */ 979 /* Parameters: fin(I) - pointer to packet information */ 980 /* */ 981 /* IPv6 Only */ 982 /* Analyse the packet for IPv6/TCP properties. */ 983 /* Is not expected to be called for fragmented packets. */ 984 /* ------------------------------------------------------------------------ */ 985 static inline void 986 ipf_pr_tcp6(fr_info_t *fin) 987 { 988 989 if (ipf_pr_tcpcommon(fin) == 0) { 990 u_char p = fin->fin_p; 991 992 fin->fin_p = IPPROTO_TCP; 993 ipf_checkv6sum(fin); 994 fin->fin_p = p; 995 } 996 } 997 998 999 /* ------------------------------------------------------------------------ */ 1000 /* Function: ipf_pr_esp6 */ 1001 /* Returns: void */ 1002 /* Parameters: fin(I) - pointer to packet information */ 1003 /* */ 1004 /* IPv6 Only */ 1005 /* Analyse the packet for ESP properties. */ 1006 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ 1007 /* even though the newer ESP packets must also have a sequence number that */ 1008 /* is 32bits as well, it is not possible(?) to determine the version from a */ 1009 /* simple packet header. */ 1010 /* ------------------------------------------------------------------------ */ 1011 static inline void 1012 ipf_pr_esp6(fr_info_t *fin) 1013 { 1014 1015 if ((fin->fin_off == 0) && (ipf_pr_pullup(fin, 8) == -1)) { 1016 ipf_main_softc_t *softc = fin->fin_main_soft; 1017 1018 LBUMPD(ipf_stats[fin->fin_out], fr_v6_esp_pullup); 1019 return; 1020 } 1021 } 1022 1023 1024 /* ------------------------------------------------------------------------ */ 1025 /* Function: ipf_pr_ah6 */ 1026 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 1027 /* Parameters: fin(I) - pointer to packet information */ 1028 /* */ 1029 /* IPv6 Only */ 1030 /* Analyse the packet for AH properties. */ 1031 /* The minimum length is taken to be the combination of all fields in the */ 1032 /* header being present and no authentication data (null algorithm used.) */ 1033 /* ------------------------------------------------------------------------ */ 1034 static inline int 1035 ipf_pr_ah6(fr_info_t *fin) 1036 { 1037 authhdr_t *ah; 1038 1039 fin->fin_flx |= FI_AH; 1040 1041 ah = (authhdr_t *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS); 1042 if (ah == NULL) { 1043 ipf_main_softc_t *softc = fin->fin_main_soft; 1044 1045 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ah_bad); 1046 return (IPPROTO_NONE); 1047 } 1048 1049 ipf_pr_short6(fin, sizeof(*ah)); 1050 1051 /* 1052 * No need for another pullup, ipf_pr_ipv6exthdr() will pullup 1053 * enough data to satisfy ah_next (the very first one.) 1054 */ 1055 return (ah->ah_next); 1056 } 1057 1058 1059 /* ------------------------------------------------------------------------ */ 1060 /* Function: ipf_pr_gre6 */ 1061 /* Returns: void */ 1062 /* Parameters: fin(I) - pointer to packet information */ 1063 /* */ 1064 /* Analyse the packet for GRE properties. */ 1065 /* ------------------------------------------------------------------------ */ 1066 static inline void 1067 ipf_pr_gre6(fr_info_t *fin) 1068 { 1069 grehdr_t *gre; 1070 1071 if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) { 1072 ipf_main_softc_t *softc = fin->fin_main_soft; 1073 1074 LBUMPD(ipf_stats[fin->fin_out], fr_v6_gre_pullup); 1075 return; 1076 } 1077 1078 gre = fin->fin_dp; 1079 if (GRE_REV(gre->gr_flags) == 1) 1080 fin->fin_data[0] = gre->gr_call; 1081 } 1082 #endif /* USE_INET6 */ 1083 1084 1085 /* ------------------------------------------------------------------------ */ 1086 /* Function: ipf_pr_pullup */ 1087 /* Returns: int - 0 == pullup succeeded, -1 == failure */ 1088 /* Parameters: fin(I) - pointer to packet information */ 1089 /* plen(I) - length (excluding L3 header) to pullup */ 1090 /* */ 1091 /* Short inline function to cut down on code duplication to perform a call */ 1092 /* to ipf_pullup to ensure there is the required amount of data, */ 1093 /* consecutively in the packet buffer. */ 1094 /* */ 1095 /* This function pulls up 'extra' data at the location of fin_dp. fin_dp */ 1096 /* points to the first byte after the complete layer 3 header, which will */ 1097 /* include all of the known extension headers for IPv6 or options for IPv4. */ 1098 /* */ 1099 /* Since fr_pullup() expects the total length of bytes to be pulled up, it */ 1100 /* is necessary to add those we can already assume to be pulled up (fin_dp */ 1101 /* - fin_ip) to what is passed through. */ 1102 /* ------------------------------------------------------------------------ */ 1103 int 1104 ipf_pr_pullup(fr_info_t *fin, int plen) 1105 { 1106 ipf_main_softc_t *softc = fin->fin_main_soft; 1107 1108 if (fin->fin_m != NULL) { 1109 if (fin->fin_dp != NULL) 1110 plen += (char *)fin->fin_dp - 1111 ((char *)fin->fin_ip + fin->fin_hlen); 1112 plen += fin->fin_hlen; 1113 if (M_LEN(fin->fin_m) < plen + fin->fin_ipoff) { 1114 #if defined(_KERNEL) 1115 if (ipf_pullup(fin->fin_m, fin, plen) == NULL) { 1116 DT1(ipf_pullup_fail, fr_info_t *, fin); 1117 LBUMP(ipf_stats[fin->fin_out].fr_pull[1]); 1118 fin->fin_reason = FRB_PULLUP; 1119 fin->fin_flx |= FI_BAD; 1120 return (-1); 1121 } 1122 LBUMP(ipf_stats[fin->fin_out].fr_pull[0]); 1123 #else 1124 LBUMP(ipf_stats[fin->fin_out].fr_pull[1]); 1125 /* 1126 * Fake ipf_pullup failing 1127 */ 1128 fin->fin_reason = FRB_PULLUP; 1129 *fin->fin_mp = NULL; 1130 fin->fin_m = NULL; 1131 fin->fin_ip = NULL; 1132 fin->fin_flx |= FI_BAD; 1133 return (-1); 1134 #endif 1135 } 1136 } 1137 return (0); 1138 } 1139 1140 1141 /* ------------------------------------------------------------------------ */ 1142 /* Function: ipf_pr_short */ 1143 /* Returns: void */ 1144 /* Parameters: fin(I) - pointer to packet information */ 1145 /* xmin(I) - minimum header size */ 1146 /* */ 1147 /* Check if a packet is "short" as defined by xmin. The rule we are */ 1148 /* applying here is that the packet must not be fragmented within the layer */ 1149 /* 4 header. That is, it must not be a fragment that has its offset set to */ 1150 /* start within the layer 4 header (hdrmin) or if it is at offset 0, the */ 1151 /* entire layer 4 header must be present (min). */ 1152 /* ------------------------------------------------------------------------ */ 1153 static inline void 1154 ipf_pr_short(fr_info_t *fin, int xmin) 1155 { 1156 1157 if (fin->fin_off == 0) { 1158 if (fin->fin_dlen < xmin) 1159 fin->fin_flx |= FI_SHORT; 1160 } else if (fin->fin_off < xmin) { 1161 fin->fin_flx |= FI_SHORT; 1162 } 1163 } 1164 1165 1166 /* ------------------------------------------------------------------------ */ 1167 /* Function: ipf_pr_icmp */ 1168 /* Returns: void */ 1169 /* Parameters: fin(I) - pointer to packet information */ 1170 /* */ 1171 /* IPv4 Only */ 1172 /* Do a sanity check on the packet for ICMP (v4). In nearly all cases, */ 1173 /* except extrememly bad packets, both type and code will be present. */ 1174 /* The expected minimum size of an ICMP packet is very much dependent on */ 1175 /* the type of it. */ 1176 /* */ 1177 /* XXX - other ICMP sanity checks? */ 1178 /* ------------------------------------------------------------------------ */ 1179 static inline void 1180 ipf_pr_icmp(fr_info_t *fin) 1181 { 1182 ipf_main_softc_t *softc = fin->fin_main_soft; 1183 int minicmpsz = sizeof(struct icmp); 1184 icmphdr_t *icmp; 1185 ip_t *oip; 1186 1187 ipf_pr_short(fin, ICMPERR_ICMPHLEN); 1188 1189 if (fin->fin_off != 0) { 1190 LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_frag); 1191 return; 1192 } 1193 1194 if (ipf_pr_pullup(fin, ICMPERR_ICMPHLEN) == -1) { 1195 LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_pullup); 1196 return; 1197 } 1198 1199 icmp = fin->fin_dp; 1200 1201 fin->fin_data[0] = *(u_short *)icmp; 1202 fin->fin_data[1] = icmp->icmp_id; 1203 1204 switch (icmp->icmp_type) 1205 { 1206 case ICMP_ECHOREPLY : 1207 case ICMP_ECHO : 1208 /* Router discovery messaes - RFC 1256 */ 1209 case ICMP_ROUTERADVERT : 1210 case ICMP_ROUTERSOLICIT : 1211 fin->fin_flx |= FI_ICMPQUERY; 1212 minicmpsz = ICMP_MINLEN; 1213 break; 1214 /* 1215 * type(1) + code(1) + cksum(2) + id(2) seq(2) + 1216 * 3 * timestamp(3 * 4) 1217 */ 1218 case ICMP_TSTAMP : 1219 case ICMP_TSTAMPREPLY : 1220 fin->fin_flx |= FI_ICMPQUERY; 1221 minicmpsz = 20; 1222 break; 1223 /* 1224 * type(1) + code(1) + cksum(2) + id(2) seq(2) + 1225 * mask(4) 1226 */ 1227 case ICMP_IREQ : 1228 case ICMP_IREQREPLY : 1229 case ICMP_MASKREQ : 1230 case ICMP_MASKREPLY : 1231 fin->fin_flx |= FI_ICMPQUERY; 1232 minicmpsz = 12; 1233 break; 1234 /* 1235 * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+) 1236 */ 1237 case ICMP_UNREACH : 1238 #ifdef icmp_nextmtu 1239 if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG) { 1240 if (icmp->icmp_nextmtu < softc->ipf_icmpminfragmtu) { 1241 fin->fin_flx |= FI_BAD; 1242 DT3(ipf_fi_bad_icmp_nextmtu, fr_info_t *, fin, u_int, icmp->icmp_nextmtu, u_int, softc->ipf_icmpminfragmtu); 1243 } 1244 } 1245 #endif 1246 /* FALLTHROUGH */ 1247 case ICMP_SOURCEQUENCH : 1248 case ICMP_REDIRECT : 1249 case ICMP_TIMXCEED : 1250 case ICMP_PARAMPROB : 1251 fin->fin_flx |= FI_ICMPERR; 1252 if (ipf_coalesce(fin) != 1) { 1253 LBUMPD(ipf_stats[fin->fin_out], fr_icmp_coalesce); 1254 return; 1255 } 1256 1257 /* 1258 * ICMP error packets should not be generated for IP 1259 * packets that are a fragment that isn't the first 1260 * fragment. 1261 */ 1262 oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN); 1263 if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0) { 1264 fin->fin_flx |= FI_BAD; 1265 DT2(ipf_fi_bad_icmp_err, fr_info_t, fin, u_int, (ntohs(oip->ip_off) & IP_OFFMASK)); 1266 } 1267 1268 /* 1269 * If the destination of this packet doesn't match the 1270 * source of the original packet then this packet is 1271 * not correct. 1272 */ 1273 if (oip->ip_src.s_addr != fin->fin_daddr) { 1274 fin->fin_flx |= FI_BAD; 1275 DT1(ipf_fi_bad_src_ne_dst, fr_info_t *, fin); 1276 } 1277 break; 1278 default : 1279 break; 1280 } 1281 1282 ipf_pr_short(fin, minicmpsz); 1283 1284 ipf_checkv4sum(fin); 1285 } 1286 1287 1288 /* ------------------------------------------------------------------------ */ 1289 /* Function: ipf_pr_tcpcommon */ 1290 /* Returns: int - 0 = header ok, 1 = bad packet, -1 = buffer error */ 1291 /* Parameters: fin(I) - pointer to packet information */ 1292 /* */ 1293 /* TCP header sanity checking. Look for bad combinations of TCP flags, */ 1294 /* and make some checks with how they interact with other fields. */ 1295 /* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is */ 1296 /* valid and mark the packet as bad if not. */ 1297 /* ------------------------------------------------------------------------ */ 1298 static inline int 1299 ipf_pr_tcpcommon(fr_info_t *fin) 1300 { 1301 ipf_main_softc_t *softc = fin->fin_main_soft; 1302 int flags, tlen; 1303 tcphdr_t *tcp; 1304 1305 fin->fin_flx |= FI_TCPUDP; 1306 if (fin->fin_off != 0) { 1307 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_frag); 1308 return (0); 1309 } 1310 1311 if (ipf_pr_pullup(fin, sizeof(*tcp)) == -1) { 1312 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup); 1313 return (-1); 1314 } 1315 1316 tcp = fin->fin_dp; 1317 if (fin->fin_dlen > 3) { 1318 fin->fin_sport = ntohs(tcp->th_sport); 1319 fin->fin_dport = ntohs(tcp->th_dport); 1320 } 1321 1322 if ((fin->fin_flx & FI_SHORT) != 0) { 1323 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_short); 1324 return (1); 1325 } 1326 1327 /* 1328 * Use of the TCP data offset *must* result in a value that is at 1329 * least the same size as the TCP header. 1330 */ 1331 tlen = TCP_OFF(tcp) << 2; 1332 if (tlen < sizeof(tcphdr_t)) { 1333 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_small); 1334 fin->fin_flx |= FI_BAD; 1335 DT3(ipf_fi_bad_tlen, fr_info_t, fin, u_int, tlen, u_int, sizeof(tcphdr_t)); 1336 return (1); 1337 } 1338 1339 flags = tcp->th_flags; 1340 fin->fin_tcpf = tcp->th_flags; 1341 1342 /* 1343 * If the urgent flag is set, then the urgent pointer must 1344 * also be set and vice versa. Good TCP packets do not have 1345 * just one of these set. 1346 */ 1347 if ((flags & TH_URG) != 0 && (tcp->th_urp == 0)) { 1348 fin->fin_flx |= FI_BAD; 1349 DT3(ipf_fi_bad_th_urg, fr_info_t*, fin, u_int, (flags & TH_URG), u_int, tcp->th_urp); 1350 #if 0 1351 } else if ((flags & TH_URG) == 0 && (tcp->th_urp != 0)) { 1352 /* 1353 * Ignore this case (#if 0) as it shows up in "real" 1354 * traffic with bogus values in the urgent pointer field. 1355 */ 1356 fin->fin_flx |= FI_BAD; 1357 DT3(ipf_fi_bad_th_urg0, fr_info_t *, fin, u_int, (flags & TH_URG), u_int, tcp->th_urp); 1358 #endif 1359 } else if (((flags & (TH_SYN|TH_FIN)) != 0) && 1360 ((flags & (TH_RST|TH_ACK)) == TH_RST)) { 1361 /* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */ 1362 fin->fin_flx |= FI_BAD; 1363 DT1(ipf_fi_bad_th_fin_rst_ack, fr_info_t, fin); 1364 #if 1 1365 } else if (((flags & TH_SYN) != 0) && 1366 ((flags & (TH_URG|TH_PUSH)) != 0)) { 1367 /* 1368 * SYN with URG and PUSH set is not for normal TCP but it is 1369 * possible(?) with T/TCP...but who uses T/TCP? 1370 */ 1371 fin->fin_flx |= FI_BAD; 1372 DT1(ipf_fi_bad_th_syn_urg_psh, fr_info_t *, fin); 1373 #endif 1374 } else if (!(flags & TH_ACK)) { 1375 /* 1376 * If the ack bit isn't set, then either the SYN or 1377 * RST bit must be set. If the SYN bit is set, then 1378 * we expect the ACK field to be 0. If the ACK is 1379 * not set and if URG, PSH or FIN are set, consdier 1380 * that to indicate a bad TCP packet. 1381 */ 1382 if ((flags == TH_SYN) && (tcp->th_ack != 0)) { 1383 /* 1384 * Cisco PIX sets the ACK field to a random value. 1385 * In light of this, do not set FI_BAD until a patch 1386 * is available from Cisco to ensure that 1387 * interoperability between existing systems is 1388 * achieved. 1389 */ 1390 /*fin->fin_flx |= FI_BAD*/; 1391 /*DT1(ipf_fi_bad_th_syn_ack, fr_info_t *, fin);*/ 1392 } else if (!(flags & (TH_RST|TH_SYN))) { 1393 fin->fin_flx |= FI_BAD; 1394 DT1(ipf_fi_bad_th_rst_syn, fr_info_t *, fin); 1395 } else if ((flags & (TH_URG|TH_PUSH|TH_FIN)) != 0) { 1396 fin->fin_flx |= FI_BAD; 1397 DT1(ipf_fi_bad_th_urg_push_fin, fr_info_t *, fin); 1398 } 1399 } 1400 if (fin->fin_flx & FI_BAD) { 1401 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_bad_flags); 1402 return (1); 1403 } 1404 1405 /* 1406 * At this point, it's not exactly clear what is to be gained by 1407 * marking up which TCP options are and are not present. The one we 1408 * are most interested in is the TCP window scale. This is only in 1409 * a SYN packet [RFC1323] so we don't need this here...? 1410 * Now if we were to analyse the header for passive fingerprinting, 1411 * then that might add some weight to adding this... 1412 */ 1413 if (tlen == sizeof(tcphdr_t)) { 1414 return (0); 1415 } 1416 1417 if (ipf_pr_pullup(fin, tlen) == -1) { 1418 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup); 1419 return (-1); 1420 } 1421 1422 #if 0 1423 tcp = fin->fin_dp; 1424 ip = fin->fin_ip; 1425 s = (u_char *)(tcp + 1); 1426 off = IP_HL(ip) << 2; 1427 # ifdef _KERNEL 1428 if (fin->fin_mp != NULL) { 1429 mb_t *m = *fin->fin_mp; 1430 1431 if (off + tlen > M_LEN(m)) 1432 return; 1433 } 1434 # endif 1435 for (tlen -= (int)sizeof(*tcp); tlen > 0; ) { 1436 opt = *s; 1437 if (opt == '\0') 1438 break; 1439 else if (opt == TCPOPT_NOP) 1440 ol = 1; 1441 else { 1442 if (tlen < 2) 1443 break; 1444 ol = (int)*(s + 1); 1445 if (ol < 2 || ol > tlen) 1446 break; 1447 } 1448 1449 for (i = 9, mv = 4; mv >= 0; ) { 1450 op = ipopts + i; 1451 if (opt == (u_char)op->ol_val) { 1452 optmsk |= op->ol_bit; 1453 break; 1454 } 1455 } 1456 tlen -= ol; 1457 s += ol; 1458 } 1459 #endif /* 0 */ 1460 1461 return (0); 1462 } 1463 1464 1465 1466 /* ------------------------------------------------------------------------ */ 1467 /* Function: ipf_pr_udpcommon */ 1468 /* Returns: int - 0 = header ok, 1 = bad packet */ 1469 /* Parameters: fin(I) - pointer to packet information */ 1470 /* */ 1471 /* Extract the UDP source and destination ports, if present. If compiled */ 1472 /* with IPFILTER_CKSUM, check to see if the UDP checksum is valid. */ 1473 /* ------------------------------------------------------------------------ */ 1474 static inline int 1475 ipf_pr_udpcommon(fr_info_t *fin) 1476 { 1477 udphdr_t *udp; 1478 1479 fin->fin_flx |= FI_TCPUDP; 1480 1481 if (!fin->fin_off && (fin->fin_dlen > 3)) { 1482 if (ipf_pr_pullup(fin, sizeof(*udp)) == -1) { 1483 ipf_main_softc_t *softc = fin->fin_main_soft; 1484 1485 fin->fin_flx |= FI_SHORT; 1486 LBUMPD(ipf_stats[fin->fin_out], fr_udp_pullup); 1487 return (1); 1488 } 1489 1490 udp = fin->fin_dp; 1491 1492 fin->fin_sport = ntohs(udp->uh_sport); 1493 fin->fin_dport = ntohs(udp->uh_dport); 1494 } 1495 1496 return (0); 1497 } 1498 1499 1500 /* ------------------------------------------------------------------------ */ 1501 /* Function: ipf_pr_tcp */ 1502 /* Returns: void */ 1503 /* Parameters: fin(I) - pointer to packet information */ 1504 /* */ 1505 /* IPv4 Only */ 1506 /* Analyse the packet for IPv4/TCP properties. */ 1507 /* ------------------------------------------------------------------------ */ 1508 static inline void 1509 ipf_pr_tcp(fr_info_t *fin) 1510 { 1511 1512 ipf_pr_short(fin, sizeof(tcphdr_t)); 1513 1514 if (ipf_pr_tcpcommon(fin) == 0) 1515 ipf_checkv4sum(fin); 1516 } 1517 1518 1519 /* ------------------------------------------------------------------------ */ 1520 /* Function: ipf_pr_udp */ 1521 /* Returns: void */ 1522 /* Parameters: fin(I) - pointer to packet information */ 1523 /* */ 1524 /* IPv4 Only */ 1525 /* Analyse the packet for IPv4/UDP properties. */ 1526 /* ------------------------------------------------------------------------ */ 1527 static inline void 1528 ipf_pr_udp(fr_info_t *fin) 1529 { 1530 1531 ipf_pr_short(fin, sizeof(udphdr_t)); 1532 1533 if (ipf_pr_udpcommon(fin) == 0) 1534 ipf_checkv4sum(fin); 1535 } 1536 1537 1538 /* ------------------------------------------------------------------------ */ 1539 /* Function: ipf_pr_esp */ 1540 /* Returns: void */ 1541 /* Parameters: fin(I) - pointer to packet information */ 1542 /* */ 1543 /* Analyse the packet for ESP properties. */ 1544 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ 1545 /* even though the newer ESP packets must also have a sequence number that */ 1546 /* is 32bits as well, it is not possible(?) to determine the version from a */ 1547 /* simple packet header. */ 1548 /* ------------------------------------------------------------------------ */ 1549 static inline void 1550 ipf_pr_esp(fr_info_t *fin) 1551 { 1552 1553 if (fin->fin_off == 0) { 1554 ipf_pr_short(fin, 8); 1555 if (ipf_pr_pullup(fin, 8) == -1) { 1556 ipf_main_softc_t *softc = fin->fin_main_soft; 1557 1558 LBUMPD(ipf_stats[fin->fin_out], fr_v4_esp_pullup); 1559 } 1560 } 1561 } 1562 1563 1564 /* ------------------------------------------------------------------------ */ 1565 /* Function: ipf_pr_ah */ 1566 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 1567 /* Parameters: fin(I) - pointer to packet information */ 1568 /* */ 1569 /* Analyse the packet for AH properties. */ 1570 /* The minimum length is taken to be the combination of all fields in the */ 1571 /* header being present and no authentication data (null algorithm used.) */ 1572 /* ------------------------------------------------------------------------ */ 1573 static inline int 1574 ipf_pr_ah(fr_info_t *fin) 1575 { 1576 ipf_main_softc_t *softc = fin->fin_main_soft; 1577 authhdr_t *ah; 1578 int len; 1579 1580 fin->fin_flx |= FI_AH; 1581 ipf_pr_short(fin, sizeof(*ah)); 1582 1583 if (((fin->fin_flx & FI_SHORT) != 0) || (fin->fin_off != 0)) { 1584 LBUMPD(ipf_stats[fin->fin_out], fr_v4_ah_bad); 1585 return (IPPROTO_NONE); 1586 } 1587 1588 if (ipf_pr_pullup(fin, sizeof(*ah)) == -1) { 1589 DT(fr_v4_ah_pullup_1); 1590 LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup); 1591 return (IPPROTO_NONE); 1592 } 1593 1594 ah = (authhdr_t *)fin->fin_dp; 1595 1596 len = (ah->ah_plen + 2) << 2; 1597 ipf_pr_short(fin, len); 1598 if (ipf_pr_pullup(fin, len) == -1) { 1599 DT(fr_v4_ah_pullup_2); 1600 LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup); 1601 return (IPPROTO_NONE); 1602 } 1603 1604 /* 1605 * Adjust fin_dp and fin_dlen for skipping over the authentication 1606 * header. 1607 */ 1608 fin->fin_dp = (char *)fin->fin_dp + len; 1609 fin->fin_dlen -= len; 1610 return (ah->ah_next); 1611 } 1612 1613 1614 /* ------------------------------------------------------------------------ */ 1615 /* Function: ipf_pr_gre */ 1616 /* Returns: void */ 1617 /* Parameters: fin(I) - pointer to packet information */ 1618 /* */ 1619 /* Analyse the packet for GRE properties. */ 1620 /* ------------------------------------------------------------------------ */ 1621 static inline void 1622 ipf_pr_gre(fr_info_t *fin) 1623 { 1624 ipf_main_softc_t *softc = fin->fin_main_soft; 1625 grehdr_t *gre; 1626 1627 ipf_pr_short(fin, sizeof(grehdr_t)); 1628 1629 if (fin->fin_off != 0) { 1630 LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_frag); 1631 return; 1632 } 1633 1634 if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) { 1635 LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_pullup); 1636 return; 1637 } 1638 1639 gre = fin->fin_dp; 1640 if (GRE_REV(gre->gr_flags) == 1) 1641 fin->fin_data[0] = gre->gr_call; 1642 } 1643 1644 1645 /* ------------------------------------------------------------------------ */ 1646 /* Function: ipf_pr_ipv4hdr */ 1647 /* Returns: void */ 1648 /* Parameters: fin(I) - pointer to packet information */ 1649 /* */ 1650 /* IPv4 Only */ 1651 /* Analyze the IPv4 header and set fields in the fr_info_t structure. */ 1652 /* Check all options present and flag their presence if any exist. */ 1653 /* ------------------------------------------------------------------------ */ 1654 static inline void 1655 ipf_pr_ipv4hdr(fr_info_t *fin) 1656 { 1657 u_short optmsk = 0, secmsk = 0, auth = 0; 1658 int hlen, ol, mv, p, i; 1659 const struct optlist *op; 1660 u_char *s, opt; 1661 u_short off; 1662 fr_ip_t *fi; 1663 ip_t *ip; 1664 1665 fi = &fin->fin_fi; 1666 hlen = fin->fin_hlen; 1667 1668 ip = fin->fin_ip; 1669 p = ip->ip_p; 1670 fi->fi_p = p; 1671 fin->fin_crc = p; 1672 fi->fi_tos = ip->ip_tos; 1673 fin->fin_id = ntohs(ip->ip_id); 1674 off = ntohs(ip->ip_off); 1675 1676 /* Get both TTL and protocol */ 1677 fi->fi_p = ip->ip_p; 1678 fi->fi_ttl = ip->ip_ttl; 1679 1680 /* Zero out bits not used in IPv6 address */ 1681 fi->fi_src.i6[1] = 0; 1682 fi->fi_src.i6[2] = 0; 1683 fi->fi_src.i6[3] = 0; 1684 fi->fi_dst.i6[1] = 0; 1685 fi->fi_dst.i6[2] = 0; 1686 fi->fi_dst.i6[3] = 0; 1687 1688 fi->fi_saddr = ip->ip_src.s_addr; 1689 fin->fin_crc += fi->fi_saddr; 1690 fi->fi_daddr = ip->ip_dst.s_addr; 1691 fin->fin_crc += fi->fi_daddr; 1692 if (IN_MULTICAST(ntohl(fi->fi_daddr))) 1693 fin->fin_flx |= FI_MULTICAST|FI_MBCAST; 1694 1695 /* 1696 * set packet attribute flags based on the offset and 1697 * calculate the byte offset that it represents. 1698 */ 1699 off &= IP_MF|IP_OFFMASK; 1700 if (off != 0) { 1701 int morefrag = off & IP_MF; 1702 1703 fi->fi_flx |= FI_FRAG; 1704 off &= IP_OFFMASK; 1705 if (off == 1 && p == IPPROTO_TCP) { 1706 fin->fin_flx |= FI_SHORT; /* RFC 3128 */ 1707 DT1(ipf_fi_tcp_frag_off_1, fr_info_t *, fin); 1708 } 1709 if (off != 0) { 1710 fin->fin_flx |= FI_FRAGBODY; 1711 off <<= 3; 1712 if ((off + fin->fin_dlen > 65535) || 1713 (fin->fin_dlen == 0) || 1714 ((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) { 1715 /* 1716 * The length of the packet, starting at its 1717 * offset cannot exceed 65535 (0xffff) as the 1718 * length of an IP packet is only 16 bits. 1719 * 1720 * Any fragment that isn't the last fragment 1721 * must have a length greater than 0 and it 1722 * must be an even multiple of 8. 1723 */ 1724 fi->fi_flx |= FI_BAD; 1725 DT1(ipf_fi_bad_fragbody_gt_65535, fr_info_t *, fin); 1726 } 1727 } 1728 } 1729 fin->fin_off = off; 1730 1731 /* 1732 * Call per-protocol setup and checking 1733 */ 1734 if (p == IPPROTO_AH) { 1735 /* 1736 * Treat AH differently because we expect there to be another 1737 * layer 4 header after it. 1738 */ 1739 p = ipf_pr_ah(fin); 1740 } 1741 1742 switch (p) 1743 { 1744 case IPPROTO_UDP : 1745 ipf_pr_udp(fin); 1746 break; 1747 case IPPROTO_TCP : 1748 ipf_pr_tcp(fin); 1749 break; 1750 case IPPROTO_ICMP : 1751 ipf_pr_icmp(fin); 1752 break; 1753 case IPPROTO_ESP : 1754 ipf_pr_esp(fin); 1755 break; 1756 case IPPROTO_GRE : 1757 ipf_pr_gre(fin); 1758 break; 1759 } 1760 1761 ip = fin->fin_ip; 1762 if (ip == NULL) 1763 return; 1764 1765 /* 1766 * If it is a standard IP header (no options), set the flag fields 1767 * which relate to options to 0. 1768 */ 1769 if (hlen == sizeof(*ip)) { 1770 fi->fi_optmsk = 0; 1771 fi->fi_secmsk = 0; 1772 fi->fi_auth = 0; 1773 return; 1774 } 1775 1776 /* 1777 * So the IP header has some IP options attached. Walk the entire 1778 * list of options present with this packet and set flags to indicate 1779 * which ones are here and which ones are not. For the somewhat out 1780 * of date and obscure security classification options, set a flag to 1781 * represent which classification is present. 1782 */ 1783 fi->fi_flx |= FI_OPTIONS; 1784 1785 for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) { 1786 opt = *s; 1787 if (opt == '\0') 1788 break; 1789 else if (opt == IPOPT_NOP) 1790 ol = 1; 1791 else { 1792 if (hlen < 2) 1793 break; 1794 ol = (int)*(s + 1); 1795 if (ol < 2 || ol > hlen) 1796 break; 1797 } 1798 for (i = 9, mv = 4; mv >= 0; ) { 1799 op = ipopts + i; 1800 1801 if ((opt == (u_char)op->ol_val) && (ol > 4)) { 1802 u_32_t doi; 1803 1804 switch (opt) 1805 { 1806 case IPOPT_SECURITY : 1807 if (optmsk & op->ol_bit) { 1808 fin->fin_flx |= FI_BAD; 1809 DT2(ipf_fi_bad_ipopt_security, fr_info_t *, fin, u_short, (optmsk & op->ol_bit)); 1810 } else { 1811 doi = ipf_checkripso(s); 1812 secmsk = doi >> 16; 1813 auth = doi & 0xffff; 1814 } 1815 break; 1816 1817 case IPOPT_CIPSO : 1818 1819 if (optmsk & op->ol_bit) { 1820 fin->fin_flx |= FI_BAD; 1821 DT2(ipf_fi_bad_ipopt_cipso, fr_info_t *, fin, u_short, (optmsk & op->ol_bit)); 1822 } else { 1823 doi = ipf_checkcipso(fin, 1824 s, ol); 1825 secmsk = doi >> 16; 1826 auth = doi & 0xffff; 1827 } 1828 break; 1829 } 1830 optmsk |= op->ol_bit; 1831 } 1832 1833 if (opt < op->ol_val) 1834 i -= mv; 1835 else 1836 i += mv; 1837 mv--; 1838 } 1839 hlen -= ol; 1840 s += ol; 1841 } 1842 1843 /* 1844 * 1845 */ 1846 if (auth && !(auth & 0x0100)) 1847 auth &= 0xff00; 1848 fi->fi_optmsk = optmsk; 1849 fi->fi_secmsk = secmsk; 1850 fi->fi_auth = auth; 1851 } 1852 1853 1854 /* ------------------------------------------------------------------------ */ 1855 /* Function: ipf_checkripso */ 1856 /* Returns: void */ 1857 /* Parameters: s(I) - pointer to start of RIPSO option */ 1858 /* */ 1859 /* ------------------------------------------------------------------------ */ 1860 static u_32_t 1861 ipf_checkripso(u_char *s) 1862 { 1863 const struct optlist *sp; 1864 u_short secmsk = 0, auth = 0; 1865 u_char sec; 1866 int j, m; 1867 1868 sec = *(s + 2); /* classification */ 1869 for (j = 3, m = 2; m >= 0; ) { 1870 sp = secopt + j; 1871 if (sec == sp->ol_val) { 1872 secmsk |= sp->ol_bit; 1873 auth = *(s + 3); 1874 auth *= 256; 1875 auth += *(s + 4); 1876 break; 1877 } 1878 if (sec < sp->ol_val) 1879 j -= m; 1880 else 1881 j += m; 1882 m--; 1883 } 1884 1885 return (secmsk << 16) | auth; 1886 } 1887 1888 1889 /* ------------------------------------------------------------------------ */ 1890 /* Function: ipf_checkcipso */ 1891 /* Returns: u_32_t - 0 = failure, else the doi from the header */ 1892 /* Parameters: fin(IO) - pointer to packet information */ 1893 /* s(I) - pointer to start of CIPSO option */ 1894 /* ol(I) - length of CIPSO option field */ 1895 /* */ 1896 /* This function returns the domain of integrity (DOI) field from the CIPSO */ 1897 /* header and returns that whilst also storing the highest sensitivity */ 1898 /* value found in the fr_info_t structure. */ 1899 /* */ 1900 /* No attempt is made to extract the category bitmaps as these are defined */ 1901 /* by the user (rather than the protocol) and can be rather numerous on the */ 1902 /* end nodes. */ 1903 /* ------------------------------------------------------------------------ */ 1904 static u_32_t 1905 ipf_checkcipso(fr_info_t *fin, u_char *s, int ol) 1906 { 1907 ipf_main_softc_t *softc = fin->fin_main_soft; 1908 fr_ip_t *fi; 1909 u_32_t doi; 1910 u_char *t, tag, tlen, sensitivity; 1911 int len; 1912 1913 if (ol < 6 || ol > 40) { 1914 LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_bad); 1915 fin->fin_flx |= FI_BAD; 1916 DT2(ipf_fi_bad_checkcipso_ol, fr_info_t *, fin, u_int, ol); 1917 return (0); 1918 } 1919 1920 fi = &fin->fin_fi; 1921 fi->fi_sensitivity = 0; 1922 /* 1923 * The DOI field MUST be there. 1924 */ 1925 bcopy(s + 2, &doi, sizeof(doi)); 1926 1927 t = (u_char *)s + 6; 1928 for (len = ol - 6; len >= 2; len -= tlen, t+= tlen) { 1929 tag = *t; 1930 tlen = *(t + 1); 1931 if (tlen > len || tlen < 4 || tlen > 34) { 1932 LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_tlen); 1933 fin->fin_flx |= FI_BAD; 1934 DT2(ipf_fi_bad_checkcipso_tlen, fr_info_t *, fin, u_int, tlen); 1935 return (0); 1936 } 1937 1938 sensitivity = 0; 1939 /* 1940 * Tag numbers 0, 1, 2, 5 are laid out in the CIPSO Internet 1941 * draft (16 July 1992) that has expired. 1942 */ 1943 if (tag == 0) { 1944 fin->fin_flx |= FI_BAD; 1945 DT2(ipf_fi_bad_checkcipso_tag, fr_info_t *, fin, u_int, tag); 1946 continue; 1947 } else if (tag == 1) { 1948 if (*(t + 2) != 0) { 1949 fin->fin_flx |= FI_BAD; 1950 DT2(ipf_fi_bad_checkcipso_tag1_t2, fr_info_t *, fin, u_int, (*t + 2)); 1951 continue; 1952 } 1953 sensitivity = *(t + 3); 1954 /* Category bitmap for categories 0-239 */ 1955 1956 } else if (tag == 4) { 1957 if (*(t + 2) != 0) { 1958 fin->fin_flx |= FI_BAD; 1959 DT2(ipf_fi_bad_checkcipso_tag4_t2, fr_info_t *, fin, u_int, (*t + 2)); 1960 continue; 1961 } 1962 sensitivity = *(t + 3); 1963 /* Enumerated categories, 16bits each, upto 15 */ 1964 1965 } else if (tag == 5) { 1966 if (*(t + 2) != 0) { 1967 fin->fin_flx |= FI_BAD; 1968 DT2(ipf_fi_bad_checkcipso_tag5_t2, fr_info_t *, fin, u_int, (*t + 2)); 1969 continue; 1970 } 1971 sensitivity = *(t + 3); 1972 /* Range of categories (2*16bits), up to 7 pairs */ 1973 1974 } else if (tag > 127) { 1975 /* Custom defined DOI */ 1976 ; 1977 } else { 1978 fin->fin_flx |= FI_BAD; 1979 DT2(ipf_fi_bad_checkcipso_tag127, fr_info_t *, fin, u_int, tag); 1980 continue; 1981 } 1982 1983 if (sensitivity > fi->fi_sensitivity) 1984 fi->fi_sensitivity = sensitivity; 1985 } 1986 1987 return (doi); 1988 } 1989 1990 1991 /* ------------------------------------------------------------------------ */ 1992 /* Function: ipf_makefrip */ 1993 /* Returns: int - 0 == packet ok, -1 == packet freed */ 1994 /* Parameters: hlen(I) - length of IP packet header */ 1995 /* ip(I) - pointer to the IP header */ 1996 /* fin(IO) - pointer to packet information */ 1997 /* */ 1998 /* Compact the IP header into a structure which contains just the info. */ 1999 /* which is useful for comparing IP headers with and store this information */ 2000 /* in the fr_info_t structure pointer to by fin. At present, it is assumed */ 2001 /* this function will be called with either an IPv4 or IPv6 packet. */ 2002 /* ------------------------------------------------------------------------ */ 2003 int 2004 ipf_makefrip(int hlen, ip_t *ip, fr_info_t *fin) 2005 { 2006 ipf_main_softc_t *softc = fin->fin_main_soft; 2007 int v; 2008 2009 fin->fin_depth = 0; 2010 fin->fin_hlen = (u_short)hlen; 2011 fin->fin_ip = ip; 2012 fin->fin_rule = 0xffffffff; 2013 fin->fin_group[0] = -1; 2014 fin->fin_group[1] = '\0'; 2015 fin->fin_dp = (char *)ip + hlen; 2016 2017 v = fin->fin_v; 2018 if (v == 4) { 2019 fin->fin_plen = ntohs(ip->ip_len); 2020 fin->fin_dlen = fin->fin_plen - hlen; 2021 ipf_pr_ipv4hdr(fin); 2022 #ifdef USE_INET6 2023 } else if (v == 6) { 2024 fin->fin_plen = ntohs(((ip6_t *)ip)->ip6_plen); 2025 fin->fin_dlen = fin->fin_plen; 2026 fin->fin_plen += hlen; 2027 2028 ipf_pr_ipv6hdr(fin); 2029 #endif 2030 } 2031 if (fin->fin_ip == NULL) { 2032 LBUMP(ipf_stats[fin->fin_out].fr_ip_freed); 2033 return (-1); 2034 } 2035 return (0); 2036 } 2037 2038 2039 /* ------------------------------------------------------------------------ */ 2040 /* Function: ipf_portcheck */ 2041 /* Returns: int - 1 == port matched, 0 == port match failed */ 2042 /* Parameters: frp(I) - pointer to port check `expression' */ 2043 /* pop(I) - port number to evaluate */ 2044 /* */ 2045 /* Perform a comparison of a port number against some other(s), using a */ 2046 /* structure with compare information stored in it. */ 2047 /* ------------------------------------------------------------------------ */ 2048 static inline int 2049 ipf_portcheck(frpcmp_t *frp, u_32_t pop) 2050 { 2051 int err = 1; 2052 u_32_t po; 2053 2054 po = frp->frp_port; 2055 2056 /* 2057 * Do opposite test to that required and continue if that succeeds. 2058 */ 2059 switch (frp->frp_cmp) 2060 { 2061 case FR_EQUAL : 2062 if (pop != po) /* EQUAL */ 2063 err = 0; 2064 break; 2065 case FR_NEQUAL : 2066 if (pop == po) /* NOTEQUAL */ 2067 err = 0; 2068 break; 2069 case FR_LESST : 2070 if (pop >= po) /* LESSTHAN */ 2071 err = 0; 2072 break; 2073 case FR_GREATERT : 2074 if (pop <= po) /* GREATERTHAN */ 2075 err = 0; 2076 break; 2077 case FR_LESSTE : 2078 if (pop > po) /* LT or EQ */ 2079 err = 0; 2080 break; 2081 case FR_GREATERTE : 2082 if (pop < po) /* GT or EQ */ 2083 err = 0; 2084 break; 2085 case FR_OUTRANGE : 2086 if (pop >= po && pop <= frp->frp_top) /* Out of range */ 2087 err = 0; 2088 break; 2089 case FR_INRANGE : 2090 if (pop <= po || pop >= frp->frp_top) /* In range */ 2091 err = 0; 2092 break; 2093 case FR_INCRANGE : 2094 if (pop < po || pop > frp->frp_top) /* Inclusive range */ 2095 err = 0; 2096 break; 2097 default : 2098 break; 2099 } 2100 return (err); 2101 } 2102 2103 2104 /* ------------------------------------------------------------------------ */ 2105 /* Function: ipf_tcpudpchk */ 2106 /* Returns: int - 1 == protocol matched, 0 == check failed */ 2107 /* Parameters: fda(I) - pointer to packet information */ 2108 /* ft(I) - pointer to structure with comparison data */ 2109 /* */ 2110 /* Compares the current pcket (assuming it is TCP/UDP) information with a */ 2111 /* structure containing information that we want to match against. */ 2112 /* ------------------------------------------------------------------------ */ 2113 int 2114 ipf_tcpudpchk(fr_ip_t *fi, frtuc_t *ft) 2115 { 2116 int err = 1; 2117 2118 /* 2119 * Both ports should *always* be in the first fragment. 2120 * So far, I cannot find any cases where they can not be. 2121 * 2122 * compare destination ports 2123 */ 2124 if (ft->ftu_dcmp) 2125 err = ipf_portcheck(&ft->ftu_dst, fi->fi_ports[1]); 2126 2127 /* 2128 * compare source ports 2129 */ 2130 if (err && ft->ftu_scmp) 2131 err = ipf_portcheck(&ft->ftu_src, fi->fi_ports[0]); 2132 2133 /* 2134 * If we don't have all the TCP/UDP header, then how can we 2135 * expect to do any sort of match on it ? If we were looking for 2136 * TCP flags, then NO match. If not, then match (which should 2137 * satisfy the "short" class too). 2138 */ 2139 if (err && (fi->fi_p == IPPROTO_TCP)) { 2140 if (fi->fi_flx & FI_SHORT) 2141 return (!(ft->ftu_tcpf | ft->ftu_tcpfm)); 2142 /* 2143 * Match the flags ? If not, abort this match. 2144 */ 2145 if (ft->ftu_tcpfm && 2146 ft->ftu_tcpf != (fi->fi_tcpf & ft->ftu_tcpfm)) { 2147 FR_DEBUG(("f. %#x & %#x != %#x\n", fi->fi_tcpf, 2148 ft->ftu_tcpfm, ft->ftu_tcpf)); 2149 err = 0; 2150 } 2151 } 2152 return (err); 2153 } 2154 2155 2156 /* ------------------------------------------------------------------------ */ 2157 /* Function: ipf_check_ipf */ 2158 /* Returns: int - 0 == match, else no match */ 2159 /* Parameters: fin(I) - pointer to packet information */ 2160 /* fr(I) - pointer to filter rule */ 2161 /* portcmp(I) - flag indicating whether to attempt matching on */ 2162 /* TCP/UDP port data. */ 2163 /* */ 2164 /* Check to see if a packet matches an IPFilter rule. Checks of addresses, */ 2165 /* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */ 2166 /* this function. */ 2167 /* ------------------------------------------------------------------------ */ 2168 static inline int 2169 ipf_check_ipf(fr_info_t *fin, frentry_t *fr, int portcmp) 2170 { 2171 u_32_t *ld, *lm, *lip; 2172 fripf_t *fri; 2173 fr_ip_t *fi; 2174 int i; 2175 2176 fi = &fin->fin_fi; 2177 fri = fr->fr_ipf; 2178 lip = (u_32_t *)fi; 2179 lm = (u_32_t *)&fri->fri_mip; 2180 ld = (u_32_t *)&fri->fri_ip; 2181 2182 /* 2183 * first 32 bits to check coversion: 2184 * IP version, TOS, TTL, protocol 2185 */ 2186 i = ((*lip & *lm) != *ld); 2187 FR_DEBUG(("0. %#08x & %#08x != %#08x\n", 2188 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2189 if (i) 2190 return (1); 2191 2192 /* 2193 * Next 32 bits is a constructed bitmask indicating which IP options 2194 * are present (if any) in this packet. 2195 */ 2196 lip++, lm++, ld++; 2197 i = ((*lip & *lm) != *ld); 2198 FR_DEBUG(("1. %#08x & %#08x != %#08x\n", 2199 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2200 if (i != 0) 2201 return (1); 2202 2203 lip++, lm++, ld++; 2204 /* 2205 * Unrolled loops (4 each, for 32 bits) for address checks. 2206 */ 2207 /* 2208 * Check the source address. 2209 */ 2210 if (fr->fr_satype == FRI_LOOKUP) { 2211 i = (*fr->fr_srcfunc)(fin->fin_main_soft, fr->fr_srcptr, 2212 fi->fi_v, lip, fin->fin_plen); 2213 if (i == -1) 2214 return (1); 2215 lip += 3; 2216 lm += 3; 2217 ld += 3; 2218 } else { 2219 i = ((*lip & *lm) != *ld); 2220 FR_DEBUG(("2a. %#08x & %#08x != %#08x\n", 2221 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2222 if (fi->fi_v == 6) { 2223 lip++, lm++, ld++; 2224 i |= ((*lip & *lm) != *ld); 2225 FR_DEBUG(("2b. %#08x & %#08x != %#08x\n", 2226 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2227 lip++, lm++, ld++; 2228 i |= ((*lip & *lm) != *ld); 2229 FR_DEBUG(("2c. %#08x & %#08x != %#08x\n", 2230 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2231 lip++, lm++, ld++; 2232 i |= ((*lip & *lm) != *ld); 2233 FR_DEBUG(("2d. %#08x & %#08x != %#08x\n", 2234 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2235 } else { 2236 lip += 3; 2237 lm += 3; 2238 ld += 3; 2239 } 2240 } 2241 i ^= (fr->fr_flags & FR_NOTSRCIP) >> 6; 2242 if (i != 0) 2243 return (1); 2244 2245 /* 2246 * Check the destination address. 2247 */ 2248 lip++, lm++, ld++; 2249 if (fr->fr_datype == FRI_LOOKUP) { 2250 i = (*fr->fr_dstfunc)(fin->fin_main_soft, fr->fr_dstptr, 2251 fi->fi_v, lip, fin->fin_plen); 2252 if (i == -1) 2253 return (1); 2254 lip += 3; 2255 lm += 3; 2256 ld += 3; 2257 } else { 2258 i = ((*lip & *lm) != *ld); 2259 FR_DEBUG(("3a. %#08x & %#08x != %#08x\n", 2260 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2261 if (fi->fi_v == 6) { 2262 lip++, lm++, ld++; 2263 i |= ((*lip & *lm) != *ld); 2264 FR_DEBUG(("3b. %#08x & %#08x != %#08x\n", 2265 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2266 lip++, lm++, ld++; 2267 i |= ((*lip & *lm) != *ld); 2268 FR_DEBUG(("3c. %#08x & %#08x != %#08x\n", 2269 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2270 lip++, lm++, ld++; 2271 i |= ((*lip & *lm) != *ld); 2272 FR_DEBUG(("3d. %#08x & %#08x != %#08x\n", 2273 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2274 } else { 2275 lip += 3; 2276 lm += 3; 2277 ld += 3; 2278 } 2279 } 2280 i ^= (fr->fr_flags & FR_NOTDSTIP) >> 7; 2281 if (i != 0) 2282 return (1); 2283 /* 2284 * IP addresses matched. The next 32bits contains: 2285 * mast of old IP header security & authentication bits. 2286 */ 2287 lip++, lm++, ld++; 2288 i = (*ld - (*lip & *lm)); 2289 FR_DEBUG(("4. %#08x & %#08x != %#08x\n", *lip, *lm, *ld)); 2290 2291 /* 2292 * Next we have 32 bits of packet flags. 2293 */ 2294 lip++, lm++, ld++; 2295 i |= (*ld - (*lip & *lm)); 2296 FR_DEBUG(("5. %#08x & %#08x != %#08x\n", *lip, *lm, *ld)); 2297 2298 if (i == 0) { 2299 /* 2300 * If a fragment, then only the first has what we're 2301 * looking for here... 2302 */ 2303 if (portcmp) { 2304 if (!ipf_tcpudpchk(&fin->fin_fi, &fr->fr_tuc)) 2305 i = 1; 2306 } else { 2307 if (fr->fr_dcmp || fr->fr_scmp || 2308 fr->fr_tcpf || fr->fr_tcpfm) 2309 i = 1; 2310 if (fr->fr_icmpm || fr->fr_icmp) { 2311 if (((fi->fi_p != IPPROTO_ICMP) && 2312 (fi->fi_p != IPPROTO_ICMPV6)) || 2313 fin->fin_off || (fin->fin_dlen < 2)) 2314 i = 1; 2315 else if ((fin->fin_data[0] & fr->fr_icmpm) != 2316 fr->fr_icmp) { 2317 FR_DEBUG(("i. %#x & %#x != %#x\n", 2318 fin->fin_data[0], 2319 fr->fr_icmpm, fr->fr_icmp)); 2320 i = 1; 2321 } 2322 } 2323 } 2324 } 2325 return (i); 2326 } 2327 2328 2329 /* ------------------------------------------------------------------------ */ 2330 /* Function: ipf_scanlist */ 2331 /* Returns: int - result flags of scanning filter list */ 2332 /* Parameters: fin(I) - pointer to packet information */ 2333 /* pass(I) - default result to return for filtering */ 2334 /* */ 2335 /* Check the input/output list of rules for a match to the current packet. */ 2336 /* If a match is found, the value of fr_flags from the rule becomes the */ 2337 /* return value and fin->fin_fr points to the matched rule. */ 2338 /* */ 2339 /* This function may be called recursively upto 16 times (limit inbuilt.) */ 2340 /* When unwinding, it should finish up with fin_depth as 0. */ 2341 /* */ 2342 /* Could be per interface, but this gets real nasty when you don't have, */ 2343 /* or can't easily change, the kernel source code to . */ 2344 /* ------------------------------------------------------------------------ */ 2345 int 2346 ipf_scanlist(fr_info_t *fin, u_32_t pass) 2347 { 2348 ipf_main_softc_t *softc = fin->fin_main_soft; 2349 int rulen, portcmp, off, skip; 2350 struct frentry *fr, *fnext; 2351 u_32_t passt, passo; 2352 2353 /* 2354 * Do not allow nesting deeper than 16 levels. 2355 */ 2356 if (fin->fin_depth >= 16) 2357 return (pass); 2358 2359 fr = fin->fin_fr; 2360 2361 /* 2362 * If there are no rules in this list, return now. 2363 */ 2364 if (fr == NULL) 2365 return (pass); 2366 2367 skip = 0; 2368 portcmp = 0; 2369 fin->fin_depth++; 2370 fin->fin_fr = NULL; 2371 off = fin->fin_off; 2372 2373 if ((fin->fin_flx & FI_TCPUDP) && (fin->fin_dlen > 3) && !off) 2374 portcmp = 1; 2375 2376 for (rulen = 0; fr; fr = fnext, rulen++) { 2377 fnext = fr->fr_next; 2378 if (skip != 0) { 2379 FR_VERBOSE(("SKIP %d (%#x)\n", skip, fr->fr_flags)); 2380 skip--; 2381 continue; 2382 } 2383 2384 /* 2385 * In all checks below, a null (zero) value in the 2386 * filter struture is taken to mean a wildcard. 2387 * 2388 * check that we are working for the right interface 2389 */ 2390 #ifdef _KERNEL 2391 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) 2392 continue; 2393 #else 2394 if (opts & (OPT_VERBOSE|OPT_DEBUG)) 2395 printf("\n"); 2396 FR_VERBOSE(("%c", FR_ISSKIP(pass) ? 's' : 2397 FR_ISPASS(pass) ? 'p' : 2398 FR_ISACCOUNT(pass) ? 'A' : 2399 FR_ISAUTH(pass) ? 'a' : 2400 (pass & FR_NOMATCH) ? 'n' :'b')); 2401 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) 2402 continue; 2403 FR_VERBOSE((":i")); 2404 #endif 2405 2406 switch (fr->fr_type) 2407 { 2408 case FR_T_IPF : 2409 case FR_T_IPF_BUILTIN : 2410 if (ipf_check_ipf(fin, fr, portcmp)) 2411 continue; 2412 break; 2413 #if defined(IPFILTER_BPF) 2414 case FR_T_BPFOPC : 2415 case FR_T_BPFOPC_BUILTIN : 2416 { 2417 u_char *mc; 2418 int wlen; 2419 2420 if (*fin->fin_mp == NULL) 2421 continue; 2422 if (fin->fin_family != fr->fr_family) 2423 continue; 2424 mc = (u_char *)fin->fin_m; 2425 wlen = fin->fin_dlen + fin->fin_hlen; 2426 if (!bpf_filter(fr->fr_data, mc, wlen, 0)) 2427 continue; 2428 break; 2429 } 2430 #endif 2431 case FR_T_CALLFUNC_BUILTIN : 2432 { 2433 frentry_t *f; 2434 2435 f = (*fr->fr_func)(fin, &pass); 2436 if (f != NULL) 2437 fr = f; 2438 else 2439 continue; 2440 break; 2441 } 2442 2443 case FR_T_IPFEXPR : 2444 case FR_T_IPFEXPR_BUILTIN : 2445 if (fin->fin_family != fr->fr_family) 2446 continue; 2447 if (ipf_fr_matcharray(fin, fr->fr_data) == 0) 2448 continue; 2449 break; 2450 2451 default : 2452 break; 2453 } 2454 2455 if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) { 2456 if (fin->fin_nattag == NULL) 2457 continue; 2458 if (ipf_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0) 2459 continue; 2460 } 2461 FR_VERBOSE(("=%d/%d.%d *", fr->fr_grhead, fr->fr_group, rulen)); 2462 2463 passt = fr->fr_flags; 2464 2465 /* 2466 * If the rule is a "call now" rule, then call the function 2467 * in the rule, if it exists and use the results from that. 2468 * If the function pointer is bad, just make like we ignore 2469 * it, except for increasing the hit counter. 2470 */ 2471 if ((passt & FR_CALLNOW) != 0) { 2472 frentry_t *frs; 2473 2474 ATOMIC_INC64(fr->fr_hits); 2475 if ((fr->fr_func == NULL) || 2476 (fr->fr_func == (ipfunc_t)-1)) 2477 continue; 2478 2479 frs = fin->fin_fr; 2480 fin->fin_fr = fr; 2481 fr = (*fr->fr_func)(fin, &passt); 2482 if (fr == NULL) { 2483 fin->fin_fr = frs; 2484 continue; 2485 } 2486 passt = fr->fr_flags; 2487 } 2488 fin->fin_fr = fr; 2489 2490 #ifdef IPFILTER_LOG 2491 /* 2492 * Just log this packet... 2493 */ 2494 if ((passt & FR_LOGMASK) == FR_LOG) { 2495 if (ipf_log_pkt(fin, passt) == -1) { 2496 if (passt & FR_LOGORBLOCK) { 2497 DT(frb_logfail); 2498 passt &= ~FR_CMDMASK; 2499 passt |= FR_BLOCK|FR_QUICK; 2500 fin->fin_reason = FRB_LOGFAIL; 2501 } 2502 } 2503 } 2504 #endif /* IPFILTER_LOG */ 2505 2506 MUTEX_ENTER(&fr->fr_lock); 2507 fr->fr_bytes += (U_QUAD_T)fin->fin_plen; 2508 fr->fr_hits++; 2509 MUTEX_EXIT(&fr->fr_lock); 2510 fin->fin_rule = rulen; 2511 2512 passo = pass; 2513 if (FR_ISSKIP(passt)) { 2514 skip = fr->fr_arg; 2515 continue; 2516 } else if (((passt & FR_LOGMASK) != FR_LOG) && 2517 ((passt & FR_LOGMASK) != FR_DECAPSULATE)) { 2518 pass = passt; 2519 } 2520 2521 if (passt & (FR_RETICMP|FR_FAKEICMP)) 2522 fin->fin_icode = fr->fr_icode; 2523 2524 if (fr->fr_group != -1) { 2525 (void) strncpy(fin->fin_group, 2526 FR_NAME(fr, fr_group), 2527 strlen(FR_NAME(fr, fr_group))); 2528 } else { 2529 fin->fin_group[0] = '\0'; 2530 } 2531 2532 FR_DEBUG(("pass %#x/%#x/%x\n", passo, pass, passt)); 2533 2534 if (fr->fr_grphead != NULL) { 2535 fin->fin_fr = fr->fr_grphead->fg_start; 2536 FR_VERBOSE(("group %s\n", FR_NAME(fr, fr_grhead))); 2537 2538 if (FR_ISDECAPS(passt)) 2539 passt = ipf_decaps(fin, pass, fr->fr_icode); 2540 else 2541 passt = ipf_scanlist(fin, pass); 2542 2543 if (fin->fin_fr == NULL) { 2544 fin->fin_rule = rulen; 2545 if (fr->fr_group != -1) 2546 (void) strncpy(fin->fin_group, 2547 fr->fr_names + 2548 fr->fr_group, 2549 strlen(fr->fr_names + 2550 fr->fr_group)); 2551 fin->fin_fr = fr; 2552 passt = pass; 2553 } 2554 pass = passt; 2555 } 2556 2557 if (pass & FR_QUICK) { 2558 /* 2559 * Finally, if we've asked to track state for this 2560 * packet, set it up. Add state for "quick" rules 2561 * here so that if the action fails we can consider 2562 * the rule to "not match" and keep on processing 2563 * filter rules. 2564 */ 2565 if ((pass & FR_KEEPSTATE) && !FR_ISAUTH(pass) && 2566 !(fin->fin_flx & FI_STATE)) { 2567 int out = fin->fin_out; 2568 2569 fin->fin_fr = fr; 2570 if (ipf_state_add(softc, fin, NULL, 0) == 0) { 2571 LBUMPD(ipf_stats[out], fr_ads); 2572 } else { 2573 LBUMPD(ipf_stats[out], fr_bads); 2574 pass = passo; 2575 continue; 2576 } 2577 } 2578 break; 2579 } 2580 } 2581 fin->fin_depth--; 2582 return (pass); 2583 } 2584 2585 2586 /* ------------------------------------------------------------------------ */ 2587 /* Function: ipf_acctpkt */ 2588 /* Returns: frentry_t* - always returns NULL */ 2589 /* Parameters: fin(I) - pointer to packet information */ 2590 /* passp(IO) - pointer to current/new filter decision (unused) */ 2591 /* */ 2592 /* Checks a packet against accounting rules, if there are any for the given */ 2593 /* IP protocol version. */ 2594 /* */ 2595 /* N.B.: this function returns NULL to match the prototype used by other */ 2596 /* functions called from the IPFilter "mainline" in ipf_check(). */ 2597 /* ------------------------------------------------------------------------ */ 2598 frentry_t * 2599 ipf_acctpkt(fr_info_t *fin, u_32_t *passp) 2600 { 2601 ipf_main_softc_t *softc = fin->fin_main_soft; 2602 char group[FR_GROUPLEN]; 2603 frentry_t *fr, *frsave; 2604 u_32_t pass, rulen; 2605 2606 passp = passp; 2607 fr = softc->ipf_acct[fin->fin_out][softc->ipf_active]; 2608 2609 if (fr != NULL) { 2610 frsave = fin->fin_fr; 2611 bcopy(fin->fin_group, group, FR_GROUPLEN); 2612 rulen = fin->fin_rule; 2613 fin->fin_fr = fr; 2614 pass = ipf_scanlist(fin, FR_NOMATCH); 2615 if (FR_ISACCOUNT(pass)) { 2616 LBUMPD(ipf_stats[0], fr_acct); 2617 } 2618 fin->fin_fr = frsave; 2619 bcopy(group, fin->fin_group, FR_GROUPLEN); 2620 fin->fin_rule = rulen; 2621 } 2622 return (NULL); 2623 } 2624 2625 2626 /* ------------------------------------------------------------------------ */ 2627 /* Function: ipf_firewall */ 2628 /* Returns: frentry_t* - returns pointer to matched rule, if no matches */ 2629 /* were found, returns NULL. */ 2630 /* Parameters: fin(I) - pointer to packet information */ 2631 /* passp(IO) - pointer to current/new filter decision (unused) */ 2632 /* */ 2633 /* Applies an appropriate set of firewall rules to the packet, to see if */ 2634 /* there are any matches. The first check is to see if a match can be seen */ 2635 /* in the cache. If not, then search an appropriate list of rules. Once a */ 2636 /* matching rule is found, take any appropriate actions as defined by the */ 2637 /* rule - except logging. */ 2638 /* ------------------------------------------------------------------------ */ 2639 static frentry_t * 2640 ipf_firewall(fr_info_t *fin, u_32_t *passp) 2641 { 2642 ipf_main_softc_t *softc = fin->fin_main_soft; 2643 frentry_t *fr; 2644 u_32_t pass; 2645 int out; 2646 2647 out = fin->fin_out; 2648 pass = *passp; 2649 2650 /* 2651 * This rule cache will only affect packets that are not being 2652 * statefully filtered. 2653 */ 2654 fin->fin_fr = softc->ipf_rules[out][softc->ipf_active]; 2655 if (fin->fin_fr != NULL) 2656 pass = ipf_scanlist(fin, softc->ipf_pass); 2657 2658 if ((pass & FR_NOMATCH)) { 2659 LBUMPD(ipf_stats[out], fr_nom); 2660 } 2661 fr = fin->fin_fr; 2662 2663 /* 2664 * Apply packets per second rate-limiting to a rule as required. 2665 */ 2666 if ((fr != NULL) && (fr->fr_pps != 0) && 2667 !ppsratecheck(&fr->fr_lastpkt, &fr->fr_curpps, fr->fr_pps)) { 2668 DT2(frb_ppsrate, fr_info_t *, fin, frentry_t *, fr); 2669 pass &= ~(FR_CMDMASK|FR_RETICMP|FR_RETRST); 2670 pass |= FR_BLOCK; 2671 LBUMPD(ipf_stats[out], fr_ppshit); 2672 fin->fin_reason = FRB_PPSRATE; 2673 } 2674 2675 /* 2676 * If we fail to add a packet to the authorization queue, then we 2677 * drop the packet later. However, if it was added then pretend 2678 * we've dropped it already. 2679 */ 2680 if (FR_ISAUTH(pass)) { 2681 if (ipf_auth_new(fin->fin_m, fin) != 0) { 2682 DT1(frb_authnew, fr_info_t *, fin); 2683 fin->fin_m = *fin->fin_mp = NULL; 2684 fin->fin_reason = FRB_AUTHNEW; 2685 fin->fin_error = 0; 2686 } else { 2687 IPFERROR(1); 2688 fin->fin_error = ENOSPC; 2689 } 2690 } 2691 2692 if ((fr != NULL) && (fr->fr_func != NULL) && 2693 (fr->fr_func != (ipfunc_t)-1) && !(pass & FR_CALLNOW)) 2694 (void) (*fr->fr_func)(fin, &pass); 2695 2696 /* 2697 * If a rule is a pre-auth rule, check again in the list of rules 2698 * loaded for authenticated use. It does not particulary matter 2699 * if this search fails because a "preauth" result, from a rule, 2700 * is treated as "not a pass", hence the packet is blocked. 2701 */ 2702 if (FR_ISPREAUTH(pass)) { 2703 pass = ipf_auth_pre_scanlist(softc, fin, pass); 2704 } 2705 2706 /* 2707 * If the rule has "keep frag" and the packet is actually a fragment, 2708 * then create a fragment state entry. 2709 */ 2710 if (pass & FR_KEEPFRAG) { 2711 if (fin->fin_flx & FI_FRAG) { 2712 if (ipf_frag_new(softc, fin, pass) == -1) { 2713 LBUMP(ipf_stats[out].fr_bnfr); 2714 } else { 2715 LBUMP(ipf_stats[out].fr_nfr); 2716 } 2717 } else { 2718 LBUMP(ipf_stats[out].fr_cfr); 2719 } 2720 } 2721 2722 fr = fin->fin_fr; 2723 *passp = pass; 2724 2725 return (fr); 2726 } 2727 2728 2729 /* ------------------------------------------------------------------------ */ 2730 /* Function: ipf_check */ 2731 /* Returns: int - 0 == packet allowed through, */ 2732 /* User space: */ 2733 /* -1 == packet blocked */ 2734 /* 1 == packet not matched */ 2735 /* -2 == requires authentication */ 2736 /* Kernel: */ 2737 /* > 0 == filter error # for packet */ 2738 /* Parameters: ctx(I) - pointer to the instance context */ 2739 /* ip(I) - pointer to start of IPv4/6 packet */ 2740 /* hlen(I) - length of header */ 2741 /* ifp(I) - pointer to interface this packet is on */ 2742 /* out(I) - 0 == packet going in, 1 == packet going out */ 2743 /* mp(IO) - pointer to caller's buffer pointer that holds this */ 2744 /* IP packet. */ 2745 /* Solaris: */ 2746 /* qpi(I) - pointer to STREAMS queue information for this */ 2747 /* interface & direction. */ 2748 /* */ 2749 /* ipf_check() is the master function for all IPFilter packet processing. */ 2750 /* It orchestrates: Network Address Translation (NAT), checking for packet */ 2751 /* authorisation (or pre-authorisation), presence of related state info., */ 2752 /* generating log entries, IP packet accounting, routing of packets as */ 2753 /* directed by firewall rules and of course whether or not to allow the */ 2754 /* packet to be further processed by the kernel. */ 2755 /* */ 2756 /* For packets blocked, the contents of "mp" will be NULL'd and the buffer */ 2757 /* freed. Packets passed may be returned with the pointer pointed to by */ 2758 /* by "mp" changed to a new buffer. */ 2759 /* ------------------------------------------------------------------------ */ 2760 int 2761 ipf_check(void *ctx, ip_t *ip, int hlen, struct ifnet *ifp, int out 2762 #if defined(_KERNEL) && SOLARIS 2763 , void* qif, mb_t **mp) 2764 #else 2765 , mb_t **mp) 2766 #endif 2767 { 2768 /* 2769 * The above really sucks, but short of writing a diff 2770 */ 2771 ipf_main_softc_t *softc = ctx; 2772 fr_info_t frinfo; 2773 fr_info_t *fin = &frinfo; 2774 u_32_t pass = softc->ipf_pass; 2775 frentry_t *fr = NULL; 2776 int v = IP_V(ip); 2777 mb_t *mc = NULL; 2778 mb_t *m; 2779 /* 2780 * The first part of ipf_check() deals with making sure that what goes 2781 * into the filtering engine makes some sense. Information about the 2782 * the packet is distilled, collected into a fr_info_t structure and 2783 * the an attempt to ensure the buffer the packet is in is big enough 2784 * to hold all the required packet headers. 2785 */ 2786 #ifdef _KERNEL 2787 # if SOLARIS 2788 qpktinfo_t *qpi = qif; 2789 2790 # ifdef __sparc 2791 if ((u_int)ip & 0x3) 2792 return (2); 2793 # endif 2794 # else 2795 SPL_INT(s); 2796 # endif 2797 2798 if (softc->ipf_running <= 0) { 2799 return (0); 2800 } 2801 2802 bzero((char *)fin, sizeof(*fin)); 2803 2804 # if SOLARIS 2805 if (qpi->qpi_flags & QF_BROADCAST) 2806 fin->fin_flx |= FI_MBCAST|FI_BROADCAST; 2807 if (qpi->qpi_flags & QF_MULTICAST) 2808 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2809 m = qpi->qpi_m; 2810 fin->fin_qfm = m; 2811 fin->fin_qpi = qpi; 2812 # else /* SOLARIS */ 2813 2814 m = *mp; 2815 2816 # if defined(M_MCAST) 2817 if ((m->m_flags & M_MCAST) != 0) 2818 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2819 # endif 2820 # if defined(M_MLOOP) 2821 if ((m->m_flags & M_MLOOP) != 0) 2822 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2823 # endif 2824 # if defined(M_BCAST) 2825 if ((m->m_flags & M_BCAST) != 0) 2826 fin->fin_flx |= FI_MBCAST|FI_BROADCAST; 2827 # endif 2828 # ifdef M_CANFASTFWD 2829 /* 2830 * XXX For now, IP Filter and fast-forwarding of cached flows 2831 * XXX are mutually exclusive. Eventually, IP Filter should 2832 * XXX get a "can-fast-forward" filter rule. 2833 */ 2834 m->m_flags &= ~M_CANFASTFWD; 2835 # endif /* M_CANFASTFWD */ 2836 # if defined(CSUM_DELAY_DATA) && !defined(__FreeBSD__) 2837 /* 2838 * disable delayed checksums. 2839 */ 2840 if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 2841 in_delayed_cksum(m); 2842 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 2843 } 2844 # endif /* CSUM_DELAY_DATA */ 2845 # endif /* SOLARIS */ 2846 #else 2847 bzero((char *)fin, sizeof(*fin)); 2848 m = *mp; 2849 # if defined(M_MCAST) 2850 if ((m->m_flags & M_MCAST) != 0) 2851 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2852 # endif 2853 # if defined(M_MLOOP) 2854 if ((m->m_flags & M_MLOOP) != 0) 2855 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2856 # endif 2857 # if defined(M_BCAST) 2858 if ((m->m_flags & M_BCAST) != 0) 2859 fin->fin_flx |= FI_MBCAST|FI_BROADCAST; 2860 # endif 2861 #endif /* _KERNEL */ 2862 2863 fin->fin_v = v; 2864 fin->fin_m = m; 2865 fin->fin_ip = ip; 2866 fin->fin_mp = mp; 2867 fin->fin_out = out; 2868 fin->fin_ifp = ifp; 2869 fin->fin_error = ENETUNREACH; 2870 fin->fin_hlen = (u_short)hlen; 2871 fin->fin_dp = (char *)ip + hlen; 2872 fin->fin_main_soft = softc; 2873 2874 fin->fin_ipoff = (char *)ip - MTOD(m, char *); 2875 2876 SPL_NET(s); 2877 2878 #ifdef USE_INET6 2879 if (v == 6) { 2880 LBUMP(ipf_stats[out].fr_ipv6); 2881 /* 2882 * Jumbo grams are quite likely too big for internal buffer 2883 * structures to handle comfortably, for now, so just drop 2884 * them. 2885 */ 2886 if (((ip6_t *)ip)->ip6_plen == 0) { 2887 DT1(frb_jumbo, ip6_t *, (ip6_t *)ip); 2888 pass = FR_BLOCK|FR_NOMATCH; 2889 fin->fin_reason = FRB_JUMBO; 2890 goto finished; 2891 } 2892 fin->fin_family = AF_INET6; 2893 } else 2894 #endif 2895 { 2896 fin->fin_family = AF_INET; 2897 } 2898 2899 if (ipf_makefrip(hlen, ip, fin) == -1) { 2900 DT1(frb_makefrip, fr_info_t *, fin); 2901 pass = FR_BLOCK|FR_NOMATCH; 2902 fin->fin_reason = FRB_MAKEFRIP; 2903 goto finished; 2904 } 2905 2906 /* 2907 * For at least IPv6 packets, if a m_pullup() fails then this pointer 2908 * becomes NULL and so we have no packet to free. 2909 */ 2910 if (*fin->fin_mp == NULL) 2911 goto finished; 2912 2913 if (!out) { 2914 if (v == 4) { 2915 if (softc->ipf_chksrc && !ipf_verifysrc(fin)) { 2916 LBUMPD(ipf_stats[0], fr_v4_badsrc); 2917 fin->fin_flx |= FI_BADSRC; 2918 } 2919 if (fin->fin_ip->ip_ttl < softc->ipf_minttl) { 2920 LBUMPD(ipf_stats[0], fr_v4_badttl); 2921 fin->fin_flx |= FI_LOWTTL; 2922 } 2923 } 2924 #ifdef USE_INET6 2925 else if (v == 6) { 2926 if (((ip6_t *)ip)->ip6_hlim < softc->ipf_minttl) { 2927 LBUMPD(ipf_stats[0], fr_v6_badttl); 2928 fin->fin_flx |= FI_LOWTTL; 2929 } 2930 } 2931 #endif 2932 } 2933 2934 if (fin->fin_flx & FI_SHORT) { 2935 LBUMPD(ipf_stats[out], fr_short); 2936 } 2937 2938 READ_ENTER(&softc->ipf_mutex); 2939 2940 if (!out) { 2941 switch (fin->fin_v) 2942 { 2943 case 4 : 2944 if (ipf_nat_checkin(fin, &pass) == -1) { 2945 goto filterdone; 2946 } 2947 break; 2948 #ifdef USE_INET6 2949 case 6 : 2950 if (ipf_nat6_checkin(fin, &pass) == -1) { 2951 goto filterdone; 2952 } 2953 break; 2954 #endif 2955 default : 2956 break; 2957 } 2958 } 2959 /* 2960 * Check auth now. 2961 * If a packet is found in the auth table, then skip checking 2962 * the access lists for permission but we do need to consider 2963 * the result as if it were from the ACL's. In addition, being 2964 * found in the auth table means it has been seen before, so do 2965 * not pass it through accounting (again), lest it be counted twice. 2966 */ 2967 fr = ipf_auth_check(fin, &pass); 2968 if (!out && (fr == NULL)) 2969 (void) ipf_acctpkt(fin, NULL); 2970 2971 if (fr == NULL) { 2972 if ((fin->fin_flx & FI_FRAG) != 0) 2973 fr = ipf_frag_known(fin, &pass); 2974 2975 if (fr == NULL) 2976 fr = ipf_state_check(fin, &pass); 2977 } 2978 2979 if ((pass & FR_NOMATCH) || (fr == NULL)) 2980 fr = ipf_firewall(fin, &pass); 2981 2982 /* 2983 * If we've asked to track state for this packet, set it up. 2984 * Here rather than ipf_firewall because ipf_checkauth may decide 2985 * to return a packet for "keep state" 2986 */ 2987 if ((pass & FR_KEEPSTATE) && (fin->fin_m != NULL) && 2988 !(fin->fin_flx & FI_STATE)) { 2989 if (ipf_state_add(softc, fin, NULL, 0) == 0) { 2990 LBUMP(ipf_stats[out].fr_ads); 2991 } else { 2992 LBUMP(ipf_stats[out].fr_bads); 2993 if (FR_ISPASS(pass)) { 2994 DT(frb_stateadd); 2995 pass &= ~FR_CMDMASK; 2996 pass |= FR_BLOCK; 2997 fin->fin_reason = FRB_STATEADD; 2998 } 2999 } 3000 } 3001 3002 fin->fin_fr = fr; 3003 if ((fr != NULL) && !(fin->fin_flx & FI_STATE)) { 3004 fin->fin_dif = &fr->fr_dif; 3005 fin->fin_tif = &fr->fr_tifs[fin->fin_rev]; 3006 } 3007 3008 /* 3009 * Only count/translate packets which will be passed on, out the 3010 * interface. 3011 */ 3012 if (out && FR_ISPASS(pass)) { 3013 (void) ipf_acctpkt(fin, NULL); 3014 3015 switch (fin->fin_v) 3016 { 3017 case 4 : 3018 if (ipf_nat_checkout(fin, &pass) == -1) { 3019 ; 3020 } else if ((softc->ipf_update_ipid != 0) && (v == 4)) { 3021 if (ipf_updateipid(fin) == -1) { 3022 DT(frb_updateipid); 3023 LBUMP(ipf_stats[1].fr_ipud); 3024 pass &= ~FR_CMDMASK; 3025 pass |= FR_BLOCK; 3026 fin->fin_reason = FRB_UPDATEIPID; 3027 } else { 3028 LBUMP(ipf_stats[0].fr_ipud); 3029 } 3030 } 3031 break; 3032 #ifdef USE_INET6 3033 case 6 : 3034 (void) ipf_nat6_checkout(fin, &pass); 3035 break; 3036 #endif 3037 default : 3038 break; 3039 } 3040 } 3041 3042 filterdone: 3043 #ifdef IPFILTER_LOG 3044 if ((softc->ipf_flags & FF_LOGGING) || (pass & FR_LOGMASK)) { 3045 (void) ipf_dolog(fin, &pass); 3046 } 3047 #endif 3048 3049 /* 3050 * The FI_STATE flag is cleared here so that calling ipf_state_check 3051 * will work when called from inside of fr_fastroute. Although 3052 * there is a similar flag, FI_NATED, for NAT, it does have the same 3053 * impact on code execution. 3054 */ 3055 fin->fin_flx &= ~FI_STATE; 3056 3057 #if defined(FASTROUTE_RECURSION) 3058 /* 3059 * Up the reference on fr_lock and exit ipf_mutex. The generation of 3060 * a packet below can sometimes cause a recursive call into IPFilter. 3061 * On those platforms where that does happen, we need to hang onto 3062 * the filter rule just in case someone decides to remove or flush it 3063 * in the meantime. 3064 */ 3065 if (fr != NULL) { 3066 MUTEX_ENTER(&fr->fr_lock); 3067 fr->fr_ref++; 3068 MUTEX_EXIT(&fr->fr_lock); 3069 } 3070 3071 RWLOCK_EXIT(&softc->ipf_mutex); 3072 #endif 3073 3074 if ((pass & FR_RETMASK) != 0) { 3075 /* 3076 * Should we return an ICMP packet to indicate error 3077 * status passing through the packet filter ? 3078 * WARNING: ICMP error packets AND TCP RST packets should 3079 * ONLY be sent in repsonse to incoming packets. Sending 3080 * them in response to outbound packets can result in a 3081 * panic on some operating systems. 3082 */ 3083 if (!out) { 3084 if (pass & FR_RETICMP) { 3085 int dst; 3086 3087 if ((pass & FR_RETMASK) == FR_FAKEICMP) 3088 dst = 1; 3089 else 3090 dst = 0; 3091 (void) ipf_send_icmp_err(ICMP_UNREACH, fin, 3092 dst); 3093 LBUMP(ipf_stats[0].fr_ret); 3094 } else if (((pass & FR_RETMASK) == FR_RETRST) && 3095 !(fin->fin_flx & FI_SHORT)) { 3096 if (((fin->fin_flx & FI_OOW) != 0) || 3097 (ipf_send_reset(fin) == 0)) { 3098 LBUMP(ipf_stats[1].fr_ret); 3099 } 3100 } 3101 3102 /* 3103 * When using return-* with auth rules, the auth code 3104 * takes over disposing of this packet. 3105 */ 3106 if (FR_ISAUTH(pass) && (fin->fin_m != NULL)) { 3107 DT1(frb_authcapture, fr_info_t *, fin); 3108 fin->fin_m = *fin->fin_mp = NULL; 3109 fin->fin_reason = FRB_AUTHCAPTURE; 3110 m = NULL; 3111 } 3112 } else { 3113 if (pass & FR_RETRST) { 3114 fin->fin_error = ECONNRESET; 3115 } 3116 } 3117 } 3118 3119 /* 3120 * After the above so that ICMP unreachables and TCP RSTs get 3121 * created properly. 3122 */ 3123 if (FR_ISBLOCK(pass) && (fin->fin_flx & FI_NEWNAT)) 3124 ipf_nat_uncreate(fin); 3125 3126 /* 3127 * If we didn't drop off the bottom of the list of rules (and thus 3128 * the 'current' rule fr is not NULL), then we may have some extra 3129 * instructions about what to do with a packet. 3130 * Once we're finished return to our caller, freeing the packet if 3131 * we are dropping it. 3132 */ 3133 if (fr != NULL) { 3134 frdest_t *fdp; 3135 3136 /* 3137 * Generate a duplicated packet first because ipf_fastroute 3138 * can lead to fin_m being free'd... not good. 3139 */ 3140 fdp = fin->fin_dif; 3141 if ((fdp != NULL) && (fdp->fd_ptr != NULL) && 3142 (fdp->fd_ptr != (void *)-1)) { 3143 mc = M_COPY(fin->fin_m); 3144 if (mc != NULL) 3145 ipf_fastroute(mc, &mc, fin, fdp); 3146 } 3147 3148 fdp = fin->fin_tif; 3149 if (!out && (pass & FR_FASTROUTE)) { 3150 /* 3151 * For fastroute rule, no destination interface defined 3152 * so pass NULL as the frdest_t parameter 3153 */ 3154 (void) ipf_fastroute(fin->fin_m, mp, fin, NULL); 3155 m = *mp = NULL; 3156 } else if ((fdp != NULL) && (fdp->fd_ptr != NULL) && 3157 (fdp->fd_ptr != (struct ifnet *)-1)) { 3158 /* this is for to rules: */ 3159 ipf_fastroute(fin->fin_m, mp, fin, fdp); 3160 m = *mp = NULL; 3161 } 3162 3163 #if defined(FASTROUTE_RECURSION) 3164 (void) ipf_derefrule(softc, &fr); 3165 #endif 3166 } 3167 #if !defined(FASTROUTE_RECURSION) 3168 RWLOCK_EXIT(&softc->ipf_mutex); 3169 #endif 3170 3171 finished: 3172 if (!FR_ISPASS(pass)) { 3173 LBUMP(ipf_stats[out].fr_block); 3174 if (*mp != NULL) { 3175 #ifdef _KERNEL 3176 FREE_MB_T(*mp); 3177 #endif 3178 m = *mp = NULL; 3179 } 3180 } else { 3181 LBUMP(ipf_stats[out].fr_pass); 3182 } 3183 3184 SPL_X(s); 3185 3186 if (fin->fin_m == NULL && fin->fin_flx & FI_BAD && 3187 fin->fin_reason == FRB_PULLUP) { 3188 /* m_pullup() has freed the mbuf */ 3189 LBUMP(ipf_stats[out].fr_blocked[fin->fin_reason]); 3190 return (-1); 3191 } 3192 3193 3194 #ifdef _KERNEL 3195 if (FR_ISPASS(pass)) 3196 return (0); 3197 LBUMP(ipf_stats[out].fr_blocked[fin->fin_reason]); 3198 return (fin->fin_error); 3199 #else /* _KERNEL */ 3200 if (*mp != NULL) 3201 (*mp)->mb_ifp = fin->fin_ifp; 3202 blockreason = fin->fin_reason; 3203 FR_VERBOSE(("fin_flx %#x pass %#x ", fin->fin_flx, pass)); 3204 /*if ((pass & FR_CMDMASK) == (softc->ipf_pass & FR_CMDMASK))*/ 3205 if ((pass & FR_NOMATCH) != 0) 3206 return (1); 3207 3208 if ((pass & FR_RETMASK) != 0) 3209 switch (pass & FR_RETMASK) 3210 { 3211 case FR_RETRST : 3212 return (3); 3213 case FR_RETICMP : 3214 return (4); 3215 case FR_FAKEICMP : 3216 return (5); 3217 } 3218 3219 switch (pass & FR_CMDMASK) 3220 { 3221 case FR_PASS : 3222 return (0); 3223 case FR_BLOCK : 3224 return (-1); 3225 case FR_AUTH : 3226 return (-2); 3227 case FR_ACCOUNT : 3228 return (-3); 3229 case FR_PREAUTH : 3230 return (-4); 3231 } 3232 return (2); 3233 #endif /* _KERNEL */ 3234 } 3235 3236 3237 #ifdef IPFILTER_LOG 3238 /* ------------------------------------------------------------------------ */ 3239 /* Function: ipf_dolog */ 3240 /* Returns: frentry_t* - returns contents of fin_fr (no change made) */ 3241 /* Parameters: fin(I) - pointer to packet information */ 3242 /* passp(IO) - pointer to current/new filter decision (unused) */ 3243 /* */ 3244 /* Checks flags set to see how a packet should be logged, if it is to be */ 3245 /* logged. Adjust statistics based on its success or not. */ 3246 /* ------------------------------------------------------------------------ */ 3247 frentry_t * 3248 ipf_dolog(fr_info_t *fin, u_32_t *passp) 3249 { 3250 ipf_main_softc_t *softc = fin->fin_main_soft; 3251 u_32_t pass; 3252 int out; 3253 3254 out = fin->fin_out; 3255 pass = *passp; 3256 3257 if ((softc->ipf_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) { 3258 pass |= FF_LOGNOMATCH; 3259 LBUMPD(ipf_stats[out], fr_npkl); 3260 goto logit; 3261 3262 } else if (((pass & FR_LOGMASK) == FR_LOGP) || 3263 (FR_ISPASS(pass) && (softc->ipf_flags & FF_LOGPASS))) { 3264 if ((pass & FR_LOGMASK) != FR_LOGP) 3265 pass |= FF_LOGPASS; 3266 LBUMPD(ipf_stats[out], fr_ppkl); 3267 goto logit; 3268 3269 } else if (((pass & FR_LOGMASK) == FR_LOGB) || 3270 (FR_ISBLOCK(pass) && (softc->ipf_flags & FF_LOGBLOCK))) { 3271 if ((pass & FR_LOGMASK) != FR_LOGB) 3272 pass |= FF_LOGBLOCK; 3273 LBUMPD(ipf_stats[out], fr_bpkl); 3274 3275 logit: 3276 if (ipf_log_pkt(fin, pass) == -1) { 3277 /* 3278 * If the "or-block" option has been used then 3279 * block the packet if we failed to log it. 3280 */ 3281 if ((pass & FR_LOGORBLOCK) && FR_ISPASS(pass)) { 3282 DT1(frb_logfail2, u_int, pass); 3283 pass &= ~FR_CMDMASK; 3284 pass |= FR_BLOCK; 3285 fin->fin_reason = FRB_LOGFAIL2; 3286 } 3287 } 3288 *passp = pass; 3289 } 3290 3291 return (fin->fin_fr); 3292 } 3293 #endif /* IPFILTER_LOG */ 3294 3295 3296 /* ------------------------------------------------------------------------ */ 3297 /* Function: ipf_cksum */ 3298 /* Returns: u_short - IP header checksum */ 3299 /* Parameters: addr(I) - pointer to start of buffer to checksum */ 3300 /* len(I) - length of buffer in bytes */ 3301 /* */ 3302 /* Calculate the two's complement 16 bit checksum of the buffer passed. */ 3303 /* */ 3304 /* N.B.: addr should be 16bit aligned. */ 3305 /* ------------------------------------------------------------------------ */ 3306 u_short 3307 ipf_cksum(u_short *addr, int len) 3308 { 3309 u_32_t sum = 0; 3310 3311 for (sum = 0; len > 1; len -= 2) 3312 sum += *addr++; 3313 3314 /* mop up an odd byte, if necessary */ 3315 if (len == 1) 3316 sum += *(u_char *)addr; 3317 3318 /* 3319 * add back carry outs from top 16 bits to low 16 bits 3320 */ 3321 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 3322 sum += (sum >> 16); /* add carry */ 3323 return (u_short)(~sum); 3324 } 3325 3326 3327 /* ------------------------------------------------------------------------ */ 3328 /* Function: fr_cksum */ 3329 /* Returns: u_short - layer 4 checksum */ 3330 /* Parameters: fin(I) - pointer to packet information */ 3331 /* ip(I) - pointer to IP header */ 3332 /* l4proto(I) - protocol to caclulate checksum for */ 3333 /* l4hdr(I) - pointer to layer 4 header */ 3334 /* */ 3335 /* Calculates the TCP checksum for the packet held in "m", using the data */ 3336 /* in the IP header "ip" to seed it. */ 3337 /* */ 3338 /* NB: This function assumes we've pullup'd enough for all of the IP header */ 3339 /* and the TCP header. We also assume that data blocks aren't allocated in */ 3340 /* odd sizes. */ 3341 /* */ 3342 /* Expects ip_len and ip_off to be in network byte order when called. */ 3343 /* ------------------------------------------------------------------------ */ 3344 u_short 3345 fr_cksum(fr_info_t *fin, ip_t *ip, int l4proto, void *l4hdr) 3346 { 3347 u_short *sp, slen, sumsave, *csump; 3348 u_int sum, sum2; 3349 int hlen; 3350 int off; 3351 #ifdef USE_INET6 3352 ip6_t *ip6; 3353 #endif 3354 3355 csump = NULL; 3356 sumsave = 0; 3357 sp = NULL; 3358 slen = 0; 3359 hlen = 0; 3360 sum = 0; 3361 3362 sum = htons((u_short)l4proto); 3363 /* 3364 * Add up IP Header portion 3365 */ 3366 #ifdef USE_INET6 3367 if (IP_V(ip) == 4) { 3368 #endif 3369 hlen = IP_HL(ip) << 2; 3370 off = hlen; 3371 sp = (u_short *)&ip->ip_src; 3372 sum += *sp++; /* ip_src */ 3373 sum += *sp++; 3374 sum += *sp++; /* ip_dst */ 3375 sum += *sp++; 3376 slen = fin->fin_plen - off; 3377 sum += htons(slen); 3378 #ifdef USE_INET6 3379 } else if (IP_V(ip) == 6) { 3380 mb_t *m; 3381 3382 m = fin->fin_m; 3383 ip6 = (ip6_t *)ip; 3384 off = ((caddr_t)ip6 - m->m_data) + sizeof(struct ip6_hdr); 3385 int len = ntohs(ip6->ip6_plen) - (off - sizeof(*ip6)); 3386 return (ipf_pcksum6(m, ip6, off, len)); 3387 } else { 3388 return (0xffff); 3389 } 3390 #endif 3391 3392 switch (l4proto) 3393 { 3394 case IPPROTO_UDP : 3395 csump = &((udphdr_t *)l4hdr)->uh_sum; 3396 break; 3397 3398 case IPPROTO_TCP : 3399 csump = &((tcphdr_t *)l4hdr)->th_sum; 3400 break; 3401 case IPPROTO_ICMP : 3402 csump = &((icmphdr_t *)l4hdr)->icmp_cksum; 3403 sum = 0; /* Pseudo-checksum is not included */ 3404 break; 3405 #ifdef USE_INET6 3406 case IPPROTO_ICMPV6 : 3407 csump = &((struct icmp6_hdr *)l4hdr)->icmp6_cksum; 3408 break; 3409 #endif 3410 default : 3411 break; 3412 } 3413 3414 if (csump != NULL) { 3415 sumsave = *csump; 3416 *csump = 0; 3417 } 3418 3419 sum2 = ipf_pcksum(fin, off, sum); 3420 if (csump != NULL) 3421 *csump = sumsave; 3422 return (sum2); 3423 } 3424 3425 3426 /* ------------------------------------------------------------------------ */ 3427 /* Function: ipf_findgroup */ 3428 /* Returns: frgroup_t * - NULL = group not found, else pointer to group */ 3429 /* Parameters: softc(I) - pointer to soft context main structure */ 3430 /* group(I) - group name to search for */ 3431 /* unit(I) - device to which this group belongs */ 3432 /* set(I) - which set of rules (inactive/inactive) this is */ 3433 /* fgpp(O) - pointer to place to store pointer to the pointer */ 3434 /* to where to add the next (last) group or where */ 3435 /* to delete group from. */ 3436 /* */ 3437 /* Search amongst the defined groups for a particular group number. */ 3438 /* ------------------------------------------------------------------------ */ 3439 frgroup_t * 3440 ipf_findgroup(ipf_main_softc_t *softc, char *group, minor_t unit, int set, 3441 frgroup_t ***fgpp) 3442 { 3443 frgroup_t *fg, **fgp; 3444 3445 /* 3446 * Which list of groups to search in is dependent on which list of 3447 * rules are being operated on. 3448 */ 3449 fgp = &softc->ipf_groups[unit][set]; 3450 3451 while ((fg = *fgp) != NULL) { 3452 if (strncmp(group, fg->fg_name, FR_GROUPLEN) == 0) 3453 break; 3454 else 3455 fgp = &fg->fg_next; 3456 } 3457 if (fgpp != NULL) 3458 *fgpp = fgp; 3459 return (fg); 3460 } 3461 3462 3463 /* ------------------------------------------------------------------------ */ 3464 /* Function: ipf_group_add */ 3465 /* Returns: frgroup_t * - NULL == did not create group, */ 3466 /* != NULL == pointer to the group */ 3467 /* Parameters: softc(I) - pointer to soft context main structure */ 3468 /* num(I) - group number to add */ 3469 /* head(I) - rule pointer that is using this as the head */ 3470 /* flags(I) - rule flags which describe the type of rule it is */ 3471 /* unit(I) - device to which this group will belong to */ 3472 /* set(I) - which set of rules (inactive/inactive) this is */ 3473 /* Write Locks: ipf_mutex */ 3474 /* */ 3475 /* Add a new group head, or if it already exists, increase the reference */ 3476 /* count to it. */ 3477 /* ------------------------------------------------------------------------ */ 3478 frgroup_t * 3479 ipf_group_add(ipf_main_softc_t *softc, char *group, void *head, u_32_t flags, 3480 minor_t unit, int set) 3481 { 3482 frgroup_t *fg, **fgp; 3483 u_32_t gflags; 3484 3485 if (group == NULL) 3486 return (NULL); 3487 3488 if (unit == IPL_LOGIPF && *group == '\0') 3489 return (NULL); 3490 3491 fgp = NULL; 3492 gflags = flags & FR_INOUT; 3493 3494 fg = ipf_findgroup(softc, group, unit, set, &fgp); 3495 if (fg != NULL) { 3496 if (fg->fg_head == NULL && head != NULL) 3497 fg->fg_head = head; 3498 if (fg->fg_flags == 0) 3499 fg->fg_flags = gflags; 3500 else if (gflags != fg->fg_flags) 3501 return (NULL); 3502 fg->fg_ref++; 3503 return (fg); 3504 } 3505 3506 KMALLOC(fg, frgroup_t *); 3507 if (fg != NULL) { 3508 fg->fg_head = head; 3509 fg->fg_start = NULL; 3510 fg->fg_next = *fgp; 3511 bcopy(group, fg->fg_name, strlen(group) + 1); 3512 fg->fg_flags = gflags; 3513 fg->fg_ref = 1; 3514 fg->fg_set = &softc->ipf_groups[unit][set]; 3515 *fgp = fg; 3516 } 3517 return (fg); 3518 } 3519 3520 3521 /* ------------------------------------------------------------------------ */ 3522 /* Function: ipf_group_del */ 3523 /* Returns: int - number of rules deleted */ 3524 /* Parameters: softc(I) - pointer to soft context main structure */ 3525 /* group(I) - group name to delete */ 3526 /* fr(I) - filter rule from which group is referenced */ 3527 /* Write Locks: ipf_mutex */ 3528 /* */ 3529 /* This function is called whenever a reference to a group is to be dropped */ 3530 /* and thus its reference count needs to be lowered and the group free'd if */ 3531 /* the reference count reaches zero. Passing in fr is really for the sole */ 3532 /* purpose of knowing when the head rule is being deleted. */ 3533 /* ------------------------------------------------------------------------ */ 3534 void 3535 ipf_group_del(ipf_main_softc_t *softc, frgroup_t *group, frentry_t *fr) 3536 { 3537 3538 if (group->fg_head == fr) 3539 group->fg_head = NULL; 3540 3541 group->fg_ref--; 3542 if ((group->fg_ref == 0) && (group->fg_start == NULL)) 3543 ipf_group_free(group); 3544 } 3545 3546 3547 /* ------------------------------------------------------------------------ */ 3548 /* Function: ipf_group_free */ 3549 /* Returns: Nil */ 3550 /* Parameters: group(I) - pointer to filter rule group */ 3551 /* */ 3552 /* Remove the group from the list of groups and free it. */ 3553 /* ------------------------------------------------------------------------ */ 3554 static void 3555 ipf_group_free(frgroup_t *group) 3556 { 3557 frgroup_t **gp; 3558 3559 for (gp = group->fg_set; *gp != NULL; gp = &(*gp)->fg_next) { 3560 if (*gp == group) { 3561 *gp = group->fg_next; 3562 break; 3563 } 3564 } 3565 KFREE(group); 3566 } 3567 3568 3569 /* ------------------------------------------------------------------------ */ 3570 /* Function: ipf_group_flush */ 3571 /* Returns: int - number of rules flush from group */ 3572 /* Parameters: softc(I) - pointer to soft context main structure */ 3573 /* Parameters: group(I) - pointer to filter rule group */ 3574 /* */ 3575 /* Remove all of the rules that currently are listed under the given group. */ 3576 /* ------------------------------------------------------------------------ */ 3577 static int 3578 ipf_group_flush(ipf_main_softc_t *softc, frgroup_t *group) 3579 { 3580 int gone = 0; 3581 3582 (void) ipf_flushlist(softc, &gone, &group->fg_start); 3583 3584 return (gone); 3585 } 3586 3587 3588 /* ------------------------------------------------------------------------ */ 3589 /* Function: ipf_getrulen */ 3590 /* Returns: frentry_t * - NULL == not found, else pointer to rule n */ 3591 /* Parameters: softc(I) - pointer to soft context main structure */ 3592 /* Parameters: unit(I) - device for which to count the rule's number */ 3593 /* flags(I) - which set of rules to find the rule in */ 3594 /* group(I) - group name */ 3595 /* n(I) - rule number to find */ 3596 /* */ 3597 /* Find rule # n in group # g and return a pointer to it. Return NULl if */ 3598 /* group # g doesn't exist or there are less than n rules in the group. */ 3599 /* ------------------------------------------------------------------------ */ 3600 frentry_t * 3601 ipf_getrulen(ipf_main_softc_t *softc, int unit, char *group, u_32_t n) 3602 { 3603 frentry_t *fr; 3604 frgroup_t *fg; 3605 3606 fg = ipf_findgroup(softc, group, unit, softc->ipf_active, NULL); 3607 if (fg == NULL) 3608 return (NULL); 3609 for (fr = fg->fg_start; fr && n; fr = fr->fr_next, n--) 3610 ; 3611 if (n != 0) 3612 return (NULL); 3613 return (fr); 3614 } 3615 3616 3617 /* ------------------------------------------------------------------------ */ 3618 /* Function: ipf_flushlist */ 3619 /* Returns: int - >= 0 - number of flushed rules */ 3620 /* Parameters: softc(I) - pointer to soft context main structure */ 3621 /* nfreedp(O) - pointer to int where flush count is stored */ 3622 /* listp(I) - pointer to list to flush pointer */ 3623 /* Write Locks: ipf_mutex */ 3624 /* */ 3625 /* Recursively flush rules from the list, descending groups as they are */ 3626 /* encountered. if a rule is the head of a group and it has lost all its */ 3627 /* group members, then also delete the group reference. nfreedp is needed */ 3628 /* to store the accumulating count of rules removed, whereas the returned */ 3629 /* value is just the number removed from the current list. The latter is */ 3630 /* needed to correctly adjust reference counts on rules that define groups. */ 3631 /* */ 3632 /* NOTE: Rules not loaded from user space cannot be flushed. */ 3633 /* ------------------------------------------------------------------------ */ 3634 static int 3635 ipf_flushlist(ipf_main_softc_t *softc, int *nfreedp, frentry_t **listp) 3636 { 3637 int freed = 0; 3638 frentry_t *fp; 3639 3640 while ((fp = *listp) != NULL) { 3641 if ((fp->fr_type & FR_T_BUILTIN) || 3642 !(fp->fr_flags & FR_COPIED)) { 3643 listp = &fp->fr_next; 3644 continue; 3645 } 3646 *listp = fp->fr_next; 3647 if (fp->fr_next != NULL) 3648 fp->fr_next->fr_pnext = fp->fr_pnext; 3649 fp->fr_pnext = NULL; 3650 3651 if (fp->fr_grphead != NULL) { 3652 freed += ipf_group_flush(softc, fp->fr_grphead); 3653 fp->fr_names[fp->fr_grhead] = '\0'; 3654 } 3655 3656 if (fp->fr_icmpgrp != NULL) { 3657 freed += ipf_group_flush(softc, fp->fr_icmpgrp); 3658 fp->fr_names[fp->fr_icmphead] = '\0'; 3659 } 3660 3661 if (fp->fr_srctrack.ht_max_nodes) 3662 ipf_rb_ht_flush(&fp->fr_srctrack); 3663 3664 fp->fr_next = NULL; 3665 3666 ASSERT(fp->fr_ref > 0); 3667 if (ipf_derefrule(softc, &fp) == 0) 3668 freed++; 3669 } 3670 *nfreedp += freed; 3671 return (freed); 3672 } 3673 3674 3675 /* ------------------------------------------------------------------------ */ 3676 /* Function: ipf_flush */ 3677 /* Returns: int - >= 0 - number of flushed rules */ 3678 /* Parameters: softc(I) - pointer to soft context main structure */ 3679 /* unit(I) - device for which to flush rules */ 3680 /* flags(I) - which set of rules to flush */ 3681 /* */ 3682 /* Calls flushlist() for all filter rules (accounting, firewall - both IPv4 */ 3683 /* and IPv6) as defined by the value of flags. */ 3684 /* ------------------------------------------------------------------------ */ 3685 int 3686 ipf_flush(ipf_main_softc_t *softc, minor_t unit, int flags) 3687 { 3688 int flushed = 0, set; 3689 3690 WRITE_ENTER(&softc->ipf_mutex); 3691 3692 set = softc->ipf_active; 3693 if ((flags & FR_INACTIVE) == FR_INACTIVE) 3694 set = 1 - set; 3695 3696 if (flags & FR_OUTQUE) { 3697 ipf_flushlist(softc, &flushed, &softc->ipf_rules[1][set]); 3698 ipf_flushlist(softc, &flushed, &softc->ipf_acct[1][set]); 3699 } 3700 if (flags & FR_INQUE) { 3701 ipf_flushlist(softc, &flushed, &softc->ipf_rules[0][set]); 3702 ipf_flushlist(softc, &flushed, &softc->ipf_acct[0][set]); 3703 } 3704 3705 flushed += ipf_flush_groups(softc, &softc->ipf_groups[unit][set], 3706 flags & (FR_INQUE|FR_OUTQUE)); 3707 3708 RWLOCK_EXIT(&softc->ipf_mutex); 3709 3710 if (unit == IPL_LOGIPF) { 3711 int tmp; 3712 3713 tmp = ipf_flush(softc, IPL_LOGCOUNT, flags); 3714 if (tmp >= 0) 3715 flushed += tmp; 3716 } 3717 return (flushed); 3718 } 3719 3720 3721 /* ------------------------------------------------------------------------ */ 3722 /* Function: ipf_flush_groups */ 3723 /* Returns: int - >= 0 - number of flushed rules */ 3724 /* Parameters: softc(I) - soft context pointerto work with */ 3725 /* grhead(I) - pointer to the start of the group list to flush */ 3726 /* flags(I) - which set of rules to flush */ 3727 /* */ 3728 /* Walk through all of the groups under the given group head and remove all */ 3729 /* of those that match the flags passed in. The for loop here is bit more */ 3730 /* complicated than usual because the removal of a rule with ipf_derefrule */ 3731 /* may end up removing not only the structure pointed to by "fg" but also */ 3732 /* what is fg_next and fg_next after that. So if a filter rule is actually */ 3733 /* removed from the group then it is necessary to start again. */ 3734 /* ------------------------------------------------------------------------ */ 3735 static int 3736 ipf_flush_groups(ipf_main_softc_t *softc, frgroup_t **grhead, int flags) 3737 { 3738 frentry_t *fr, **frp; 3739 frgroup_t *fg, **fgp; 3740 int flushed = 0; 3741 int removed = 0; 3742 3743 for (fgp = grhead; (fg = *fgp) != NULL; ) { 3744 while ((fg != NULL) && ((fg->fg_flags & flags) == 0)) 3745 fg = fg->fg_next; 3746 if (fg == NULL) 3747 break; 3748 removed = 0; 3749 frp = &fg->fg_start; 3750 while ((removed == 0) && ((fr = *frp) != NULL)) { 3751 if ((fr->fr_flags & flags) == 0) { 3752 frp = &fr->fr_next; 3753 } else { 3754 if (fr->fr_next != NULL) 3755 fr->fr_next->fr_pnext = fr->fr_pnext; 3756 *frp = fr->fr_next; 3757 fr->fr_pnext = NULL; 3758 fr->fr_next = NULL; 3759 (void) ipf_derefrule(softc, &fr); 3760 flushed++; 3761 removed++; 3762 } 3763 } 3764 if (removed == 0) 3765 fgp = &fg->fg_next; 3766 } 3767 return (flushed); 3768 } 3769 3770 3771 /* ------------------------------------------------------------------------ */ 3772 /* Function: memstr */ 3773 /* Returns: char * - NULL if failed, != NULL pointer to matching bytes */ 3774 /* Parameters: src(I) - pointer to byte sequence to match */ 3775 /* dst(I) - pointer to byte sequence to search */ 3776 /* slen(I) - match length */ 3777 /* dlen(I) - length available to search in */ 3778 /* */ 3779 /* Search dst for a sequence of bytes matching those at src and extend for */ 3780 /* slen bytes. */ 3781 /* ------------------------------------------------------------------------ */ 3782 char * 3783 memstr(const char *src, char *dst, size_t slen, size_t dlen) 3784 { 3785 char *s = NULL; 3786 3787 while (dlen >= slen) { 3788 if (bcmp(src, dst, slen) == 0) { 3789 s = dst; 3790 break; 3791 } 3792 dst++; 3793 dlen--; 3794 } 3795 return (s); 3796 } 3797 /* ------------------------------------------------------------------------ */ 3798 /* Function: ipf_fixskip */ 3799 /* Returns: Nil */ 3800 /* Parameters: listp(IO) - pointer to start of list with skip rule */ 3801 /* rp(I) - rule added/removed with skip in it. */ 3802 /* addremove(I) - adjustment (-1/+1) to make to skip count, */ 3803 /* depending on whether a rule was just added */ 3804 /* or removed. */ 3805 /* */ 3806 /* Adjust all the rules in a list which would have skip'd past the position */ 3807 /* where we are inserting to skip to the right place given the change. */ 3808 /* ------------------------------------------------------------------------ */ 3809 void 3810 ipf_fixskip(frentry_t **listp, frentry_t *rp, int addremove) 3811 { 3812 int rules, rn; 3813 frentry_t *fp; 3814 3815 rules = 0; 3816 for (fp = *listp; (fp != NULL) && (fp != rp); fp = fp->fr_next) 3817 rules++; 3818 3819 if (fp == NULL) 3820 return; 3821 3822 for (rn = 0, fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++) 3823 if (FR_ISSKIP(fp->fr_flags) && (rn + fp->fr_arg >= rules)) 3824 fp->fr_arg += addremove; 3825 } 3826 3827 3828 #ifdef _KERNEL 3829 /* ------------------------------------------------------------------------ */ 3830 /* Function: count4bits */ 3831 /* Returns: int - >= 0 - number of consecutive bits in input */ 3832 /* Parameters: ip(I) - 32bit IP address */ 3833 /* */ 3834 /* IPv4 ONLY */ 3835 /* count consecutive 1's in bit mask. If the mask generated by counting */ 3836 /* consecutive 1's is different to that passed, return -1, else return # */ 3837 /* of bits. */ 3838 /* ------------------------------------------------------------------------ */ 3839 int 3840 count4bits(u_32_t ip) 3841 { 3842 u_32_t ipn; 3843 int cnt = 0, i, j; 3844 3845 ip = ipn = ntohl(ip); 3846 for (i = 32; i; i--, ipn *= 2) 3847 if (ipn & 0x80000000) 3848 cnt++; 3849 else 3850 break; 3851 ipn = 0; 3852 for (i = 32, j = cnt; i; i--, j--) { 3853 ipn *= 2; 3854 if (j > 0) 3855 ipn++; 3856 } 3857 if (ipn == ip) 3858 return (cnt); 3859 return (-1); 3860 } 3861 3862 3863 /* ------------------------------------------------------------------------ */ 3864 /* Function: count6bits */ 3865 /* Returns: int - >= 0 - number of consecutive bits in input */ 3866 /* Parameters: msk(I) - pointer to start of IPv6 bitmask */ 3867 /* */ 3868 /* IPv6 ONLY */ 3869 /* count consecutive 1's in bit mask. */ 3870 /* ------------------------------------------------------------------------ */ 3871 # ifdef USE_INET6 3872 int 3873 count6bits(u_32_t *msk) 3874 { 3875 int i = 0, k; 3876 u_32_t j; 3877 3878 for (k = 3; k >= 0; k--) 3879 if (msk[k] == 0xffffffff) 3880 i += 32; 3881 else { 3882 for (j = msk[k]; j; j <<= 1) 3883 if (j & 0x80000000) 3884 i++; 3885 } 3886 return (i); 3887 } 3888 # endif 3889 #endif /* _KERNEL */ 3890 3891 3892 /* ------------------------------------------------------------------------ */ 3893 /* Function: ipf_synclist */ 3894 /* Returns: int - 0 = no failures, else indication of first failure */ 3895 /* Parameters: fr(I) - start of filter list to sync interface names for */ 3896 /* ifp(I) - interface pointer for limiting sync lookups */ 3897 /* Write Locks: ipf_mutex */ 3898 /* */ 3899 /* Walk through a list of filter rules and resolve any interface names into */ 3900 /* pointers. Where dynamic addresses are used, also update the IP address */ 3901 /* used in the rule. The interface pointer is used to limit the lookups to */ 3902 /* a specific set of matching names if it is non-NULL. */ 3903 /* Errors can occur when resolving the destination name of to/dup-to fields */ 3904 /* when the name points to a pool and that pool doest not exist. If this */ 3905 /* does happen then it is necessary to check if there are any lookup refs */ 3906 /* that need to be dropped before returning with an error. */ 3907 /* ------------------------------------------------------------------------ */ 3908 static int 3909 ipf_synclist(ipf_main_softc_t *softc, frentry_t *fr, void *ifp) 3910 { 3911 frentry_t *frt, *start = fr; 3912 frdest_t *fdp; 3913 char *name; 3914 int error; 3915 void *ifa; 3916 int v, i; 3917 3918 error = 0; 3919 3920 for (; fr; fr = fr->fr_next) { 3921 if (fr->fr_family == AF_INET) 3922 v = 4; 3923 else if (fr->fr_family == AF_INET6) 3924 v = 6; 3925 else 3926 v = 0; 3927 3928 /* 3929 * Lookup all the interface names that are part of the rule. 3930 */ 3931 for (i = 0; i < FR_NUM(fr->fr_ifas); i++) { 3932 if ((ifp != NULL) && (fr->fr_ifas[i] != ifp)) 3933 continue; 3934 if (fr->fr_ifnames[i] == -1) 3935 continue; 3936 name = FR_NAME(fr, fr_ifnames[i]); 3937 fr->fr_ifas[i] = ipf_resolvenic(softc, name, v); 3938 } 3939 3940 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) { 3941 if (fr->fr_satype != FRI_NORMAL && 3942 fr->fr_satype != FRI_LOOKUP) { 3943 ifa = ipf_resolvenic(softc, fr->fr_names + 3944 fr->fr_sifpidx, v); 3945 ipf_ifpaddr(softc, v, fr->fr_satype, ifa, 3946 &fr->fr_src6, &fr->fr_smsk6); 3947 } 3948 if (fr->fr_datype != FRI_NORMAL && 3949 fr->fr_datype != FRI_LOOKUP) { 3950 ifa = ipf_resolvenic(softc, fr->fr_names + 3951 fr->fr_sifpidx, v); 3952 ipf_ifpaddr(softc, v, fr->fr_datype, ifa, 3953 &fr->fr_dst6, &fr->fr_dmsk6); 3954 } 3955 } 3956 3957 fdp = &fr->fr_tifs[0]; 3958 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) { 3959 error = ipf_resolvedest(softc, fr->fr_names, fdp, v); 3960 if (error != 0) 3961 goto unwind; 3962 } 3963 3964 fdp = &fr->fr_tifs[1]; 3965 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) { 3966 error = ipf_resolvedest(softc, fr->fr_names, fdp, v); 3967 if (error != 0) 3968 goto unwind; 3969 } 3970 3971 fdp = &fr->fr_dif; 3972 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) { 3973 error = ipf_resolvedest(softc, fr->fr_names, fdp, v); 3974 if (error != 0) 3975 goto unwind; 3976 } 3977 3978 if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 3979 (fr->fr_satype == FRI_LOOKUP) && (fr->fr_srcptr == NULL)) { 3980 fr->fr_srcptr = ipf_lookup_res_num(softc, 3981 fr->fr_srctype, 3982 IPL_LOGIPF, 3983 fr->fr_srcnum, 3984 &fr->fr_srcfunc); 3985 } 3986 if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 3987 (fr->fr_datype == FRI_LOOKUP) && (fr->fr_dstptr == NULL)) { 3988 fr->fr_dstptr = ipf_lookup_res_num(softc, 3989 fr->fr_dsttype, 3990 IPL_LOGIPF, 3991 fr->fr_dstnum, 3992 &fr->fr_dstfunc); 3993 } 3994 } 3995 return (0); 3996 3997 unwind: 3998 for (frt = start; frt != fr; fr = fr->fr_next) { 3999 if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 4000 (frt->fr_satype == FRI_LOOKUP) && (frt->fr_srcptr != NULL)) 4001 ipf_lookup_deref(softc, frt->fr_srctype, 4002 frt->fr_srcptr); 4003 if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 4004 (frt->fr_datype == FRI_LOOKUP) && (frt->fr_dstptr != NULL)) 4005 ipf_lookup_deref(softc, frt->fr_dsttype, 4006 frt->fr_dstptr); 4007 } 4008 return (error); 4009 } 4010 4011 4012 /* ------------------------------------------------------------------------ */ 4013 /* Function: ipf_sync */ 4014 /* Returns: void */ 4015 /* Parameters: Nil */ 4016 /* */ 4017 /* ipf_sync() is called when we suspect that the interface list or */ 4018 /* information about interfaces (like IP#) has changed. Go through all */ 4019 /* filter rules, NAT entries and the state table and check if anything */ 4020 /* needs to be changed/updated. */ 4021 /* ------------------------------------------------------------------------ */ 4022 int 4023 ipf_sync(ipf_main_softc_t *softc, void *ifp) 4024 { 4025 int i; 4026 4027 #if !SOLARIS 4028 ipf_nat_sync(softc, ifp); 4029 ipf_state_sync(softc, ifp); 4030 ipf_lookup_sync(softc, ifp); 4031 #endif 4032 4033 WRITE_ENTER(&softc->ipf_mutex); 4034 (void) ipf_synclist(softc, softc->ipf_acct[0][softc->ipf_active], ifp); 4035 (void) ipf_synclist(softc, softc->ipf_acct[1][softc->ipf_active], ifp); 4036 (void) ipf_synclist(softc, softc->ipf_rules[0][softc->ipf_active], ifp); 4037 (void) ipf_synclist(softc, softc->ipf_rules[1][softc->ipf_active], ifp); 4038 4039 for (i = 0; i < IPL_LOGSIZE; i++) { 4040 frgroup_t *g; 4041 4042 for (g = softc->ipf_groups[i][0]; g != NULL; g = g->fg_next) 4043 (void) ipf_synclist(softc, g->fg_start, ifp); 4044 for (g = softc->ipf_groups[i][1]; g != NULL; g = g->fg_next) 4045 (void) ipf_synclist(softc, g->fg_start, ifp); 4046 } 4047 RWLOCK_EXIT(&softc->ipf_mutex); 4048 4049 return (0); 4050 } 4051 4052 4053 /* 4054 * In the functions below, bcopy() is called because the pointer being 4055 * copied _from_ in this instance is a pointer to a char buf (which could 4056 * end up being unaligned) and on the kernel's local stack. 4057 */ 4058 /* ------------------------------------------------------------------------ */ 4059 /* Function: copyinptr */ 4060 /* Returns: int - 0 = success, else failure */ 4061 /* Parameters: src(I) - pointer to the source address */ 4062 /* dst(I) - destination address */ 4063 /* size(I) - number of bytes to copy */ 4064 /* */ 4065 /* Copy a block of data in from user space, given a pointer to the pointer */ 4066 /* to start copying from (src) and a pointer to where to store it (dst). */ 4067 /* NB: src - pointer to user space pointer, dst - kernel space pointer */ 4068 /* ------------------------------------------------------------------------ */ 4069 int 4070 copyinptr(ipf_main_softc_t *softc, void *src, void *dst, size_t size) 4071 { 4072 caddr_t ca; 4073 int error; 4074 4075 #if SOLARIS 4076 error = COPYIN(src, &ca, sizeof(ca)); 4077 if (error != 0) 4078 return (error); 4079 #else 4080 bcopy(src, (caddr_t)&ca, sizeof(ca)); 4081 #endif 4082 error = COPYIN(ca, dst, size); 4083 if (error != 0) { 4084 IPFERROR(3); 4085 error = EFAULT; 4086 } 4087 return (error); 4088 } 4089 4090 4091 /* ------------------------------------------------------------------------ */ 4092 /* Function: copyoutptr */ 4093 /* Returns: int - 0 = success, else failure */ 4094 /* Parameters: src(I) - pointer to the source address */ 4095 /* dst(I) - destination address */ 4096 /* size(I) - number of bytes to copy */ 4097 /* */ 4098 /* Copy a block of data out to user space, given a pointer to the pointer */ 4099 /* to start copying from (src) and a pointer to where to store it (dst). */ 4100 /* NB: src - kernel space pointer, dst - pointer to user space pointer. */ 4101 /* ------------------------------------------------------------------------ */ 4102 int 4103 copyoutptr(ipf_main_softc_t *softc, void *src, void *dst, size_t size) 4104 { 4105 caddr_t ca; 4106 int error; 4107 4108 bcopy(dst, (caddr_t)&ca, sizeof(ca)); 4109 error = COPYOUT(src, ca, size); 4110 if (error != 0) { 4111 IPFERROR(4); 4112 error = EFAULT; 4113 } 4114 return (error); 4115 } 4116 4117 4118 /* ------------------------------------------------------------------------ */ 4119 /* Function: ipf_lock */ 4120 /* Returns: int - 0 = success, else error */ 4121 /* Parameters: data(I) - pointer to lock value to set */ 4122 /* lockp(O) - pointer to location to store old lock value */ 4123 /* */ 4124 /* Get the new value for the lock integer, set it and return the old value */ 4125 /* in *lockp. */ 4126 /* ------------------------------------------------------------------------ */ 4127 int 4128 ipf_lock(caddr_t data, int *lockp) 4129 { 4130 int arg, err; 4131 4132 err = BCOPYIN(data, &arg, sizeof(arg)); 4133 if (err != 0) 4134 return (EFAULT); 4135 err = BCOPYOUT(lockp, data, sizeof(*lockp)); 4136 if (err != 0) 4137 return (EFAULT); 4138 *lockp = arg; 4139 return (0); 4140 } 4141 4142 4143 /* ------------------------------------------------------------------------ */ 4144 /* Function: ipf_getstat */ 4145 /* Returns: Nil */ 4146 /* Parameters: softc(I) - pointer to soft context main structure */ 4147 /* fiop(I) - pointer to ipfilter stats structure */ 4148 /* rev(I) - version claim by program doing ioctl */ 4149 /* */ 4150 /* Stores a copy of current pointers, counters, etc, in the friostat */ 4151 /* structure. */ 4152 /* If IPFILTER_COMPAT is compiled, we pretend to be whatever version the */ 4153 /* program is looking for. This ensure that validation of the version it */ 4154 /* expects will always succeed. Thus kernels with IPFILTER_COMPAT will */ 4155 /* allow older binaries to work but kernels without it will not. */ 4156 /* ------------------------------------------------------------------------ */ 4157 /*ARGSUSED*/ 4158 static void 4159 ipf_getstat(ipf_main_softc_t *softc, friostat_t *fiop, int rev) 4160 { 4161 int i; 4162 4163 bcopy((char *)softc->ipf_stats, (char *)fiop->f_st, 4164 sizeof(ipf_statistics_t) * 2); 4165 fiop->f_locks[IPL_LOGSTATE] = -1; 4166 fiop->f_locks[IPL_LOGNAT] = -1; 4167 fiop->f_locks[IPL_LOGIPF] = -1; 4168 fiop->f_locks[IPL_LOGAUTH] = -1; 4169 4170 fiop->f_ipf[0][0] = softc->ipf_rules[0][0]; 4171 fiop->f_acct[0][0] = softc->ipf_acct[0][0]; 4172 fiop->f_ipf[0][1] = softc->ipf_rules[0][1]; 4173 fiop->f_acct[0][1] = softc->ipf_acct[0][1]; 4174 fiop->f_ipf[1][0] = softc->ipf_rules[1][0]; 4175 fiop->f_acct[1][0] = softc->ipf_acct[1][0]; 4176 fiop->f_ipf[1][1] = softc->ipf_rules[1][1]; 4177 fiop->f_acct[1][1] = softc->ipf_acct[1][1]; 4178 4179 fiop->f_ticks = softc->ipf_ticks; 4180 fiop->f_active = softc->ipf_active; 4181 fiop->f_froute[0] = softc->ipf_frouteok[0]; 4182 fiop->f_froute[1] = softc->ipf_frouteok[1]; 4183 fiop->f_rb_no_mem = softc->ipf_rb_no_mem; 4184 fiop->f_rb_node_max = softc->ipf_rb_node_max; 4185 4186 fiop->f_running = softc->ipf_running; 4187 for (i = 0; i < IPL_LOGSIZE; i++) { 4188 fiop->f_groups[i][0] = softc->ipf_groups[i][0]; 4189 fiop->f_groups[i][1] = softc->ipf_groups[i][1]; 4190 } 4191 #ifdef IPFILTER_LOG 4192 fiop->f_log_ok = ipf_log_logok(softc, IPL_LOGIPF); 4193 fiop->f_log_fail = ipf_log_failures(softc, IPL_LOGIPF); 4194 fiop->f_logging = 1; 4195 #else 4196 fiop->f_log_ok = 0; 4197 fiop->f_log_fail = 0; 4198 fiop->f_logging = 0; 4199 #endif 4200 fiop->f_defpass = softc->ipf_pass; 4201 fiop->f_features = ipf_features; 4202 4203 #ifdef IPFILTER_COMPAT 4204 snprintf(fiop->f_version, sizeof(friostat.f_version), "IP Filter: v%d.%d.%d", 4205 (rev / 1000000) % 100, 4206 (rev / 10000) % 100, 4207 (rev / 100) % 100); 4208 #else 4209 rev = rev; 4210 (void) strncpy(fiop->f_version, ipfilter_version, 4211 sizeof(fiop->f_version)); 4212 #endif 4213 } 4214 4215 4216 #ifdef USE_INET6 4217 int icmptoicmp6types[ICMP_MAXTYPE+1] = { 4218 ICMP6_ECHO_REPLY, /* 0: ICMP_ECHOREPLY */ 4219 -1, /* 1: UNUSED */ 4220 -1, /* 2: UNUSED */ 4221 ICMP6_DST_UNREACH, /* 3: ICMP_UNREACH */ 4222 -1, /* 4: ICMP_SOURCEQUENCH */ 4223 ND_REDIRECT, /* 5: ICMP_REDIRECT */ 4224 -1, /* 6: UNUSED */ 4225 -1, /* 7: UNUSED */ 4226 ICMP6_ECHO_REQUEST, /* 8: ICMP_ECHO */ 4227 -1, /* 9: UNUSED */ 4228 -1, /* 10: UNUSED */ 4229 ICMP6_TIME_EXCEEDED, /* 11: ICMP_TIMXCEED */ 4230 ICMP6_PARAM_PROB, /* 12: ICMP_PARAMPROB */ 4231 -1, /* 13: ICMP_TSTAMP */ 4232 -1, /* 14: ICMP_TSTAMPREPLY */ 4233 -1, /* 15: ICMP_IREQ */ 4234 -1, /* 16: ICMP_IREQREPLY */ 4235 -1, /* 17: ICMP_MASKREQ */ 4236 -1, /* 18: ICMP_MASKREPLY */ 4237 }; 4238 4239 4240 int icmptoicmp6unreach[ICMP_MAX_UNREACH] = { 4241 ICMP6_DST_UNREACH_ADDR, /* 0: ICMP_UNREACH_NET */ 4242 ICMP6_DST_UNREACH_ADDR, /* 1: ICMP_UNREACH_HOST */ 4243 -1, /* 2: ICMP_UNREACH_PROTOCOL */ 4244 ICMP6_DST_UNREACH_NOPORT, /* 3: ICMP_UNREACH_PORT */ 4245 -1, /* 4: ICMP_UNREACH_NEEDFRAG */ 4246 ICMP6_DST_UNREACH_NOTNEIGHBOR, /* 5: ICMP_UNREACH_SRCFAIL */ 4247 ICMP6_DST_UNREACH_ADDR, /* 6: ICMP_UNREACH_NET_UNKNOWN */ 4248 ICMP6_DST_UNREACH_ADDR, /* 7: ICMP_UNREACH_HOST_UNKNOWN */ 4249 -1, /* 8: ICMP_UNREACH_ISOLATED */ 4250 ICMP6_DST_UNREACH_ADMIN, /* 9: ICMP_UNREACH_NET_PROHIB */ 4251 ICMP6_DST_UNREACH_ADMIN, /* 10: ICMP_UNREACH_HOST_PROHIB */ 4252 -1, /* 11: ICMP_UNREACH_TOSNET */ 4253 -1, /* 12: ICMP_UNREACH_TOSHOST */ 4254 ICMP6_DST_UNREACH_ADMIN, /* 13: ICMP_UNREACH_ADMIN_PROHIBIT */ 4255 }; 4256 int icmpreplytype6[ICMP6_MAXTYPE + 1]; 4257 #endif 4258 4259 int icmpreplytype4[ICMP_MAXTYPE + 1]; 4260 4261 4262 /* ------------------------------------------------------------------------ */ 4263 /* Function: ipf_matchicmpqueryreply */ 4264 /* Returns: int - 1 if "icmp" is a valid reply to "ic" else 0. */ 4265 /* Parameters: v(I) - IP protocol version (4 or 6) */ 4266 /* ic(I) - ICMP information */ 4267 /* icmp(I) - ICMP packet header */ 4268 /* rev(I) - direction (0 = forward/1 = reverse) of packet */ 4269 /* */ 4270 /* Check if the ICMP packet defined by the header pointed to by icmp is a */ 4271 /* reply to one as described by what's in ic. If it is a match, return 1, */ 4272 /* else return 0 for no match. */ 4273 /* ------------------------------------------------------------------------ */ 4274 int 4275 ipf_matchicmpqueryreply(int v, icmpinfo_t *ic, icmphdr_t *icmp, int rev) 4276 { 4277 int ictype; 4278 4279 ictype = ic->ici_type; 4280 4281 if (v == 4) { 4282 /* 4283 * If we matched its type on the way in, then when going out 4284 * it will still be the same type. 4285 */ 4286 if ((!rev && (icmp->icmp_type == ictype)) || 4287 (rev && (icmpreplytype4[ictype] == icmp->icmp_type))) { 4288 if (icmp->icmp_type != ICMP_ECHOREPLY) 4289 return (1); 4290 if (icmp->icmp_id == ic->ici_id) 4291 return (1); 4292 } 4293 } 4294 #ifdef USE_INET6 4295 else if (v == 6) { 4296 if ((!rev && (icmp->icmp_type == ictype)) || 4297 (rev && (icmpreplytype6[ictype] == icmp->icmp_type))) { 4298 if (icmp->icmp_type != ICMP6_ECHO_REPLY) 4299 return (1); 4300 if (icmp->icmp_id == ic->ici_id) 4301 return (1); 4302 } 4303 } 4304 #endif 4305 return (0); 4306 } 4307 4308 4309 /* 4310 * IFNAMES are located in the variable length field starting at 4311 * frentry.fr_names. As pointers within the struct cannot be passed 4312 * to the kernel from ipf(8), an offset is used. An offset of -1 means it 4313 * is unused (invalid). If it is used (valid) it is an offset to the 4314 * character string of an interface name or a comment. The following 4315 * macros will assist those who follow to understand the code. 4316 */ 4317 #define IPF_IFNAME_VALID(_a) (_a != -1) 4318 #define IPF_IFNAME_INVALID(_a) (_a == -1) 4319 #define IPF_IFNAMES_DIFFERENT(_a) \ 4320 !((IPF_IFNAME_INVALID(fr1->_a) && \ 4321 IPF_IFNAME_INVALID(fr2->_a)) || \ 4322 (IPF_IFNAME_VALID(fr1->_a) && \ 4323 IPF_IFNAME_VALID(fr2->_a) && \ 4324 !strcmp(FR_NAME(fr1, _a), FR_NAME(fr2, _a)))) 4325 #define IPF_FRDEST_DIFFERENT(_a) \ 4326 (memcmp(&fr1->_a.fd_addr, &fr2->_a.fd_addr, \ 4327 offsetof(frdest_t, fd_name) - offsetof(frdest_t, fd_addr)) || \ 4328 IPF_IFNAMES_DIFFERENT(_a.fd_name)) 4329 4330 4331 /* ------------------------------------------------------------------------ */ 4332 /* Function: ipf_rule_compare */ 4333 /* Parameters: fr1(I) - first rule structure to compare */ 4334 /* fr2(I) - second rule structure to compare */ 4335 /* Returns: int - 0 == rules are the same, else mismatch */ 4336 /* */ 4337 /* Compare two rules and return 0 if they match or a number indicating */ 4338 /* which of the individual checks failed. */ 4339 /* ------------------------------------------------------------------------ */ 4340 static int 4341 ipf_rule_compare(frentry_t *fr1, frentry_t *fr2) 4342 { 4343 int i; 4344 4345 if (fr1->fr_cksum != fr2->fr_cksum) 4346 return (1); 4347 if (fr1->fr_size != fr2->fr_size) 4348 return (2); 4349 if (fr1->fr_dsize != fr2->fr_dsize) 4350 return (3); 4351 if (bcmp((char *)&fr1->fr_func, (char *)&fr2->fr_func, FR_CMPSIZ) 4352 != 0) 4353 return (4); 4354 /* 4355 * XXX: There is still a bug here as different rules with the 4356 * the same interfaces but in a different order will compare 4357 * differently. But since multiple interfaces in a rule doesn't 4358 * work anyway a simple straightforward compare is performed 4359 * here. Ultimately frentry_t creation will need to be 4360 * revisited in ipf_y.y. While the other issue, recognition 4361 * of only the first interface in a list of interfaces will 4362 * need to be separately addressed along with why only four. 4363 */ 4364 for (i = 0; i < FR_NUM(fr1->fr_ifnames); i++) { 4365 /* 4366 * XXX: It's either the same index or uninitialized. 4367 * We assume this because multiple interfaces 4368 * referenced by the same rule doesn't work anyway. 4369 */ 4370 if (IPF_IFNAMES_DIFFERENT(fr_ifnames[i])) 4371 return (5); 4372 } 4373 4374 if (IPF_FRDEST_DIFFERENT(fr_tif)) 4375 return (6); 4376 if (IPF_FRDEST_DIFFERENT(fr_rif)) 4377 return (7); 4378 if (IPF_FRDEST_DIFFERENT(fr_dif)) 4379 return (8); 4380 if (!fr1->fr_data && !fr2->fr_data) 4381 return (0); /* move along, nothing to see here */ 4382 if (fr1->fr_data && fr2->fr_data) { 4383 if (bcmp(fr1->fr_caddr, fr2->fr_caddr, fr1->fr_dsize) == 0) 4384 return (0); /* same */ 4385 } 4386 return (9); 4387 } 4388 4389 4390 /* ------------------------------------------------------------------------ */ 4391 /* Function: frrequest */ 4392 /* Returns: int - 0 == success, > 0 == errno value */ 4393 /* Parameters: unit(I) - device for which this is for */ 4394 /* req(I) - ioctl command (SIOC*) */ 4395 /* data(I) - pointr to ioctl data */ 4396 /* set(I) - 1 or 0 (filter set) */ 4397 /* makecopy(I) - flag indicating whether data points to a rule */ 4398 /* in kernel space & hence doesn't need copying. */ 4399 /* */ 4400 /* This function handles all the requests which operate on the list of */ 4401 /* filter rules. This includes adding, deleting, insertion. It is also */ 4402 /* responsible for creating groups when a "head" rule is loaded. Interface */ 4403 /* names are resolved here and other sanity checks are made on the content */ 4404 /* of the rule structure being loaded. If a rule has user defined timeouts */ 4405 /* then make sure they are created and initialised before exiting. */ 4406 /* ------------------------------------------------------------------------ */ 4407 int 4408 frrequest(ipf_main_softc_t *softc, int unit, ioctlcmd_t req, caddr_t data, 4409 int set, int makecopy) 4410 { 4411 int error = 0, in, family, need_free = 0; 4412 enum { OP_ADD, /* add rule */ 4413 OP_REM, /* remove rule */ 4414 OP_ZERO /* zero statistics and counters */ } 4415 addrem = OP_ADD; 4416 frentry_t frd, *fp, *f, **fprev, **ftail; 4417 void *ptr, *uptr, *cptr; 4418 u_int *p, *pp; 4419 frgroup_t *fg; 4420 char *group; 4421 4422 ptr = NULL; 4423 cptr = NULL; 4424 fg = NULL; 4425 fp = &frd; 4426 if (makecopy != 0) { 4427 bzero(fp, sizeof(frd)); 4428 error = ipf_inobj(softc, data, NULL, fp, IPFOBJ_FRENTRY); 4429 if (error) { 4430 return (error); 4431 } 4432 if ((fp->fr_type & FR_T_BUILTIN) != 0) { 4433 IPFERROR(6); 4434 return (EINVAL); 4435 } 4436 KMALLOCS(f, frentry_t *, fp->fr_size); 4437 if (f == NULL) { 4438 IPFERROR(131); 4439 return (ENOMEM); 4440 } 4441 bzero(f, fp->fr_size); 4442 error = ipf_inobjsz(softc, data, f, IPFOBJ_FRENTRY, 4443 fp->fr_size); 4444 if (error) { 4445 KFREES(f, fp->fr_size); 4446 return (error); 4447 } 4448 4449 fp = f; 4450 f = NULL; 4451 fp->fr_next = NULL; 4452 fp->fr_dnext = NULL; 4453 fp->fr_pnext = NULL; 4454 fp->fr_pdnext = NULL; 4455 fp->fr_grp = NULL; 4456 fp->fr_grphead = NULL; 4457 fp->fr_icmpgrp = NULL; 4458 fp->fr_isc = (void *)-1; 4459 fp->fr_ptr = NULL; 4460 fp->fr_ref = 0; 4461 fp->fr_flags |= FR_COPIED; 4462 } else { 4463 fp = (frentry_t *)data; 4464 if ((fp->fr_type & FR_T_BUILTIN) == 0) { 4465 IPFERROR(7); 4466 return (EINVAL); 4467 } 4468 fp->fr_flags &= ~FR_COPIED; 4469 } 4470 4471 if (((fp->fr_dsize == 0) && (fp->fr_data != NULL)) || 4472 ((fp->fr_dsize != 0) && (fp->fr_data == NULL))) { 4473 IPFERROR(8); 4474 error = EINVAL; 4475 goto donenolock; 4476 } 4477 4478 family = fp->fr_family; 4479 uptr = fp->fr_data; 4480 4481 if (req == (ioctlcmd_t)SIOCINAFR || req == (ioctlcmd_t)SIOCINIFR || 4482 req == (ioctlcmd_t)SIOCADAFR || req == (ioctlcmd_t)SIOCADIFR) 4483 addrem = OP_ADD; /* Add rule */ 4484 else if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR) 4485 addrem = OP_REM; /* Remove rule */ 4486 else if (req == (ioctlcmd_t)SIOCZRLST) 4487 addrem = OP_ZERO; /* Zero statistics and counters */ 4488 else { 4489 IPFERROR(9); 4490 error = EINVAL; 4491 goto donenolock; 4492 } 4493 4494 /* 4495 * Only filter rules for IPv4 or IPv6 are accepted. 4496 */ 4497 if (family == AF_INET) { 4498 /*EMPTY*/; 4499 #ifdef USE_INET6 4500 } else if (family == AF_INET6) { 4501 /*EMPTY*/; 4502 #endif 4503 } else if (family != 0) { 4504 IPFERROR(10); 4505 error = EINVAL; 4506 goto donenolock; 4507 } 4508 4509 /* 4510 * If the rule is being loaded from user space, i.e. we had to copy it 4511 * into kernel space, then do not trust the function pointer in the 4512 * rule. 4513 */ 4514 if ((makecopy == 1) && (fp->fr_func != NULL)) { 4515 if (ipf_findfunc(fp->fr_func) == NULL) { 4516 IPFERROR(11); 4517 error = ESRCH; 4518 goto donenolock; 4519 } 4520 4521 if (addrem == OP_ADD) { 4522 error = ipf_funcinit(softc, fp); 4523 if (error != 0) 4524 goto donenolock; 4525 } 4526 } 4527 if ((fp->fr_flags & FR_CALLNOW) && 4528 ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) { 4529 IPFERROR(142); 4530 error = ESRCH; 4531 goto donenolock; 4532 } 4533 if (((fp->fr_flags & FR_CMDMASK) == FR_CALL) && 4534 ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) { 4535 IPFERROR(143); 4536 error = ESRCH; 4537 goto donenolock; 4538 } 4539 4540 ptr = NULL; 4541 cptr = NULL; 4542 4543 if (FR_ISACCOUNT(fp->fr_flags)) 4544 unit = IPL_LOGCOUNT; 4545 4546 /* 4547 * Check that each group name in the rule has a start index that 4548 * is valid. 4549 */ 4550 if (fp->fr_icmphead != -1) { 4551 if ((fp->fr_icmphead < 0) || 4552 (fp->fr_icmphead >= fp->fr_namelen)) { 4553 IPFERROR(136); 4554 error = EINVAL; 4555 goto donenolock; 4556 } 4557 if (!strcmp(FR_NAME(fp, fr_icmphead), "0")) 4558 fp->fr_names[fp->fr_icmphead] = '\0'; 4559 } 4560 4561 if (fp->fr_grhead != -1) { 4562 if ((fp->fr_grhead < 0) || 4563 (fp->fr_grhead >= fp->fr_namelen)) { 4564 IPFERROR(137); 4565 error = EINVAL; 4566 goto donenolock; 4567 } 4568 if (!strcmp(FR_NAME(fp, fr_grhead), "0")) 4569 fp->fr_names[fp->fr_grhead] = '\0'; 4570 } 4571 4572 if (fp->fr_group != -1) { 4573 if ((fp->fr_group < 0) || 4574 (fp->fr_group >= fp->fr_namelen)) { 4575 IPFERROR(138); 4576 error = EINVAL; 4577 goto donenolock; 4578 } 4579 if ((req != (int)SIOCZRLST) && (fp->fr_group != -1)) { 4580 /* 4581 * Allow loading rules that are in groups to cause 4582 * them to be created if they don't already exit. 4583 */ 4584 group = FR_NAME(fp, fr_group); 4585 if (addrem == OP_ADD) { 4586 fg = ipf_group_add(softc, group, NULL, 4587 fp->fr_flags, unit, set); 4588 fp->fr_grp = fg; 4589 } else { 4590 fg = ipf_findgroup(softc, group, unit, 4591 set, NULL); 4592 if (fg == NULL) { 4593 IPFERROR(12); 4594 error = ESRCH; 4595 goto donenolock; 4596 } 4597 } 4598 4599 if (fg->fg_flags == 0) { 4600 fg->fg_flags = fp->fr_flags & FR_INOUT; 4601 } else if (fg->fg_flags != (fp->fr_flags & FR_INOUT)) { 4602 IPFERROR(13); 4603 error = ESRCH; 4604 goto donenolock; 4605 } 4606 } 4607 } else { 4608 /* 4609 * If a rule is going to be part of a group then it does 4610 * not matter whether it is an in or out rule, but if it 4611 * isn't in a group, then it does... 4612 */ 4613 if ((fp->fr_flags & (FR_INQUE|FR_OUTQUE)) == 0) { 4614 IPFERROR(14); 4615 error = EINVAL; 4616 goto donenolock; 4617 } 4618 } 4619 in = (fp->fr_flags & FR_INQUE) ? 0 : 1; 4620 4621 /* 4622 * Work out which rule list this change is being applied to. 4623 */ 4624 ftail = NULL; 4625 fprev = NULL; 4626 if (unit == IPL_LOGAUTH) { 4627 if ((fp->fr_tifs[0].fd_ptr != NULL) || 4628 (fp->fr_tifs[1].fd_ptr != NULL) || 4629 (fp->fr_dif.fd_ptr != NULL) || 4630 (fp->fr_flags & FR_FASTROUTE)) { 4631 softc->ipf_interror = 145; 4632 error = EINVAL; 4633 goto donenolock; 4634 } 4635 fprev = ipf_auth_rulehead(softc); 4636 } else { 4637 if (FR_ISACCOUNT(fp->fr_flags)) 4638 fprev = &softc->ipf_acct[in][set]; 4639 else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0) 4640 fprev = &softc->ipf_rules[in][set]; 4641 } 4642 if (fprev == NULL) { 4643 IPFERROR(15); 4644 error = ESRCH; 4645 goto donenolock; 4646 } 4647 4648 if (fg != NULL) 4649 fprev = &fg->fg_start; 4650 4651 /* 4652 * Copy in extra data for the rule. 4653 */ 4654 if (fp->fr_dsize != 0) { 4655 if (makecopy != 0) { 4656 KMALLOCS(ptr, void *, fp->fr_dsize); 4657 if (ptr == NULL) { 4658 IPFERROR(16); 4659 error = ENOMEM; 4660 goto donenolock; 4661 } 4662 4663 /* 4664 * The bcopy case is for when the data is appended 4665 * to the rule by ipf_in_compat(). 4666 */ 4667 if (uptr >= (void *)fp && 4668 uptr < (void *)((char *)fp + fp->fr_size)) { 4669 bcopy(uptr, ptr, fp->fr_dsize); 4670 error = 0; 4671 } else { 4672 error = COPYIN(uptr, ptr, fp->fr_dsize); 4673 if (error != 0) { 4674 IPFERROR(17); 4675 error = EFAULT; 4676 goto donenolock; 4677 } 4678 } 4679 } else { 4680 ptr = uptr; 4681 } 4682 fp->fr_data = ptr; 4683 } else { 4684 fp->fr_data = NULL; 4685 } 4686 4687 /* 4688 * Perform per-rule type sanity checks of their members. 4689 * All code after this needs to be aware that allocated memory 4690 * may need to be free'd before exiting. 4691 */ 4692 switch (fp->fr_type & ~FR_T_BUILTIN) 4693 { 4694 #if defined(IPFILTER_BPF) 4695 case FR_T_BPFOPC : 4696 if (fp->fr_dsize == 0) { 4697 IPFERROR(19); 4698 error = EINVAL; 4699 break; 4700 } 4701 if (!bpf_validate(ptr, fp->fr_dsize/sizeof(struct bpf_insn))) { 4702 IPFERROR(20); 4703 error = EINVAL; 4704 break; 4705 } 4706 break; 4707 #endif 4708 case FR_T_IPF : 4709 /* 4710 * Preparation for error case at the bottom of this function. 4711 */ 4712 if (fp->fr_datype == FRI_LOOKUP) 4713 fp->fr_dstptr = NULL; 4714 if (fp->fr_satype == FRI_LOOKUP) 4715 fp->fr_srcptr = NULL; 4716 4717 if (fp->fr_dsize != sizeof(fripf_t)) { 4718 IPFERROR(21); 4719 error = EINVAL; 4720 break; 4721 } 4722 4723 /* 4724 * Allowing a rule with both "keep state" and "with oow" is 4725 * pointless because adding a state entry to the table will 4726 * fail with the out of window (oow) flag set. 4727 */ 4728 if ((fp->fr_flags & FR_KEEPSTATE) && (fp->fr_flx & FI_OOW)) { 4729 IPFERROR(22); 4730 error = EINVAL; 4731 break; 4732 } 4733 4734 switch (fp->fr_satype) 4735 { 4736 case FRI_BROADCAST : 4737 case FRI_DYNAMIC : 4738 case FRI_NETWORK : 4739 case FRI_NETMASKED : 4740 case FRI_PEERADDR : 4741 if (fp->fr_sifpidx < 0) { 4742 IPFERROR(23); 4743 error = EINVAL; 4744 } 4745 break; 4746 case FRI_LOOKUP : 4747 fp->fr_srcptr = ipf_findlookup(softc, unit, fp, 4748 &fp->fr_src6, 4749 &fp->fr_smsk6); 4750 if (fp->fr_srcfunc == NULL) { 4751 IPFERROR(132); 4752 error = ESRCH; 4753 break; 4754 } 4755 break; 4756 case FRI_NORMAL : 4757 break; 4758 default : 4759 IPFERROR(133); 4760 error = EINVAL; 4761 break; 4762 } 4763 if (error != 0) 4764 break; 4765 4766 switch (fp->fr_datype) 4767 { 4768 case FRI_BROADCAST : 4769 case FRI_DYNAMIC : 4770 case FRI_NETWORK : 4771 case FRI_NETMASKED : 4772 case FRI_PEERADDR : 4773 if (fp->fr_difpidx < 0) { 4774 IPFERROR(24); 4775 error = EINVAL; 4776 } 4777 break; 4778 case FRI_LOOKUP : 4779 fp->fr_dstptr = ipf_findlookup(softc, unit, fp, 4780 &fp->fr_dst6, 4781 &fp->fr_dmsk6); 4782 if (fp->fr_dstfunc == NULL) { 4783 IPFERROR(134); 4784 error = ESRCH; 4785 } 4786 break; 4787 case FRI_NORMAL : 4788 break; 4789 default : 4790 IPFERROR(135); 4791 error = EINVAL; 4792 } 4793 break; 4794 4795 case FR_T_NONE : 4796 case FR_T_CALLFUNC : 4797 case FR_T_COMPIPF : 4798 break; 4799 4800 case FR_T_IPFEXPR : 4801 if (ipf_matcharray_verify(fp->fr_data, fp->fr_dsize) == -1) { 4802 IPFERROR(25); 4803 error = EINVAL; 4804 } 4805 break; 4806 4807 default : 4808 IPFERROR(26); 4809 error = EINVAL; 4810 break; 4811 } 4812 if (error != 0) 4813 goto donenolock; 4814 4815 if (fp->fr_tif.fd_name != -1) { 4816 if ((fp->fr_tif.fd_name < 0) || 4817 (fp->fr_tif.fd_name >= fp->fr_namelen)) { 4818 IPFERROR(139); 4819 error = EINVAL; 4820 goto donenolock; 4821 } 4822 } 4823 4824 if (fp->fr_dif.fd_name != -1) { 4825 if ((fp->fr_dif.fd_name < 0) || 4826 (fp->fr_dif.fd_name >= fp->fr_namelen)) { 4827 IPFERROR(140); 4828 error = EINVAL; 4829 goto donenolock; 4830 } 4831 } 4832 4833 if (fp->fr_rif.fd_name != -1) { 4834 if ((fp->fr_rif.fd_name < 0) || 4835 (fp->fr_rif.fd_name >= fp->fr_namelen)) { 4836 IPFERROR(141); 4837 error = EINVAL; 4838 goto donenolock; 4839 } 4840 } 4841 4842 /* 4843 * Lookup all the interface names that are part of the rule. 4844 */ 4845 error = ipf_synclist(softc, fp, NULL); 4846 if (error != 0) 4847 goto donenolock; 4848 fp->fr_statecnt = 0; 4849 if (fp->fr_srctrack.ht_max_nodes != 0) 4850 ipf_rb_ht_init(&fp->fr_srctrack); 4851 4852 /* 4853 * Look for an existing matching filter rule, but don't include the 4854 * next or interface pointer in the comparison (fr_next, fr_ifa). 4855 * This elminates rules which are indentical being loaded. Checksum 4856 * the constant part of the filter rule to make comparisons quicker 4857 * (this meaning no pointers are included). 4858 */ 4859 pp = (u_int *)(fp->fr_caddr + fp->fr_dsize); 4860 for (fp->fr_cksum = 0, p = (u_int *)fp->fr_data; p < pp; p++) 4861 fp->fr_cksum += *p; 4862 4863 WRITE_ENTER(&softc->ipf_mutex); 4864 4865 /* 4866 * Now that the filter rule lists are locked, we can walk the 4867 * chain of them without fear. 4868 */ 4869 ftail = fprev; 4870 for (f = *ftail; (f = *ftail) != NULL; ftail = &f->fr_next) { 4871 if (fp->fr_collect <= f->fr_collect) { 4872 ftail = fprev; 4873 f = NULL; 4874 break; 4875 } 4876 fprev = ftail; 4877 } 4878 4879 for (; (f = *ftail) != NULL; ftail = &f->fr_next) { 4880 if (ipf_rule_compare(fp, f) == 0) 4881 break; 4882 } 4883 4884 /* 4885 * If zero'ing statistics, copy current to caller and zero. 4886 */ 4887 if (addrem == OP_ZERO) { 4888 if (f == NULL) { 4889 IPFERROR(27); 4890 error = ESRCH; 4891 } else { 4892 /* 4893 * Copy and reduce lock because of impending copyout. 4894 * Well we should, but if we do then the atomicity of 4895 * this call and the correctness of fr_hits and 4896 * fr_bytes cannot be guaranteed. As it is, this code 4897 * only resets them to 0 if they are successfully 4898 * copied out into user space. 4899 */ 4900 bcopy((char *)f, (char *)fp, f->fr_size); 4901 /* MUTEX_DOWNGRADE(&softc->ipf_mutex); */ 4902 4903 /* 4904 * When we copy this rule back out, set the data 4905 * pointer to be what it was in user space. 4906 */ 4907 fp->fr_data = uptr; 4908 error = ipf_outobj(softc, data, fp, IPFOBJ_FRENTRY); 4909 4910 if (error == 0) { 4911 if ((f->fr_dsize != 0) && (uptr != NULL)) { 4912 error = COPYOUT(f->fr_data, uptr, 4913 f->fr_dsize); 4914 if (error == 0) { 4915 f->fr_hits = 0; 4916 f->fr_bytes = 0; 4917 } else { 4918 IPFERROR(28); 4919 error = EFAULT; 4920 } 4921 } 4922 } 4923 } 4924 4925 if (makecopy != 0) { 4926 if (ptr != NULL) { 4927 KFREES(ptr, fp->fr_dsize); 4928 } 4929 KFREES(fp, fp->fr_size); 4930 } 4931 RWLOCK_EXIT(&softc->ipf_mutex); 4932 return (error); 4933 } 4934 4935 if (f == NULL) { 4936 /* 4937 * At the end of this, ftail must point to the place where the 4938 * new rule is to be saved/inserted/added. 4939 * For SIOCAD*FR, this should be the last rule in the group of 4940 * rules that have equal fr_collect fields. 4941 * For SIOCIN*FR, ... 4942 */ 4943 if (req == (ioctlcmd_t)SIOCADAFR || 4944 req == (ioctlcmd_t)SIOCADIFR) { 4945 4946 for (ftail = fprev; (f = *ftail) != NULL; ) { 4947 if (f->fr_collect > fp->fr_collect) 4948 break; 4949 ftail = &f->fr_next; 4950 fprev = ftail; 4951 } 4952 ftail = fprev; 4953 f = NULL; 4954 ptr = NULL; 4955 } else if (req == (ioctlcmd_t)SIOCINAFR || 4956 req == (ioctlcmd_t)SIOCINIFR) { 4957 while ((f = *fprev) != NULL) { 4958 if (f->fr_collect >= fp->fr_collect) 4959 break; 4960 fprev = &f->fr_next; 4961 } 4962 ftail = fprev; 4963 if (fp->fr_hits != 0) { 4964 while (fp->fr_hits && (f = *ftail)) { 4965 if (f->fr_collect != fp->fr_collect) 4966 break; 4967 fprev = ftail; 4968 ftail = &f->fr_next; 4969 fp->fr_hits--; 4970 } 4971 } 4972 f = NULL; 4973 ptr = NULL; 4974 } 4975 } 4976 4977 /* 4978 * Request to remove a rule. 4979 */ 4980 if (addrem == OP_REM) { 4981 if (f == NULL) { 4982 IPFERROR(29); 4983 error = ESRCH; 4984 } else { 4985 /* 4986 * Do not allow activity from user space to interfere 4987 * with rules not loaded that way. 4988 */ 4989 if ((makecopy == 1) && !(f->fr_flags & FR_COPIED)) { 4990 IPFERROR(30); 4991 error = EPERM; 4992 goto done; 4993 } 4994 4995 /* 4996 * Return EBUSY if the rule is being reference by 4997 * something else (eg state information.) 4998 */ 4999 if (f->fr_ref > 1) { 5000 IPFERROR(31); 5001 error = EBUSY; 5002 goto done; 5003 } 5004 #ifdef IPFILTER_SCAN 5005 if (f->fr_isctag != -1 && 5006 (f->fr_isc != (struct ipscan *)-1)) 5007 ipf_scan_detachfr(f); 5008 #endif 5009 5010 if (unit == IPL_LOGAUTH) { 5011 error = ipf_auth_precmd(softc, req, f, ftail); 5012 goto done; 5013 } 5014 5015 ipf_rule_delete(softc, f, unit, set); 5016 5017 need_free = makecopy; 5018 } 5019 } else { 5020 /* 5021 * Not removing, so we must be adding/inserting a rule. 5022 */ 5023 if (f != NULL) { 5024 IPFERROR(32); 5025 error = EEXIST; 5026 goto done; 5027 } 5028 if (unit == IPL_LOGAUTH) { 5029 error = ipf_auth_precmd(softc, req, fp, ftail); 5030 goto done; 5031 } 5032 5033 MUTEX_NUKE(&fp->fr_lock); 5034 MUTEX_INIT(&fp->fr_lock, "filter rule lock"); 5035 if (fp->fr_die != 0) 5036 ipf_rule_expire_insert(softc, fp, set); 5037 5038 fp->fr_hits = 0; 5039 if (makecopy != 0) 5040 fp->fr_ref = 1; 5041 fp->fr_pnext = ftail; 5042 fp->fr_next = *ftail; 5043 if (fp->fr_next != NULL) 5044 fp->fr_next->fr_pnext = &fp->fr_next; 5045 *ftail = fp; 5046 ipf_fixskip(ftail, fp, 1); 5047 5048 fp->fr_icmpgrp = NULL; 5049 if (fp->fr_icmphead != -1) { 5050 group = FR_NAME(fp, fr_icmphead); 5051 fg = ipf_group_add(softc, group, fp, 0, unit, set); 5052 fp->fr_icmpgrp = fg; 5053 } 5054 5055 fp->fr_grphead = NULL; 5056 if (fp->fr_grhead != -1) { 5057 group = FR_NAME(fp, fr_grhead); 5058 fg = ipf_group_add(softc, group, fp, fp->fr_flags, 5059 unit, set); 5060 fp->fr_grphead = fg; 5061 } 5062 } 5063 done: 5064 RWLOCK_EXIT(&softc->ipf_mutex); 5065 donenolock: 5066 if (need_free || (error != 0)) { 5067 if ((fp->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) { 5068 if ((fp->fr_satype == FRI_LOOKUP) && 5069 (fp->fr_srcptr != NULL)) 5070 ipf_lookup_deref(softc, fp->fr_srctype, 5071 fp->fr_srcptr); 5072 if ((fp->fr_datype == FRI_LOOKUP) && 5073 (fp->fr_dstptr != NULL)) 5074 ipf_lookup_deref(softc, fp->fr_dsttype, 5075 fp->fr_dstptr); 5076 } 5077 if (fp->fr_grp != NULL) { 5078 WRITE_ENTER(&softc->ipf_mutex); 5079 ipf_group_del(softc, fp->fr_grp, fp); 5080 RWLOCK_EXIT(&softc->ipf_mutex); 5081 } 5082 if ((ptr != NULL) && (makecopy != 0)) { 5083 KFREES(ptr, fp->fr_dsize); 5084 } 5085 KFREES(fp, fp->fr_size); 5086 } 5087 return (error); 5088 } 5089 5090 5091 /* ------------------------------------------------------------------------ */ 5092 /* Function: ipf_rule_delete */ 5093 /* Returns: Nil */ 5094 /* Parameters: softc(I) - pointer to soft context main structure */ 5095 /* f(I) - pointer to the rule being deleted */ 5096 /* ftail(I) - pointer to the pointer to f */ 5097 /* unit(I) - device for which this is for */ 5098 /* set(I) - 1 or 0 (filter set) */ 5099 /* */ 5100 /* This function attempts to do what it can to delete a filter rule: remove */ 5101 /* it from any linked lists and remove any groups it is responsible for. */ 5102 /* But in the end, removing a rule can only drop the reference count - we */ 5103 /* must use that as the guide for whether or not it can be freed. */ 5104 /* ------------------------------------------------------------------------ */ 5105 static void 5106 ipf_rule_delete(ipf_main_softc_t *softc, frentry_t *f, int unit, int set) 5107 { 5108 5109 /* 5110 * If fr_pdnext is set, then the rule is on the expire list, so 5111 * remove it from there. 5112 */ 5113 if (f->fr_pdnext != NULL) { 5114 *f->fr_pdnext = f->fr_dnext; 5115 if (f->fr_dnext != NULL) 5116 f->fr_dnext->fr_pdnext = f->fr_pdnext; 5117 f->fr_pdnext = NULL; 5118 f->fr_dnext = NULL; 5119 } 5120 5121 ipf_fixskip(f->fr_pnext, f, -1); 5122 if (f->fr_pnext != NULL) 5123 *f->fr_pnext = f->fr_next; 5124 if (f->fr_next != NULL) 5125 f->fr_next->fr_pnext = f->fr_pnext; 5126 f->fr_pnext = NULL; 5127 f->fr_next = NULL; 5128 5129 (void) ipf_derefrule(softc, &f); 5130 } 5131 5132 /* ------------------------------------------------------------------------ */ 5133 /* Function: ipf_rule_expire_insert */ 5134 /* Returns: Nil */ 5135 /* Parameters: softc(I) - pointer to soft context main structure */ 5136 /* f(I) - pointer to rule to be added to expire list */ 5137 /* set(I) - 1 or 0 (filter set) */ 5138 /* */ 5139 /* If the new rule has a given expiration time, insert it into the list of */ 5140 /* expiring rules with the ones to be removed first added to the front of */ 5141 /* the list. The insertion is O(n) but it is kept sorted for quick scans at */ 5142 /* expiration interval checks. */ 5143 /* ------------------------------------------------------------------------ */ 5144 static void 5145 ipf_rule_expire_insert(ipf_main_softc_t *softc, frentry_t *f, int set) 5146 { 5147 frentry_t *fr; 5148 5149 /* 5150 */ 5151 5152 f->fr_die = softc->ipf_ticks + IPF_TTLVAL(f->fr_die); 5153 for (fr = softc->ipf_rule_explist[set]; fr != NULL; 5154 fr = fr->fr_dnext) { 5155 if (f->fr_die < fr->fr_die) 5156 break; 5157 if (fr->fr_dnext == NULL) { 5158 /* 5159 * We've got to the last rule and everything 5160 * wanted to be expired before this new node, 5161 * so we have to tack it on the end... 5162 */ 5163 fr->fr_dnext = f; 5164 f->fr_pdnext = &fr->fr_dnext; 5165 fr = NULL; 5166 break; 5167 } 5168 } 5169 5170 if (softc->ipf_rule_explist[set] == NULL) { 5171 softc->ipf_rule_explist[set] = f; 5172 f->fr_pdnext = &softc->ipf_rule_explist[set]; 5173 } else if (fr != NULL) { 5174 f->fr_dnext = fr; 5175 f->fr_pdnext = fr->fr_pdnext; 5176 fr->fr_pdnext = &f->fr_dnext; 5177 } 5178 } 5179 5180 5181 /* ------------------------------------------------------------------------ */ 5182 /* Function: ipf_findlookup */ 5183 /* Returns: NULL = failure, else success */ 5184 /* Parameters: softc(I) - pointer to soft context main structure */ 5185 /* unit(I) - ipf device we want to find match for */ 5186 /* fp(I) - rule for which lookup is for */ 5187 /* addrp(I) - pointer to lookup information in address struct */ 5188 /* maskp(O) - pointer to lookup information for storage */ 5189 /* */ 5190 /* When using pools and hash tables to store addresses for matching in */ 5191 /* rules, it is necessary to resolve both the object referred to by the */ 5192 /* name or address (and return that pointer) and also provide the means by */ 5193 /* which to determine if an address belongs to that object to make the */ 5194 /* packet matching quicker. */ 5195 /* ------------------------------------------------------------------------ */ 5196 static void * 5197 ipf_findlookup(ipf_main_softc_t *softc, int unit, frentry_t *fr, 5198 i6addr_t *addrp, i6addr_t *maskp) 5199 { 5200 void *ptr = NULL; 5201 5202 switch (addrp->iplookupsubtype) 5203 { 5204 case 0 : 5205 ptr = ipf_lookup_res_num(softc, unit, addrp->iplookuptype, 5206 addrp->iplookupnum, 5207 &maskp->iplookupfunc); 5208 break; 5209 case 1 : 5210 if (addrp->iplookupname < 0) 5211 break; 5212 if (addrp->iplookupname >= fr->fr_namelen) 5213 break; 5214 ptr = ipf_lookup_res_name(softc, unit, addrp->iplookuptype, 5215 fr->fr_names + addrp->iplookupname, 5216 &maskp->iplookupfunc); 5217 break; 5218 default : 5219 break; 5220 } 5221 5222 return (ptr); 5223 } 5224 5225 5226 /* ------------------------------------------------------------------------ */ 5227 /* Function: ipf_funcinit */ 5228 /* Returns: int - 0 == success, else ESRCH: cannot resolve rule details */ 5229 /* Parameters: softc(I) - pointer to soft context main structure */ 5230 /* fr(I) - pointer to filter rule */ 5231 /* */ 5232 /* If a rule is a call rule, then check if the function it points to needs */ 5233 /* an init function to be called now the rule has been loaded. */ 5234 /* ------------------------------------------------------------------------ */ 5235 static int 5236 ipf_funcinit(ipf_main_softc_t *softc, frentry_t *fr) 5237 { 5238 ipfunc_resolve_t *ft; 5239 int err; 5240 5241 IPFERROR(34); 5242 err = ESRCH; 5243 5244 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5245 if (ft->ipfu_addr == fr->fr_func) { 5246 err = 0; 5247 if (ft->ipfu_init != NULL) 5248 err = (*ft->ipfu_init)(softc, fr); 5249 break; 5250 } 5251 return (err); 5252 } 5253 5254 5255 /* ------------------------------------------------------------------------ */ 5256 /* Function: ipf_funcfini */ 5257 /* Returns: Nil */ 5258 /* Parameters: softc(I) - pointer to soft context main structure */ 5259 /* fr(I) - pointer to filter rule */ 5260 /* */ 5261 /* For a given filter rule, call the matching "fini" function if the rule */ 5262 /* is using a known function that would have resulted in the "init" being */ 5263 /* called for ealier. */ 5264 /* ------------------------------------------------------------------------ */ 5265 static void 5266 ipf_funcfini(ipf_main_softc_t *softc, frentry_t *fr) 5267 { 5268 ipfunc_resolve_t *ft; 5269 5270 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5271 if (ft->ipfu_addr == fr->fr_func) { 5272 if (ft->ipfu_fini != NULL) 5273 (void) (*ft->ipfu_fini)(softc, fr); 5274 break; 5275 } 5276 } 5277 5278 5279 /* ------------------------------------------------------------------------ */ 5280 /* Function: ipf_findfunc */ 5281 /* Returns: ipfunc_t - pointer to function if found, else NULL */ 5282 /* Parameters: funcptr(I) - function pointer to lookup */ 5283 /* */ 5284 /* Look for a function in the table of known functions. */ 5285 /* ------------------------------------------------------------------------ */ 5286 static ipfunc_t 5287 ipf_findfunc(ipfunc_t funcptr) 5288 { 5289 ipfunc_resolve_t *ft; 5290 5291 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5292 if (ft->ipfu_addr == funcptr) 5293 return (funcptr); 5294 return (NULL); 5295 } 5296 5297 5298 /* ------------------------------------------------------------------------ */ 5299 /* Function: ipf_resolvefunc */ 5300 /* Returns: int - 0 == success, else error */ 5301 /* Parameters: data(IO) - ioctl data pointer to ipfunc_resolve_t struct */ 5302 /* */ 5303 /* Copy in a ipfunc_resolve_t structure and then fill in the missing field. */ 5304 /* This will either be the function name (if the pointer is set) or the */ 5305 /* function pointer if the name is set. When found, fill in the other one */ 5306 /* so that the entire, complete, structure can be copied back to user space.*/ 5307 /* ------------------------------------------------------------------------ */ 5308 int 5309 ipf_resolvefunc(ipf_main_softc_t *softc, void *data) 5310 { 5311 ipfunc_resolve_t res, *ft; 5312 int error; 5313 5314 error = BCOPYIN(data, &res, sizeof(res)); 5315 if (error != 0) { 5316 IPFERROR(123); 5317 return (EFAULT); 5318 } 5319 5320 if (res.ipfu_addr == NULL && res.ipfu_name[0] != '\0') { 5321 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5322 if (strncmp(res.ipfu_name, ft->ipfu_name, 5323 sizeof(res.ipfu_name)) == 0) { 5324 res.ipfu_addr = ft->ipfu_addr; 5325 res.ipfu_init = ft->ipfu_init; 5326 if (COPYOUT(&res, data, sizeof(res)) != 0) { 5327 IPFERROR(35); 5328 return (EFAULT); 5329 } 5330 return (0); 5331 } 5332 } 5333 if (res.ipfu_addr != NULL && res.ipfu_name[0] == '\0') { 5334 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5335 if (ft->ipfu_addr == res.ipfu_addr) { 5336 (void) strncpy(res.ipfu_name, ft->ipfu_name, 5337 sizeof(res.ipfu_name)); 5338 res.ipfu_init = ft->ipfu_init; 5339 if (COPYOUT(&res, data, sizeof(res)) != 0) { 5340 IPFERROR(36); 5341 return (EFAULT); 5342 } 5343 return (0); 5344 } 5345 } 5346 IPFERROR(37); 5347 return (ESRCH); 5348 } 5349 5350 5351 #if !defined(_KERNEL) || SOLARIS 5352 /* 5353 * From: NetBSD 5354 * ppsratecheck(): packets (or events) per second limitation. 5355 */ 5356 int 5357 ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps) 5358 /* maxpps: maximum pps allowed */ 5359 { 5360 struct timeval tv, delta; 5361 int rv; 5362 5363 GETKTIME(&tv); 5364 5365 delta.tv_sec = tv.tv_sec - lasttime->tv_sec; 5366 delta.tv_usec = tv.tv_usec - lasttime->tv_usec; 5367 if (delta.tv_usec < 0) { 5368 delta.tv_sec--; 5369 delta.tv_usec += 1000000; 5370 } 5371 5372 /* 5373 * check for 0,0 is so that the message will be seen at least once. 5374 * if more than one second have passed since the last update of 5375 * lasttime, reset the counter. 5376 * 5377 * we do increment *curpps even in *curpps < maxpps case, as some may 5378 * try to use *curpps for stat purposes as well. 5379 */ 5380 if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) || 5381 delta.tv_sec >= 1) { 5382 *lasttime = tv; 5383 *curpps = 0; 5384 rv = 1; 5385 } else if (maxpps < 0) 5386 rv = 1; 5387 else if (*curpps < maxpps) 5388 rv = 1; 5389 else 5390 rv = 0; 5391 *curpps = *curpps + 1; 5392 5393 return (rv); 5394 } 5395 #endif 5396 5397 5398 /* ------------------------------------------------------------------------ */ 5399 /* Function: ipf_derefrule */ 5400 /* Returns: int - 0 == rule freed up, else rule not freed */ 5401 /* Parameters: fr(I) - pointer to filter rule */ 5402 /* */ 5403 /* Decrement the reference counter to a rule by one. If it reaches zero, */ 5404 /* free it and any associated storage space being used by it. */ 5405 /* ------------------------------------------------------------------------ */ 5406 int 5407 ipf_derefrule(ipf_main_softc_t *softc, frentry_t **frp) 5408 { 5409 frentry_t *fr; 5410 frdest_t *fdp; 5411 5412 fr = *frp; 5413 *frp = NULL; 5414 5415 MUTEX_ENTER(&fr->fr_lock); 5416 fr->fr_ref--; 5417 if (fr->fr_ref == 0) { 5418 MUTEX_EXIT(&fr->fr_lock); 5419 MUTEX_DESTROY(&fr->fr_lock); 5420 5421 ipf_funcfini(softc, fr); 5422 5423 fdp = &fr->fr_tif; 5424 if (fdp->fd_type == FRD_DSTLIST) 5425 ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr); 5426 5427 fdp = &fr->fr_rif; 5428 if (fdp->fd_type == FRD_DSTLIST) 5429 ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr); 5430 5431 fdp = &fr->fr_dif; 5432 if (fdp->fd_type == FRD_DSTLIST) 5433 ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr); 5434 5435 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF && 5436 fr->fr_satype == FRI_LOOKUP) 5437 ipf_lookup_deref(softc, fr->fr_srctype, fr->fr_srcptr); 5438 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF && 5439 fr->fr_datype == FRI_LOOKUP) 5440 ipf_lookup_deref(softc, fr->fr_dsttype, fr->fr_dstptr); 5441 5442 if (fr->fr_grp != NULL) 5443 ipf_group_del(softc, fr->fr_grp, fr); 5444 5445 if (fr->fr_grphead != NULL) 5446 ipf_group_del(softc, fr->fr_grphead, fr); 5447 5448 if (fr->fr_icmpgrp != NULL) 5449 ipf_group_del(softc, fr->fr_icmpgrp, fr); 5450 5451 if ((fr->fr_flags & FR_COPIED) != 0) { 5452 if (fr->fr_dsize) { 5453 KFREES(fr->fr_data, fr->fr_dsize); 5454 } 5455 KFREES(fr, fr->fr_size); 5456 return (0); 5457 } 5458 return (1); 5459 } else { 5460 MUTEX_EXIT(&fr->fr_lock); 5461 } 5462 return (-1); 5463 } 5464 5465 5466 /* ------------------------------------------------------------------------ */ 5467 /* Function: ipf_grpmapinit */ 5468 /* Returns: int - 0 == success, else ESRCH because table entry not found*/ 5469 /* Parameters: fr(I) - pointer to rule to find hash table for */ 5470 /* */ 5471 /* Looks for group hash table fr_arg and stores a pointer to it in fr_ptr. */ 5472 /* fr_ptr is later used by ipf_srcgrpmap and ipf_dstgrpmap. */ 5473 /* ------------------------------------------------------------------------ */ 5474 static int 5475 ipf_grpmapinit(ipf_main_softc_t *softc, frentry_t *fr) 5476 { 5477 char name[FR_GROUPLEN]; 5478 iphtable_t *iph; 5479 5480 (void) snprintf(name, sizeof(name), "%d", fr->fr_arg); 5481 iph = ipf_lookup_find_htable(softc, IPL_LOGIPF, name); 5482 if (iph == NULL) { 5483 IPFERROR(38); 5484 return (ESRCH); 5485 } 5486 if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT)) { 5487 IPFERROR(39); 5488 return (ESRCH); 5489 } 5490 iph->iph_ref++; 5491 fr->fr_ptr = iph; 5492 return (0); 5493 } 5494 5495 5496 /* ------------------------------------------------------------------------ */ 5497 /* Function: ipf_grpmapfini */ 5498 /* Returns: int - 0 == success, else ESRCH because table entry not found*/ 5499 /* Parameters: softc(I) - pointer to soft context main structure */ 5500 /* fr(I) - pointer to rule to release hash table for */ 5501 /* */ 5502 /* For rules that have had ipf_grpmapinit called, ipf_lookup_deref needs to */ 5503 /* be called to undo what ipf_grpmapinit caused to be done. */ 5504 /* ------------------------------------------------------------------------ */ 5505 static int 5506 ipf_grpmapfini(ipf_main_softc_t *softc, frentry_t *fr) 5507 { 5508 iphtable_t *iph; 5509 iph = fr->fr_ptr; 5510 if (iph != NULL) 5511 ipf_lookup_deref(softc, IPLT_HASH, iph); 5512 return (0); 5513 } 5514 5515 5516 /* ------------------------------------------------------------------------ */ 5517 /* Function: ipf_srcgrpmap */ 5518 /* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ 5519 /* Parameters: fin(I) - pointer to packet information */ 5520 /* passp(IO) - pointer to current/new filter decision (unused) */ 5521 /* */ 5522 /* Look for a rule group head in a hash table, using the source address as */ 5523 /* the key, and descend into that group and continue matching rules against */ 5524 /* the packet. */ 5525 /* ------------------------------------------------------------------------ */ 5526 frentry_t * 5527 ipf_srcgrpmap(fr_info_t *fin, u_32_t *passp) 5528 { 5529 frgroup_t *fg; 5530 void *rval; 5531 5532 rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr, 5533 &fin->fin_src); 5534 if (rval == NULL) 5535 return (NULL); 5536 5537 fg = rval; 5538 fin->fin_fr = fg->fg_start; 5539 (void) ipf_scanlist(fin, *passp); 5540 return (fin->fin_fr); 5541 } 5542 5543 5544 /* ------------------------------------------------------------------------ */ 5545 /* Function: ipf_dstgrpmap */ 5546 /* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ 5547 /* Parameters: fin(I) - pointer to packet information */ 5548 /* passp(IO) - pointer to current/new filter decision (unused) */ 5549 /* */ 5550 /* Look for a rule group head in a hash table, using the destination */ 5551 /* address as the key, and descend into that group and continue matching */ 5552 /* rules against the packet. */ 5553 /* ------------------------------------------------------------------------ */ 5554 frentry_t * 5555 ipf_dstgrpmap(fr_info_t *fin, u_32_t *passp) 5556 { 5557 frgroup_t *fg; 5558 void *rval; 5559 5560 rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr, 5561 &fin->fin_dst); 5562 if (rval == NULL) 5563 return (NULL); 5564 5565 fg = rval; 5566 fin->fin_fr = fg->fg_start; 5567 (void) ipf_scanlist(fin, *passp); 5568 return (fin->fin_fr); 5569 } 5570 5571 /* 5572 * Queue functions 5573 * =============== 5574 * These functions manage objects on queues for efficient timeouts. There 5575 * are a number of system defined queues as well as user defined timeouts. 5576 * It is expected that a lock is held in the domain in which the queue 5577 * belongs (i.e. either state or NAT) when calling any of these functions 5578 * that prevents ipf_freetimeoutqueue() from being called at the same time 5579 * as any other. 5580 */ 5581 5582 5583 /* ------------------------------------------------------------------------ */ 5584 /* Function: ipf_addtimeoutqueue */ 5585 /* Returns: struct ifqtq * - NULL if malloc fails, else pointer to */ 5586 /* timeout queue with given interval. */ 5587 /* Parameters: parent(I) - pointer to pointer to parent node of this list */ 5588 /* of interface queues. */ 5589 /* seconds(I) - timeout value in seconds for this queue. */ 5590 /* */ 5591 /* This routine first looks for a timeout queue that matches the interval */ 5592 /* being requested. If it finds one, increments the reference counter and */ 5593 /* returns a pointer to it. If none are found, it allocates a new one and */ 5594 /* inserts it at the top of the list. */ 5595 /* */ 5596 /* Locking. */ 5597 /* It is assumed that the caller of this function has an appropriate lock */ 5598 /* held (exclusively) in the domain that encompases 'parent'. */ 5599 /* ------------------------------------------------------------------------ */ 5600 ipftq_t * 5601 ipf_addtimeoutqueue(ipf_main_softc_t *softc, ipftq_t **parent, u_int seconds) 5602 { 5603 ipftq_t *ifq; 5604 u_int period; 5605 5606 period = seconds * IPF_HZ_DIVIDE; 5607 5608 MUTEX_ENTER(&softc->ipf_timeoutlock); 5609 for (ifq = *parent; ifq != NULL; ifq = ifq->ifq_next) { 5610 if (ifq->ifq_ttl == period) { 5611 /* 5612 * Reset the delete flag, if set, so the structure 5613 * gets reused rather than freed and reallocated. 5614 */ 5615 MUTEX_ENTER(&ifq->ifq_lock); 5616 ifq->ifq_flags &= ~IFQF_DELETE; 5617 ifq->ifq_ref++; 5618 MUTEX_EXIT(&ifq->ifq_lock); 5619 MUTEX_EXIT(&softc->ipf_timeoutlock); 5620 5621 return (ifq); 5622 } 5623 } 5624 5625 KMALLOC(ifq, ipftq_t *); 5626 if (ifq != NULL) { 5627 MUTEX_NUKE(&ifq->ifq_lock); 5628 IPFTQ_INIT(ifq, period, "ipftq mutex"); 5629 ifq->ifq_next = *parent; 5630 ifq->ifq_pnext = parent; 5631 ifq->ifq_flags = IFQF_USER; 5632 ifq->ifq_ref++; 5633 *parent = ifq; 5634 softc->ipf_userifqs++; 5635 } 5636 MUTEX_EXIT(&softc->ipf_timeoutlock); 5637 return (ifq); 5638 } 5639 5640 5641 /* ------------------------------------------------------------------------ */ 5642 /* Function: ipf_deletetimeoutqueue */ 5643 /* Returns: int - new reference count value of the timeout queue */ 5644 /* Parameters: ifq(I) - timeout queue which is losing a reference. */ 5645 /* Locks: ifq->ifq_lock */ 5646 /* */ 5647 /* This routine must be called when we're discarding a pointer to a timeout */ 5648 /* queue object, taking care of the reference counter. */ 5649 /* */ 5650 /* Now that this just sets a DELETE flag, it requires the expire code to */ 5651 /* check the list of user defined timeout queues and call the free function */ 5652 /* below (currently commented out) to stop memory leaking. It is done this */ 5653 /* way because the locking may not be sufficient to safely do a free when */ 5654 /* this function is called. */ 5655 /* ------------------------------------------------------------------------ */ 5656 int 5657 ipf_deletetimeoutqueue(ipftq_t *ifq) 5658 { 5659 5660 ifq->ifq_ref--; 5661 if ((ifq->ifq_ref == 0) && ((ifq->ifq_flags & IFQF_USER) != 0)) { 5662 ifq->ifq_flags |= IFQF_DELETE; 5663 } 5664 5665 return (ifq->ifq_ref); 5666 } 5667 5668 5669 /* ------------------------------------------------------------------------ */ 5670 /* Function: ipf_freetimeoutqueue */ 5671 /* Parameters: ifq(I) - timeout queue which is losing a reference. */ 5672 /* Returns: Nil */ 5673 /* */ 5674 /* Locking: */ 5675 /* It is assumed that the caller of this function has an appropriate lock */ 5676 /* held (exclusively) in the domain that encompases the callers "domain". */ 5677 /* The ifq_lock for this structure should not be held. */ 5678 /* */ 5679 /* Remove a user defined timeout queue from the list of queues it is in and */ 5680 /* tidy up after this is done. */ 5681 /* ------------------------------------------------------------------------ */ 5682 void 5683 ipf_freetimeoutqueue(ipf_main_softc_t *softc, ipftq_t *ifq) 5684 { 5685 5686 if (((ifq->ifq_flags & IFQF_DELETE) == 0) || (ifq->ifq_ref != 0) || 5687 ((ifq->ifq_flags & IFQF_USER) == 0)) { 5688 printf("ipf_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n", 5689 (u_long)ifq, ifq->ifq_flags, ifq->ifq_ttl, 5690 ifq->ifq_ref); 5691 return; 5692 } 5693 5694 /* 5695 * Remove from its position in the list. 5696 */ 5697 *ifq->ifq_pnext = ifq->ifq_next; 5698 if (ifq->ifq_next != NULL) 5699 ifq->ifq_next->ifq_pnext = ifq->ifq_pnext; 5700 ifq->ifq_next = NULL; 5701 ifq->ifq_pnext = NULL; 5702 5703 MUTEX_DESTROY(&ifq->ifq_lock); 5704 ATOMIC_DEC(softc->ipf_userifqs); 5705 KFREE(ifq); 5706 } 5707 5708 5709 /* ------------------------------------------------------------------------ */ 5710 /* Function: ipf_deletequeueentry */ 5711 /* Returns: Nil */ 5712 /* Parameters: tqe(I) - timeout queue entry to delete */ 5713 /* */ 5714 /* Remove a tail queue entry from its queue and make it an orphan. */ 5715 /* ipf_deletetimeoutqueue is called to make sure the reference count on the */ 5716 /* queue is correct. We can't, however, call ipf_freetimeoutqueue because */ 5717 /* the correct lock(s) may not be held that would make it safe to do so. */ 5718 /* ------------------------------------------------------------------------ */ 5719 void 5720 ipf_deletequeueentry(ipftqent_t *tqe) 5721 { 5722 ipftq_t *ifq; 5723 5724 ifq = tqe->tqe_ifq; 5725 5726 MUTEX_ENTER(&ifq->ifq_lock); 5727 5728 if (tqe->tqe_pnext != NULL) { 5729 *tqe->tqe_pnext = tqe->tqe_next; 5730 if (tqe->tqe_next != NULL) 5731 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5732 else /* we must be the tail anyway */ 5733 ifq->ifq_tail = tqe->tqe_pnext; 5734 5735 tqe->tqe_pnext = NULL; 5736 tqe->tqe_ifq = NULL; 5737 } 5738 5739 (void) ipf_deletetimeoutqueue(ifq); 5740 ASSERT(ifq->ifq_ref > 0); 5741 5742 MUTEX_EXIT(&ifq->ifq_lock); 5743 } 5744 5745 5746 /* ------------------------------------------------------------------------ */ 5747 /* Function: ipf_queuefront */ 5748 /* Returns: Nil */ 5749 /* Parameters: tqe(I) - pointer to timeout queue entry */ 5750 /* */ 5751 /* Move a queue entry to the front of the queue, if it isn't already there. */ 5752 /* ------------------------------------------------------------------------ */ 5753 void 5754 ipf_queuefront(ipftqent_t *tqe) 5755 { 5756 ipftq_t *ifq; 5757 5758 ifq = tqe->tqe_ifq; 5759 if (ifq == NULL) 5760 return; 5761 5762 MUTEX_ENTER(&ifq->ifq_lock); 5763 if (ifq->ifq_head != tqe) { 5764 *tqe->tqe_pnext = tqe->tqe_next; 5765 if (tqe->tqe_next) 5766 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5767 else 5768 ifq->ifq_tail = tqe->tqe_pnext; 5769 5770 tqe->tqe_next = ifq->ifq_head; 5771 ifq->ifq_head->tqe_pnext = &tqe->tqe_next; 5772 ifq->ifq_head = tqe; 5773 tqe->tqe_pnext = &ifq->ifq_head; 5774 } 5775 MUTEX_EXIT(&ifq->ifq_lock); 5776 } 5777 5778 5779 /* ------------------------------------------------------------------------ */ 5780 /* Function: ipf_queueback */ 5781 /* Returns: Nil */ 5782 /* Parameters: ticks(I) - ipf tick time to use with this call */ 5783 /* tqe(I) - pointer to timeout queue entry */ 5784 /* */ 5785 /* Move a queue entry to the back of the queue, if it isn't already there. */ 5786 /* We use use ticks to calculate the expiration and mark for when we last */ 5787 /* touched the structure. */ 5788 /* ------------------------------------------------------------------------ */ 5789 void 5790 ipf_queueback(u_long ticks, ipftqent_t *tqe) 5791 { 5792 ipftq_t *ifq; 5793 5794 ifq = tqe->tqe_ifq; 5795 if (ifq == NULL) 5796 return; 5797 tqe->tqe_die = ticks + ifq->ifq_ttl; 5798 tqe->tqe_touched = ticks; 5799 5800 MUTEX_ENTER(&ifq->ifq_lock); 5801 if (tqe->tqe_next != NULL) { /* at the end already ? */ 5802 /* 5803 * Remove from list 5804 */ 5805 *tqe->tqe_pnext = tqe->tqe_next; 5806 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5807 5808 /* 5809 * Make it the last entry. 5810 */ 5811 tqe->tqe_next = NULL; 5812 tqe->tqe_pnext = ifq->ifq_tail; 5813 *ifq->ifq_tail = tqe; 5814 ifq->ifq_tail = &tqe->tqe_next; 5815 } 5816 MUTEX_EXIT(&ifq->ifq_lock); 5817 } 5818 5819 5820 /* ------------------------------------------------------------------------ */ 5821 /* Function: ipf_queueappend */ 5822 /* Returns: Nil */ 5823 /* Parameters: ticks(I) - ipf tick time to use with this call */ 5824 /* tqe(I) - pointer to timeout queue entry */ 5825 /* ifq(I) - pointer to timeout queue */ 5826 /* parent(I) - owing object pointer */ 5827 /* */ 5828 /* Add a new item to this queue and put it on the very end. */ 5829 /* We use use ticks to calculate the expiration and mark for when we last */ 5830 /* touched the structure. */ 5831 /* ------------------------------------------------------------------------ */ 5832 void 5833 ipf_queueappend(u_long ticks, ipftqent_t *tqe, ipftq_t *ifq, void *parent) 5834 { 5835 5836 MUTEX_ENTER(&ifq->ifq_lock); 5837 tqe->tqe_parent = parent; 5838 tqe->tqe_pnext = ifq->ifq_tail; 5839 *ifq->ifq_tail = tqe; 5840 ifq->ifq_tail = &tqe->tqe_next; 5841 tqe->tqe_next = NULL; 5842 tqe->tqe_ifq = ifq; 5843 tqe->tqe_die = ticks + ifq->ifq_ttl; 5844 tqe->tqe_touched = ticks; 5845 ifq->ifq_ref++; 5846 MUTEX_EXIT(&ifq->ifq_lock); 5847 } 5848 5849 5850 /* ------------------------------------------------------------------------ */ 5851 /* Function: ipf_movequeue */ 5852 /* Returns: Nil */ 5853 /* Parameters: tq(I) - pointer to timeout queue information */ 5854 /* oifp(I) - old timeout queue entry was on */ 5855 /* nifp(I) - new timeout queue to put entry on */ 5856 /* */ 5857 /* Move a queue entry from one timeout queue to another timeout queue. */ 5858 /* If it notices that the current entry is already last and does not need */ 5859 /* to move queue, the return. */ 5860 /* ------------------------------------------------------------------------ */ 5861 void 5862 ipf_movequeue(u_long ticks, ipftqent_t *tqe, ipftq_t *oifq, ipftq_t *nifq) 5863 { 5864 5865 /* 5866 * If the queue hasn't changed and we last touched this entry at the 5867 * same ipf time, then we're not going to achieve anything by either 5868 * changing the ttl or moving it on the queue. 5869 */ 5870 if (oifq == nifq && tqe->tqe_touched == ticks) 5871 return; 5872 5873 /* 5874 * For any of this to be outside the lock, there is a risk that two 5875 * packets entering simultaneously, with one changing to a different 5876 * queue and one not, could end up with things in a bizarre state. 5877 */ 5878 MUTEX_ENTER(&oifq->ifq_lock); 5879 5880 tqe->tqe_touched = ticks; 5881 tqe->tqe_die = ticks + nifq->ifq_ttl; 5882 /* 5883 * Is the operation here going to be a no-op ? 5884 */ 5885 if (oifq == nifq) { 5886 if ((tqe->tqe_next == NULL) || 5887 (tqe->tqe_next->tqe_die == tqe->tqe_die)) { 5888 MUTEX_EXIT(&oifq->ifq_lock); 5889 return; 5890 } 5891 } 5892 5893 /* 5894 * Remove from the old queue 5895 */ 5896 *tqe->tqe_pnext = tqe->tqe_next; 5897 if (tqe->tqe_next) 5898 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5899 else 5900 oifq->ifq_tail = tqe->tqe_pnext; 5901 tqe->tqe_next = NULL; 5902 5903 /* 5904 * If we're moving from one queue to another, release the 5905 * lock on the old queue and get a lock on the new queue. 5906 * For user defined queues, if we're moving off it, call 5907 * delete in case it can now be freed. 5908 */ 5909 if (oifq != nifq) { 5910 tqe->tqe_ifq = NULL; 5911 5912 (void) ipf_deletetimeoutqueue(oifq); 5913 5914 MUTEX_EXIT(&oifq->ifq_lock); 5915 5916 MUTEX_ENTER(&nifq->ifq_lock); 5917 5918 tqe->tqe_ifq = nifq; 5919 nifq->ifq_ref++; 5920 } 5921 5922 /* 5923 * Add to the bottom of the new queue 5924 */ 5925 tqe->tqe_pnext = nifq->ifq_tail; 5926 *nifq->ifq_tail = tqe; 5927 nifq->ifq_tail = &tqe->tqe_next; 5928 MUTEX_EXIT(&nifq->ifq_lock); 5929 } 5930 5931 5932 /* ------------------------------------------------------------------------ */ 5933 /* Function: ipf_updateipid */ 5934 /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 5935 /* Parameters: fin(I) - pointer to packet information */ 5936 /* */ 5937 /* When we are doing NAT, change the IP of every packet to represent a */ 5938 /* single sequence of packets coming from the host, hiding any host */ 5939 /* specific sequencing that might otherwise be revealed. If the packet is */ 5940 /* a fragment, then store the 'new' IPid in the fragment cache and look up */ 5941 /* the fragment cache for non-leading fragments. If a non-leading fragment */ 5942 /* has no match in the cache, return an error. */ 5943 /* ------------------------------------------------------------------------ */ 5944 static int 5945 ipf_updateipid(fr_info_t *fin) 5946 { 5947 u_short id, ido, sums; 5948 u_32_t sumd, sum; 5949 ip_t *ip; 5950 5951 ip = fin->fin_ip; 5952 ido = ntohs(ip->ip_id); 5953 if (fin->fin_off != 0) { 5954 sum = ipf_frag_ipidknown(fin); 5955 if (sum == 0xffffffff) 5956 return (-1); 5957 sum &= 0xffff; 5958 id = (u_short)sum; 5959 ip->ip_id = htons(id); 5960 } else { 5961 ip_fillid(ip); 5962 id = ntohs(ip->ip_id); 5963 if ((fin->fin_flx & FI_FRAG) != 0) 5964 (void) ipf_frag_ipidnew(fin, (u_32_t)id); 5965 } 5966 5967 if (id == ido) 5968 return (0); 5969 CALC_SUMD(ido, id, sumd); /* DESTRUCTIVE MACRO! id,ido change */ 5970 sum = (~ntohs(ip->ip_sum)) & 0xffff; 5971 sum += sumd; 5972 sum = (sum >> 16) + (sum & 0xffff); 5973 sum = (sum >> 16) + (sum & 0xffff); 5974 sums = ~(u_short)sum; 5975 ip->ip_sum = htons(sums); 5976 return (0); 5977 } 5978 5979 5980 #ifdef NEED_FRGETIFNAME 5981 /* ------------------------------------------------------------------------ */ 5982 /* Function: ipf_getifname */ 5983 /* Returns: char * - pointer to interface name */ 5984 /* Parameters: ifp(I) - pointer to network interface */ 5985 /* buffer(O) - pointer to where to store interface name */ 5986 /* */ 5987 /* Constructs an interface name in the buffer passed. The buffer passed is */ 5988 /* expected to be at least LIFNAMSIZ in bytes big. If buffer is passed in */ 5989 /* as a NULL pointer then return a pointer to a static array. */ 5990 /* ------------------------------------------------------------------------ */ 5991 char * 5992 ipf_getifname(struct ifnet *ifp, char *buffer) 5993 { 5994 static char namebuf[LIFNAMSIZ]; 5995 # if SOLARIS || defined(__FreeBSD__) 5996 int unit, space; 5997 char temp[20]; 5998 char *s; 5999 # endif 6000 6001 if (buffer == NULL) 6002 buffer = namebuf; 6003 (void) strncpy(buffer, ifp->if_name, LIFNAMSIZ); 6004 buffer[LIFNAMSIZ - 1] = '\0'; 6005 # if SOLARIS || defined(__FreeBSD__) 6006 for (s = buffer; *s; s++) 6007 ; 6008 unit = ifp->if_unit; 6009 space = LIFNAMSIZ - (s - buffer); 6010 if ((space > 0) && (unit >= 0)) { 6011 (void) snprintf(temp, sizeof(name), "%d", unit); 6012 (void) strncpy(s, temp, space); 6013 } 6014 # endif 6015 return (buffer); 6016 } 6017 #endif 6018 6019 6020 /* ------------------------------------------------------------------------ */ 6021 /* Function: ipf_ioctlswitch */ 6022 /* Returns: int - -1 continue processing, else ioctl return value */ 6023 /* Parameters: unit(I) - device unit opened */ 6024 /* data(I) - pointer to ioctl data */ 6025 /* cmd(I) - ioctl command */ 6026 /* mode(I) - mode value */ 6027 /* uid(I) - uid making the ioctl call */ 6028 /* ctx(I) - pointer to context data */ 6029 /* */ 6030 /* Based on the value of unit, call the appropriate ioctl handler or return */ 6031 /* EIO if ipfilter is not running. Also checks if write perms are req'd */ 6032 /* for the device in order to execute the ioctl. A special case is made */ 6033 /* SIOCIPFINTERROR so that the same code isn't required in every handler. */ 6034 /* The context data pointer is passed through as this is used as the key */ 6035 /* for locating a matching token for continued access for walking lists, */ 6036 /* etc. */ 6037 /* ------------------------------------------------------------------------ */ 6038 int 6039 ipf_ioctlswitch(ipf_main_softc_t *softc, int unit, void *data, ioctlcmd_t cmd, 6040 int mode, int uid, void *ctx) 6041 { 6042 int error = 0; 6043 6044 switch (cmd) 6045 { 6046 case SIOCIPFINTERROR : 6047 error = BCOPYOUT(&softc->ipf_interror, data, 6048 sizeof(softc->ipf_interror)); 6049 if (error != 0) { 6050 IPFERROR(40); 6051 error = EFAULT; 6052 } 6053 return (error); 6054 default : 6055 break; 6056 } 6057 6058 switch (unit) 6059 { 6060 case IPL_LOGIPF : 6061 error = ipf_ipf_ioctl(softc, data, cmd, mode, uid, ctx); 6062 break; 6063 case IPL_LOGNAT : 6064 if (softc->ipf_running > 0) { 6065 error = ipf_nat_ioctl(softc, data, cmd, mode, 6066 uid, ctx); 6067 } else { 6068 IPFERROR(42); 6069 error = EIO; 6070 } 6071 break; 6072 case IPL_LOGSTATE : 6073 if (softc->ipf_running > 0) { 6074 error = ipf_state_ioctl(softc, data, cmd, mode, 6075 uid, ctx); 6076 } else { 6077 IPFERROR(43); 6078 error = EIO; 6079 } 6080 break; 6081 case IPL_LOGAUTH : 6082 if (softc->ipf_running > 0) { 6083 error = ipf_auth_ioctl(softc, data, cmd, mode, 6084 uid, ctx); 6085 } else { 6086 IPFERROR(44); 6087 error = EIO; 6088 } 6089 break; 6090 case IPL_LOGSYNC : 6091 if (softc->ipf_running > 0) { 6092 error = ipf_sync_ioctl(softc, data, cmd, mode, 6093 uid, ctx); 6094 } else { 6095 error = EIO; 6096 IPFERROR(45); 6097 } 6098 break; 6099 case IPL_LOGSCAN : 6100 #ifdef IPFILTER_SCAN 6101 if (softc->ipf_running > 0) 6102 error = ipf_scan_ioctl(softc, data, cmd, mode, 6103 uid, ctx); 6104 else 6105 #endif 6106 { 6107 error = EIO; 6108 IPFERROR(46); 6109 } 6110 break; 6111 case IPL_LOGLOOKUP : 6112 if (softc->ipf_running > 0) { 6113 error = ipf_lookup_ioctl(softc, data, cmd, mode, 6114 uid, ctx); 6115 } else { 6116 error = EIO; 6117 IPFERROR(47); 6118 } 6119 break; 6120 default : 6121 IPFERROR(48); 6122 error = EIO; 6123 break; 6124 } 6125 6126 return (error); 6127 } 6128 6129 6130 /* 6131 * This array defines the expected size of objects coming into the kernel 6132 * for the various recognised object types. The first column is flags (see 6133 * below), 2nd column is current size, 3rd column is the version number of 6134 * when the current size became current. 6135 * Flags: 6136 * 1 = minimum size, not absolute size 6137 */ 6138 static const int ipf_objbytes[IPFOBJ_COUNT][3] = { 6139 { 1, sizeof(struct frentry), 5010000 }, /* 0 */ 6140 { 1, sizeof(struct friostat), 5010000 }, 6141 { 0, sizeof(struct fr_info), 5010000 }, 6142 { 0, sizeof(struct ipf_authstat), 4010100 }, 6143 { 0, sizeof(struct ipfrstat), 5010000 }, 6144 { 1, sizeof(struct ipnat), 5010000 }, /* 5 */ 6145 { 0, sizeof(struct natstat), 5010000 }, 6146 { 0, sizeof(struct ipstate_save), 5010000 }, 6147 { 1, sizeof(struct nat_save), 5010000 }, 6148 { 0, sizeof(struct natlookup), 5010000 }, 6149 { 1, sizeof(struct ipstate), 5010000 }, /* 10 */ 6150 { 0, sizeof(struct ips_stat), 5010000 }, 6151 { 0, sizeof(struct frauth), 5010000 }, 6152 { 0, sizeof(struct ipftune), 4010100 }, 6153 { 0, sizeof(struct nat), 5010000 }, 6154 { 0, sizeof(struct ipfruleiter), 4011400 }, /* 15 */ 6155 { 0, sizeof(struct ipfgeniter), 4011400 }, 6156 { 0, sizeof(struct ipftable), 4011400 }, 6157 { 0, sizeof(struct ipflookupiter), 4011400 }, 6158 { 0, sizeof(struct ipftq) * IPF_TCP_NSTATES }, 6159 { 1, 0, 0 }, /* IPFEXPR */ 6160 { 0, 0, 0 }, /* PROXYCTL */ 6161 { 0, sizeof (struct fripf), 5010000 } 6162 }; 6163 6164 6165 /* ------------------------------------------------------------------------ */ 6166 /* Function: ipf_inobj */ 6167 /* Returns: int - 0 = success, else failure */ 6168 /* Parameters: softc(I) - soft context pointerto work with */ 6169 /* data(I) - pointer to ioctl data */ 6170 /* objp(O) - where to store ipfobj structure */ 6171 /* ptr(I) - pointer to data to copy out */ 6172 /* type(I) - type of structure being moved */ 6173 /* */ 6174 /* Copy in the contents of what the ipfobj_t points to. In future, we */ 6175 /* add things to check for version numbers, sizes, etc, to make it backward */ 6176 /* compatible at the ABI for user land. */ 6177 /* If objp is not NULL then we assume that the caller wants to see what is */ 6178 /* in the ipfobj_t structure being copied in. As an example, this can tell */ 6179 /* the caller what version of ipfilter the ioctl program was written to. */ 6180 /* ------------------------------------------------------------------------ */ 6181 int 6182 ipf_inobj(ipf_main_softc_t *softc, void *data, ipfobj_t *objp, void *ptr, 6183 int type) 6184 { 6185 ipfobj_t obj; 6186 int error; 6187 int size; 6188 6189 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6190 IPFERROR(49); 6191 return (EINVAL); 6192 } 6193 6194 if (objp == NULL) 6195 objp = &obj; 6196 error = BCOPYIN(data, objp, sizeof(*objp)); 6197 if (error != 0) { 6198 IPFERROR(124); 6199 return (EFAULT); 6200 } 6201 6202 if (objp->ipfo_type != type) { 6203 IPFERROR(50); 6204 return (EINVAL); 6205 } 6206 6207 if (objp->ipfo_rev >= ipf_objbytes[type][2]) { 6208 if ((ipf_objbytes[type][0] & 1) != 0) { 6209 if (objp->ipfo_size < ipf_objbytes[type][1]) { 6210 IPFERROR(51); 6211 return (EINVAL); 6212 } 6213 size = ipf_objbytes[type][1]; 6214 } else if (objp->ipfo_size == ipf_objbytes[type][1]) { 6215 size = objp->ipfo_size; 6216 } else { 6217 IPFERROR(52); 6218 return (EINVAL); 6219 } 6220 error = COPYIN(objp->ipfo_ptr, ptr, size); 6221 if (error != 0) { 6222 IPFERROR(55); 6223 error = EFAULT; 6224 } 6225 } else { 6226 #ifdef IPFILTER_COMPAT 6227 error = ipf_in_compat(softc, objp, ptr, 0); 6228 #else 6229 IPFERROR(54); 6230 error = EINVAL; 6231 #endif 6232 } 6233 return (error); 6234 } 6235 6236 6237 /* ------------------------------------------------------------------------ */ 6238 /* Function: ipf_inobjsz */ 6239 /* Returns: int - 0 = success, else failure */ 6240 /* Parameters: softc(I) - soft context pointerto work with */ 6241 /* data(I) - pointer to ioctl data */ 6242 /* ptr(I) - pointer to store real data in */ 6243 /* type(I) - type of structure being moved */ 6244 /* sz(I) - size of data to copy */ 6245 /* */ 6246 /* As per ipf_inobj, except the size of the object to copy in is passed in */ 6247 /* but it must not be smaller than the size defined for the type and the */ 6248 /* type must allow for varied sized objects. The extra requirement here is */ 6249 /* that sz must match the size of the object being passed in - this is not */ 6250 /* not possible nor required in ipf_inobj(). */ 6251 /* ------------------------------------------------------------------------ */ 6252 int 6253 ipf_inobjsz(ipf_main_softc_t *softc, void *data, void *ptr, int type, int sz) 6254 { 6255 ipfobj_t obj; 6256 int error; 6257 6258 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6259 IPFERROR(56); 6260 return (EINVAL); 6261 } 6262 6263 error = BCOPYIN(data, &obj, sizeof(obj)); 6264 if (error != 0) { 6265 IPFERROR(125); 6266 return (EFAULT); 6267 } 6268 6269 if (obj.ipfo_type != type) { 6270 IPFERROR(58); 6271 return (EINVAL); 6272 } 6273 6274 if (obj.ipfo_rev >= ipf_objbytes[type][2]) { 6275 if (((ipf_objbytes[type][0] & 1) == 0) || 6276 (sz < ipf_objbytes[type][1])) { 6277 IPFERROR(57); 6278 return (EINVAL); 6279 } 6280 error = COPYIN(obj.ipfo_ptr, ptr, sz); 6281 if (error != 0) { 6282 IPFERROR(61); 6283 error = EFAULT; 6284 } 6285 } else { 6286 #ifdef IPFILTER_COMPAT 6287 error = ipf_in_compat(softc, &obj, ptr, sz); 6288 #else 6289 IPFERROR(60); 6290 error = EINVAL; 6291 #endif 6292 } 6293 return (error); 6294 } 6295 6296 6297 /* ------------------------------------------------------------------------ */ 6298 /* Function: ipf_outobjsz */ 6299 /* Returns: int - 0 = success, else failure */ 6300 /* Parameters: data(I) - pointer to ioctl data */ 6301 /* ptr(I) - pointer to store real data in */ 6302 /* type(I) - type of structure being moved */ 6303 /* sz(I) - size of data to copy */ 6304 /* */ 6305 /* As per ipf_outobj, except the size of the object to copy out is passed in*/ 6306 /* but it must not be smaller than the size defined for the type and the */ 6307 /* type must allow for varied sized objects. The extra requirement here is */ 6308 /* that sz must match the size of the object being passed in - this is not */ 6309 /* not possible nor required in ipf_outobj(). */ 6310 /* ------------------------------------------------------------------------ */ 6311 int 6312 ipf_outobjsz(ipf_main_softc_t *softc, void *data, void *ptr, int type, int sz) 6313 { 6314 ipfobj_t obj; 6315 int error; 6316 6317 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6318 IPFERROR(62); 6319 return (EINVAL); 6320 } 6321 6322 error = BCOPYIN(data, &obj, sizeof(obj)); 6323 if (error != 0) { 6324 IPFERROR(127); 6325 return (EFAULT); 6326 } 6327 6328 if (obj.ipfo_type != type) { 6329 IPFERROR(63); 6330 return (EINVAL); 6331 } 6332 6333 if (obj.ipfo_rev >= ipf_objbytes[type][2]) { 6334 if (((ipf_objbytes[type][0] & 1) == 0) || 6335 (sz < ipf_objbytes[type][1])) { 6336 IPFERROR(146); 6337 return (EINVAL); 6338 } 6339 error = COPYOUT(ptr, obj.ipfo_ptr, sz); 6340 if (error != 0) { 6341 IPFERROR(66); 6342 error = EFAULT; 6343 } 6344 } else { 6345 #ifdef IPFILTER_COMPAT 6346 error = ipf_out_compat(softc, &obj, ptr); 6347 #else 6348 IPFERROR(65); 6349 error = EINVAL; 6350 #endif 6351 } 6352 return (error); 6353 } 6354 6355 6356 /* ------------------------------------------------------------------------ */ 6357 /* Function: ipf_outobj */ 6358 /* Returns: int - 0 = success, else failure */ 6359 /* Parameters: data(I) - pointer to ioctl data */ 6360 /* ptr(I) - pointer to store real data in */ 6361 /* type(I) - type of structure being moved */ 6362 /* */ 6363 /* Copy out the contents of what ptr is to where ipfobj points to. In */ 6364 /* future, we add things to check for version numbers, sizes, etc, to make */ 6365 /* it backward compatible at the ABI for user land. */ 6366 /* ------------------------------------------------------------------------ */ 6367 int 6368 ipf_outobj(ipf_main_softc_t *softc, void *data, void *ptr, int type) 6369 { 6370 ipfobj_t obj; 6371 int error; 6372 6373 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6374 IPFERROR(67); 6375 return (EINVAL); 6376 } 6377 6378 error = BCOPYIN(data, &obj, sizeof(obj)); 6379 if (error != 0) { 6380 IPFERROR(126); 6381 return (EFAULT); 6382 } 6383 6384 if (obj.ipfo_type != type) { 6385 IPFERROR(68); 6386 return (EINVAL); 6387 } 6388 6389 if (obj.ipfo_rev >= ipf_objbytes[type][2]) { 6390 if ((ipf_objbytes[type][0] & 1) != 0) { 6391 if (obj.ipfo_size < ipf_objbytes[type][1]) { 6392 IPFERROR(69); 6393 return (EINVAL); 6394 } 6395 } else if (obj.ipfo_size != ipf_objbytes[type][1]) { 6396 IPFERROR(70); 6397 return (EINVAL); 6398 } 6399 6400 error = COPYOUT(ptr, obj.ipfo_ptr, obj.ipfo_size); 6401 if (error != 0) { 6402 IPFERROR(73); 6403 error = EFAULT; 6404 } 6405 } else { 6406 #ifdef IPFILTER_COMPAT 6407 error = ipf_out_compat(softc, &obj, ptr); 6408 #else 6409 IPFERROR(72); 6410 error = EINVAL; 6411 #endif 6412 } 6413 return (error); 6414 } 6415 6416 6417 /* ------------------------------------------------------------------------ */ 6418 /* Function: ipf_outobjk */ 6419 /* Returns: int - 0 = success, else failure */ 6420 /* Parameters: obj(I) - pointer to data description structure */ 6421 /* ptr(I) - pointer to kernel data to copy out */ 6422 /* */ 6423 /* In the above functions, the ipfobj_t structure is copied into the kernel,*/ 6424 /* telling ipfilter how to copy out data. In this instance, the ipfobj_t is */ 6425 /* already populated with information and now we just need to use it. */ 6426 /* There is no need for this function to have a "type" parameter as there */ 6427 /* is no point in validating information that comes from the kernel with */ 6428 /* itself. */ 6429 /* ------------------------------------------------------------------------ */ 6430 int 6431 ipf_outobjk(ipf_main_softc_t *softc, ipfobj_t *obj, void *ptr) 6432 { 6433 int type = obj->ipfo_type; 6434 int error; 6435 6436 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6437 IPFERROR(147); 6438 return (EINVAL); 6439 } 6440 6441 if (obj->ipfo_rev >= ipf_objbytes[type][2]) { 6442 if ((ipf_objbytes[type][0] & 1) != 0) { 6443 if (obj->ipfo_size < ipf_objbytes[type][1]) { 6444 IPFERROR(148); 6445 return (EINVAL); 6446 } 6447 6448 } else if (obj->ipfo_size != ipf_objbytes[type][1]) { 6449 IPFERROR(149); 6450 return (EINVAL); 6451 } 6452 6453 error = COPYOUT(ptr, obj->ipfo_ptr, obj->ipfo_size); 6454 if (error != 0) { 6455 IPFERROR(150); 6456 error = EFAULT; 6457 } 6458 } else { 6459 #ifdef IPFILTER_COMPAT 6460 error = ipf_out_compat(softc, obj, ptr); 6461 #else 6462 IPFERROR(151); 6463 error = EINVAL; 6464 #endif 6465 } 6466 return (error); 6467 } 6468 6469 6470 /* ------------------------------------------------------------------------ */ 6471 /* Function: ipf_checkl4sum */ 6472 /* Returns: int - 0 = good, -1 = bad, 1 = cannot check */ 6473 /* Parameters: fin(I) - pointer to packet information */ 6474 /* */ 6475 /* If possible, calculate the layer 4 checksum for the packet. If this is */ 6476 /* not possible, return without indicating a failure or success but in a */ 6477 /* way that is ditinguishable. This function should only be called by the */ 6478 /* ipf_checkv6sum() for each platform. */ 6479 /* ------------------------------------------------------------------------ */ 6480 inline int 6481 ipf_checkl4sum(fr_info_t *fin) 6482 { 6483 u_short sum, hdrsum, *csump; 6484 udphdr_t *udp; 6485 int dosum; 6486 6487 /* 6488 * If the TCP packet isn't a fragment, isn't too short and otherwise 6489 * isn't already considered "bad", then validate the checksum. If 6490 * this check fails then considered the packet to be "bad". 6491 */ 6492 if ((fin->fin_flx & (FI_FRAG|FI_SHORT|FI_BAD)) != 0) 6493 return (1); 6494 6495 DT2(l4sumo, int, fin->fin_out, int, (int)fin->fin_p); 6496 if (fin->fin_out == 1) { 6497 fin->fin_cksum = FI_CK_SUMOK; 6498 return (0); 6499 } 6500 6501 csump = NULL; 6502 hdrsum = 0; 6503 dosum = 0; 6504 sum = 0; 6505 6506 switch (fin->fin_p) 6507 { 6508 case IPPROTO_TCP : 6509 csump = &((tcphdr_t *)fin->fin_dp)->th_sum; 6510 dosum = 1; 6511 break; 6512 6513 case IPPROTO_UDP : 6514 udp = fin->fin_dp; 6515 if (udp->uh_sum != 0) { 6516 csump = &udp->uh_sum; 6517 dosum = 1; 6518 } 6519 break; 6520 6521 #ifdef USE_INET6 6522 case IPPROTO_ICMPV6 : 6523 csump = &((struct icmp6_hdr *)fin->fin_dp)->icmp6_cksum; 6524 dosum = 1; 6525 break; 6526 #endif 6527 6528 case IPPROTO_ICMP : 6529 csump = &((struct icmp *)fin->fin_dp)->icmp_cksum; 6530 dosum = 1; 6531 break; 6532 6533 default : 6534 return (1); 6535 /*NOTREACHED*/ 6536 } 6537 6538 if (csump != NULL) { 6539 hdrsum = *csump; 6540 if (fin->fin_p == IPPROTO_UDP && hdrsum == 0xffff) 6541 hdrsum = 0x0000; 6542 } 6543 6544 if (dosum) { 6545 sum = fr_cksum(fin, fin->fin_ip, fin->fin_p, fin->fin_dp); 6546 } 6547 #if !defined(_KERNEL) 6548 if (sum == hdrsum) { 6549 FR_DEBUG(("checkl4sum: %hx == %hx\n", sum, hdrsum)); 6550 } else { 6551 FR_DEBUG(("checkl4sum: %hx != %hx\n", sum, hdrsum)); 6552 } 6553 #endif 6554 DT3(l4sums, u_short, hdrsum, u_short, sum, fr_info_t *, fin); 6555 #ifdef USE_INET6 6556 if (hdrsum == sum || (sum == 0 && IP_V(fin->fin_ip) == 6)) { 6557 #else 6558 if (hdrsum == sum) { 6559 #endif 6560 fin->fin_cksum = FI_CK_SUMOK; 6561 return (0); 6562 } 6563 fin->fin_cksum = FI_CK_BAD; 6564 return (-1); 6565 } 6566 6567 6568 /* ------------------------------------------------------------------------ */ 6569 /* Function: ipf_ifpfillv4addr */ 6570 /* Returns: int - 0 = address update, -1 = address not updated */ 6571 /* Parameters: atype(I) - type of network address update to perform */ 6572 /* sin(I) - pointer to source of address information */ 6573 /* mask(I) - pointer to source of netmask information */ 6574 /* inp(I) - pointer to destination address store */ 6575 /* inpmask(I) - pointer to destination netmask store */ 6576 /* */ 6577 /* Given a type of network address update (atype) to perform, copy */ 6578 /* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ 6579 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ 6580 /* which case the operation fails. For all values of atype other than */ 6581 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ 6582 /* value. */ 6583 /* ------------------------------------------------------------------------ */ 6584 int 6585 ipf_ifpfillv4addr(int atype, struct sockaddr_in *sin, struct sockaddr_in *mask, 6586 struct in_addr *inp, struct in_addr *inpmask) 6587 { 6588 if (inpmask != NULL && atype != FRI_NETMASKED) 6589 inpmask->s_addr = 0xffffffff; 6590 6591 if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { 6592 if (atype == FRI_NETMASKED) { 6593 if (inpmask == NULL) 6594 return (-1); 6595 inpmask->s_addr = mask->sin_addr.s_addr; 6596 } 6597 inp->s_addr = sin->sin_addr.s_addr & mask->sin_addr.s_addr; 6598 } else { 6599 inp->s_addr = sin->sin_addr.s_addr; 6600 } 6601 return (0); 6602 } 6603 6604 6605 #ifdef USE_INET6 6606 /* ------------------------------------------------------------------------ */ 6607 /* Function: ipf_ifpfillv6addr */ 6608 /* Returns: int - 0 = address update, -1 = address not updated */ 6609 /* Parameters: atype(I) - type of network address update to perform */ 6610 /* sin(I) - pointer to source of address information */ 6611 /* mask(I) - pointer to source of netmask information */ 6612 /* inp(I) - pointer to destination address store */ 6613 /* inpmask(I) - pointer to destination netmask store */ 6614 /* */ 6615 /* Given a type of network address update (atype) to perform, copy */ 6616 /* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ 6617 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ 6618 /* which case the operation fails. For all values of atype other than */ 6619 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ 6620 /* value. */ 6621 /* ------------------------------------------------------------------------ */ 6622 int 6623 ipf_ifpfillv6addr(int atype, struct sockaddr_in6 *sin, 6624 struct sockaddr_in6 *mask, i6addr_t *inp, i6addr_t *inpmask) 6625 { 6626 i6addr_t *src, *and; 6627 6628 src = (i6addr_t *)&sin->sin6_addr; 6629 and = (i6addr_t *)&mask->sin6_addr; 6630 6631 if (inpmask != NULL && atype != FRI_NETMASKED) { 6632 inpmask->i6[0] = 0xffffffff; 6633 inpmask->i6[1] = 0xffffffff; 6634 inpmask->i6[2] = 0xffffffff; 6635 inpmask->i6[3] = 0xffffffff; 6636 } 6637 6638 if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { 6639 if (atype == FRI_NETMASKED) { 6640 if (inpmask == NULL) 6641 return (-1); 6642 inpmask->i6[0] = and->i6[0]; 6643 inpmask->i6[1] = and->i6[1]; 6644 inpmask->i6[2] = and->i6[2]; 6645 inpmask->i6[3] = and->i6[3]; 6646 } 6647 6648 inp->i6[0] = src->i6[0] & and->i6[0]; 6649 inp->i6[1] = src->i6[1] & and->i6[1]; 6650 inp->i6[2] = src->i6[2] & and->i6[2]; 6651 inp->i6[3] = src->i6[3] & and->i6[3]; 6652 } else { 6653 inp->i6[0] = src->i6[0]; 6654 inp->i6[1] = src->i6[1]; 6655 inp->i6[2] = src->i6[2]; 6656 inp->i6[3] = src->i6[3]; 6657 } 6658 return (0); 6659 } 6660 #endif 6661 6662 6663 /* ------------------------------------------------------------------------ */ 6664 /* Function: ipf_matchtag */ 6665 /* Returns: 0 == mismatch, 1 == match. */ 6666 /* Parameters: tag1(I) - pointer to first tag to compare */ 6667 /* tag2(I) - pointer to second tag to compare */ 6668 /* */ 6669 /* Returns true (non-zero) or false(0) if the two tag structures can be */ 6670 /* considered to be a match or not match, respectively. The tag is 16 */ 6671 /* bytes long (16 characters) but that is overlayed with 4 32bit ints so */ 6672 /* compare the ints instead, for speed. tag1 is the master of the */ 6673 /* comparison. This function should only be called with both tag1 and tag2 */ 6674 /* as non-NULL pointers. */ 6675 /* ------------------------------------------------------------------------ */ 6676 int 6677 ipf_matchtag(ipftag_t *tag1, ipftag_t *tag2) 6678 { 6679 if (tag1 == tag2) 6680 return (1); 6681 6682 if ((tag1->ipt_num[0] == 0) && (tag2->ipt_num[0] == 0)) 6683 return (1); 6684 6685 if ((tag1->ipt_num[0] == tag2->ipt_num[0]) && 6686 (tag1->ipt_num[1] == tag2->ipt_num[1]) && 6687 (tag1->ipt_num[2] == tag2->ipt_num[2]) && 6688 (tag1->ipt_num[3] == tag2->ipt_num[3])) 6689 return (1); 6690 return (0); 6691 } 6692 6693 6694 /* ------------------------------------------------------------------------ */ 6695 /* Function: ipf_coalesce */ 6696 /* Returns: 1 == success, -1 == failure, 0 == no change */ 6697 /* Parameters: fin(I) - pointer to packet information */ 6698 /* */ 6699 /* Attempt to get all of the packet data into a single, contiguous buffer. */ 6700 /* If this call returns a failure then the buffers have also been freed. */ 6701 /* ------------------------------------------------------------------------ */ 6702 int 6703 ipf_coalesce(fr_info_t *fin) 6704 { 6705 6706 if ((fin->fin_flx & FI_COALESCE) != 0) 6707 return (1); 6708 6709 /* 6710 * If the mbuf pointers indicate that there is no mbuf to work with, 6711 * return but do not indicate success or failure. 6712 */ 6713 if (fin->fin_m == NULL || fin->fin_mp == NULL) 6714 return (0); 6715 6716 #if defined(_KERNEL) 6717 if (ipf_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) { 6718 ipf_main_softc_t *softc = fin->fin_main_soft; 6719 6720 DT1(frb_coalesce, fr_info_t *, fin); 6721 LBUMP(ipf_stats[fin->fin_out].fr_badcoalesces); 6722 # if SOLARIS 6723 FREE_MB_T(*fin->fin_mp); 6724 # endif 6725 fin->fin_reason = FRB_COALESCE; 6726 *fin->fin_mp = NULL; 6727 fin->fin_m = NULL; 6728 return (-1); 6729 } 6730 #else 6731 fin = fin; /* LINT */ 6732 #endif 6733 return (1); 6734 } 6735 6736 6737 /* 6738 * The following table lists all of the tunable variables that can be 6739 * accessed via SIOCIPFGET/SIOCIPFSET/SIOCIPFGETNEXt. The format of each row 6740 * in the table below is as follows: 6741 * 6742 * pointer to value, name of value, minimum, maximum, size of the value's 6743 * container, value attribute flags 6744 * 6745 * For convienience, IPFT_RDONLY means the value is read-only, IPFT_WRDISABLED 6746 * means the value can only be written to when IPFilter is loaded but disabled. 6747 * The obvious implication is if neither of these are set then the value can be 6748 * changed at any time without harm. 6749 */ 6750 6751 6752 /* ------------------------------------------------------------------------ */ 6753 /* Function: ipf_tune_findbycookie */ 6754 /* Returns: NULL = search failed, else pointer to tune struct */ 6755 /* Parameters: cookie(I) - cookie value to search for amongst tuneables */ 6756 /* next(O) - pointer to place to store the cookie for the */ 6757 /* "next" tuneable, if it is desired. */ 6758 /* */ 6759 /* This function is used to walk through all of the existing tunables with */ 6760 /* successive calls. It searches the known tunables for the one which has */ 6761 /* a matching value for "cookie" - ie its address. When returning a match, */ 6762 /* the next one to be found may be returned inside next. */ 6763 /* ------------------------------------------------------------------------ */ 6764 static ipftuneable_t * 6765 ipf_tune_findbycookie(ipftuneable_t **ptop, void *cookie, void **next) 6766 { 6767 ipftuneable_t *ta, **tap; 6768 6769 for (ta = *ptop; ta->ipft_name != NULL; ta++) 6770 if (ta == cookie) { 6771 if (next != NULL) { 6772 /* 6773 * If the next entry in the array has a name 6774 * present, then return a pointer to it for 6775 * where to go next, else return a pointer to 6776 * the dynaminc list as a key to search there 6777 * next. This facilitates a weak linking of 6778 * the two "lists" together. 6779 */ 6780 if ((ta + 1)->ipft_name != NULL) 6781 *next = ta + 1; 6782 else 6783 *next = ptop; 6784 } 6785 return (ta); 6786 } 6787 6788 for (tap = ptop; (ta = *tap) != NULL; tap = &ta->ipft_next) 6789 if (tap == cookie) { 6790 if (next != NULL) 6791 *next = &ta->ipft_next; 6792 return (ta); 6793 } 6794 6795 if (next != NULL) 6796 *next = NULL; 6797 return (NULL); 6798 } 6799 6800 6801 /* ------------------------------------------------------------------------ */ 6802 /* Function: ipf_tune_findbyname */ 6803 /* Returns: NULL = search failed, else pointer to tune struct */ 6804 /* Parameters: name(I) - name of the tuneable entry to find. */ 6805 /* */ 6806 /* Search the static array of tuneables and the list of dynamic tuneables */ 6807 /* for an entry with a matching name. If we can find one, return a pointer */ 6808 /* to the matching structure. */ 6809 /* ------------------------------------------------------------------------ */ 6810 static ipftuneable_t * 6811 ipf_tune_findbyname(ipftuneable_t *top, const char *name) 6812 { 6813 ipftuneable_t *ta; 6814 6815 for (ta = top; ta != NULL; ta = ta->ipft_next) 6816 if (!strcmp(ta->ipft_name, name)) { 6817 return (ta); 6818 } 6819 6820 return (NULL); 6821 } 6822 6823 6824 /* ------------------------------------------------------------------------ */ 6825 /* Function: ipf_tune_add_array */ 6826 /* Returns: int - 0 == success, else failure */ 6827 /* Parameters: newtune - pointer to new tune array to add to tuneables */ 6828 /* */ 6829 /* Appends tune structures from the array passed in (newtune) to the end of */ 6830 /* the current list of "dynamic" tuneable parameters. */ 6831 /* If any entry to be added is already present (by name) then the operation */ 6832 /* is aborted - entries that have been added are removed before returning. */ 6833 /* An entry with no name (NULL) is used as the indication that the end of */ 6834 /* the array has been reached. */ 6835 /* ------------------------------------------------------------------------ */ 6836 int 6837 ipf_tune_add_array(ipf_main_softc_t *softc, ipftuneable_t *newtune) 6838 { 6839 ipftuneable_t *nt, *dt; 6840 int error = 0; 6841 6842 for (nt = newtune; nt->ipft_name != NULL; nt++) { 6843 error = ipf_tune_add(softc, nt); 6844 if (error != 0) { 6845 for (dt = newtune; dt != nt; dt++) { 6846 (void) ipf_tune_del(softc, dt); 6847 } 6848 } 6849 } 6850 6851 return (error); 6852 } 6853 6854 6855 /* ------------------------------------------------------------------------ */ 6856 /* Function: ipf_tune_array_link */ 6857 /* Returns: 0 == success, -1 == failure */ 6858 /* Parameters: softc(I) - soft context pointerto work with */ 6859 /* array(I) - pointer to an array of tuneables */ 6860 /* */ 6861 /* Given an array of tunables (array), append them to the current list of */ 6862 /* tuneables for this context (softc->ipf_tuners.) To properly prepare the */ 6863 /* the array for being appended to the list, initialise all of the next */ 6864 /* pointers so we don't need to walk parts of it with ++ and others with */ 6865 /* next. The array is expected to have an entry with a NULL name as the */ 6866 /* terminator. Trying to add an array with no non-NULL names will return as */ 6867 /* a failure. */ 6868 /* ------------------------------------------------------------------------ */ 6869 int 6870 ipf_tune_array_link(ipf_main_softc_t *softc, ipftuneable_t *array) 6871 { 6872 ipftuneable_t *t, **p; 6873 6874 t = array; 6875 if (t->ipft_name == NULL) 6876 return (-1); 6877 6878 for (; t[1].ipft_name != NULL; t++) 6879 t[0].ipft_next = &t[1]; 6880 t->ipft_next = NULL; 6881 6882 /* 6883 * Since a pointer to the last entry isn't kept, we need to find it 6884 * each time we want to add new variables to the list. 6885 */ 6886 for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next) 6887 if (t->ipft_name == NULL) 6888 break; 6889 *p = array; 6890 6891 return (0); 6892 } 6893 6894 6895 /* ------------------------------------------------------------------------ */ 6896 /* Function: ipf_tune_array_unlink */ 6897 /* Returns: 0 == success, -1 == failure */ 6898 /* Parameters: softc(I) - soft context pointerto work with */ 6899 /* array(I) - pointer to an array of tuneables */ 6900 /* */ 6901 /* ------------------------------------------------------------------------ */ 6902 int 6903 ipf_tune_array_unlink(ipf_main_softc_t *softc, ipftuneable_t *array) 6904 { 6905 ipftuneable_t *t, **p; 6906 6907 for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next) 6908 if (t == array) 6909 break; 6910 if (t == NULL) 6911 return (-1); 6912 6913 for (; t[1].ipft_name != NULL; t++) 6914 ; 6915 6916 *p = t->ipft_next; 6917 6918 return (0); 6919 } 6920 6921 6922 /* ------------------------------------------------------------------------ */ 6923 /* Function: ipf_tune_array_copy */ 6924 /* Returns: NULL = failure, else pointer to new array */ 6925 /* Parameters: base(I) - pointer to structure base */ 6926 /* size(I) - size of the array at template */ 6927 /* template(I) - original array to copy */ 6928 /* */ 6929 /* Allocate memory for a new set of tuneable values and copy everything */ 6930 /* from template into the new region of memory. The new region is full of */ 6931 /* uninitialised pointers (ipft_next) so set them up. Now, ipftp_offset... */ 6932 /* */ 6933 /* NOTE: the following assumes that sizeof(long) == sizeof(void *) */ 6934 /* In the array template, ipftp_offset is the offset (in bytes) of the */ 6935 /* location of the tuneable value inside the structure pointed to by base. */ 6936 /* As ipftp_offset is a union over the pointers to the tuneable values, if */ 6937 /* we add base to the copy's ipftp_offset, copy ends up with a pointer in */ 6938 /* ipftp_void that points to the stored value. */ 6939 /* ------------------------------------------------------------------------ */ 6940 ipftuneable_t * 6941 ipf_tune_array_copy(void *base, size_t size, ipftuneable_t *template) 6942 { 6943 ipftuneable_t *copy; 6944 int i; 6945 6946 6947 KMALLOCS(copy, ipftuneable_t *, size); 6948 if (copy == NULL) { 6949 return (NULL); 6950 } 6951 bcopy(template, copy, size); 6952 6953 for (i = 0; copy[i].ipft_name; i++) { 6954 copy[i].ipft_una.ipftp_offset += (u_long)base; 6955 copy[i].ipft_next = copy + i + 1; 6956 } 6957 6958 return (copy); 6959 } 6960 6961 6962 /* ------------------------------------------------------------------------ */ 6963 /* Function: ipf_tune_add */ 6964 /* Returns: int - 0 == success, else failure */ 6965 /* Parameters: newtune - pointer to new tune entry to add to tuneables */ 6966 /* */ 6967 /* Appends tune structures from the array passed in (newtune) to the end of */ 6968 /* the current list of "dynamic" tuneable parameters. Once added, the */ 6969 /* owner of the object is not expected to ever change "ipft_next". */ 6970 /* ------------------------------------------------------------------------ */ 6971 int 6972 ipf_tune_add(ipf_main_softc_t *softc, ipftuneable_t *newtune) 6973 { 6974 ipftuneable_t *ta, **tap; 6975 6976 ta = ipf_tune_findbyname(softc->ipf_tuners, newtune->ipft_name); 6977 if (ta != NULL) { 6978 IPFERROR(74); 6979 return (EEXIST); 6980 } 6981 6982 for (tap = &softc->ipf_tuners; *tap != NULL; tap = &(*tap)->ipft_next) 6983 ; 6984 6985 newtune->ipft_next = NULL; 6986 *tap = newtune; 6987 return (0); 6988 } 6989 6990 6991 /* ------------------------------------------------------------------------ */ 6992 /* Function: ipf_tune_del */ 6993 /* Returns: int - 0 == success, else failure */ 6994 /* Parameters: oldtune - pointer to tune entry to remove from the list of */ 6995 /* current dynamic tuneables */ 6996 /* */ 6997 /* Search for the tune structure, by pointer, in the list of those that are */ 6998 /* dynamically added at run time. If found, adjust the list so that this */ 6999 /* structure is no longer part of it. */ 7000 /* ------------------------------------------------------------------------ */ 7001 int 7002 ipf_tune_del(ipf_main_softc_t *softc, ipftuneable_t *oldtune) 7003 { 7004 ipftuneable_t *ta, **tap; 7005 int error = 0; 7006 7007 for (tap = &softc->ipf_tuners; (ta = *tap) != NULL; 7008 tap = &ta->ipft_next) { 7009 if (ta == oldtune) { 7010 *tap = oldtune->ipft_next; 7011 oldtune->ipft_next = NULL; 7012 break; 7013 } 7014 } 7015 7016 if (ta == NULL) { 7017 error = ESRCH; 7018 IPFERROR(75); 7019 } 7020 return (error); 7021 } 7022 7023 7024 /* ------------------------------------------------------------------------ */ 7025 /* Function: ipf_tune_del_array */ 7026 /* Returns: int - 0 == success, else failure */ 7027 /* Parameters: oldtune - pointer to tuneables array */ 7028 /* */ 7029 /* Remove each tuneable entry in the array from the list of "dynamic" */ 7030 /* tunables. If one entry should fail to be found, an error will be */ 7031 /* returned and no further ones removed. */ 7032 /* An entry with a NULL name is used as the indicator of the last entry in */ 7033 /* the array. */ 7034 /* ------------------------------------------------------------------------ */ 7035 int 7036 ipf_tune_del_array(ipf_main_softc_t *softc, ipftuneable_t *oldtune) 7037 { 7038 ipftuneable_t *ot; 7039 int error = 0; 7040 7041 for (ot = oldtune; ot->ipft_name != NULL; ot++) { 7042 error = ipf_tune_del(softc, ot); 7043 if (error != 0) 7044 break; 7045 } 7046 7047 return (error); 7048 7049 } 7050 7051 7052 /* ------------------------------------------------------------------------ */ 7053 /* Function: ipf_tune */ 7054 /* Returns: int - 0 == success, else failure */ 7055 /* Parameters: cmd(I) - ioctl command number */ 7056 /* data(I) - pointer to ioctl data structure */ 7057 /* */ 7058 /* Implement handling of SIOCIPFGETNEXT, SIOCIPFGET and SIOCIPFSET. These */ 7059 /* three ioctls provide the means to access and control global variables */ 7060 /* within IPFilter, allowing (for example) timeouts and table sizes to be */ 7061 /* changed without rebooting, reloading or recompiling. The initialisation */ 7062 /* and 'destruction' routines of the various components of ipfilter are all */ 7063 /* each responsible for handling their own values being too big. */ 7064 /* ------------------------------------------------------------------------ */ 7065 int 7066 ipf_ipftune(ipf_main_softc_t *softc, ioctlcmd_t cmd, void *data) 7067 { 7068 ipftuneable_t *ta; 7069 ipftune_t tu; 7070 void *cookie; 7071 int error; 7072 7073 error = ipf_inobj(softc, data, NULL, &tu, IPFOBJ_TUNEABLE); 7074 if (error != 0) 7075 return (error); 7076 7077 tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0'; 7078 cookie = tu.ipft_cookie; 7079 ta = NULL; 7080 7081 switch (cmd) 7082 { 7083 case SIOCIPFGETNEXT : 7084 /* 7085 * If cookie is non-NULL, assume it to be a pointer to the last 7086 * entry we looked at, so find it (if possible) and return a 7087 * pointer to the next one after it. The last entry in the 7088 * the table is a NULL entry, so when we get to it, set cookie 7089 * to NULL and return that, indicating end of list, erstwhile 7090 * if we come in with cookie set to NULL, we are starting anew 7091 * at the front of the list. 7092 */ 7093 if (cookie != NULL) { 7094 ta = ipf_tune_findbycookie(&softc->ipf_tuners, 7095 cookie, &tu.ipft_cookie); 7096 } else { 7097 ta = softc->ipf_tuners; 7098 tu.ipft_cookie = ta + 1; 7099 } 7100 if (ta != NULL) { 7101 /* 7102 * Entry found, but does the data pointed to by that 7103 * row fit in what we can return? 7104 */ 7105 if (ta->ipft_sz > sizeof(tu.ipft_un)) { 7106 IPFERROR(76); 7107 return (EINVAL); 7108 } 7109 7110 tu.ipft_vlong = 0; 7111 if (ta->ipft_sz == sizeof(u_long)) 7112 tu.ipft_vlong = *ta->ipft_plong; 7113 else if (ta->ipft_sz == sizeof(u_int)) 7114 tu.ipft_vint = *ta->ipft_pint; 7115 else if (ta->ipft_sz == sizeof(u_short)) 7116 tu.ipft_vshort = *ta->ipft_pshort; 7117 else if (ta->ipft_sz == sizeof(u_char)) 7118 tu.ipft_vchar = *ta->ipft_pchar; 7119 7120 tu.ipft_sz = ta->ipft_sz; 7121 tu.ipft_min = ta->ipft_min; 7122 tu.ipft_max = ta->ipft_max; 7123 tu.ipft_flags = ta->ipft_flags; 7124 bcopy(ta->ipft_name, tu.ipft_name, 7125 MIN(sizeof(tu.ipft_name), 7126 strlen(ta->ipft_name) + 1)); 7127 } 7128 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE); 7129 break; 7130 7131 case SIOCIPFGET : 7132 case SIOCIPFSET : 7133 /* 7134 * Search by name or by cookie value for a particular entry 7135 * in the tuning parameter table. 7136 */ 7137 IPFERROR(77); 7138 error = ESRCH; 7139 if (cookie != NULL) { 7140 ta = ipf_tune_findbycookie(&softc->ipf_tuners, 7141 cookie, NULL); 7142 if (ta != NULL) 7143 error = 0; 7144 } else if (tu.ipft_name[0] != '\0') { 7145 ta = ipf_tune_findbyname(softc->ipf_tuners, 7146 tu.ipft_name); 7147 if (ta != NULL) 7148 error = 0; 7149 } 7150 if (error != 0) 7151 break; 7152 7153 if (cmd == (ioctlcmd_t)SIOCIPFGET) { 7154 /* 7155 * Fetch the tuning parameters for a particular value 7156 */ 7157 tu.ipft_vlong = 0; 7158 if (ta->ipft_sz == sizeof(u_long)) 7159 tu.ipft_vlong = *ta->ipft_plong; 7160 else if (ta->ipft_sz == sizeof(u_int)) 7161 tu.ipft_vint = *ta->ipft_pint; 7162 else if (ta->ipft_sz == sizeof(u_short)) 7163 tu.ipft_vshort = *ta->ipft_pshort; 7164 else if (ta->ipft_sz == sizeof(u_char)) 7165 tu.ipft_vchar = *ta->ipft_pchar; 7166 tu.ipft_cookie = ta; 7167 tu.ipft_sz = ta->ipft_sz; 7168 tu.ipft_min = ta->ipft_min; 7169 tu.ipft_max = ta->ipft_max; 7170 tu.ipft_flags = ta->ipft_flags; 7171 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE); 7172 7173 } else if (cmd == (ioctlcmd_t)SIOCIPFSET) { 7174 /* 7175 * Set an internal parameter. The hard part here is 7176 * getting the new value safely and correctly out of 7177 * the kernel (given we only know its size, not type.) 7178 */ 7179 u_long in; 7180 7181 if (((ta->ipft_flags & IPFT_WRDISABLED) != 0) && 7182 (softc->ipf_running > 0)) { 7183 IPFERROR(78); 7184 error = EBUSY; 7185 break; 7186 } 7187 7188 in = tu.ipft_vlong; 7189 if (in < ta->ipft_min || in > ta->ipft_max) { 7190 IPFERROR(79); 7191 error = EINVAL; 7192 break; 7193 } 7194 7195 if (ta->ipft_func != NULL) { 7196 SPL_INT(s); 7197 7198 SPL_NET(s); 7199 error = (*ta->ipft_func)(softc, ta, 7200 &tu.ipft_un); 7201 SPL_X(s); 7202 7203 } else if (ta->ipft_sz == sizeof(u_long)) { 7204 tu.ipft_vlong = *ta->ipft_plong; 7205 *ta->ipft_plong = in; 7206 7207 } else if (ta->ipft_sz == sizeof(u_int)) { 7208 tu.ipft_vint = *ta->ipft_pint; 7209 *ta->ipft_pint = (u_int)(in & 0xffffffff); 7210 7211 } else if (ta->ipft_sz == sizeof(u_short)) { 7212 tu.ipft_vshort = *ta->ipft_pshort; 7213 *ta->ipft_pshort = (u_short)(in & 0xffff); 7214 7215 } else if (ta->ipft_sz == sizeof(u_char)) { 7216 tu.ipft_vchar = *ta->ipft_pchar; 7217 *ta->ipft_pchar = (u_char)(in & 0xff); 7218 } 7219 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE); 7220 } 7221 break; 7222 7223 default : 7224 IPFERROR(80); 7225 error = EINVAL; 7226 break; 7227 } 7228 7229 return (error); 7230 } 7231 7232 7233 /* ------------------------------------------------------------------------ */ 7234 /* Function: ipf_zerostats */ 7235 /* Returns: int - 0 = success, else failure */ 7236 /* Parameters: data(O) - pointer to pointer for copying data back to */ 7237 /* */ 7238 /* Copies the current statistics out to userspace and then zero's the */ 7239 /* current ones in the kernel. The lock is only held across the bzero() as */ 7240 /* the copyout may result in paging (ie network activity.) */ 7241 /* ------------------------------------------------------------------------ */ 7242 int 7243 ipf_zerostats(ipf_main_softc_t *softc, caddr_t data) 7244 { 7245 friostat_t fio; 7246 ipfobj_t obj; 7247 int error; 7248 7249 error = ipf_inobj(softc, data, &obj, &fio, IPFOBJ_IPFSTAT); 7250 if (error != 0) 7251 return (error); 7252 ipf_getstat(softc, &fio, obj.ipfo_rev); 7253 error = ipf_outobj(softc, data, &fio, IPFOBJ_IPFSTAT); 7254 if (error != 0) 7255 return (error); 7256 7257 WRITE_ENTER(&softc->ipf_mutex); 7258 bzero(&softc->ipf_stats, sizeof(softc->ipf_stats)); 7259 RWLOCK_EXIT(&softc->ipf_mutex); 7260 7261 return (0); 7262 } 7263 7264 7265 /* ------------------------------------------------------------------------ */ 7266 /* Function: ipf_resolvedest */ 7267 /* Returns: Nil */ 7268 /* Parameters: softc(I) - pointer to soft context main structure */ 7269 /* base(I) - where strings are stored */ 7270 /* fdp(IO) - pointer to destination information to resolve */ 7271 /* v(I) - IP protocol version to match */ 7272 /* */ 7273 /* Looks up an interface name in the frdest structure pointed to by fdp and */ 7274 /* if a matching name can be found for the particular IP protocol version */ 7275 /* then store the interface pointer in the frdest struct. If no match is */ 7276 /* found, then set the interface pointer to be -1 as NULL is considered to */ 7277 /* indicate there is no information at all in the structure. */ 7278 /* ------------------------------------------------------------------------ */ 7279 int 7280 ipf_resolvedest(ipf_main_softc_t *softc, char *base, frdest_t *fdp, int v) 7281 { 7282 int errval = 0; 7283 void *ifp; 7284 7285 ifp = NULL; 7286 7287 if (fdp->fd_name != -1) { 7288 if (fdp->fd_type == FRD_DSTLIST) { 7289 ifp = ipf_lookup_res_name(softc, IPL_LOGIPF, 7290 IPLT_DSTLIST, 7291 base + fdp->fd_name, 7292 NULL); 7293 if (ifp == NULL) { 7294 IPFERROR(144); 7295 errval = ESRCH; 7296 } 7297 } else { 7298 ifp = GETIFP(base + fdp->fd_name, v); 7299 if (ifp == NULL) 7300 ifp = (void *)-1; 7301 } 7302 } 7303 fdp->fd_ptr = ifp; 7304 7305 return (errval); 7306 } 7307 7308 7309 /* ------------------------------------------------------------------------ */ 7310 /* Function: ipf_resolvenic */ 7311 /* Returns: void* - NULL = wildcard name, -1 = failed to find NIC, else */ 7312 /* pointer to interface structure for NIC */ 7313 /* Parameters: softc(I)- pointer to soft context main structure */ 7314 /* name(I) - complete interface name */ 7315 /* v(I) - IP protocol version */ 7316 /* */ 7317 /* Look for a network interface structure that firstly has a matching name */ 7318 /* to that passed in and that is also being used for that IP protocol */ 7319 /* version (necessary on some platforms where there are separate listings */ 7320 /* for both IPv4 and IPv6 on the same physical NIC. */ 7321 /* ------------------------------------------------------------------------ */ 7322 void * 7323 ipf_resolvenic(ipf_main_softc_t *softc, char *name, int v) 7324 { 7325 void *nic; 7326 7327 softc = softc; /* gcc -Wextra */ 7328 if (name[0] == '\0') 7329 return (NULL); 7330 7331 if ((name[1] == '\0') && ((name[0] == '-') || (name[0] == '*'))) { 7332 return (NULL); 7333 } 7334 7335 nic = GETIFP(name, v); 7336 if (nic == NULL) 7337 nic = (void *)-1; 7338 return (nic); 7339 } 7340 7341 7342 /* ------------------------------------------------------------------------ */ 7343 /* Function: ipf_token_expire */ 7344 /* Returns: None. */ 7345 /* Parameters: softc(I) - pointer to soft context main structure */ 7346 /* */ 7347 /* This function is run every ipf tick to see if there are any tokens that */ 7348 /* have been held for too long and need to be freed up. */ 7349 /* ------------------------------------------------------------------------ */ 7350 void 7351 ipf_token_expire(ipf_main_softc_t *softc) 7352 { 7353 ipftoken_t *it; 7354 7355 WRITE_ENTER(&softc->ipf_tokens); 7356 while ((it = softc->ipf_token_head) != NULL) { 7357 if (it->ipt_die > softc->ipf_ticks) 7358 break; 7359 7360 ipf_token_deref(softc, it); 7361 } 7362 RWLOCK_EXIT(&softc->ipf_tokens); 7363 } 7364 7365 7366 /* ------------------------------------------------------------------------ */ 7367 /* Function: ipf_token_flush */ 7368 /* Returns: None. */ 7369 /* Parameters: softc(I) - pointer to soft context main structure */ 7370 /* */ 7371 /* Loop through all of the existing tokens and call deref to see if they */ 7372 /* can be freed. Normally a function like this might just loop on */ 7373 /* ipf_token_head but there is a chance that a token might have a ref count */ 7374 /* of greater than one and in that case the reference would drop twice */ 7375 /* by code that is only entitled to drop it once. */ 7376 /* ------------------------------------------------------------------------ */ 7377 static void 7378 ipf_token_flush(ipf_main_softc_t *softc) 7379 { 7380 ipftoken_t *it, *next; 7381 7382 WRITE_ENTER(&softc->ipf_tokens); 7383 for (it = softc->ipf_token_head; it != NULL; it = next) { 7384 next = it->ipt_next; 7385 (void) ipf_token_deref(softc, it); 7386 } 7387 RWLOCK_EXIT(&softc->ipf_tokens); 7388 } 7389 7390 7391 /* ------------------------------------------------------------------------ */ 7392 /* Function: ipf_token_del */ 7393 /* Returns: int - 0 = success, else error */ 7394 /* Parameters: softc(I)- pointer to soft context main structure */ 7395 /* type(I) - the token type to match */ 7396 /* uid(I) - uid owning the token */ 7397 /* ptr(I) - context pointer for the token */ 7398 /* */ 7399 /* This function looks for a token in the current list that matches up */ 7400 /* the fields (type, uid, ptr). If none is found, ESRCH is returned, else */ 7401 /* call ipf_token_dewref() to remove it from the list. In the event that */ 7402 /* the token has a reference held elsewhere, setting ipt_complete to 2 */ 7403 /* enables debugging to distinguish between the two paths that ultimately */ 7404 /* lead to a token to be deleted. */ 7405 /* ------------------------------------------------------------------------ */ 7406 int 7407 ipf_token_del(ipf_main_softc_t *softc, int type, int uid, void *ptr) 7408 { 7409 ipftoken_t *it; 7410 int error; 7411 7412 IPFERROR(82); 7413 error = ESRCH; 7414 7415 WRITE_ENTER(&softc->ipf_tokens); 7416 for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) { 7417 if (ptr == it->ipt_ctx && type == it->ipt_type && 7418 uid == it->ipt_uid) { 7419 it->ipt_complete = 2; 7420 ipf_token_deref(softc, it); 7421 error = 0; 7422 break; 7423 } 7424 } 7425 RWLOCK_EXIT(&softc->ipf_tokens); 7426 7427 return (error); 7428 } 7429 7430 7431 /* ------------------------------------------------------------------------ */ 7432 /* Function: ipf_token_mark_complete */ 7433 /* Returns: None. */ 7434 /* Parameters: token(I) - pointer to token structure */ 7435 /* */ 7436 /* Mark a token as being ineligable for being found with ipf_token_find. */ 7437 /* ------------------------------------------------------------------------ */ 7438 void 7439 ipf_token_mark_complete(ipftoken_t *token) 7440 { 7441 if (token->ipt_complete == 0) 7442 token->ipt_complete = 1; 7443 } 7444 7445 7446 /* ------------------------------------------------------------------------ */ 7447 /* Function: ipf_token_find */ 7448 /* Returns: ipftoken_t * - NULL if no memory, else pointer to token */ 7449 /* Parameters: softc(I)- pointer to soft context main structure */ 7450 /* type(I) - the token type to match */ 7451 /* uid(I) - uid owning the token */ 7452 /* ptr(I) - context pointer for the token */ 7453 /* */ 7454 /* This function looks for a live token in the list of current tokens that */ 7455 /* matches the tuple (type, uid, ptr). If one cannot be found then one is */ 7456 /* allocated. If one is found then it is moved to the top of the list of */ 7457 /* currently active tokens. */ 7458 /* ------------------------------------------------------------------------ */ 7459 ipftoken_t * 7460 ipf_token_find(ipf_main_softc_t *softc, int type, int uid, void *ptr) 7461 { 7462 ipftoken_t *it, *new; 7463 7464 KMALLOC(new, ipftoken_t *); 7465 if (new != NULL) 7466 bzero((char *)new, sizeof(*new)); 7467 7468 WRITE_ENTER(&softc->ipf_tokens); 7469 for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) { 7470 if ((ptr == it->ipt_ctx) && (type == it->ipt_type) && 7471 (uid == it->ipt_uid) && (it->ipt_complete < 2)) 7472 break; 7473 } 7474 7475 if (it == NULL) { 7476 it = new; 7477 new = NULL; 7478 if (it == NULL) { 7479 RWLOCK_EXIT(&softc->ipf_tokens); 7480 return (NULL); 7481 } 7482 it->ipt_ctx = ptr; 7483 it->ipt_uid = uid; 7484 it->ipt_type = type; 7485 it->ipt_ref = 1; 7486 } else { 7487 if (new != NULL) { 7488 KFREE(new); 7489 new = NULL; 7490 } 7491 7492 if (it->ipt_complete > 0) 7493 it = NULL; 7494 else 7495 ipf_token_unlink(softc, it); 7496 } 7497 7498 if (it != NULL) { 7499 it->ipt_pnext = softc->ipf_token_tail; 7500 *softc->ipf_token_tail = it; 7501 softc->ipf_token_tail = &it->ipt_next; 7502 it->ipt_next = NULL; 7503 it->ipt_ref++; 7504 7505 it->ipt_die = softc->ipf_ticks + 20; 7506 } 7507 7508 RWLOCK_EXIT(&softc->ipf_tokens); 7509 7510 return (it); 7511 } 7512 7513 7514 /* ------------------------------------------------------------------------ */ 7515 /* Function: ipf_token_unlink */ 7516 /* Returns: None. */ 7517 /* Parameters: softc(I) - pointer to soft context main structure */ 7518 /* token(I) - pointer to token structure */ 7519 /* Write Locks: ipf_tokens */ 7520 /* */ 7521 /* This function unlinks a token structure from the linked list of tokens */ 7522 /* that "own" it. The head pointer never needs to be explicitly adjusted */ 7523 /* but the tail does due to the linked list implementation. */ 7524 /* ------------------------------------------------------------------------ */ 7525 static void 7526 ipf_token_unlink(ipf_main_softc_t *softc, ipftoken_t *token) 7527 { 7528 7529 if (softc->ipf_token_tail == &token->ipt_next) 7530 softc->ipf_token_tail = token->ipt_pnext; 7531 7532 *token->ipt_pnext = token->ipt_next; 7533 if (token->ipt_next != NULL) 7534 token->ipt_next->ipt_pnext = token->ipt_pnext; 7535 token->ipt_next = NULL; 7536 token->ipt_pnext = NULL; 7537 } 7538 7539 7540 /* ------------------------------------------------------------------------ */ 7541 /* Function: ipf_token_deref */ 7542 /* Returns: int - 0 == token freed, else reference count */ 7543 /* Parameters: softc(I) - pointer to soft context main structure */ 7544 /* token(I) - pointer to token structure */ 7545 /* Write Locks: ipf_tokens */ 7546 /* */ 7547 /* Drop the reference count on the token structure and if it drops to zero, */ 7548 /* call the dereference function for the token type because it is then */ 7549 /* possible to free the token data structure. */ 7550 /* ------------------------------------------------------------------------ */ 7551 int 7552 ipf_token_deref(ipf_main_softc_t *softc, ipftoken_t *token) 7553 { 7554 void *data, **datap; 7555 7556 ASSERT(token->ipt_ref > 0); 7557 token->ipt_ref--; 7558 if (token->ipt_ref > 0) 7559 return (token->ipt_ref); 7560 7561 data = token->ipt_data; 7562 datap = &data; 7563 7564 if ((data != NULL) && (data != (void *)-1)) { 7565 switch (token->ipt_type) 7566 { 7567 case IPFGENITER_IPF : 7568 (void) ipf_derefrule(softc, (frentry_t **)datap); 7569 break; 7570 case IPFGENITER_IPNAT : 7571 WRITE_ENTER(&softc->ipf_nat); 7572 ipf_nat_rule_deref(softc, (ipnat_t **)datap); 7573 RWLOCK_EXIT(&softc->ipf_nat); 7574 break; 7575 case IPFGENITER_NAT : 7576 ipf_nat_deref(softc, (nat_t **)datap); 7577 break; 7578 case IPFGENITER_STATE : 7579 ipf_state_deref(softc, (ipstate_t **)datap); 7580 break; 7581 case IPFGENITER_FRAG : 7582 ipf_frag_pkt_deref(softc, (ipfr_t **)datap); 7583 break; 7584 case IPFGENITER_NATFRAG : 7585 ipf_frag_nat_deref(softc, (ipfr_t **)datap); 7586 break; 7587 case IPFGENITER_HOSTMAP : 7588 WRITE_ENTER(&softc->ipf_nat); 7589 ipf_nat_hostmapdel(softc, (hostmap_t **)datap); 7590 RWLOCK_EXIT(&softc->ipf_nat); 7591 break; 7592 default : 7593 ipf_lookup_iterderef(softc, token->ipt_type, data); 7594 break; 7595 } 7596 } 7597 7598 ipf_token_unlink(softc, token); 7599 KFREE(token); 7600 return (0); 7601 } 7602 7603 7604 /* ------------------------------------------------------------------------ */ 7605 /* Function: ipf_nextrule */ 7606 /* Returns: frentry_t * - NULL == no more rules, else pointer to next */ 7607 /* Parameters: softc(I) - pointer to soft context main structure */ 7608 /* fr(I) - pointer to filter rule */ 7609 /* out(I) - 1 == out rules, 0 == input rules */ 7610 /* */ 7611 /* Starting with "fr", find the next rule to visit. This includes visiting */ 7612 /* the list of rule groups if either fr is NULL (empty list) or it is the */ 7613 /* last rule in the list. When walking rule lists, it is either input or */ 7614 /* output rules that are returned, never both. */ 7615 /* ------------------------------------------------------------------------ */ 7616 static frentry_t * 7617 ipf_nextrule(ipf_main_softc_t *softc, int active, int unit, frentry_t *fr, 7618 int out) 7619 { 7620 frentry_t *next; 7621 frgroup_t *fg; 7622 7623 if (fr != NULL && fr->fr_group != -1) { 7624 fg = ipf_findgroup(softc, fr->fr_names + fr->fr_group, 7625 unit, active, NULL); 7626 if (fg != NULL) 7627 fg = fg->fg_next; 7628 } else { 7629 fg = softc->ipf_groups[unit][active]; 7630 } 7631 7632 while (fg != NULL) { 7633 next = fg->fg_start; 7634 while (next != NULL) { 7635 if (out) { 7636 if (next->fr_flags & FR_OUTQUE) 7637 return (next); 7638 } else if (next->fr_flags & FR_INQUE) { 7639 return (next); 7640 } 7641 next = next->fr_next; 7642 } 7643 if (next == NULL) 7644 fg = fg->fg_next; 7645 } 7646 7647 return (NULL); 7648 } 7649 7650 /* ------------------------------------------------------------------------ */ 7651 /* Function: ipf_getnextrule */ 7652 /* Returns: int - 0 = success, else error */ 7653 /* Parameters: softc(I)- pointer to soft context main structure */ 7654 /* t(I) - pointer to destination information to resolve */ 7655 /* ptr(I) - pointer to ipfobj_t to copyin from user space */ 7656 /* */ 7657 /* This function's first job is to bring in the ipfruleiter_t structure via */ 7658 /* the ipfobj_t structure to determine what should be the next rule to */ 7659 /* return. Once the ipfruleiter_t has been brought in, it then tries to */ 7660 /* find the 'next rule'. This may include searching rule group lists or */ 7661 /* just be as simple as looking at the 'next' field in the rule structure. */ 7662 /* When we have found the rule to return, increase its reference count and */ 7663 /* if we used an existing rule to get here, decrease its reference count. */ 7664 /* ------------------------------------------------------------------------ */ 7665 int 7666 ipf_getnextrule(ipf_main_softc_t *softc, ipftoken_t *t, void *ptr) 7667 { 7668 frentry_t *fr, *next, zero; 7669 ipfruleiter_t it; 7670 int error, out; 7671 frgroup_t *fg; 7672 ipfobj_t obj; 7673 int predict; 7674 char *dst; 7675 int unit; 7676 7677 if (t == NULL || ptr == NULL) { 7678 IPFERROR(84); 7679 return (EFAULT); 7680 } 7681 7682 error = ipf_inobj(softc, ptr, &obj, &it, IPFOBJ_IPFITER); 7683 if (error != 0) 7684 return (error); 7685 7686 if ((it.iri_inout < 0) || (it.iri_inout > 3)) { 7687 IPFERROR(85); 7688 return (EINVAL); 7689 } 7690 if ((it.iri_active != 0) && (it.iri_active != 1)) { 7691 IPFERROR(86); 7692 return (EINVAL); 7693 } 7694 if (it.iri_nrules == 0) { 7695 IPFERROR(87); 7696 return (ENOSPC); 7697 } 7698 if (it.iri_rule == NULL) { 7699 IPFERROR(88); 7700 return (EFAULT); 7701 } 7702 7703 fg = NULL; 7704 fr = t->ipt_data; 7705 if ((it.iri_inout & F_OUT) != 0) 7706 out = 1; 7707 else 7708 out = 0; 7709 if ((it.iri_inout & F_ACIN) != 0) 7710 unit = IPL_LOGCOUNT; 7711 else 7712 unit = IPL_LOGIPF; 7713 7714 READ_ENTER(&softc->ipf_mutex); 7715 if (fr == NULL) { 7716 if (*it.iri_group == '\0') { 7717 if (unit == IPL_LOGCOUNT) { 7718 next = softc->ipf_acct[out][it.iri_active]; 7719 } else { 7720 next = softc->ipf_rules[out][it.iri_active]; 7721 } 7722 if (next == NULL) 7723 next = ipf_nextrule(softc, it.iri_active, 7724 unit, NULL, out); 7725 } else { 7726 fg = ipf_findgroup(softc, it.iri_group, unit, 7727 it.iri_active, NULL); 7728 if (fg != NULL) 7729 next = fg->fg_start; 7730 else 7731 next = NULL; 7732 } 7733 } else { 7734 next = fr->fr_next; 7735 if (next == NULL) 7736 next = ipf_nextrule(softc, it.iri_active, unit, 7737 fr, out); 7738 } 7739 7740 if (next != NULL && next->fr_next != NULL) 7741 predict = 1; 7742 else if (ipf_nextrule(softc, it.iri_active, unit, next, out) != NULL) 7743 predict = 1; 7744 else 7745 predict = 0; 7746 7747 if (fr != NULL) 7748 (void) ipf_derefrule(softc, &fr); 7749 7750 obj.ipfo_type = IPFOBJ_FRENTRY; 7751 dst = (char *)it.iri_rule; 7752 7753 if (next != NULL) { 7754 obj.ipfo_size = next->fr_size; 7755 MUTEX_ENTER(&next->fr_lock); 7756 next->fr_ref++; 7757 MUTEX_EXIT(&next->fr_lock); 7758 t->ipt_data = next; 7759 } else { 7760 obj.ipfo_size = sizeof(frentry_t); 7761 bzero(&zero, sizeof(zero)); 7762 next = &zero; 7763 t->ipt_data = NULL; 7764 } 7765 it.iri_rule = predict ? next : NULL; 7766 if (predict == 0) 7767 ipf_token_mark_complete(t); 7768 7769 RWLOCK_EXIT(&softc->ipf_mutex); 7770 7771 obj.ipfo_ptr = dst; 7772 error = ipf_outobjk(softc, &obj, next); 7773 if (error == 0 && t->ipt_data != NULL) { 7774 dst += obj.ipfo_size; 7775 if (next->fr_data != NULL) { 7776 ipfobj_t dobj; 7777 7778 if (next->fr_type == FR_T_IPFEXPR) 7779 dobj.ipfo_type = IPFOBJ_IPFEXPR; 7780 else 7781 dobj.ipfo_type = IPFOBJ_FRIPF; 7782 dobj.ipfo_size = next->fr_dsize; 7783 dobj.ipfo_rev = obj.ipfo_rev; 7784 dobj.ipfo_ptr = dst; 7785 error = ipf_outobjk(softc, &dobj, next->fr_data); 7786 } 7787 } 7788 7789 if ((fr != NULL) && (next == &zero)) 7790 (void) ipf_derefrule(softc, &fr); 7791 7792 return (error); 7793 } 7794 7795 7796 /* ------------------------------------------------------------------------ */ 7797 /* Function: ipf_frruleiter */ 7798 /* Returns: int - 0 = success, else error */ 7799 /* Parameters: softc(I)- pointer to soft context main structure */ 7800 /* data(I) - the token type to match */ 7801 /* uid(I) - uid owning the token */ 7802 /* ptr(I) - context pointer for the token */ 7803 /* */ 7804 /* This function serves as a stepping stone between ipf_ipf_ioctl and */ 7805 /* ipf_getnextrule. It's role is to find the right token in the kernel for */ 7806 /* the process doing the ioctl and use that to ask for the next rule. */ 7807 /* ------------------------------------------------------------------------ */ 7808 static int 7809 ipf_frruleiter(ipf_main_softc_t *softc, void *data, int uid, void *ctx) 7810 { 7811 ipftoken_t *token; 7812 ipfruleiter_t it; 7813 ipfobj_t obj; 7814 int error; 7815 7816 token = ipf_token_find(softc, IPFGENITER_IPF, uid, ctx); 7817 if (token != NULL) { 7818 error = ipf_getnextrule(softc, token, data); 7819 WRITE_ENTER(&softc->ipf_tokens); 7820 ipf_token_deref(softc, token); 7821 RWLOCK_EXIT(&softc->ipf_tokens); 7822 } else { 7823 error = ipf_inobj(softc, data, &obj, &it, IPFOBJ_IPFITER); 7824 if (error != 0) 7825 return (error); 7826 it.iri_rule = NULL; 7827 error = ipf_outobj(softc, data, &it, IPFOBJ_IPFITER); 7828 } 7829 7830 return (error); 7831 } 7832 7833 7834 /* ------------------------------------------------------------------------ */ 7835 /* Function: ipf_geniter */ 7836 /* Returns: int - 0 = success, else error */ 7837 /* Parameters: softc(I) - pointer to soft context main structure */ 7838 /* token(I) - pointer to ipftoken_t structure */ 7839 /* itp(I) - pointer to iterator data */ 7840 /* */ 7841 /* Decide which iterator function to call using information passed through */ 7842 /* the ipfgeniter_t structure at itp. */ 7843 /* ------------------------------------------------------------------------ */ 7844 static int 7845 ipf_geniter(ipf_main_softc_t *softc, ipftoken_t *token, ipfgeniter_t *itp) 7846 { 7847 int error; 7848 7849 switch (itp->igi_type) 7850 { 7851 case IPFGENITER_FRAG : 7852 error = ipf_frag_pkt_next(softc, token, itp); 7853 break; 7854 default : 7855 IPFERROR(92); 7856 error = EINVAL; 7857 break; 7858 } 7859 7860 return (error); 7861 } 7862 7863 7864 /* ------------------------------------------------------------------------ */ 7865 /* Function: ipf_genericiter */ 7866 /* Returns: int - 0 = success, else error */ 7867 /* Parameters: softc(I)- pointer to soft context main structure */ 7868 /* data(I) - the token type to match */ 7869 /* uid(I) - uid owning the token */ 7870 /* ptr(I) - context pointer for the token */ 7871 /* */ 7872 /* Handle the SIOCGENITER ioctl for the ipfilter device. The primary role */ 7873 /* ------------------------------------------------------------------------ */ 7874 int 7875 ipf_genericiter(ipf_main_softc_t *softc, void *data, int uid, void *ctx) 7876 { 7877 ipftoken_t *token; 7878 ipfgeniter_t iter; 7879 int error; 7880 7881 error = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_GENITER); 7882 if (error != 0) 7883 return (error); 7884 7885 token = ipf_token_find(softc, iter.igi_type, uid, ctx); 7886 if (token != NULL) { 7887 token->ipt_subtype = iter.igi_type; 7888 error = ipf_geniter(softc, token, &iter); 7889 WRITE_ENTER(&softc->ipf_tokens); 7890 ipf_token_deref(softc, token); 7891 RWLOCK_EXIT(&softc->ipf_tokens); 7892 } else { 7893 IPFERROR(93); 7894 error = 0; 7895 } 7896 7897 return (error); 7898 } 7899 7900 7901 /* ------------------------------------------------------------------------ */ 7902 /* Function: ipf_ipf_ioctl */ 7903 /* Returns: int - 0 = success, else error */ 7904 /* Parameters: softc(I)- pointer to soft context main structure */ 7905 /* data(I) - the token type to match */ 7906 /* cmd(I) - the ioctl command number */ 7907 /* mode(I) - mode flags for the ioctl */ 7908 /* uid(I) - uid owning the token */ 7909 /* ptr(I) - context pointer for the token */ 7910 /* */ 7911 /* This function handles all of the ioctl command that are actually isssued */ 7912 /* to the /dev/ipl device. */ 7913 /* ------------------------------------------------------------------------ */ 7914 int 7915 ipf_ipf_ioctl(ipf_main_softc_t *softc, caddr_t data, ioctlcmd_t cmd, int mode, 7916 int uid, void *ctx) 7917 { 7918 friostat_t fio; 7919 int error, tmp; 7920 ipfobj_t obj; 7921 SPL_INT(s); 7922 7923 switch (cmd) 7924 { 7925 case SIOCFRENB : 7926 if (!(mode & FWRITE)) { 7927 IPFERROR(94); 7928 error = EPERM; 7929 } else { 7930 error = BCOPYIN(data, &tmp, sizeof(tmp)); 7931 if (error != 0) { 7932 IPFERROR(95); 7933 error = EFAULT; 7934 break; 7935 } 7936 7937 WRITE_ENTER(&softc->ipf_global); 7938 if (tmp) { 7939 if (softc->ipf_running > 0) 7940 error = 0; 7941 else 7942 error = ipfattach(softc); 7943 if (error == 0) 7944 softc->ipf_running = 1; 7945 else 7946 (void) ipfdetach(softc); 7947 } else { 7948 if (softc->ipf_running == 1) 7949 error = ipfdetach(softc); 7950 else 7951 error = 0; 7952 if (error == 0) 7953 softc->ipf_running = -1; 7954 } 7955 RWLOCK_EXIT(&softc->ipf_global); 7956 } 7957 break; 7958 7959 case SIOCIPFSET : 7960 if (!(mode & FWRITE)) { 7961 IPFERROR(96); 7962 error = EPERM; 7963 break; 7964 } 7965 /* FALLTHRU */ 7966 case SIOCIPFGETNEXT : 7967 case SIOCIPFGET : 7968 error = ipf_ipftune(softc, cmd, (void *)data); 7969 break; 7970 7971 case SIOCSETFF : 7972 if (!(mode & FWRITE)) { 7973 IPFERROR(97); 7974 error = EPERM; 7975 } else { 7976 error = BCOPYIN(data, &softc->ipf_flags, 7977 sizeof(softc->ipf_flags)); 7978 if (error != 0) { 7979 IPFERROR(98); 7980 error = EFAULT; 7981 } 7982 } 7983 break; 7984 7985 case SIOCGETFF : 7986 error = BCOPYOUT(&softc->ipf_flags, data, 7987 sizeof(softc->ipf_flags)); 7988 if (error != 0) { 7989 IPFERROR(99); 7990 error = EFAULT; 7991 } 7992 break; 7993 7994 case SIOCFUNCL : 7995 error = ipf_resolvefunc(softc, (void *)data); 7996 break; 7997 7998 case SIOCINAFR : 7999 case SIOCRMAFR : 8000 case SIOCADAFR : 8001 case SIOCZRLST : 8002 if (!(mode & FWRITE)) { 8003 IPFERROR(100); 8004 error = EPERM; 8005 } else { 8006 error = frrequest(softc, IPL_LOGIPF, cmd, (caddr_t)data, 8007 softc->ipf_active, 1); 8008 } 8009 break; 8010 8011 case SIOCINIFR : 8012 case SIOCRMIFR : 8013 case SIOCADIFR : 8014 if (!(mode & FWRITE)) { 8015 IPFERROR(101); 8016 error = EPERM; 8017 } else { 8018 error = frrequest(softc, IPL_LOGIPF, cmd, (caddr_t)data, 8019 1 - softc->ipf_active, 1); 8020 } 8021 break; 8022 8023 case SIOCSWAPA : 8024 if (!(mode & FWRITE)) { 8025 IPFERROR(102); 8026 error = EPERM; 8027 } else { 8028 WRITE_ENTER(&softc->ipf_mutex); 8029 error = BCOPYOUT(&softc->ipf_active, data, 8030 sizeof(softc->ipf_active)); 8031 if (error != 0) { 8032 IPFERROR(103); 8033 error = EFAULT; 8034 } else { 8035 softc->ipf_active = 1 - softc->ipf_active; 8036 } 8037 RWLOCK_EXIT(&softc->ipf_mutex); 8038 } 8039 break; 8040 8041 case SIOCGETFS : 8042 error = ipf_inobj(softc, (void *)data, &obj, &fio, 8043 IPFOBJ_IPFSTAT); 8044 if (error != 0) 8045 break; 8046 ipf_getstat(softc, &fio, obj.ipfo_rev); 8047 error = ipf_outobj(softc, (void *)data, &fio, IPFOBJ_IPFSTAT); 8048 break; 8049 8050 case SIOCFRZST : 8051 if (!(mode & FWRITE)) { 8052 IPFERROR(104); 8053 error = EPERM; 8054 } else 8055 error = ipf_zerostats(softc, (caddr_t)data); 8056 break; 8057 8058 case SIOCIPFFL : 8059 if (!(mode & FWRITE)) { 8060 IPFERROR(105); 8061 error = EPERM; 8062 } else { 8063 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8064 if (!error) { 8065 tmp = ipf_flush(softc, IPL_LOGIPF, tmp); 8066 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8067 if (error != 0) { 8068 IPFERROR(106); 8069 error = EFAULT; 8070 } 8071 } else { 8072 IPFERROR(107); 8073 error = EFAULT; 8074 } 8075 } 8076 break; 8077 8078 #ifdef USE_INET6 8079 case SIOCIPFL6 : 8080 if (!(mode & FWRITE)) { 8081 IPFERROR(108); 8082 error = EPERM; 8083 } else { 8084 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8085 if (!error) { 8086 tmp = ipf_flush(softc, IPL_LOGIPF, tmp); 8087 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8088 if (error != 0) { 8089 IPFERROR(109); 8090 error = EFAULT; 8091 } 8092 } else { 8093 IPFERROR(110); 8094 error = EFAULT; 8095 } 8096 } 8097 break; 8098 #endif 8099 8100 case SIOCSTLCK : 8101 if (!(mode & FWRITE)) { 8102 IPFERROR(122); 8103 error = EPERM; 8104 } else { 8105 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8106 if (error == 0) { 8107 ipf_state_setlock(softc->ipf_state_soft, tmp); 8108 ipf_nat_setlock(softc->ipf_nat_soft, tmp); 8109 ipf_frag_setlock(softc->ipf_frag_soft, tmp); 8110 ipf_auth_setlock(softc->ipf_auth_soft, tmp); 8111 } else { 8112 IPFERROR(111); 8113 error = EFAULT; 8114 } 8115 } 8116 break; 8117 8118 #ifdef IPFILTER_LOG 8119 case SIOCIPFFB : 8120 if (!(mode & FWRITE)) { 8121 IPFERROR(112); 8122 error = EPERM; 8123 } else { 8124 tmp = ipf_log_clear(softc, IPL_LOGIPF); 8125 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8126 if (error) { 8127 IPFERROR(113); 8128 error = EFAULT; 8129 } 8130 } 8131 break; 8132 #endif /* IPFILTER_LOG */ 8133 8134 case SIOCFRSYN : 8135 if (!(mode & FWRITE)) { 8136 IPFERROR(114); 8137 error = EPERM; 8138 } else { 8139 WRITE_ENTER(&softc->ipf_global); 8140 #if (SOLARIS && defined(_KERNEL)) && !defined(INSTANCES) 8141 error = ipfsync(); 8142 #else 8143 ipf_sync(softc, NULL); 8144 error = 0; 8145 #endif 8146 RWLOCK_EXIT(&softc->ipf_global); 8147 8148 } 8149 break; 8150 8151 case SIOCGFRST : 8152 error = ipf_outobj(softc, (void *)data, 8153 ipf_frag_stats(softc->ipf_frag_soft), 8154 IPFOBJ_FRAGSTAT); 8155 break; 8156 8157 #ifdef IPFILTER_LOG 8158 case FIONREAD : 8159 tmp = ipf_log_bytesused(softc, IPL_LOGIPF); 8160 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8161 break; 8162 #endif 8163 8164 case SIOCIPFITER : 8165 SPL_SCHED(s); 8166 error = ipf_frruleiter(softc, data, uid, ctx); 8167 SPL_X(s); 8168 break; 8169 8170 case SIOCGENITER : 8171 SPL_SCHED(s); 8172 error = ipf_genericiter(softc, data, uid, ctx); 8173 SPL_X(s); 8174 break; 8175 8176 case SIOCIPFDELTOK : 8177 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8178 if (error == 0) { 8179 SPL_SCHED(s); 8180 error = ipf_token_del(softc, tmp, uid, ctx); 8181 SPL_X(s); 8182 } 8183 break; 8184 8185 default : 8186 IPFERROR(115); 8187 error = EINVAL; 8188 break; 8189 } 8190 8191 return (error); 8192 } 8193 8194 8195 /* ------------------------------------------------------------------------ */ 8196 /* Function: ipf_decaps */ 8197 /* Returns: int - -1 == decapsulation failed, else bit mask of */ 8198 /* flags indicating packet filtering decision. */ 8199 /* Parameters: fin(I) - pointer to packet information */ 8200 /* pass(I) - IP protocol version to match */ 8201 /* l5proto(I) - layer 5 protocol to decode UDP data as. */ 8202 /* */ 8203 /* This function is called for packets that are wrapt up in other packets, */ 8204 /* for example, an IP packet that is the entire data segment for another IP */ 8205 /* packet. If the basic constraints for this are satisfied, change the */ 8206 /* buffer to point to the start of the inner packet and start processing */ 8207 /* rules belonging to the head group this rule specifies. */ 8208 /* ------------------------------------------------------------------------ */ 8209 u_32_t 8210 ipf_decaps(fr_info_t *fin, u_32_t pass, int l5proto) 8211 { 8212 fr_info_t fin2, *fino = NULL; 8213 int elen, hlen, nh; 8214 grehdr_t gre; 8215 ip_t *ip; 8216 mb_t *m; 8217 8218 if ((fin->fin_flx & FI_COALESCE) == 0) 8219 if (ipf_coalesce(fin) == -1) 8220 goto cantdecaps; 8221 8222 m = fin->fin_m; 8223 hlen = fin->fin_hlen; 8224 8225 switch (fin->fin_p) 8226 { 8227 case IPPROTO_UDP : 8228 /* 8229 * In this case, the specific protocol being decapsulated 8230 * inside UDP frames comes from the rule. 8231 */ 8232 nh = fin->fin_fr->fr_icode; 8233 break; 8234 8235 case IPPROTO_GRE : /* 47 */ 8236 bcopy(fin->fin_dp, (char *)&gre, sizeof(gre)); 8237 hlen += sizeof(grehdr_t); 8238 if (gre.gr_R|gre.gr_s) 8239 goto cantdecaps; 8240 if (gre.gr_C) 8241 hlen += 4; 8242 if (gre.gr_K) 8243 hlen += 4; 8244 if (gre.gr_S) 8245 hlen += 4; 8246 8247 nh = IPPROTO_IP; 8248 8249 /* 8250 * If the routing options flag is set, validate that it is 8251 * there and bounce over it. 8252 */ 8253 #if 0 8254 /* This is really heavy weight and lots of room for error, */ 8255 /* so for now, put it off and get the simple stuff right. */ 8256 if (gre.gr_R) { 8257 u_char off, len, *s; 8258 u_short af; 8259 int end; 8260 8261 end = 0; 8262 s = fin->fin_dp; 8263 s += hlen; 8264 aplen = fin->fin_plen - hlen; 8265 while (aplen > 3) { 8266 af = (s[0] << 8) | s[1]; 8267 off = s[2]; 8268 len = s[3]; 8269 aplen -= 4; 8270 s += 4; 8271 if (af == 0 && len == 0) { 8272 end = 1; 8273 break; 8274 } 8275 if (aplen < len) 8276 break; 8277 s += len; 8278 aplen -= len; 8279 } 8280 if (end != 1) 8281 goto cantdecaps; 8282 hlen = s - (u_char *)fin->fin_dp; 8283 } 8284 #endif 8285 break; 8286 8287 #ifdef IPPROTO_IPIP 8288 case IPPROTO_IPIP : /* 4 */ 8289 #endif 8290 nh = IPPROTO_IP; 8291 break; 8292 8293 default : /* Includes ESP, AH is special for IPv4 */ 8294 goto cantdecaps; 8295 } 8296 8297 switch (nh) 8298 { 8299 case IPPROTO_IP : 8300 case IPPROTO_IPV6 : 8301 break; 8302 default : 8303 goto cantdecaps; 8304 } 8305 8306 bcopy((char *)fin, (char *)&fin2, sizeof(fin2)); 8307 fino = fin; 8308 fin = &fin2; 8309 elen = hlen; 8310 #if SOLARIS && defined(_KERNEL) 8311 m->b_rptr += elen; 8312 #else 8313 m->m_data += elen; 8314 m->m_len -= elen; 8315 #endif 8316 fin->fin_plen -= elen; 8317 8318 ip = (ip_t *)((char *)fin->fin_ip + elen); 8319 8320 /* 8321 * Make sure we have at least enough data for the network layer 8322 * header. 8323 */ 8324 if (IP_V(ip) == 4) 8325 hlen = IP_HL(ip) << 2; 8326 #ifdef USE_INET6 8327 else if (IP_V(ip) == 6) 8328 hlen = sizeof(ip6_t); 8329 #endif 8330 else 8331 goto cantdecaps2; 8332 8333 if (fin->fin_plen < hlen) 8334 goto cantdecaps2; 8335 8336 fin->fin_dp = (char *)ip + hlen; 8337 8338 if (IP_V(ip) == 4) { 8339 /* 8340 * Perform IPv4 header checksum validation. 8341 */ 8342 if (ipf_cksum((u_short *)ip, hlen)) 8343 goto cantdecaps2; 8344 } 8345 8346 if (ipf_makefrip(hlen, ip, fin) == -1) { 8347 cantdecaps2: 8348 if (m != NULL) { 8349 #if SOLARIS && defined(_KERNEL) 8350 m->b_rptr -= elen; 8351 #else 8352 m->m_data -= elen; 8353 m->m_len += elen; 8354 #endif 8355 } 8356 cantdecaps: 8357 DT1(frb_decapfrip, fr_info_t *, fin); 8358 pass &= ~FR_CMDMASK; 8359 pass |= FR_BLOCK|FR_QUICK; 8360 fin->fin_reason = FRB_DECAPFRIP; 8361 return (-1); 8362 } 8363 8364 pass = ipf_scanlist(fin, pass); 8365 8366 /* 8367 * Copy the packet filter "result" fields out of the fr_info_t struct 8368 * that is local to the decapsulation processing and back into the 8369 * one we were called with. 8370 */ 8371 fino->fin_flx = fin->fin_flx; 8372 fino->fin_rev = fin->fin_rev; 8373 fino->fin_icode = fin->fin_icode; 8374 fino->fin_rule = fin->fin_rule; 8375 (void) strncpy(fino->fin_group, fin->fin_group, FR_GROUPLEN); 8376 fino->fin_fr = fin->fin_fr; 8377 fino->fin_error = fin->fin_error; 8378 fino->fin_mp = fin->fin_mp; 8379 fino->fin_m = fin->fin_m; 8380 m = fin->fin_m; 8381 if (m != NULL) { 8382 #if SOLARIS && defined(_KERNEL) 8383 m->b_rptr -= elen; 8384 #else 8385 m->m_data -= elen; 8386 m->m_len += elen; 8387 #endif 8388 } 8389 return (pass); 8390 } 8391 8392 8393 /* ------------------------------------------------------------------------ */ 8394 /* Function: ipf_matcharray_load */ 8395 /* Returns: int - 0 = success, else error */ 8396 /* Parameters: softc(I) - pointer to soft context main structure */ 8397 /* data(I) - pointer to ioctl data */ 8398 /* objp(I) - ipfobj_t structure to load data into */ 8399 /* arrayptr(I) - pointer to location to store array pointer */ 8400 /* */ 8401 /* This function loads in a mathing array through the ipfobj_t struct that */ 8402 /* describes it. Sanity checking and array size limitations are enforced */ 8403 /* in this function to prevent userspace from trying to load in something */ 8404 /* that is insanely big. Once the size of the array is known, the memory */ 8405 /* required is malloc'd and returned through changing *arrayptr. The */ 8406 /* contents of the array are verified before returning. Only in the event */ 8407 /* of a successful call is the caller required to free up the malloc area. */ 8408 /* ------------------------------------------------------------------------ */ 8409 int 8410 ipf_matcharray_load(ipf_main_softc_t *softc, caddr_t data, ipfobj_t *objp, 8411 int **arrayptr) 8412 { 8413 int arraysize, *array, error; 8414 8415 *arrayptr = NULL; 8416 8417 error = BCOPYIN(data, objp, sizeof(*objp)); 8418 if (error != 0) { 8419 IPFERROR(116); 8420 return (EFAULT); 8421 } 8422 8423 if (objp->ipfo_type != IPFOBJ_IPFEXPR) { 8424 IPFERROR(117); 8425 return (EINVAL); 8426 } 8427 8428 if (((objp->ipfo_size & 3) != 0) || (objp->ipfo_size == 0) || 8429 (objp->ipfo_size > 1024)) { 8430 IPFERROR(118); 8431 return (EINVAL); 8432 } 8433 8434 arraysize = objp->ipfo_size * sizeof(*array); 8435 KMALLOCS(array, int *, arraysize); 8436 if (array == NULL) { 8437 IPFERROR(119); 8438 return (ENOMEM); 8439 } 8440 8441 error = COPYIN(objp->ipfo_ptr, array, arraysize); 8442 if (error != 0) { 8443 KFREES(array, arraysize); 8444 IPFERROR(120); 8445 return (EFAULT); 8446 } 8447 8448 if (ipf_matcharray_verify(array, arraysize) != 0) { 8449 KFREES(array, arraysize); 8450 IPFERROR(121); 8451 return (EINVAL); 8452 } 8453 8454 *arrayptr = array; 8455 return (0); 8456 } 8457 8458 8459 /* ------------------------------------------------------------------------ */ 8460 /* Function: ipf_matcharray_verify */ 8461 /* Returns: Nil */ 8462 /* Parameters: array(I) - pointer to matching array */ 8463 /* arraysize(I) - number of elements in the array */ 8464 /* */ 8465 /* Verify the contents of a matching array by stepping through each element */ 8466 /* in it. The actual commands in the array are not verified for */ 8467 /* correctness, only that all of the sizes are correctly within limits. */ 8468 /* ------------------------------------------------------------------------ */ 8469 int 8470 ipf_matcharray_verify(int *array, int arraysize) 8471 { 8472 int i, nelem, maxidx; 8473 ipfexp_t *e; 8474 8475 nelem = arraysize / sizeof(*array); 8476 8477 /* 8478 * Currently, it makes no sense to have an array less than 6 8479 * elements long - the initial size at the from, a single operation 8480 * (minimum 4 in length) and a trailer, for a total of 6. 8481 */ 8482 if ((array[0] < 6) || (arraysize < 24) || (arraysize > 4096)) { 8483 return (-1); 8484 } 8485 8486 /* 8487 * Verify the size of data pointed to by array with how long 8488 * the array claims to be itself. 8489 */ 8490 if (array[0] * sizeof(*array) != arraysize) { 8491 return (-1); 8492 } 8493 8494 maxidx = nelem - 1; 8495 /* 8496 * The last opcode in this array should be an IPF_EXP_END. 8497 */ 8498 if (array[maxidx] != IPF_EXP_END) { 8499 return (-1); 8500 } 8501 8502 for (i = 1; i < maxidx; ) { 8503 e = (ipfexp_t *)(array + i); 8504 8505 /* 8506 * The length of the bits to check must be at least 1 8507 * (or else there is nothing to comapre with!) and it 8508 * cannot exceed the length of the data present. 8509 */ 8510 if ((e->ipfe_size < 1 ) || 8511 (e->ipfe_size + i > maxidx)) { 8512 return (-1); 8513 } 8514 i += e->ipfe_size; 8515 } 8516 return (0); 8517 } 8518 8519 8520 /* ------------------------------------------------------------------------ */ 8521 /* Function: ipf_fr_matcharray */ 8522 /* Returns: int - 0 = match failed, else positive match */ 8523 /* Parameters: fin(I) - pointer to packet information */ 8524 /* array(I) - pointer to matching array */ 8525 /* */ 8526 /* This function is used to apply a matching array against a packet and */ 8527 /* return an indication of whether or not the packet successfully matches */ 8528 /* all of the commands in it. */ 8529 /* ------------------------------------------------------------------------ */ 8530 static int 8531 ipf_fr_matcharray(fr_info_t *fin, int *array) 8532 { 8533 int i, n, *x, rv, p; 8534 ipfexp_t *e; 8535 8536 rv = 0; 8537 n = array[0]; 8538 x = array + 1; 8539 8540 for (; n > 0; x += 3 + x[3], rv = 0) { 8541 e = (ipfexp_t *)x; 8542 if (e->ipfe_cmd == IPF_EXP_END) 8543 break; 8544 n -= e->ipfe_size; 8545 8546 /* 8547 * The upper 16 bits currently store the protocol value. 8548 * This is currently used with TCP and UDP port compares and 8549 * allows "tcp.port = 80" without requiring an explicit 8550 " "ip.pr = tcp" first. 8551 */ 8552 p = e->ipfe_cmd >> 16; 8553 if ((p != 0) && (p != fin->fin_p)) 8554 break; 8555 8556 switch (e->ipfe_cmd) 8557 { 8558 case IPF_EXP_IP_PR : 8559 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8560 rv |= (fin->fin_p == e->ipfe_arg0[i]); 8561 } 8562 break; 8563 8564 case IPF_EXP_IP_SRCADDR : 8565 if (fin->fin_v != 4) 8566 break; 8567 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8568 rv |= ((fin->fin_saddr & 8569 e->ipfe_arg0[i * 2 + 1]) == 8570 e->ipfe_arg0[i * 2]); 8571 } 8572 break; 8573 8574 case IPF_EXP_IP_DSTADDR : 8575 if (fin->fin_v != 4) 8576 break; 8577 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8578 rv |= ((fin->fin_daddr & 8579 e->ipfe_arg0[i * 2 + 1]) == 8580 e->ipfe_arg0[i * 2]); 8581 } 8582 break; 8583 8584 case IPF_EXP_IP_ADDR : 8585 if (fin->fin_v != 4) 8586 break; 8587 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8588 rv |= ((fin->fin_saddr & 8589 e->ipfe_arg0[i * 2 + 1]) == 8590 e->ipfe_arg0[i * 2]) || 8591 ((fin->fin_daddr & 8592 e->ipfe_arg0[i * 2 + 1]) == 8593 e->ipfe_arg0[i * 2]); 8594 } 8595 break; 8596 8597 #ifdef USE_INET6 8598 case IPF_EXP_IP6_SRCADDR : 8599 if (fin->fin_v != 6) 8600 break; 8601 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8602 rv |= IP6_MASKEQ(&fin->fin_src6, 8603 &e->ipfe_arg0[i * 8 + 4], 8604 &e->ipfe_arg0[i * 8]); 8605 } 8606 break; 8607 8608 case IPF_EXP_IP6_DSTADDR : 8609 if (fin->fin_v != 6) 8610 break; 8611 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8612 rv |= IP6_MASKEQ(&fin->fin_dst6, 8613 &e->ipfe_arg0[i * 8 + 4], 8614 &e->ipfe_arg0[i * 8]); 8615 } 8616 break; 8617 8618 case IPF_EXP_IP6_ADDR : 8619 if (fin->fin_v != 6) 8620 break; 8621 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8622 rv |= IP6_MASKEQ(&fin->fin_src6, 8623 &e->ipfe_arg0[i * 8 + 4], 8624 &e->ipfe_arg0[i * 8]) || 8625 IP6_MASKEQ(&fin->fin_dst6, 8626 &e->ipfe_arg0[i * 8 + 4], 8627 &e->ipfe_arg0[i * 8]); 8628 } 8629 break; 8630 #endif 8631 8632 case IPF_EXP_UDP_PORT : 8633 case IPF_EXP_TCP_PORT : 8634 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8635 rv |= (fin->fin_sport == e->ipfe_arg0[i]) || 8636 (fin->fin_dport == e->ipfe_arg0[i]); 8637 } 8638 break; 8639 8640 case IPF_EXP_UDP_SPORT : 8641 case IPF_EXP_TCP_SPORT : 8642 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8643 rv |= (fin->fin_sport == e->ipfe_arg0[i]); 8644 } 8645 break; 8646 8647 case IPF_EXP_UDP_DPORT : 8648 case IPF_EXP_TCP_DPORT : 8649 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8650 rv |= (fin->fin_dport == e->ipfe_arg0[i]); 8651 } 8652 break; 8653 8654 case IPF_EXP_TCP_FLAGS : 8655 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8656 rv |= ((fin->fin_tcpf & 8657 e->ipfe_arg0[i * 2 + 1]) == 8658 e->ipfe_arg0[i * 2]); 8659 } 8660 break; 8661 } 8662 rv ^= e->ipfe_not; 8663 8664 if (rv == 0) 8665 break; 8666 } 8667 8668 return (rv); 8669 } 8670 8671 8672 /* ------------------------------------------------------------------------ */ 8673 /* Function: ipf_queueflush */ 8674 /* Returns: int - number of entries flushed (0 = none) */ 8675 /* Parameters: softc(I) - pointer to soft context main structure */ 8676 /* deletefn(I) - function to call to delete entry */ 8677 /* ipfqs(I) - top of the list of ipf internal queues */ 8678 /* userqs(I) - top of the list of user defined timeouts */ 8679 /* */ 8680 /* This fucntion gets called when the state/NAT hash tables fill up and we */ 8681 /* need to try a bit harder to free up some space. The algorithm used here */ 8682 /* split into two parts but both halves have the same goal: to reduce the */ 8683 /* number of connections considered to be "active" to the low watermark. */ 8684 /* There are two steps in doing this: */ 8685 /* 1) Remove any TCP connections that are already considered to be "closed" */ 8686 /* but have not yet been removed from the state table. The two states */ 8687 /* TCPS_TIME_WAIT and TCPS_CLOSED are considered to be the perfect */ 8688 /* candidates for this style of removal. If freeing up entries in */ 8689 /* CLOSED or both CLOSED and TIME_WAIT brings us to the low watermark, */ 8690 /* we do not go on to step 2. */ 8691 /* */ 8692 /* 2) Look for the oldest entries on each timeout queue and free them if */ 8693 /* they are within the given window we are considering. Where the */ 8694 /* window starts and the steps taken to increase its size depend upon */ 8695 /* how long ipf has been running (ipf_ticks.) Anything modified in the */ 8696 /* last 30 seconds is not touched. */ 8697 /* touched */ 8698 /* die ipf_ticks 30*1.5 1800*1.5 | 43200*1.5 */ 8699 /* | | | | | | */ 8700 /* future <--+----------+--------+-----------+-----+-----+-----------> past */ 8701 /* now \_int=30s_/ \_int=1hr_/ \_int=12hr */ 8702 /* */ 8703 /* Points to note: */ 8704 /* - tqe_die is the time, in the future, when entries die. */ 8705 /* - tqe_die - ipf_ticks is how long left the connection has to live in ipf */ 8706 /* ticks. */ 8707 /* - tqe_touched is when the entry was last used by NAT/state */ 8708 /* - the closer tqe_touched is to ipf_ticks, the further tqe_die will be */ 8709 /* ipf_ticks any given timeout queue and vice versa. */ 8710 /* - both tqe_die and tqe_touched increase over time */ 8711 /* - timeout queues are sorted with the highest value of tqe_die at the */ 8712 /* bottom and therefore the smallest values of each are at the top */ 8713 /* - the pointer passed in as ipfqs should point to an array of timeout */ 8714 /* queues representing each of the TCP states */ 8715 /* */ 8716 /* We start by setting up a maximum range to scan for things to move of */ 8717 /* iend (newest) to istart (oldest) in chunks of "interval". If nothing is */ 8718 /* found in that range, "interval" is adjusted (so long as it isn't 30) and */ 8719 /* we start again with a new value for "iend" and "istart". This is */ 8720 /* continued until we either finish the scan of 30 second intervals or the */ 8721 /* low water mark is reached. */ 8722 /* ------------------------------------------------------------------------ */ 8723 int 8724 ipf_queueflush(ipf_main_softc_t *softc, ipftq_delete_fn_t deletefn, 8725 ipftq_t *ipfqs, ipftq_t *userqs, u_int *activep, int size, int low) 8726 { 8727 u_long interval, istart, iend; 8728 ipftq_t *ifq, *ifqnext; 8729 ipftqent_t *tqe, *tqn; 8730 int removed = 0; 8731 8732 for (tqn = ipfqs[IPF_TCPS_CLOSED].ifq_head; ((tqe = tqn) != NULL); ) { 8733 tqn = tqe->tqe_next; 8734 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8735 removed++; 8736 } 8737 if ((*activep * 100 / size) > low) { 8738 for (tqn = ipfqs[IPF_TCPS_TIME_WAIT].ifq_head; 8739 ((tqe = tqn) != NULL); ) { 8740 tqn = tqe->tqe_next; 8741 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8742 removed++; 8743 } 8744 } 8745 8746 if ((*activep * 100 / size) <= low) { 8747 return (removed); 8748 } 8749 8750 /* 8751 * NOTE: Use of "* 15 / 10" is required here because if "* 1.5" is 8752 * used then the operations are upgraded to floating point 8753 * and kernels don't like floating point... 8754 */ 8755 if (softc->ipf_ticks > IPF_TTLVAL(43200 * 15 / 10)) { 8756 istart = IPF_TTLVAL(86400 * 4); 8757 interval = IPF_TTLVAL(43200); 8758 } else if (softc->ipf_ticks > IPF_TTLVAL(1800 * 15 / 10)) { 8759 istart = IPF_TTLVAL(43200); 8760 interval = IPF_TTLVAL(1800); 8761 } else if (softc->ipf_ticks > IPF_TTLVAL(30 * 15 / 10)) { 8762 istart = IPF_TTLVAL(1800); 8763 interval = IPF_TTLVAL(30); 8764 } else { 8765 return (0); 8766 } 8767 if (istart > softc->ipf_ticks) { 8768 if (softc->ipf_ticks - interval < interval) 8769 istart = interval; 8770 else 8771 istart = (softc->ipf_ticks / interval) * interval; 8772 } 8773 8774 iend = softc->ipf_ticks - interval; 8775 8776 while ((*activep * 100 / size) > low) { 8777 u_long try; 8778 8779 try = softc->ipf_ticks - istart; 8780 8781 for (ifq = ipfqs; ifq != NULL; ifq = ifq->ifq_next) { 8782 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { 8783 if (try < tqe->tqe_touched) 8784 break; 8785 tqn = tqe->tqe_next; 8786 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8787 removed++; 8788 } 8789 } 8790 8791 for (ifq = userqs; ifq != NULL; ifq = ifqnext) { 8792 ifqnext = ifq->ifq_next; 8793 8794 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { 8795 if (try < tqe->tqe_touched) 8796 break; 8797 tqn = tqe->tqe_next; 8798 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8799 removed++; 8800 } 8801 } 8802 8803 if (try >= iend) { 8804 if (interval == IPF_TTLVAL(43200)) { 8805 interval = IPF_TTLVAL(1800); 8806 } else if (interval == IPF_TTLVAL(1800)) { 8807 interval = IPF_TTLVAL(30); 8808 } else { 8809 break; 8810 } 8811 if (interval >= softc->ipf_ticks) 8812 break; 8813 8814 iend = softc->ipf_ticks - interval; 8815 } 8816 istart -= interval; 8817 } 8818 8819 return (removed); 8820 } 8821 8822 8823 /* ------------------------------------------------------------------------ */ 8824 /* Function: ipf_deliverlocal */ 8825 /* Returns: int - 1 = local address, 0 = non-local address */ 8826 /* Parameters: softc(I) - pointer to soft context main structure */ 8827 /* ipversion(I) - IP protocol version (4 or 6) */ 8828 /* ifp(I) - network interface pointer */ 8829 /* ipaddr(I) - IPv4/6 destination address */ 8830 /* */ 8831 /* This fucntion is used to determine in the address "ipaddr" belongs to */ 8832 /* the network interface represented by ifp. */ 8833 /* ------------------------------------------------------------------------ */ 8834 int 8835 ipf_deliverlocal(ipf_main_softc_t *softc, int ipversion, void *ifp, 8836 i6addr_t *ipaddr) 8837 { 8838 i6addr_t addr; 8839 int islocal = 0; 8840 8841 if (ipversion == 4) { 8842 if (ipf_ifpaddr(softc, 4, FRI_NORMAL, ifp, &addr, NULL) == 0) { 8843 if (addr.in4.s_addr == ipaddr->in4.s_addr) 8844 islocal = 1; 8845 } 8846 8847 #ifdef USE_INET6 8848 } else if (ipversion == 6) { 8849 if (ipf_ifpaddr(softc, 6, FRI_NORMAL, ifp, &addr, NULL) == 0) { 8850 if (IP6_EQ(&addr, ipaddr)) 8851 islocal = 1; 8852 } 8853 #endif 8854 } 8855 8856 return (islocal); 8857 } 8858 8859 8860 /* ------------------------------------------------------------------------ */ 8861 /* Function: ipf_settimeout */ 8862 /* Returns: int - 0 = success, -1 = failure */ 8863 /* Parameters: softc(I) - pointer to soft context main structure */ 8864 /* t(I) - pointer to tuneable array entry */ 8865 /* p(I) - pointer to values passed in to apply */ 8866 /* */ 8867 /* This function is called to set the timeout values for each distinct */ 8868 /* queue timeout that is available. When called, it calls into both the */ 8869 /* state and NAT code, telling them to update their timeout queues. */ 8870 /* ------------------------------------------------------------------------ */ 8871 static int 8872 ipf_settimeout(struct ipf_main_softc_s *softc, ipftuneable_t *t, 8873 ipftuneval_t *p) 8874 { 8875 8876 /* 8877 * ipf_interror should be set by the functions called here, not 8878 * by this function - it's just a middle man. 8879 */ 8880 if (ipf_state_settimeout(softc, t, p) == -1) 8881 return (-1); 8882 if (ipf_nat_settimeout(softc, t, p) == -1) 8883 return (-1); 8884 return (0); 8885 } 8886 8887 8888 /* ------------------------------------------------------------------------ */ 8889 /* Function: ipf_apply_timeout */ 8890 /* Returns: int - 0 = success, -1 = failure */ 8891 /* Parameters: head(I) - pointer to tuneable array entry */ 8892 /* seconds(I) - pointer to values passed in to apply */ 8893 /* */ 8894 /* This function applies a timeout of "seconds" to the timeout queue that */ 8895 /* is pointed to by "head". All entries on this list have an expiration */ 8896 /* set to be the current tick value of ipf plus the ttl. Given that this */ 8897 /* function should only be called when the delta is non-zero, the task is */ 8898 /* to walk the entire list and apply the change. The sort order will not */ 8899 /* change. The only catch is that this is O(n) across the list, so if the */ 8900 /* queue has lots of entries (10s of thousands or 100s of thousands), it */ 8901 /* could take a relatively long time to work through them all. */ 8902 /* ------------------------------------------------------------------------ */ 8903 void 8904 ipf_apply_timeout(ipftq_t *head, u_int seconds) 8905 { 8906 u_int oldtimeout, newtimeout; 8907 ipftqent_t *tqe; 8908 int delta; 8909 8910 MUTEX_ENTER(&head->ifq_lock); 8911 oldtimeout = head->ifq_ttl; 8912 newtimeout = IPF_TTLVAL(seconds); 8913 delta = oldtimeout - newtimeout; 8914 8915 head->ifq_ttl = newtimeout; 8916 8917 for (tqe = head->ifq_head; tqe != NULL; tqe = tqe->tqe_next) { 8918 tqe->tqe_die += delta; 8919 } 8920 MUTEX_EXIT(&head->ifq_lock); 8921 } 8922 8923 8924 /* ------------------------------------------------------------------------ */ 8925 /* Function: ipf_settimeout_tcp */ 8926 /* Returns: int - 0 = successfully applied, -1 = failed */ 8927 /* Parameters: t(I) - pointer to tuneable to change */ 8928 /* p(I) - pointer to new timeout information */ 8929 /* tab(I) - pointer to table of TCP queues */ 8930 /* */ 8931 /* This function applies the new timeout (p) to the TCP tunable (t) and */ 8932 /* updates all of the entries on the relevant timeout queue by calling */ 8933 /* ipf_apply_timeout(). */ 8934 /* ------------------------------------------------------------------------ */ 8935 int 8936 ipf_settimeout_tcp(ipftuneable_t *t, ipftuneval_t *p, ipftq_t *tab) 8937 { 8938 if (!strcmp(t->ipft_name, "tcp_idle_timeout") || 8939 !strcmp(t->ipft_name, "tcp_established")) { 8940 ipf_apply_timeout(&tab[IPF_TCPS_ESTABLISHED], p->ipftu_int); 8941 } else if (!strcmp(t->ipft_name, "tcp_close_wait")) { 8942 ipf_apply_timeout(&tab[IPF_TCPS_CLOSE_WAIT], p->ipftu_int); 8943 } else if (!strcmp(t->ipft_name, "tcp_last_ack")) { 8944 ipf_apply_timeout(&tab[IPF_TCPS_LAST_ACK], p->ipftu_int); 8945 } else if (!strcmp(t->ipft_name, "tcp_timeout")) { 8946 ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int); 8947 ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int); 8948 ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int); 8949 } else if (!strcmp(t->ipft_name, "tcp_listen")) { 8950 ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int); 8951 } else if (!strcmp(t->ipft_name, "tcp_half_established")) { 8952 ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int); 8953 } else if (!strcmp(t->ipft_name, "tcp_closing")) { 8954 ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int); 8955 } else if (!strcmp(t->ipft_name, "tcp_syn_received")) { 8956 ipf_apply_timeout(&tab[IPF_TCPS_SYN_RECEIVED], p->ipftu_int); 8957 } else if (!strcmp(t->ipft_name, "tcp_syn_sent")) { 8958 ipf_apply_timeout(&tab[IPF_TCPS_SYN_SENT], p->ipftu_int); 8959 } else if (!strcmp(t->ipft_name, "tcp_closed")) { 8960 ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int); 8961 } else if (!strcmp(t->ipft_name, "tcp_half_closed")) { 8962 ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int); 8963 } else if (!strcmp(t->ipft_name, "tcp_time_wait")) { 8964 ipf_apply_timeout(&tab[IPF_TCPS_TIME_WAIT], p->ipftu_int); 8965 } else { 8966 /* 8967 * ipf_interror isn't set here because it should be set 8968 * by whatever called this function. 8969 */ 8970 return (-1); 8971 } 8972 return (0); 8973 } 8974 8975 8976 /* ------------------------------------------------------------------------ */ 8977 /* Function: ipf_main_soft_create */ 8978 /* Returns: NULL = failure, else success */ 8979 /* Parameters: arg(I) - pointer to soft context structure if already allocd */ 8980 /* */ 8981 /* Create the foundation soft context structure. In circumstances where it */ 8982 /* is not required to dynamically allocate the context, a pointer can be */ 8983 /* passed in (rather than NULL) to a structure to be initialised. */ 8984 /* The main thing of interest is that a number of locks are initialised */ 8985 /* here instead of in the where might be expected - in the relevant create */ 8986 /* function elsewhere. This is done because the current locking design has */ 8987 /* some areas where these locks are used outside of their module. */ 8988 /* Possibly the most important exercise that is done here is setting of all */ 8989 /* the timeout values, allowing them to be changed before init(). */ 8990 /* ------------------------------------------------------------------------ */ 8991 void * 8992 ipf_main_soft_create(void *arg) 8993 { 8994 ipf_main_softc_t *softc; 8995 8996 if (arg == NULL) { 8997 KMALLOC(softc, ipf_main_softc_t *); 8998 if (softc == NULL) 8999 return (NULL); 9000 } else { 9001 softc = arg; 9002 } 9003 9004 bzero((char *)softc, sizeof(*softc)); 9005 9006 /* 9007 * This serves as a flag as to whether or not the softc should be 9008 * free'd when _destroy is called. 9009 */ 9010 softc->ipf_dynamic_softc = (arg == NULL) ? 1 : 0; 9011 9012 softc->ipf_tuners = ipf_tune_array_copy(softc, 9013 sizeof(ipf_main_tuneables), 9014 ipf_main_tuneables); 9015 if (softc->ipf_tuners == NULL) { 9016 ipf_main_soft_destroy(softc); 9017 return (NULL); 9018 } 9019 9020 MUTEX_INIT(&softc->ipf_rw, "ipf rw mutex"); 9021 MUTEX_INIT(&softc->ipf_timeoutlock, "ipf timeout lock"); 9022 RWLOCK_INIT(&softc->ipf_global, "ipf filter load/unload mutex"); 9023 RWLOCK_INIT(&softc->ipf_mutex, "ipf filter rwlock"); 9024 RWLOCK_INIT(&softc->ipf_tokens, "ipf token rwlock"); 9025 RWLOCK_INIT(&softc->ipf_state, "ipf state rwlock"); 9026 RWLOCK_INIT(&softc->ipf_nat, "ipf IP NAT rwlock"); 9027 RWLOCK_INIT(&softc->ipf_poolrw, "ipf pool rwlock"); 9028 RWLOCK_INIT(&softc->ipf_frag, "ipf frag rwlock"); 9029 9030 softc->ipf_token_head = NULL; 9031 softc->ipf_token_tail = &softc->ipf_token_head; 9032 9033 softc->ipf_tcpidletimeout = FIVE_DAYS; 9034 softc->ipf_tcpclosewait = IPF_TTLVAL(2 * TCP_MSL); 9035 softc->ipf_tcplastack = IPF_TTLVAL(30); 9036 softc->ipf_tcptimewait = IPF_TTLVAL(2 * TCP_MSL); 9037 softc->ipf_tcptimeout = IPF_TTLVAL(2 * TCP_MSL); 9038 softc->ipf_tcpsynsent = IPF_TTLVAL(2 * TCP_MSL); 9039 softc->ipf_tcpsynrecv = IPF_TTLVAL(2 * TCP_MSL); 9040 softc->ipf_tcpclosed = IPF_TTLVAL(30); 9041 softc->ipf_tcphalfclosed = IPF_TTLVAL(2 * 3600); 9042 softc->ipf_udptimeout = IPF_TTLVAL(120); 9043 softc->ipf_udpacktimeout = IPF_TTLVAL(12); 9044 softc->ipf_icmptimeout = IPF_TTLVAL(60); 9045 softc->ipf_icmpacktimeout = IPF_TTLVAL(6); 9046 softc->ipf_iptimeout = IPF_TTLVAL(60); 9047 9048 #if defined(IPFILTER_DEFAULT_BLOCK) 9049 softc->ipf_pass = FR_BLOCK|FR_NOMATCH; 9050 #else 9051 softc->ipf_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH; 9052 #endif 9053 softc->ipf_minttl = 4; 9054 softc->ipf_icmpminfragmtu = 68; 9055 softc->ipf_flags = IPF_LOGGING; 9056 9057 #ifdef LARGE_NAT 9058 softc->ipf_large_nat = 1; 9059 #endif 9060 ipf_fbsd_kenv_get(softc); 9061 9062 return (softc); 9063 } 9064 9065 /* ------------------------------------------------------------------------ */ 9066 /* Function: ipf_main_soft_init */ 9067 /* Returns: 0 = success, -1 = failure */ 9068 /* Parameters: softc(I) - pointer to soft context main structure */ 9069 /* */ 9070 /* A null-op function that exists as a placeholder so that the flow in */ 9071 /* other functions is obvious. */ 9072 /* ------------------------------------------------------------------------ */ 9073 /*ARGSUSED*/ 9074 int 9075 ipf_main_soft_init(ipf_main_softc_t *softc) 9076 { 9077 return (0); 9078 } 9079 9080 9081 /* ------------------------------------------------------------------------ */ 9082 /* Function: ipf_main_soft_destroy */ 9083 /* Returns: void */ 9084 /* Parameters: softc(I) - pointer to soft context main structure */ 9085 /* */ 9086 /* Undo everything that we did in ipf_main_soft_create. */ 9087 /* */ 9088 /* The most important check that needs to be made here is whether or not */ 9089 /* the structure was allocated by ipf_main_soft_create() by checking what */ 9090 /* value is stored in ipf_dynamic_main. */ 9091 /* ------------------------------------------------------------------------ */ 9092 /*ARGSUSED*/ 9093 void 9094 ipf_main_soft_destroy(ipf_main_softc_t *softc) 9095 { 9096 9097 RW_DESTROY(&softc->ipf_frag); 9098 RW_DESTROY(&softc->ipf_poolrw); 9099 RW_DESTROY(&softc->ipf_nat); 9100 RW_DESTROY(&softc->ipf_state); 9101 RW_DESTROY(&softc->ipf_tokens); 9102 RW_DESTROY(&softc->ipf_mutex); 9103 RW_DESTROY(&softc->ipf_global); 9104 MUTEX_DESTROY(&softc->ipf_timeoutlock); 9105 MUTEX_DESTROY(&softc->ipf_rw); 9106 9107 if (softc->ipf_tuners != NULL) { 9108 KFREES(softc->ipf_tuners, sizeof(ipf_main_tuneables)); 9109 } 9110 if (softc->ipf_dynamic_softc == 1) { 9111 KFREE(softc); 9112 } 9113 } 9114 9115 9116 /* ------------------------------------------------------------------------ */ 9117 /* Function: ipf_main_soft_fini */ 9118 /* Returns: 0 = success, -1 = failure */ 9119 /* Parameters: softc(I) - pointer to soft context main structure */ 9120 /* */ 9121 /* Clean out the rules which have been added since _init was last called, */ 9122 /* the only dynamic part of the mainline. */ 9123 /* ------------------------------------------------------------------------ */ 9124 int 9125 ipf_main_soft_fini(ipf_main_softc_t *softc) 9126 { 9127 (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE|FR_INACTIVE); 9128 (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE); 9129 (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE|FR_INACTIVE); 9130 (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE); 9131 9132 return (0); 9133 } 9134 9135 9136 /* ------------------------------------------------------------------------ */ 9137 /* Function: ipf_main_load */ 9138 /* Returns: 0 = success, -1 = failure */ 9139 /* Parameters: none */ 9140 /* */ 9141 /* Handle global initialisation that needs to be done for the base part of */ 9142 /* IPFilter. At present this just amounts to initialising some ICMP lookup */ 9143 /* arrays that get used by the state/NAT code. */ 9144 /* ------------------------------------------------------------------------ */ 9145 int 9146 ipf_main_load(void) 9147 { 9148 int i; 9149 9150 /* fill icmp reply type table */ 9151 for (i = 0; i <= ICMP_MAXTYPE; i++) 9152 icmpreplytype4[i] = -1; 9153 icmpreplytype4[ICMP_ECHO] = ICMP_ECHOREPLY; 9154 icmpreplytype4[ICMP_TSTAMP] = ICMP_TSTAMPREPLY; 9155 icmpreplytype4[ICMP_IREQ] = ICMP_IREQREPLY; 9156 icmpreplytype4[ICMP_MASKREQ] = ICMP_MASKREPLY; 9157 9158 #ifdef USE_INET6 9159 /* fill icmp reply type table */ 9160 for (i = 0; i <= ICMP6_MAXTYPE; i++) 9161 icmpreplytype6[i] = -1; 9162 icmpreplytype6[ICMP6_ECHO_REQUEST] = ICMP6_ECHO_REPLY; 9163 icmpreplytype6[ICMP6_MEMBERSHIP_QUERY] = ICMP6_MEMBERSHIP_REPORT; 9164 icmpreplytype6[ICMP6_NI_QUERY] = ICMP6_NI_REPLY; 9165 icmpreplytype6[ND_ROUTER_SOLICIT] = ND_ROUTER_ADVERT; 9166 icmpreplytype6[ND_NEIGHBOR_SOLICIT] = ND_NEIGHBOR_ADVERT; 9167 #endif 9168 9169 return (0); 9170 } 9171 9172 9173 /* ------------------------------------------------------------------------ */ 9174 /* Function: ipf_main_unload */ 9175 /* Returns: 0 = success, -1 = failure */ 9176 /* Parameters: none */ 9177 /* */ 9178 /* A null-op function that exists as a placeholder so that the flow in */ 9179 /* other functions is obvious. */ 9180 /* ------------------------------------------------------------------------ */ 9181 int 9182 ipf_main_unload(void) 9183 { 9184 return (0); 9185 } 9186 9187 9188 /* ------------------------------------------------------------------------ */ 9189 /* Function: ipf_load_all */ 9190 /* Returns: 0 = success, -1 = failure */ 9191 /* Parameters: none */ 9192 /* */ 9193 /* Work through all of the subsystems inside IPFilter and call the load */ 9194 /* function for each in an order that won't lead to a crash :) */ 9195 /* ------------------------------------------------------------------------ */ 9196 int 9197 ipf_load_all(void) 9198 { 9199 if (ipf_main_load() == -1) 9200 return (-1); 9201 9202 if (ipf_state_main_load() == -1) 9203 return (-1); 9204 9205 if (ipf_nat_main_load() == -1) 9206 return (-1); 9207 9208 if (ipf_frag_main_load() == -1) 9209 return (-1); 9210 9211 if (ipf_auth_main_load() == -1) 9212 return (-1); 9213 9214 if (ipf_proxy_main_load() == -1) 9215 return (-1); 9216 9217 return (0); 9218 } 9219 9220 9221 /* ------------------------------------------------------------------------ */ 9222 /* Function: ipf_unload_all */ 9223 /* Returns: 0 = success, -1 = failure */ 9224 /* Parameters: none */ 9225 /* */ 9226 /* Work through all of the subsystems inside IPFilter and call the unload */ 9227 /* function for each in an order that won't lead to a crash :) */ 9228 /* ------------------------------------------------------------------------ */ 9229 int 9230 ipf_unload_all(void) 9231 { 9232 if (ipf_proxy_main_unload() == -1) 9233 return (-1); 9234 9235 if (ipf_auth_main_unload() == -1) 9236 return (-1); 9237 9238 if (ipf_frag_main_unload() == -1) 9239 return (-1); 9240 9241 if (ipf_nat_main_unload() == -1) 9242 return (-1); 9243 9244 if (ipf_state_main_unload() == -1) 9245 return (-1); 9246 9247 if (ipf_main_unload() == -1) 9248 return (-1); 9249 9250 return (0); 9251 } 9252 9253 9254 /* ------------------------------------------------------------------------ */ 9255 /* Function: ipf_create_all */ 9256 /* Returns: NULL = failure, else success */ 9257 /* Parameters: arg(I) - pointer to soft context main structure */ 9258 /* */ 9259 /* Work through all of the subsystems inside IPFilter and call the create */ 9260 /* function for each in an order that won't lead to a crash :) */ 9261 /* ------------------------------------------------------------------------ */ 9262 ipf_main_softc_t * 9263 ipf_create_all(void *arg) 9264 { 9265 ipf_main_softc_t *softc; 9266 9267 softc = ipf_main_soft_create(arg); 9268 if (softc == NULL) 9269 return (NULL); 9270 9271 #ifdef IPFILTER_LOG 9272 softc->ipf_log_soft = ipf_log_soft_create(softc); 9273 if (softc->ipf_log_soft == NULL) { 9274 ipf_destroy_all(softc); 9275 return (NULL); 9276 } 9277 #endif 9278 9279 softc->ipf_lookup_soft = ipf_lookup_soft_create(softc); 9280 if (softc->ipf_lookup_soft == NULL) { 9281 ipf_destroy_all(softc); 9282 return (NULL); 9283 } 9284 9285 softc->ipf_sync_soft = ipf_sync_soft_create(softc); 9286 if (softc->ipf_sync_soft == NULL) { 9287 ipf_destroy_all(softc); 9288 return (NULL); 9289 } 9290 9291 softc->ipf_state_soft = ipf_state_soft_create(softc); 9292 if (softc->ipf_state_soft == NULL) { 9293 ipf_destroy_all(softc); 9294 return (NULL); 9295 } 9296 9297 softc->ipf_nat_soft = ipf_nat_soft_create(softc); 9298 if (softc->ipf_nat_soft == NULL) { 9299 ipf_destroy_all(softc); 9300 return (NULL); 9301 } 9302 9303 softc->ipf_frag_soft = ipf_frag_soft_create(softc); 9304 if (softc->ipf_frag_soft == NULL) { 9305 ipf_destroy_all(softc); 9306 return (NULL); 9307 } 9308 9309 softc->ipf_auth_soft = ipf_auth_soft_create(softc); 9310 if (softc->ipf_auth_soft == NULL) { 9311 ipf_destroy_all(softc); 9312 return (NULL); 9313 } 9314 9315 softc->ipf_proxy_soft = ipf_proxy_soft_create(softc); 9316 if (softc->ipf_proxy_soft == NULL) { 9317 ipf_destroy_all(softc); 9318 return (NULL); 9319 } 9320 9321 return (softc); 9322 } 9323 9324 9325 /* ------------------------------------------------------------------------ */ 9326 /* Function: ipf_destroy_all */ 9327 /* Returns: void */ 9328 /* Parameters: softc(I) - pointer to soft context main structure */ 9329 /* */ 9330 /* Work through all of the subsystems inside IPFilter and call the destroy */ 9331 /* function for each in an order that won't lead to a crash :) */ 9332 /* */ 9333 /* Every one of these functions is expected to succeed, so there is no */ 9334 /* checking of return values. */ 9335 /* ------------------------------------------------------------------------ */ 9336 void 9337 ipf_destroy_all(ipf_main_softc_t *softc) 9338 { 9339 9340 if (softc->ipf_state_soft != NULL) { 9341 ipf_state_soft_destroy(softc, softc->ipf_state_soft); 9342 softc->ipf_state_soft = NULL; 9343 } 9344 9345 if (softc->ipf_nat_soft != NULL) { 9346 ipf_nat_soft_destroy(softc, softc->ipf_nat_soft); 9347 softc->ipf_nat_soft = NULL; 9348 } 9349 9350 if (softc->ipf_frag_soft != NULL) { 9351 ipf_frag_soft_destroy(softc, softc->ipf_frag_soft); 9352 softc->ipf_frag_soft = NULL; 9353 } 9354 9355 if (softc->ipf_auth_soft != NULL) { 9356 ipf_auth_soft_destroy(softc, softc->ipf_auth_soft); 9357 softc->ipf_auth_soft = NULL; 9358 } 9359 9360 if (softc->ipf_proxy_soft != NULL) { 9361 ipf_proxy_soft_destroy(softc, softc->ipf_proxy_soft); 9362 softc->ipf_proxy_soft = NULL; 9363 } 9364 9365 if (softc->ipf_sync_soft != NULL) { 9366 ipf_sync_soft_destroy(softc, softc->ipf_sync_soft); 9367 softc->ipf_sync_soft = NULL; 9368 } 9369 9370 if (softc->ipf_lookup_soft != NULL) { 9371 ipf_lookup_soft_destroy(softc, softc->ipf_lookup_soft); 9372 softc->ipf_lookup_soft = NULL; 9373 } 9374 9375 #ifdef IPFILTER_LOG 9376 if (softc->ipf_log_soft != NULL) { 9377 ipf_log_soft_destroy(softc, softc->ipf_log_soft); 9378 softc->ipf_log_soft = NULL; 9379 } 9380 #endif 9381 9382 ipf_main_soft_destroy(softc); 9383 } 9384 9385 9386 /* ------------------------------------------------------------------------ */ 9387 /* Function: ipf_init_all */ 9388 /* Returns: 0 = success, -1 = failure */ 9389 /* Parameters: softc(I) - pointer to soft context main structure */ 9390 /* */ 9391 /* Work through all of the subsystems inside IPFilter and call the init */ 9392 /* function for each in an order that won't lead to a crash :) */ 9393 /* ------------------------------------------------------------------------ */ 9394 int 9395 ipf_init_all(ipf_main_softc_t *softc) 9396 { 9397 9398 if (ipf_main_soft_init(softc) == -1) 9399 return (-1); 9400 9401 #ifdef IPFILTER_LOG 9402 if (ipf_log_soft_init(softc, softc->ipf_log_soft) == -1) 9403 return (-1); 9404 #endif 9405 9406 if (ipf_lookup_soft_init(softc, softc->ipf_lookup_soft) == -1) 9407 return (-1); 9408 9409 if (ipf_sync_soft_init(softc, softc->ipf_sync_soft) == -1) 9410 return (-1); 9411 9412 if (ipf_state_soft_init(softc, softc->ipf_state_soft) == -1) 9413 return (-1); 9414 9415 if (ipf_nat_soft_init(softc, softc->ipf_nat_soft) == -1) 9416 return (-1); 9417 9418 if (ipf_frag_soft_init(softc, softc->ipf_frag_soft) == -1) 9419 return (-1); 9420 9421 if (ipf_auth_soft_init(softc, softc->ipf_auth_soft) == -1) 9422 return (-1); 9423 9424 if (ipf_proxy_soft_init(softc, softc->ipf_proxy_soft) == -1) 9425 return (-1); 9426 9427 return (0); 9428 } 9429 9430 9431 /* ------------------------------------------------------------------------ */ 9432 /* Function: ipf_fini_all */ 9433 /* Returns: 0 = success, -1 = failure */ 9434 /* Parameters: softc(I) - pointer to soft context main structure */ 9435 /* */ 9436 /* Work through all of the subsystems inside IPFilter and call the fini */ 9437 /* function for each in an order that won't lead to a crash :) */ 9438 /* ------------------------------------------------------------------------ */ 9439 int 9440 ipf_fini_all(ipf_main_softc_t *softc) 9441 { 9442 9443 ipf_token_flush(softc); 9444 9445 if (ipf_proxy_soft_fini(softc, softc->ipf_proxy_soft) == -1) 9446 return (-1); 9447 9448 if (ipf_auth_soft_fini(softc, softc->ipf_auth_soft) == -1) 9449 return (-1); 9450 9451 if (ipf_frag_soft_fini(softc, softc->ipf_frag_soft) == -1) 9452 return (-1); 9453 9454 if (ipf_nat_soft_fini(softc, softc->ipf_nat_soft) == -1) 9455 return (-1); 9456 9457 if (ipf_state_soft_fini(softc, softc->ipf_state_soft) == -1) 9458 return (-1); 9459 9460 if (ipf_sync_soft_fini(softc, softc->ipf_sync_soft) == -1) 9461 return (-1); 9462 9463 if (ipf_lookup_soft_fini(softc, softc->ipf_lookup_soft) == -1) 9464 return (-1); 9465 9466 #ifdef IPFILTER_LOG 9467 if (ipf_log_soft_fini(softc, softc->ipf_log_soft) == -1) 9468 return (-1); 9469 #endif 9470 9471 if (ipf_main_soft_fini(softc) == -1) 9472 return (-1); 9473 9474 return (0); 9475 } 9476 9477 9478 /* ------------------------------------------------------------------------ */ 9479 /* Function: ipf_rule_expire */ 9480 /* Returns: Nil */ 9481 /* Parameters: softc(I) - pointer to soft context main structure */ 9482 /* */ 9483 /* At present this function exists just to support temporary addition of */ 9484 /* firewall rules. Both inactive and active lists are scanned for items to */ 9485 /* purge, as by rights, the expiration is computed as soon as the rule is */ 9486 /* loaded in. */ 9487 /* ------------------------------------------------------------------------ */ 9488 void 9489 ipf_rule_expire(ipf_main_softc_t *softc) 9490 { 9491 frentry_t *fr; 9492 9493 if ((softc->ipf_rule_explist[0] == NULL) && 9494 (softc->ipf_rule_explist[1] == NULL)) 9495 return; 9496 9497 WRITE_ENTER(&softc->ipf_mutex); 9498 9499 while ((fr = softc->ipf_rule_explist[0]) != NULL) { 9500 /* 9501 * Because the list is kept sorted on insertion, the fist 9502 * one that dies in the future means no more work to do. 9503 */ 9504 if (fr->fr_die > softc->ipf_ticks) 9505 break; 9506 ipf_rule_delete(softc, fr, IPL_LOGIPF, 0); 9507 } 9508 9509 while ((fr = softc->ipf_rule_explist[1]) != NULL) { 9510 /* 9511 * Because the list is kept sorted on insertion, the fist 9512 * one that dies in the future means no more work to do. 9513 */ 9514 if (fr->fr_die > softc->ipf_ticks) 9515 break; 9516 ipf_rule_delete(softc, fr, IPL_LOGIPF, 1); 9517 } 9518 9519 RWLOCK_EXIT(&softc->ipf_mutex); 9520 } 9521 9522 9523 static int ipf_ht_node_cmp(struct host_node_s *, struct host_node_s *); 9524 static void ipf_ht_node_make_key(host_track_t *, host_node_t *, int, 9525 i6addr_t *); 9526 9527 host_node_t RBI_ZERO(ipf_rb); 9528 RBI_CODE(ipf_rb, host_node_t, hn_entry, ipf_ht_node_cmp) 9529 9530 9531 /* ------------------------------------------------------------------------ */ 9532 /* Function: ipf_ht_node_cmp */ 9533 /* Returns: int - 0 == nodes are the same, .. */ 9534 /* Parameters: k1(I) - pointer to first key to compare */ 9535 /* k2(I) - pointer to second key to compare */ 9536 /* */ 9537 /* The "key" for the node is a combination of two fields: the address */ 9538 /* family and the address itself. */ 9539 /* */ 9540 /* Because we're not actually interpreting the address data, it isn't */ 9541 /* necessary to convert them to/from network/host byte order. The mask is */ 9542 /* just used to remove bits that aren't significant - it doesn't matter */ 9543 /* where they are, as long as they're always in the same place. */ 9544 /* */ 9545 /* As with IP6_EQ, comparing IPv6 addresses starts at the bottom because */ 9546 /* this is where individual ones will differ the most - but not true for */ 9547 /* for /48's, etc. */ 9548 /* ------------------------------------------------------------------------ */ 9549 static int 9550 ipf_ht_node_cmp(struct host_node_s *k1, struct host_node_s *k2) 9551 { 9552 int i; 9553 9554 i = (k2->hn_addr.adf_family - k1->hn_addr.adf_family); 9555 if (i != 0) 9556 return (i); 9557 9558 if (k1->hn_addr.adf_family == AF_INET) 9559 return (k2->hn_addr.adf_addr.in4.s_addr - 9560 k1->hn_addr.adf_addr.in4.s_addr); 9561 9562 i = k2->hn_addr.adf_addr.i6[3] - k1->hn_addr.adf_addr.i6[3]; 9563 if (i != 0) 9564 return (i); 9565 i = k2->hn_addr.adf_addr.i6[2] - k1->hn_addr.adf_addr.i6[2]; 9566 if (i != 0) 9567 return (i); 9568 i = k2->hn_addr.adf_addr.i6[1] - k1->hn_addr.adf_addr.i6[1]; 9569 if (i != 0) 9570 return (i); 9571 i = k2->hn_addr.adf_addr.i6[0] - k1->hn_addr.adf_addr.i6[0]; 9572 return (i); 9573 } 9574 9575 9576 /* ------------------------------------------------------------------------ */ 9577 /* Function: ipf_ht_node_make_key */ 9578 /* Returns: Nil */ 9579 /* parameters: htp(I) - pointer to address tracking structure */ 9580 /* key(I) - where to store masked address for lookup */ 9581 /* family(I) - protocol family of address */ 9582 /* addr(I) - pointer to network address */ 9583 /* */ 9584 /* Using the "netmask" (number of bits) stored parent host tracking struct, */ 9585 /* copy the address passed in into the key structure whilst masking out the */ 9586 /* bits that we don't want. */ 9587 /* */ 9588 /* Because the parser will set ht_netmask to 128 if there is no protocol */ 9589 /* specified (the parser doesn't know if it should be a v4 or v6 rule), we */ 9590 /* have to be wary of that and not allow 32-128 to happen. */ 9591 /* ------------------------------------------------------------------------ */ 9592 static void 9593 ipf_ht_node_make_key(host_track_t *htp, host_node_t *key, int family, 9594 i6addr_t *addr) 9595 { 9596 key->hn_addr.adf_family = family; 9597 if (family == AF_INET) { 9598 u_32_t mask; 9599 int bits; 9600 9601 key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in4); 9602 bits = htp->ht_netmask; 9603 if (bits >= 32) { 9604 mask = 0xffffffff; 9605 } else { 9606 mask = htonl(0xffffffff << (32 - bits)); 9607 } 9608 key->hn_addr.adf_addr.in4.s_addr = addr->in4.s_addr & mask; 9609 #ifdef USE_INET6 9610 } else { 9611 int bits = htp->ht_netmask; 9612 9613 key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in6); 9614 if (bits > 96) { 9615 key->hn_addr.adf_addr.i6[3] = addr->i6[3] & 9616 htonl(0xffffffff << (128 - bits)); 9617 key->hn_addr.adf_addr.i6[2] = addr->i6[2]; 9618 key->hn_addr.adf_addr.i6[1] = addr->i6[2]; 9619 key->hn_addr.adf_addr.i6[0] = addr->i6[2]; 9620 } else if (bits > 64) { 9621 key->hn_addr.adf_addr.i6[3] = 0; 9622 key->hn_addr.adf_addr.i6[2] = addr->i6[2] & 9623 htonl(0xffffffff << (96 - bits)); 9624 key->hn_addr.adf_addr.i6[1] = addr->i6[1]; 9625 key->hn_addr.adf_addr.i6[0] = addr->i6[0]; 9626 } else if (bits > 32) { 9627 key->hn_addr.adf_addr.i6[3] = 0; 9628 key->hn_addr.adf_addr.i6[2] = 0; 9629 key->hn_addr.adf_addr.i6[1] = addr->i6[1] & 9630 htonl(0xffffffff << (64 - bits)); 9631 key->hn_addr.adf_addr.i6[0] = addr->i6[0]; 9632 } else { 9633 key->hn_addr.adf_addr.i6[3] = 0; 9634 key->hn_addr.adf_addr.i6[2] = 0; 9635 key->hn_addr.adf_addr.i6[1] = 0; 9636 key->hn_addr.adf_addr.i6[0] = addr->i6[0] & 9637 htonl(0xffffffff << (32 - bits)); 9638 } 9639 #endif 9640 } 9641 } 9642 9643 9644 /* ------------------------------------------------------------------------ */ 9645 /* Function: ipf_ht_node_add */ 9646 /* Returns: int - 0 == success, -1 == failure */ 9647 /* Parameters: softc(I) - pointer to soft context main structure */ 9648 /* htp(I) - pointer to address tracking structure */ 9649 /* family(I) - protocol family of address */ 9650 /* addr(I) - pointer to network address */ 9651 /* */ 9652 /* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS */ 9653 /* ipf_ht_node_del FROM RUNNING CONCURRENTLY ON THE SAME htp. */ 9654 /* */ 9655 /* After preparing the key with the address information to find, look in */ 9656 /* the red-black tree to see if the address is known. A successful call to */ 9657 /* this function can mean one of two things: a new node was added to the */ 9658 /* tree or a matching node exists and we're able to bump up its activity. */ 9659 /* ------------------------------------------------------------------------ */ 9660 int 9661 ipf_ht_node_add(ipf_main_softc_t *softc, host_track_t *htp, int family, 9662 i6addr_t *addr) 9663 { 9664 host_node_t *h; 9665 host_node_t k; 9666 9667 ipf_ht_node_make_key(htp, &k, family, addr); 9668 9669 h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k); 9670 if (h == NULL) { 9671 if (htp->ht_cur_nodes >= htp->ht_max_nodes) 9672 return (-1); 9673 KMALLOC(h, host_node_t *); 9674 if (h == NULL) { 9675 DT(ipf_rb_no_mem); 9676 LBUMP(ipf_rb_no_mem); 9677 return (-1); 9678 } 9679 9680 /* 9681 * If there was a macro to initialise the RB node then that 9682 * would get used here, but there isn't... 9683 */ 9684 bzero((char *)h, sizeof(*h)); 9685 h->hn_addr = k.hn_addr; 9686 h->hn_addr.adf_family = k.hn_addr.adf_family; 9687 RBI_INSERT(ipf_rb, &htp->ht_root, h); 9688 htp->ht_cur_nodes++; 9689 } else { 9690 if ((htp->ht_max_per_node != 0) && 9691 (h->hn_active >= htp->ht_max_per_node)) { 9692 DT(ipf_rb_node_max); 9693 LBUMP(ipf_rb_node_max); 9694 return (-1); 9695 } 9696 } 9697 9698 h->hn_active++; 9699 9700 return (0); 9701 } 9702 9703 9704 /* ------------------------------------------------------------------------ */ 9705 /* Function: ipf_ht_node_del */ 9706 /* Returns: int - 0 == success, -1 == failure */ 9707 /* parameters: htp(I) - pointer to address tracking structure */ 9708 /* family(I) - protocol family of address */ 9709 /* addr(I) - pointer to network address */ 9710 /* */ 9711 /* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS */ 9712 /* ipf_ht_node_add FROM RUNNING CONCURRENTLY ON THE SAME htp. */ 9713 /* */ 9714 /* Try and find the address passed in amongst the leavese on this tree to */ 9715 /* be friend. If found then drop the active account for that node drops by */ 9716 /* one. If that count reaches 0, it is time to free it all up. */ 9717 /* ------------------------------------------------------------------------ */ 9718 int 9719 ipf_ht_node_del(host_track_t *htp, int family, i6addr_t *addr) 9720 { 9721 host_node_t *h; 9722 host_node_t k; 9723 9724 ipf_ht_node_make_key(htp, &k, family, addr); 9725 9726 h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k); 9727 if (h == NULL) { 9728 return (-1); 9729 } else { 9730 h->hn_active--; 9731 if (h->hn_active == 0) { 9732 (void) RBI_DELETE(ipf_rb, &htp->ht_root, h); 9733 htp->ht_cur_nodes--; 9734 KFREE(h); 9735 } 9736 } 9737 9738 return (0); 9739 } 9740 9741 9742 /* ------------------------------------------------------------------------ */ 9743 /* Function: ipf_rb_ht_init */ 9744 /* Returns: Nil */ 9745 /* Parameters: head(I) - pointer to host tracking structure */ 9746 /* */ 9747 /* Initialise the host tracking structure to be ready for use above. */ 9748 /* ------------------------------------------------------------------------ */ 9749 void 9750 ipf_rb_ht_init(host_track_t *head) 9751 { 9752 RBI_INIT(ipf_rb, &head->ht_root); 9753 } 9754 9755 9756 /* ------------------------------------------------------------------------ */ 9757 /* Function: ipf_rb_ht_freenode */ 9758 /* Returns: Nil */ 9759 /* Parameters: head(I) - pointer to host tracking structure */ 9760 /* arg(I) - additional argument from walk caller */ 9761 /* */ 9762 /* Free an actual host_node_t structure. */ 9763 /* ------------------------------------------------------------------------ */ 9764 void 9765 ipf_rb_ht_freenode(host_node_t *node, void *arg) 9766 { 9767 KFREE(node); 9768 } 9769 9770 9771 /* ------------------------------------------------------------------------ */ 9772 /* Function: ipf_rb_ht_flush */ 9773 /* Returns: Nil */ 9774 /* Parameters: head(I) - pointer to host tracking structure */ 9775 /* */ 9776 /* Remove all of the nodes in the tree tracking hosts by calling a walker */ 9777 /* and free'ing each one. */ 9778 /* ------------------------------------------------------------------------ */ 9779 void 9780 ipf_rb_ht_flush(host_track_t *head) 9781 { 9782 RBI_WALK(ipf_rb, &head->ht_root, ipf_rb_ht_freenode, NULL); 9783 } 9784 9785 9786 /* ------------------------------------------------------------------------ */ 9787 /* Function: ipf_slowtimer */ 9788 /* Returns: Nil */ 9789 /* Parameters: ptr(I) - pointer to main ipf soft context structure */ 9790 /* */ 9791 /* Slowly expire held state for fragments. Timeouts are set * in */ 9792 /* expectation of this being called twice per second. */ 9793 /* ------------------------------------------------------------------------ */ 9794 void 9795 ipf_slowtimer(ipf_main_softc_t *softc) 9796 { 9797 9798 ipf_token_expire(softc); 9799 ipf_frag_expire(softc); 9800 ipf_state_expire(softc); 9801 ipf_nat_expire(softc); 9802 ipf_auth_expire(softc); 9803 ipf_lookup_expire(softc); 9804 ipf_rule_expire(softc); 9805 ipf_sync_expire(softc); 9806 softc->ipf_ticks++; 9807 } 9808 9809 9810 /* ------------------------------------------------------------------------ */ 9811 /* Function: ipf_inet_mask_add */ 9812 /* Returns: Nil */ 9813 /* Parameters: bits(I) - pointer to nat context information */ 9814 /* mtab(I) - pointer to mask hash table structure */ 9815 /* */ 9816 /* When called, bits represents the mask of a new NAT rule that has just */ 9817 /* been added. This function inserts a bitmask into the array of masks to */ 9818 /* search when searching for a matching NAT rule for a packet. */ 9819 /* Prevention of duplicate masks is achieved by checking the use count for */ 9820 /* a given netmask. */ 9821 /* ------------------------------------------------------------------------ */ 9822 void 9823 ipf_inet_mask_add(int bits, ipf_v4_masktab_t *mtab) 9824 { 9825 u_32_t mask; 9826 int i, j; 9827 9828 mtab->imt4_masks[bits]++; 9829 if (mtab->imt4_masks[bits] > 1) 9830 return; 9831 9832 if (bits == 0) 9833 mask = 0; 9834 else 9835 mask = 0xffffffff << (32 - bits); 9836 9837 for (i = 0; i < 33; i++) { 9838 if (ntohl(mtab->imt4_active[i]) < mask) { 9839 for (j = 32; j > i; j--) 9840 mtab->imt4_active[j] = mtab->imt4_active[j - 1]; 9841 mtab->imt4_active[i] = htonl(mask); 9842 break; 9843 } 9844 } 9845 mtab->imt4_max++; 9846 } 9847 9848 9849 /* ------------------------------------------------------------------------ */ 9850 /* Function: ipf_inet_mask_del */ 9851 /* Returns: Nil */ 9852 /* Parameters: bits(I) - number of bits set in the netmask */ 9853 /* mtab(I) - pointer to mask hash table structure */ 9854 /* */ 9855 /* Remove the 32bit bitmask represented by "bits" from the collection of */ 9856 /* netmasks stored inside of mtab. */ 9857 /* ------------------------------------------------------------------------ */ 9858 void 9859 ipf_inet_mask_del(int bits, ipf_v4_masktab_t *mtab) 9860 { 9861 u_32_t mask; 9862 int i, j; 9863 9864 mtab->imt4_masks[bits]--; 9865 if (mtab->imt4_masks[bits] > 0) 9866 return; 9867 9868 mask = htonl(0xffffffff << (32 - bits)); 9869 for (i = 0; i < 33; i++) { 9870 if (mtab->imt4_active[i] == mask) { 9871 for (j = i + 1; j < 33; j++) 9872 mtab->imt4_active[j - 1] = mtab->imt4_active[j]; 9873 break; 9874 } 9875 } 9876 mtab->imt4_max--; 9877 ASSERT(mtab->imt4_max >= 0); 9878 } 9879 9880 9881 #ifdef USE_INET6 9882 /* ------------------------------------------------------------------------ */ 9883 /* Function: ipf_inet6_mask_add */ 9884 /* Returns: Nil */ 9885 /* Parameters: bits(I) - number of bits set in mask */ 9886 /* mask(I) - pointer to mask to add */ 9887 /* mtab(I) - pointer to mask hash table structure */ 9888 /* */ 9889 /* When called, bitcount represents the mask of a IPv6 NAT map rule that */ 9890 /* has just been added. This function inserts a bitmask into the array of */ 9891 /* masks to search when searching for a matching NAT rule for a packet. */ 9892 /* Prevention of duplicate masks is achieved by checking the use count for */ 9893 /* a given netmask. */ 9894 /* ------------------------------------------------------------------------ */ 9895 void 9896 ipf_inet6_mask_add(int bits, i6addr_t *mask, ipf_v6_masktab_t *mtab) 9897 { 9898 i6addr_t zero; 9899 int i, j; 9900 9901 mtab->imt6_masks[bits]++; 9902 if (mtab->imt6_masks[bits] > 1) 9903 return; 9904 9905 if (bits == 0) { 9906 mask = &zero; 9907 zero.i6[0] = 0; 9908 zero.i6[1] = 0; 9909 zero.i6[2] = 0; 9910 zero.i6[3] = 0; 9911 } 9912 9913 for (i = 0; i < 129; i++) { 9914 if (IP6_LT(&mtab->imt6_active[i], mask)) { 9915 for (j = 128; j > i; j--) 9916 mtab->imt6_active[j] = mtab->imt6_active[j - 1]; 9917 mtab->imt6_active[i] = *mask; 9918 break; 9919 } 9920 } 9921 mtab->imt6_max++; 9922 } 9923 9924 9925 /* ------------------------------------------------------------------------ */ 9926 /* Function: ipf_inet6_mask_del */ 9927 /* Returns: Nil */ 9928 /* Parameters: bits(I) - number of bits set in mask */ 9929 /* mask(I) - pointer to mask to remove */ 9930 /* mtab(I) - pointer to mask hash table structure */ 9931 /* */ 9932 /* Remove the 128bit bitmask represented by "bits" from the collection of */ 9933 /* netmasks stored inside of mtab. */ 9934 /* ------------------------------------------------------------------------ */ 9935 void 9936 ipf_inet6_mask_del(int bits, i6addr_t *mask, ipf_v6_masktab_t *mtab) 9937 { 9938 i6addr_t zero; 9939 int i, j; 9940 9941 mtab->imt6_masks[bits]--; 9942 if (mtab->imt6_masks[bits] > 0) 9943 return; 9944 9945 if (bits == 0) 9946 mask = &zero; 9947 zero.i6[0] = 0; 9948 zero.i6[1] = 0; 9949 zero.i6[2] = 0; 9950 zero.i6[3] = 0; 9951 9952 for (i = 0; i < 129; i++) { 9953 if (IP6_EQ(&mtab->imt6_active[i], mask)) { 9954 for (j = i + 1; j < 129; j++) { 9955 mtab->imt6_active[j - 1] = mtab->imt6_active[j]; 9956 if (IP6_EQ(&mtab->imt6_active[j - 1], &zero)) 9957 break; 9958 } 9959 break; 9960 } 9961 } 9962 mtab->imt6_max--; 9963 ASSERT(mtab->imt6_max >= 0); 9964 } 9965 #endif 9966