1 2 /* 3 * Copyright (C) 2012 by Darren Reed. 4 * 5 * See the IPFILTER.LICENCE file for details on licencing. 6 * 7 * Copyright 2008 Sun Microsystems. 8 * 9 * $Id$ 10 * 11 */ 12 #if defined(KERNEL) || defined(_KERNEL) 13 # undef KERNEL 14 # undef _KERNEL 15 # define KERNEL 1 16 # define _KERNEL 1 17 #endif 18 #include <sys/errno.h> 19 #include <sys/types.h> 20 #include <sys/param.h> 21 #include <sys/time.h> 22 #if defined(_KERNEL) && defined(__FreeBSD__) 23 # if !defined(IPFILTER_LKM) 24 # include "opt_inet6.h" 25 # endif 26 # include <sys/filio.h> 27 #else 28 # include <sys/ioctl.h> 29 #endif 30 #if defined(__SVR4) || defined(sun) /* SOLARIS */ 31 # include <sys/filio.h> 32 #endif 33 # include <sys/fcntl.h> 34 #if defined(_KERNEL) 35 # include <sys/systm.h> 36 # include <sys/file.h> 37 #else 38 # include <stdio.h> 39 # include <string.h> 40 # include <stdlib.h> 41 # include <stddef.h> 42 # include <sys/file.h> 43 # define _KERNEL 44 # include <sys/uio.h> 45 # undef _KERNEL 46 #endif 47 #if !defined(__SVR4) 48 # include <sys/mbuf.h> 49 #else 50 # include <sys/byteorder.h> 51 # if (SOLARIS2 < 5) && defined(sun) 52 # include <sys/dditypes.h> 53 # endif 54 #endif 55 # include <sys/protosw.h> 56 #include <sys/socket.h> 57 #include <net/if.h> 58 #ifdef sun 59 # include <net/af.h> 60 #endif 61 #include <netinet/in.h> 62 #include <netinet/in_systm.h> 63 #include <netinet/ip.h> 64 #include <netinet/tcp.h> 65 # include <netinet/udp.h> 66 # include <netinet/ip_icmp.h> 67 #include "netinet/ip_compat.h" 68 #ifdef USE_INET6 69 # include <netinet/icmp6.h> 70 # if !SOLARIS && defined(_KERNEL) 71 # include <netinet6/in6_var.h> 72 # endif 73 #endif 74 #include "netinet/ip_fil.h" 75 #include "netinet/ip_nat.h" 76 #include "netinet/ip_frag.h" 77 #include "netinet/ip_state.h" 78 #include "netinet/ip_proxy.h" 79 #include "netinet/ip_auth.h" 80 #ifdef IPFILTER_SCAN 81 # include "netinet/ip_scan.h" 82 #endif 83 #include "netinet/ip_sync.h" 84 #include "netinet/ip_lookup.h" 85 #include "netinet/ip_pool.h" 86 #include "netinet/ip_htable.h" 87 #ifdef IPFILTER_COMPILED 88 # include "netinet/ip_rules.h" 89 #endif 90 #if defined(IPFILTER_BPF) && defined(_KERNEL) 91 # include <net/bpf.h> 92 #endif 93 #if defined(__FreeBSD__) 94 # include <sys/malloc.h> 95 #endif 96 #include "netinet/ipl.h" 97 98 #if defined(__NetBSD__) && (__NetBSD_Version__ >= 104230000) 99 # include <sys/callout.h> 100 extern struct callout ipf_slowtimer_ch; 101 #endif 102 /* END OF INCLUDES */ 103 104 105 #ifndef _KERNEL 106 # include "ipf.h" 107 # include "ipt.h" 108 extern int opts; 109 extern int blockreason; 110 #endif /* _KERNEL */ 111 112 #define FASTROUTE_RECURSION 113 114 #define LBUMP(x) softc->x++ 115 #define LBUMPD(x, y) do { softc->x.y++; DT(y); } while (0) 116 117 static inline int ipf_check_ipf(fr_info_t *, frentry_t *, int); 118 static u_32_t ipf_checkcipso(fr_info_t *, u_char *, int); 119 static u_32_t ipf_checkripso(u_char *); 120 static u_32_t ipf_decaps(fr_info_t *, u_32_t, int); 121 #ifdef IPFILTER_LOG 122 static frentry_t *ipf_dolog(fr_info_t *, u_32_t *); 123 #endif 124 static int ipf_flushlist(ipf_main_softc_t *, int *, frentry_t **); 125 static int ipf_flush_groups(ipf_main_softc_t *, frgroup_t **, 126 int); 127 static ipfunc_t ipf_findfunc(ipfunc_t); 128 static void *ipf_findlookup(ipf_main_softc_t *, int, frentry_t *, 129 i6addr_t *, i6addr_t *); 130 static frentry_t *ipf_firewall(fr_info_t *, u_32_t *); 131 static int ipf_fr_matcharray(fr_info_t *, int *); 132 static int ipf_frruleiter(ipf_main_softc_t *, void *, int, 133 void *); 134 static void ipf_funcfini(ipf_main_softc_t *, frentry_t *); 135 static int ipf_funcinit(ipf_main_softc_t *, frentry_t *); 136 static int ipf_geniter(ipf_main_softc_t *, ipftoken_t *, 137 ipfgeniter_t *); 138 static void ipf_getstat(ipf_main_softc_t *, 139 struct friostat *, int); 140 static int ipf_group_flush(ipf_main_softc_t *, frgroup_t *); 141 static void ipf_group_free(frgroup_t *); 142 static int ipf_grpmapfini(struct ipf_main_softc_s *, 143 frentry_t *); 144 static int ipf_grpmapinit(struct ipf_main_softc_s *, 145 frentry_t *); 146 static frentry_t *ipf_nextrule(ipf_main_softc_t *, int, int, 147 frentry_t *, int); 148 static int ipf_portcheck(frpcmp_t *, u_32_t); 149 static inline int ipf_pr_ah(fr_info_t *); 150 static inline void ipf_pr_esp(fr_info_t *); 151 static inline void ipf_pr_gre(fr_info_t *); 152 static inline void ipf_pr_udp(fr_info_t *); 153 static inline void ipf_pr_tcp(fr_info_t *); 154 static inline void ipf_pr_icmp(fr_info_t *); 155 static inline void ipf_pr_ipv4hdr(fr_info_t *); 156 static inline void ipf_pr_short(fr_info_t *, int); 157 static inline int ipf_pr_tcpcommon(fr_info_t *); 158 static inline int ipf_pr_udpcommon(fr_info_t *); 159 static void ipf_rule_delete(ipf_main_softc_t *, frentry_t *f, 160 int, int); 161 static void ipf_rule_expire_insert(ipf_main_softc_t *, 162 frentry_t *, int); 163 static int ipf_synclist(ipf_main_softc_t *, frentry_t *, 164 void *); 165 static void ipf_token_flush(ipf_main_softc_t *); 166 static void ipf_token_unlink(ipf_main_softc_t *, 167 ipftoken_t *); 168 static ipftuneable_t *ipf_tune_findbyname(ipftuneable_t *, 169 const char *); 170 static ipftuneable_t *ipf_tune_findbycookie(ipftuneable_t **, void *, 171 void **); 172 static int ipf_updateipid(fr_info_t *); 173 static int ipf_settimeout(struct ipf_main_softc_s *, 174 struct ipftuneable *, 175 ipftuneval_t *); 176 #if !defined(_KERNEL) || SOLARIS 177 static int ppsratecheck(struct timeval *, int *, int); 178 #endif 179 180 181 /* 182 * bit values for identifying presence of individual IP options 183 * All of these tables should be ordered by increasing key value on the left 184 * hand side to allow for binary searching of the array and include a trailer 185 * with a 0 for the bitmask for linear searches to easily find the end with. 186 */ 187 static const struct optlist ipopts[] = { 188 { IPOPT_NOP, 0x000001 }, 189 { IPOPT_RR, 0x000002 }, 190 { IPOPT_ZSU, 0x000004 }, 191 { IPOPT_MTUP, 0x000008 }, 192 { IPOPT_MTUR, 0x000010 }, 193 { IPOPT_ENCODE, 0x000020 }, 194 { IPOPT_TS, 0x000040 }, 195 { IPOPT_TR, 0x000080 }, 196 { IPOPT_SECURITY, 0x000100 }, 197 { IPOPT_LSRR, 0x000200 }, 198 { IPOPT_E_SEC, 0x000400 }, 199 { IPOPT_CIPSO, 0x000800 }, 200 { IPOPT_SATID, 0x001000 }, 201 { IPOPT_SSRR, 0x002000 }, 202 { IPOPT_ADDEXT, 0x004000 }, 203 { IPOPT_VISA, 0x008000 }, 204 { IPOPT_IMITD, 0x010000 }, 205 { IPOPT_EIP, 0x020000 }, 206 { IPOPT_FINN, 0x040000 }, 207 { 0, 0x000000 } 208 }; 209 210 #ifdef USE_INET6 211 static const struct optlist ip6exthdr[] = { 212 { IPPROTO_HOPOPTS, 0x000001 }, 213 { IPPROTO_IPV6, 0x000002 }, 214 { IPPROTO_ROUTING, 0x000004 }, 215 { IPPROTO_FRAGMENT, 0x000008 }, 216 { IPPROTO_ESP, 0x000010 }, 217 { IPPROTO_AH, 0x000020 }, 218 { IPPROTO_NONE, 0x000040 }, 219 { IPPROTO_DSTOPTS, 0x000080 }, 220 { IPPROTO_MOBILITY, 0x000100 }, 221 { 0, 0 } 222 }; 223 #endif 224 225 /* 226 * bit values for identifying presence of individual IP security options 227 */ 228 static const struct optlist secopt[] = { 229 { IPSO_CLASS_RES4, 0x01 }, 230 { IPSO_CLASS_TOPS, 0x02 }, 231 { IPSO_CLASS_SECR, 0x04 }, 232 { IPSO_CLASS_RES3, 0x08 }, 233 { IPSO_CLASS_CONF, 0x10 }, 234 { IPSO_CLASS_UNCL, 0x20 }, 235 { IPSO_CLASS_RES2, 0x40 }, 236 { IPSO_CLASS_RES1, 0x80 } 237 }; 238 239 char ipfilter_version[] = IPL_VERSION; 240 241 int ipf_features = 0 242 #ifdef IPFILTER_LKM 243 | IPF_FEAT_LKM 244 #endif 245 #ifdef IPFILTER_LOG 246 | IPF_FEAT_LOG 247 #endif 248 | IPF_FEAT_LOOKUP 249 #ifdef IPFILTER_BPF 250 | IPF_FEAT_BPF 251 #endif 252 #ifdef IPFILTER_COMPILED 253 | IPF_FEAT_COMPILED 254 #endif 255 #ifdef IPFILTER_CKSUM 256 | IPF_FEAT_CKSUM 257 #endif 258 | IPF_FEAT_SYNC 259 #ifdef IPFILTER_SCAN 260 | IPF_FEAT_SCAN 261 #endif 262 #ifdef USE_INET6 263 | IPF_FEAT_IPV6 264 #endif 265 ; 266 267 268 /* 269 * Table of functions available for use with call rules. 270 */ 271 static ipfunc_resolve_t ipf_availfuncs[] = { 272 { "srcgrpmap", ipf_srcgrpmap, ipf_grpmapinit, ipf_grpmapfini }, 273 { "dstgrpmap", ipf_dstgrpmap, ipf_grpmapinit, ipf_grpmapfini }, 274 { "", NULL, NULL, NULL } 275 }; 276 277 static ipftuneable_t ipf_main_tuneables[] = { 278 { { (void *)offsetof(struct ipf_main_softc_s, ipf_flags) }, 279 "ipf_flags", 0, 0xffffffff, 280 stsizeof(ipf_main_softc_t, ipf_flags), 281 0, NULL, NULL }, 282 { { (void *)offsetof(struct ipf_main_softc_s, ipf_active) }, 283 "active", 0, 0, 284 stsizeof(ipf_main_softc_t, ipf_active), 285 IPFT_RDONLY, NULL, NULL }, 286 { { (void *)offsetof(ipf_main_softc_t, ipf_control_forwarding) }, 287 "control_forwarding", 0, 1, 288 stsizeof(ipf_main_softc_t, ipf_control_forwarding), 289 0, NULL, NULL }, 290 { { (void *)offsetof(ipf_main_softc_t, ipf_update_ipid) }, 291 "update_ipid", 0, 1, 292 stsizeof(ipf_main_softc_t, ipf_update_ipid), 293 0, NULL, NULL }, 294 { { (void *)offsetof(ipf_main_softc_t, ipf_chksrc) }, 295 "chksrc", 0, 1, 296 stsizeof(ipf_main_softc_t, ipf_chksrc), 297 0, NULL, NULL }, 298 { { (void *)offsetof(ipf_main_softc_t, ipf_minttl) }, 299 "min_ttl", 0, 1, 300 stsizeof(ipf_main_softc_t, ipf_minttl), 301 0, NULL, NULL }, 302 { { (void *)offsetof(ipf_main_softc_t, ipf_icmpminfragmtu) }, 303 "icmp_minfragmtu", 0, 1, 304 stsizeof(ipf_main_softc_t, ipf_icmpminfragmtu), 305 0, NULL, NULL }, 306 { { (void *)offsetof(ipf_main_softc_t, ipf_pass) }, 307 "default_pass", 0, 0xffffffff, 308 stsizeof(ipf_main_softc_t, ipf_pass), 309 0, NULL, NULL }, 310 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpidletimeout) }, 311 "tcp_idle_timeout", 1, 0x7fffffff, 312 stsizeof(ipf_main_softc_t, ipf_tcpidletimeout), 313 0, NULL, ipf_settimeout }, 314 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosewait) }, 315 "tcp_close_wait", 1, 0x7fffffff, 316 stsizeof(ipf_main_softc_t, ipf_tcpclosewait), 317 0, NULL, ipf_settimeout }, 318 { { (void *)offsetof(ipf_main_softc_t, ipf_tcplastack) }, 319 "tcp_last_ack", 1, 0x7fffffff, 320 stsizeof(ipf_main_softc_t, ipf_tcplastack), 321 0, NULL, ipf_settimeout }, 322 { { (void *)offsetof(ipf_main_softc_t, ipf_tcptimeout) }, 323 "tcp_timeout", 1, 0x7fffffff, 324 stsizeof(ipf_main_softc_t, ipf_tcptimeout), 325 0, NULL, ipf_settimeout }, 326 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynsent) }, 327 "tcp_syn_sent", 1, 0x7fffffff, 328 stsizeof(ipf_main_softc_t, ipf_tcpsynsent), 329 0, NULL, ipf_settimeout }, 330 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynrecv) }, 331 "tcp_syn_received", 1, 0x7fffffff, 332 stsizeof(ipf_main_softc_t, ipf_tcpsynrecv), 333 0, NULL, ipf_settimeout }, 334 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosed) }, 335 "tcp_closed", 1, 0x7fffffff, 336 stsizeof(ipf_main_softc_t, ipf_tcpclosed), 337 0, NULL, ipf_settimeout }, 338 { { (void *)offsetof(ipf_main_softc_t, ipf_tcphalfclosed) }, 339 "tcp_half_closed", 1, 0x7fffffff, 340 stsizeof(ipf_main_softc_t, ipf_tcphalfclosed), 341 0, NULL, ipf_settimeout }, 342 { { (void *)offsetof(ipf_main_softc_t, ipf_tcptimewait) }, 343 "tcp_time_wait", 1, 0x7fffffff, 344 stsizeof(ipf_main_softc_t, ipf_tcptimewait), 345 0, NULL, ipf_settimeout }, 346 { { (void *)offsetof(ipf_main_softc_t, ipf_udptimeout) }, 347 "udp_timeout", 1, 0x7fffffff, 348 stsizeof(ipf_main_softc_t, ipf_udptimeout), 349 0, NULL, ipf_settimeout }, 350 { { (void *)offsetof(ipf_main_softc_t, ipf_udpacktimeout) }, 351 "udp_ack_timeout", 1, 0x7fffffff, 352 stsizeof(ipf_main_softc_t, ipf_udpacktimeout), 353 0, NULL, ipf_settimeout }, 354 { { (void *)offsetof(ipf_main_softc_t, ipf_icmptimeout) }, 355 "icmp_timeout", 1, 0x7fffffff, 356 stsizeof(ipf_main_softc_t, ipf_icmptimeout), 357 0, NULL, ipf_settimeout }, 358 { { (void *)offsetof(ipf_main_softc_t, ipf_icmpacktimeout) }, 359 "icmp_ack_timeout", 1, 0x7fffffff, 360 stsizeof(ipf_main_softc_t, ipf_icmpacktimeout), 361 0, NULL, ipf_settimeout }, 362 { { (void *)offsetof(ipf_main_softc_t, ipf_iptimeout) }, 363 "ip_timeout", 1, 0x7fffffff, 364 stsizeof(ipf_main_softc_t, ipf_iptimeout), 365 0, NULL, ipf_settimeout }, 366 #if defined(INSTANCES) && defined(_KERNEL) 367 { { (void *)offsetof(ipf_main_softc_t, ipf_get_loopback) }, 368 "intercept_loopback", 0, 1, 369 stsizeof(ipf_main_softc_t, ipf_get_loopback), 370 0, NULL, ipf_set_loopback }, 371 #endif 372 { { 0 }, 373 NULL, 0, 0, 374 0, 375 0, NULL, NULL } 376 }; 377 378 379 /* 380 * The next section of code is a collection of small routines that set 381 * fields in the fr_info_t structure passed based on properties of the 382 * current packet. There are different routines for the same protocol 383 * for each of IPv4 and IPv6. Adding a new protocol, for which there 384 * will "special" inspection for setup, is now more easily done by adding 385 * a new routine and expanding the ipf_pr_ipinit*() function rather than by 386 * adding more code to a growing switch statement. 387 */ 388 #ifdef USE_INET6 389 static inline int ipf_pr_ah6(fr_info_t *); 390 static inline void ipf_pr_esp6(fr_info_t *); 391 static inline void ipf_pr_gre6(fr_info_t *); 392 static inline void ipf_pr_udp6(fr_info_t *); 393 static inline void ipf_pr_tcp6(fr_info_t *); 394 static inline void ipf_pr_icmp6(fr_info_t *); 395 static inline void ipf_pr_ipv6hdr(fr_info_t *); 396 static inline void ipf_pr_short6(fr_info_t *, int); 397 static inline int ipf_pr_hopopts6(fr_info_t *); 398 static inline int ipf_pr_mobility6(fr_info_t *); 399 static inline int ipf_pr_routing6(fr_info_t *); 400 static inline int ipf_pr_dstopts6(fr_info_t *); 401 static inline int ipf_pr_fragment6(fr_info_t *); 402 static inline struct ip6_ext *ipf_pr_ipv6exthdr(fr_info_t *, int, int); 403 404 405 /* ------------------------------------------------------------------------ */ 406 /* Function: ipf_pr_short6 */ 407 /* Returns: void */ 408 /* Parameters: fin(I) - pointer to packet information */ 409 /* xmin(I) - minimum header size */ 410 /* */ 411 /* IPv6 Only */ 412 /* This is function enforces the 'is a packet too short to be legit' rule */ 413 /* for IPv6 and marks the packet with FI_SHORT if so. See function comment */ 414 /* for ipf_pr_short() for more details. */ 415 /* ------------------------------------------------------------------------ */ 416 static inline void 417 ipf_pr_short6(fr_info_t *fin, int xmin) 418 { 419 420 if (fin->fin_dlen < xmin) 421 fin->fin_flx |= FI_SHORT; 422 } 423 424 425 /* ------------------------------------------------------------------------ */ 426 /* Function: ipf_pr_ipv6hdr */ 427 /* Returns: void */ 428 /* Parameters: fin(I) - pointer to packet information */ 429 /* */ 430 /* IPv6 Only */ 431 /* Copy values from the IPv6 header into the fr_info_t struct and call the */ 432 /* per-protocol analyzer if it exists. In validating the packet, a protocol*/ 433 /* analyzer may pullup or free the packet itself so we need to be vigiliant */ 434 /* of that possibility arising. */ 435 /* ------------------------------------------------------------------------ */ 436 static inline void 437 ipf_pr_ipv6hdr(fr_info_t *fin) 438 { 439 ip6_t *ip6 = (ip6_t *)fin->fin_ip; 440 int p, go = 1, i, hdrcount; 441 fr_ip_t *fi = &fin->fin_fi; 442 443 fin->fin_off = 0; 444 445 fi->fi_tos = 0; 446 fi->fi_optmsk = 0; 447 fi->fi_secmsk = 0; 448 fi->fi_auth = 0; 449 450 p = ip6->ip6_nxt; 451 fin->fin_crc = p; 452 fi->fi_ttl = ip6->ip6_hlim; 453 fi->fi_src.in6 = ip6->ip6_src; 454 fin->fin_crc += fi->fi_src.i6[0]; 455 fin->fin_crc += fi->fi_src.i6[1]; 456 fin->fin_crc += fi->fi_src.i6[2]; 457 fin->fin_crc += fi->fi_src.i6[3]; 458 fi->fi_dst.in6 = ip6->ip6_dst; 459 fin->fin_crc += fi->fi_dst.i6[0]; 460 fin->fin_crc += fi->fi_dst.i6[1]; 461 fin->fin_crc += fi->fi_dst.i6[2]; 462 fin->fin_crc += fi->fi_dst.i6[3]; 463 fin->fin_id = 0; 464 if (IN6_IS_ADDR_MULTICAST(&fi->fi_dst.in6)) 465 fin->fin_flx |= FI_MULTICAST|FI_MBCAST; 466 467 hdrcount = 0; 468 while (go && !(fin->fin_flx & FI_SHORT)) { 469 switch (p) 470 { 471 case IPPROTO_UDP : 472 ipf_pr_udp6(fin); 473 go = 0; 474 break; 475 476 case IPPROTO_TCP : 477 ipf_pr_tcp6(fin); 478 go = 0; 479 break; 480 481 case IPPROTO_ICMPV6 : 482 ipf_pr_icmp6(fin); 483 go = 0; 484 break; 485 486 case IPPROTO_GRE : 487 ipf_pr_gre6(fin); 488 go = 0; 489 break; 490 491 case IPPROTO_HOPOPTS : 492 p = ipf_pr_hopopts6(fin); 493 break; 494 495 case IPPROTO_MOBILITY : 496 p = ipf_pr_mobility6(fin); 497 break; 498 499 case IPPROTO_DSTOPTS : 500 p = ipf_pr_dstopts6(fin); 501 break; 502 503 case IPPROTO_ROUTING : 504 p = ipf_pr_routing6(fin); 505 break; 506 507 case IPPROTO_AH : 508 p = ipf_pr_ah6(fin); 509 break; 510 511 case IPPROTO_ESP : 512 ipf_pr_esp6(fin); 513 go = 0; 514 break; 515 516 case IPPROTO_IPV6 : 517 for (i = 0; ip6exthdr[i].ol_bit != 0; i++) 518 if (ip6exthdr[i].ol_val == p) { 519 fin->fin_flx |= ip6exthdr[i].ol_bit; 520 break; 521 } 522 go = 0; 523 break; 524 525 case IPPROTO_NONE : 526 go = 0; 527 break; 528 529 case IPPROTO_FRAGMENT : 530 p = ipf_pr_fragment6(fin); 531 /* 532 * Given that the only fragments we want to let through 533 * (where fin_off != 0) are those where the non-first 534 * fragments only have data, we can safely stop looking 535 * at headers if this is a non-leading fragment. 536 */ 537 if (fin->fin_off != 0) 538 go = 0; 539 break; 540 541 default : 542 go = 0; 543 break; 544 } 545 hdrcount++; 546 547 /* 548 * It is important to note that at this point, for the 549 * extension headers (go != 0), the entire header may not have 550 * been pulled up when the code gets to this point. This is 551 * only done for "go != 0" because the other header handlers 552 * will all pullup their complete header. The other indicator 553 * of an incomplete packet is that this was just an extension 554 * header. 555 */ 556 if ((go != 0) && (p != IPPROTO_NONE) && 557 (ipf_pr_pullup(fin, 0) == -1)) { 558 p = IPPROTO_NONE; 559 break; 560 } 561 } 562 563 /* 564 * Some of the above functions, like ipf_pr_esp6(), can call ipf_pullup 565 * and destroy whatever packet was here. The caller of this function 566 * expects us to return if there is a problem with ipf_pullup. 567 */ 568 if (fin->fin_m == NULL) { 569 ipf_main_softc_t *softc = fin->fin_main_soft; 570 571 LBUMPD(ipf_stats[fin->fin_out], fr_v6_bad); 572 return; 573 } 574 575 fi->fi_p = p; 576 577 /* 578 * IPv6 fragment case 1 - see comment for ipf_pr_fragment6(). 579 * "go != 0" implies the above loop hasn't arrived at a layer 4 header. 580 */ 581 if ((go != 0) && (fin->fin_flx & FI_FRAG) && (fin->fin_off == 0)) { 582 ipf_main_softc_t *softc = fin->fin_main_soft; 583 584 fin->fin_flx |= FI_BAD; 585 DT2(ipf_fi_bad_ipv6_frag_1, fr_info_t *, fin, int, go); 586 LBUMPD(ipf_stats[fin->fin_out], fr_v6_badfrag); 587 LBUMP(ipf_stats[fin->fin_out].fr_v6_bad); 588 } 589 } 590 591 592 /* ------------------------------------------------------------------------ */ 593 /* Function: ipf_pr_ipv6exthdr */ 594 /* Returns: struct ip6_ext * - pointer to the start of the next header */ 595 /* or NULL if there is a prolblem. */ 596 /* Parameters: fin(I) - pointer to packet information */ 597 /* multiple(I) - flag indicating yes/no if multiple occurances */ 598 /* of this extension header are allowed. */ 599 /* proto(I) - protocol number for this extension header */ 600 /* */ 601 /* IPv6 Only */ 602 /* This function embodies a number of common checks that all IPv6 extension */ 603 /* headers must be subjected to. For example, making sure the packet is */ 604 /* big enough for it to be in, checking if it is repeated and setting a */ 605 /* flag to indicate its presence. */ 606 /* ------------------------------------------------------------------------ */ 607 static inline struct ip6_ext * 608 ipf_pr_ipv6exthdr(fr_info_t *fin, int multiple, int proto) 609 { 610 ipf_main_softc_t *softc = fin->fin_main_soft; 611 struct ip6_ext *hdr; 612 u_short shift; 613 int i; 614 615 fin->fin_flx |= FI_V6EXTHDR; 616 617 /* 8 is default length of extension hdr */ 618 if ((fin->fin_dlen - 8) < 0) { 619 fin->fin_flx |= FI_SHORT; 620 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_short); 621 return (NULL); 622 } 623 624 if (ipf_pr_pullup(fin, 8) == -1) { 625 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_pullup); 626 return (NULL); 627 } 628 629 hdr = fin->fin_dp; 630 switch (proto) 631 { 632 case IPPROTO_FRAGMENT : 633 shift = 8; 634 break; 635 default : 636 shift = 8 + (hdr->ip6e_len << 3); 637 break; 638 } 639 640 if (shift > fin->fin_dlen) { /* Nasty extension header length? */ 641 fin->fin_flx |= FI_BAD; 642 DT3(ipf_fi_bad_pr_ipv6exthdr_len, fr_info_t *, fin, u_short, shift, u_short, fin->fin_dlen); 643 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_hlen); 644 return (NULL); 645 } 646 647 fin->fin_dp = (char *)fin->fin_dp + shift; 648 fin->fin_dlen -= shift; 649 650 /* 651 * If we have seen a fragment header, do not set any flags to indicate 652 * the presence of this extension header as it has no impact on the 653 * end result until after it has been defragmented. 654 */ 655 if (fin->fin_flx & FI_FRAG) 656 return (hdr); 657 658 for (i = 0; ip6exthdr[i].ol_bit != 0; i++) 659 if (ip6exthdr[i].ol_val == proto) { 660 /* 661 * Most IPv6 extension headers are only allowed once. 662 */ 663 if ((multiple == 0) && 664 ((fin->fin_optmsk & ip6exthdr[i].ol_bit) != 0)) { 665 fin->fin_flx |= FI_BAD; 666 DT2(ipf_fi_bad_ipv6exthdr_once, fr_info_t *, fin, u_int, (fin->fin_optmsk & ip6exthdr[i].ol_bit)); 667 } else 668 fin->fin_optmsk |= ip6exthdr[i].ol_bit; 669 break; 670 } 671 672 return (hdr); 673 } 674 675 676 /* ------------------------------------------------------------------------ */ 677 /* Function: ipf_pr_hopopts6 */ 678 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 679 /* Parameters: fin(I) - pointer to packet information */ 680 /* */ 681 /* IPv6 Only */ 682 /* This is function checks pending hop by hop options extension header */ 683 /* ------------------------------------------------------------------------ */ 684 static inline int 685 ipf_pr_hopopts6(fr_info_t *fin) 686 { 687 struct ip6_ext *hdr; 688 689 hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS); 690 if (hdr == NULL) 691 return (IPPROTO_NONE); 692 return (hdr->ip6e_nxt); 693 } 694 695 696 /* ------------------------------------------------------------------------ */ 697 /* Function: ipf_pr_mobility6 */ 698 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 699 /* Parameters: fin(I) - pointer to packet information */ 700 /* */ 701 /* IPv6 Only */ 702 /* This is function checks the IPv6 mobility extension header */ 703 /* ------------------------------------------------------------------------ */ 704 static inline int 705 ipf_pr_mobility6(fr_info_t *fin) 706 { 707 struct ip6_ext *hdr; 708 709 hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_MOBILITY); 710 if (hdr == NULL) 711 return (IPPROTO_NONE); 712 return (hdr->ip6e_nxt); 713 } 714 715 716 /* ------------------------------------------------------------------------ */ 717 /* Function: ipf_pr_routing6 */ 718 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 719 /* Parameters: fin(I) - pointer to packet information */ 720 /* */ 721 /* IPv6 Only */ 722 /* This is function checks pending routing extension header */ 723 /* ------------------------------------------------------------------------ */ 724 static inline int 725 ipf_pr_routing6(fr_info_t *fin) 726 { 727 struct ip6_routing *hdr; 728 729 hdr = (struct ip6_routing *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_ROUTING); 730 if (hdr == NULL) 731 return (IPPROTO_NONE); 732 733 switch (hdr->ip6r_type) 734 { 735 case 0 : 736 /* 737 * Nasty extension header length? 738 */ 739 if (((hdr->ip6r_len >> 1) < hdr->ip6r_segleft) || 740 (hdr->ip6r_segleft && (hdr->ip6r_len & 1))) { 741 ipf_main_softc_t *softc = fin->fin_main_soft; 742 743 fin->fin_flx |= FI_BAD; 744 DT1(ipf_fi_bad_routing6, fr_info_t *, fin); 745 LBUMPD(ipf_stats[fin->fin_out], fr_v6_rh_bad); 746 return (IPPROTO_NONE); 747 } 748 break; 749 750 default : 751 break; 752 } 753 754 return (hdr->ip6r_nxt); 755 } 756 757 758 /* ------------------------------------------------------------------------ */ 759 /* Function: ipf_pr_fragment6 */ 760 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 761 /* Parameters: fin(I) - pointer to packet information */ 762 /* */ 763 /* IPv6 Only */ 764 /* Examine the IPv6 fragment header and extract fragment offset information.*/ 765 /* */ 766 /* Fragments in IPv6 are extraordinarily difficult to deal with - much more */ 767 /* so than in IPv4. There are 5 cases of fragments with IPv6 that all */ 768 /* packets with a fragment header can fit into. They are as follows: */ 769 /* */ 770 /* 1. [IPv6][0-n EH][FH][0-n EH] (no L4HDR present) */ 771 /* 2. [IPV6][0-n EH][FH][0-n EH][L4HDR part] (short) */ 772 /* 3. [IPV6][0-n EH][FH][L4HDR part][0-n data] (short) */ 773 /* 4. [IPV6][0-n EH][FH][0-n EH][L4HDR][0-n data] */ 774 /* 5. [IPV6][0-n EH][FH][data] */ 775 /* */ 776 /* IPV6 = IPv6 header, FH = Fragment Header, */ 777 /* 0-n EH = 0 or more extension headers, 0-n data = 0 or more bytes of data */ 778 /* */ 779 /* Packets that match 1, 2, 3 will be dropped as the only reasonable */ 780 /* scenario in which they happen is in extreme circumstances that are most */ 781 /* likely to be an indication of an attack rather than normal traffic. */ 782 /* A type 3 packet may be sent by an attacked after a type 4 packet. There */ 783 /* are two rules that can be used to guard against type 3 packets: L4 */ 784 /* headers must always be in a packet that has the offset field set to 0 */ 785 /* and no packet is allowed to overlay that where offset = 0. */ 786 /* ------------------------------------------------------------------------ */ 787 static inline int 788 ipf_pr_fragment6(fr_info_t *fin) 789 { 790 ipf_main_softc_t *softc = fin->fin_main_soft; 791 struct ip6_frag *frag; 792 793 fin->fin_flx |= FI_FRAG; 794 795 frag = (struct ip6_frag *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT); 796 if (frag == NULL) { 797 LBUMPD(ipf_stats[fin->fin_out], fr_v6_frag_bad); 798 return (IPPROTO_NONE); 799 } 800 801 if ((frag->ip6f_offlg & IP6F_MORE_FRAG) != 0) { 802 /* 803 * Any fragment that isn't the last fragment must have its 804 * length as a multiple of 8. 805 */ 806 if ((fin->fin_plen & 7) != 0) { 807 fin->fin_flx |= FI_BAD; 808 DT2(ipf_fi_bad_frag_not_8, fr_info_t *, fin, u_int, (fin->fin_plen & 7)); 809 } 810 } 811 812 fin->fin_fraghdr = frag; 813 fin->fin_id = frag->ip6f_ident; 814 fin->fin_off = ntohs(frag->ip6f_offlg & IP6F_OFF_MASK); 815 if (fin->fin_off != 0) 816 fin->fin_flx |= FI_FRAGBODY; 817 818 /* 819 * Jumbograms aren't handled, so the max. length is 64k 820 */ 821 if ((fin->fin_off << 3) + fin->fin_dlen > 65535) { 822 fin->fin_flx |= FI_BAD; 823 DT2(ipf_fi_bad_jumbogram, fr_info_t *, fin, u_int, ((fin->fin_off << 3) + fin->fin_dlen)); 824 } 825 826 /* 827 * We don't know where the transport layer header (or whatever is next 828 * is), as it could be behind destination options (amongst others) so 829 * return the fragment header as the type of packet this is. Note that 830 * this effectively disables the fragment cache for > 1 protocol at a 831 * time. 832 */ 833 return (frag->ip6f_nxt); 834 } 835 836 837 /* ------------------------------------------------------------------------ */ 838 /* Function: ipf_pr_dstopts6 */ 839 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 840 /* Parameters: fin(I) - pointer to packet information */ 841 /* */ 842 /* IPv6 Only */ 843 /* This is function checks pending destination options extension header */ 844 /* ------------------------------------------------------------------------ */ 845 static inline int 846 ipf_pr_dstopts6(fr_info_t *fin) 847 { 848 ipf_main_softc_t *softc = fin->fin_main_soft; 849 struct ip6_ext *hdr; 850 851 hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_DSTOPTS); 852 if (hdr == NULL) { 853 LBUMPD(ipf_stats[fin->fin_out], fr_v6_dst_bad); 854 return (IPPROTO_NONE); 855 } 856 return (hdr->ip6e_nxt); 857 } 858 859 860 /* ------------------------------------------------------------------------ */ 861 /* Function: ipf_pr_icmp6 */ 862 /* Returns: void */ 863 /* Parameters: fin(I) - pointer to packet information */ 864 /* */ 865 /* IPv6 Only */ 866 /* This routine is mainly concerned with determining the minimum valid size */ 867 /* for an ICMPv6 packet. */ 868 /* ------------------------------------------------------------------------ */ 869 static inline void 870 ipf_pr_icmp6(fr_info_t *fin) 871 { 872 int minicmpsz = sizeof(struct icmp6_hdr); 873 struct icmp6_hdr *icmp6; 874 875 if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1) { 876 ipf_main_softc_t *softc = fin->fin_main_soft; 877 878 LBUMPD(ipf_stats[fin->fin_out], fr_v6_icmp6_pullup); 879 return; 880 } 881 882 if (fin->fin_dlen > 1) { 883 ip6_t *ip6; 884 885 icmp6 = fin->fin_dp; 886 887 fin->fin_data[0] = *(u_short *)icmp6; 888 889 if ((icmp6->icmp6_type & ICMP6_INFOMSG_MASK) != 0) 890 fin->fin_flx |= FI_ICMPQUERY; 891 892 switch (icmp6->icmp6_type) 893 { 894 case ICMP6_ECHO_REPLY : 895 case ICMP6_ECHO_REQUEST : 896 if (fin->fin_dlen >= 6) 897 fin->fin_data[1] = icmp6->icmp6_id; 898 minicmpsz = ICMP6ERR_MINPKTLEN - sizeof(ip6_t); 899 break; 900 901 case ICMP6_DST_UNREACH : 902 case ICMP6_PACKET_TOO_BIG : 903 case ICMP6_TIME_EXCEEDED : 904 case ICMP6_PARAM_PROB : 905 fin->fin_flx |= FI_ICMPERR; 906 minicmpsz = ICMP6ERR_IPICMPHLEN - sizeof(ip6_t); 907 if (fin->fin_plen < ICMP6ERR_IPICMPHLEN) 908 break; 909 910 if (M_LEN(fin->fin_m) < fin->fin_plen) { 911 if (ipf_coalesce(fin) != 1) 912 return; 913 } 914 915 if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN) == -1) 916 return; 917 918 /* 919 * If the destination of this packet doesn't match the 920 * source of the original packet then this packet is 921 * not correct. 922 */ 923 icmp6 = fin->fin_dp; 924 ip6 = (ip6_t *)((char *)icmp6 + ICMPERR_ICMPHLEN); 925 if (IP6_NEQ(&fin->fin_fi.fi_dst, 926 (i6addr_t *)&ip6->ip6_src)) { 927 fin->fin_flx |= FI_BAD; 928 DT1(ipf_fi_bad_icmp6, fr_info_t *, fin); 929 } 930 break; 931 default : 932 break; 933 } 934 } 935 936 ipf_pr_short6(fin, minicmpsz); 937 if ((fin->fin_flx & (FI_SHORT|FI_BAD)) == 0) { 938 u_char p = fin->fin_p; 939 940 fin->fin_p = IPPROTO_ICMPV6; 941 ipf_checkv6sum(fin); 942 fin->fin_p = p; 943 } 944 } 945 946 947 /* ------------------------------------------------------------------------ */ 948 /* Function: ipf_pr_udp6 */ 949 /* Returns: void */ 950 /* Parameters: fin(I) - pointer to packet information */ 951 /* */ 952 /* IPv6 Only */ 953 /* Analyse the packet for IPv6/UDP properties. */ 954 /* Is not expected to be called for fragmented packets. */ 955 /* ------------------------------------------------------------------------ */ 956 static inline void 957 ipf_pr_udp6(fr_info_t *fin) 958 { 959 960 if (ipf_pr_udpcommon(fin) == 0) { 961 u_char p = fin->fin_p; 962 963 fin->fin_p = IPPROTO_UDP; 964 ipf_checkv6sum(fin); 965 fin->fin_p = p; 966 } 967 } 968 969 970 /* ------------------------------------------------------------------------ */ 971 /* Function: ipf_pr_tcp6 */ 972 /* Returns: void */ 973 /* Parameters: fin(I) - pointer to packet information */ 974 /* */ 975 /* IPv6 Only */ 976 /* Analyse the packet for IPv6/TCP properties. */ 977 /* Is not expected to be called for fragmented packets. */ 978 /* ------------------------------------------------------------------------ */ 979 static inline void 980 ipf_pr_tcp6(fr_info_t *fin) 981 { 982 983 if (ipf_pr_tcpcommon(fin) == 0) { 984 u_char p = fin->fin_p; 985 986 fin->fin_p = IPPROTO_TCP; 987 ipf_checkv6sum(fin); 988 fin->fin_p = p; 989 } 990 } 991 992 993 /* ------------------------------------------------------------------------ */ 994 /* Function: ipf_pr_esp6 */ 995 /* Returns: void */ 996 /* Parameters: fin(I) - pointer to packet information */ 997 /* */ 998 /* IPv6 Only */ 999 /* Analyse the packet for ESP properties. */ 1000 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ 1001 /* even though the newer ESP packets must also have a sequence number that */ 1002 /* is 32bits as well, it is not possible(?) to determine the version from a */ 1003 /* simple packet header. */ 1004 /* ------------------------------------------------------------------------ */ 1005 static inline void 1006 ipf_pr_esp6(fr_info_t *fin) 1007 { 1008 1009 if ((fin->fin_off == 0) && (ipf_pr_pullup(fin, 8) == -1)) { 1010 ipf_main_softc_t *softc = fin->fin_main_soft; 1011 1012 LBUMPD(ipf_stats[fin->fin_out], fr_v6_esp_pullup); 1013 return; 1014 } 1015 } 1016 1017 1018 /* ------------------------------------------------------------------------ */ 1019 /* Function: ipf_pr_ah6 */ 1020 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 1021 /* Parameters: fin(I) - pointer to packet information */ 1022 /* */ 1023 /* IPv6 Only */ 1024 /* Analyse the packet for AH properties. */ 1025 /* The minimum length is taken to be the combination of all fields in the */ 1026 /* header being present and no authentication data (null algorithm used.) */ 1027 /* ------------------------------------------------------------------------ */ 1028 static inline int 1029 ipf_pr_ah6(fr_info_t *fin) 1030 { 1031 authhdr_t *ah; 1032 1033 fin->fin_flx |= FI_AH; 1034 1035 ah = (authhdr_t *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS); 1036 if (ah == NULL) { 1037 ipf_main_softc_t *softc = fin->fin_main_soft; 1038 1039 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ah_bad); 1040 return (IPPROTO_NONE); 1041 } 1042 1043 ipf_pr_short6(fin, sizeof(*ah)); 1044 1045 /* 1046 * No need for another pullup, ipf_pr_ipv6exthdr() will pullup 1047 * enough data to satisfy ah_next (the very first one.) 1048 */ 1049 return (ah->ah_next); 1050 } 1051 1052 1053 /* ------------------------------------------------------------------------ */ 1054 /* Function: ipf_pr_gre6 */ 1055 /* Returns: void */ 1056 /* Parameters: fin(I) - pointer to packet information */ 1057 /* */ 1058 /* Analyse the packet for GRE properties. */ 1059 /* ------------------------------------------------------------------------ */ 1060 static inline void 1061 ipf_pr_gre6(fr_info_t *fin) 1062 { 1063 grehdr_t *gre; 1064 1065 if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) { 1066 ipf_main_softc_t *softc = fin->fin_main_soft; 1067 1068 LBUMPD(ipf_stats[fin->fin_out], fr_v6_gre_pullup); 1069 return; 1070 } 1071 1072 gre = fin->fin_dp; 1073 if (GRE_REV(gre->gr_flags) == 1) 1074 fin->fin_data[0] = gre->gr_call; 1075 } 1076 #endif /* USE_INET6 */ 1077 1078 1079 /* ------------------------------------------------------------------------ */ 1080 /* Function: ipf_pr_pullup */ 1081 /* Returns: int - 0 == pullup succeeded, -1 == failure */ 1082 /* Parameters: fin(I) - pointer to packet information */ 1083 /* plen(I) - length (excluding L3 header) to pullup */ 1084 /* */ 1085 /* Short inline function to cut down on code duplication to perform a call */ 1086 /* to ipf_pullup to ensure there is the required amount of data, */ 1087 /* consecutively in the packet buffer. */ 1088 /* */ 1089 /* This function pulls up 'extra' data at the location of fin_dp. fin_dp */ 1090 /* points to the first byte after the complete layer 3 header, which will */ 1091 /* include all of the known extension headers for IPv6 or options for IPv4. */ 1092 /* */ 1093 /* Since fr_pullup() expects the total length of bytes to be pulled up, it */ 1094 /* is necessary to add those we can already assume to be pulled up (fin_dp */ 1095 /* - fin_ip) to what is passed through. */ 1096 /* ------------------------------------------------------------------------ */ 1097 int 1098 ipf_pr_pullup(fr_info_t *fin, int plen) 1099 { 1100 ipf_main_softc_t *softc = fin->fin_main_soft; 1101 1102 if (fin->fin_m != NULL) { 1103 if (fin->fin_dp != NULL) 1104 plen += (char *)fin->fin_dp - 1105 ((char *)fin->fin_ip + fin->fin_hlen); 1106 plen += fin->fin_hlen; 1107 if (M_LEN(fin->fin_m) < plen + fin->fin_ipoff) { 1108 #if defined(_KERNEL) 1109 if (ipf_pullup(fin->fin_m, fin, plen) == NULL) { 1110 DT1(ipf_pullup_fail, fr_info_t *, fin); 1111 LBUMP(ipf_stats[fin->fin_out].fr_pull[1]); 1112 fin->fin_reason = FRB_PULLUP; 1113 fin->fin_flx |= FI_BAD; 1114 return (-1); 1115 } 1116 LBUMP(ipf_stats[fin->fin_out].fr_pull[0]); 1117 #else 1118 LBUMP(ipf_stats[fin->fin_out].fr_pull[1]); 1119 /* 1120 * Fake ipf_pullup failing 1121 */ 1122 fin->fin_reason = FRB_PULLUP; 1123 *fin->fin_mp = NULL; 1124 fin->fin_m = NULL; 1125 fin->fin_ip = NULL; 1126 fin->fin_flx |= FI_BAD; 1127 return (-1); 1128 #endif 1129 } 1130 } 1131 return (0); 1132 } 1133 1134 1135 /* ------------------------------------------------------------------------ */ 1136 /* Function: ipf_pr_short */ 1137 /* Returns: void */ 1138 /* Parameters: fin(I) - pointer to packet information */ 1139 /* xmin(I) - minimum header size */ 1140 /* */ 1141 /* Check if a packet is "short" as defined by xmin. The rule we are */ 1142 /* applying here is that the packet must not be fragmented within the layer */ 1143 /* 4 header. That is, it must not be a fragment that has its offset set to */ 1144 /* start within the layer 4 header (hdrmin) or if it is at offset 0, the */ 1145 /* entire layer 4 header must be present (min). */ 1146 /* ------------------------------------------------------------------------ */ 1147 static inline void 1148 ipf_pr_short(fr_info_t *fin, int xmin) 1149 { 1150 1151 if (fin->fin_off == 0) { 1152 if (fin->fin_dlen < xmin) 1153 fin->fin_flx |= FI_SHORT; 1154 } else if (fin->fin_off < xmin) { 1155 fin->fin_flx |= FI_SHORT; 1156 } 1157 } 1158 1159 1160 /* ------------------------------------------------------------------------ */ 1161 /* Function: ipf_pr_icmp */ 1162 /* Returns: void */ 1163 /* Parameters: fin(I) - pointer to packet information */ 1164 /* */ 1165 /* IPv4 Only */ 1166 /* Do a sanity check on the packet for ICMP (v4). In nearly all cases, */ 1167 /* except extrememly bad packets, both type and code will be present. */ 1168 /* The expected minimum size of an ICMP packet is very much dependent on */ 1169 /* the type of it. */ 1170 /* */ 1171 /* XXX - other ICMP sanity checks? */ 1172 /* ------------------------------------------------------------------------ */ 1173 static inline void 1174 ipf_pr_icmp(fr_info_t *fin) 1175 { 1176 ipf_main_softc_t *softc = fin->fin_main_soft; 1177 int minicmpsz = sizeof(struct icmp); 1178 icmphdr_t *icmp; 1179 ip_t *oip; 1180 1181 ipf_pr_short(fin, ICMPERR_ICMPHLEN); 1182 1183 if (fin->fin_off != 0) { 1184 LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_frag); 1185 return; 1186 } 1187 1188 if (ipf_pr_pullup(fin, ICMPERR_ICMPHLEN) == -1) { 1189 LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_pullup); 1190 return; 1191 } 1192 1193 icmp = fin->fin_dp; 1194 1195 fin->fin_data[0] = *(u_short *)icmp; 1196 fin->fin_data[1] = icmp->icmp_id; 1197 1198 switch (icmp->icmp_type) 1199 { 1200 case ICMP_ECHOREPLY : 1201 case ICMP_ECHO : 1202 /* Router discovery messaes - RFC 1256 */ 1203 case ICMP_ROUTERADVERT : 1204 case ICMP_ROUTERSOLICIT : 1205 fin->fin_flx |= FI_ICMPQUERY; 1206 minicmpsz = ICMP_MINLEN; 1207 break; 1208 /* 1209 * type(1) + code(1) + cksum(2) + id(2) seq(2) + 1210 * 3 * timestamp(3 * 4) 1211 */ 1212 case ICMP_TSTAMP : 1213 case ICMP_TSTAMPREPLY : 1214 fin->fin_flx |= FI_ICMPQUERY; 1215 minicmpsz = 20; 1216 break; 1217 /* 1218 * type(1) + code(1) + cksum(2) + id(2) seq(2) + 1219 * mask(4) 1220 */ 1221 case ICMP_IREQ : 1222 case ICMP_IREQREPLY : 1223 case ICMP_MASKREQ : 1224 case ICMP_MASKREPLY : 1225 fin->fin_flx |= FI_ICMPQUERY; 1226 minicmpsz = 12; 1227 break; 1228 /* 1229 * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+) 1230 */ 1231 case ICMP_UNREACH : 1232 #ifdef icmp_nextmtu 1233 if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG) { 1234 if (icmp->icmp_nextmtu < softc->ipf_icmpminfragmtu) { 1235 fin->fin_flx |= FI_BAD; 1236 DT3(ipf_fi_bad_icmp_nextmtu, fr_info_t *, fin, u_int, icmp->icmp_nextmtu, u_int, softc->ipf_icmpminfragmtu); 1237 } 1238 } 1239 #endif 1240 /* FALLTHROUGH */ 1241 case ICMP_SOURCEQUENCH : 1242 case ICMP_REDIRECT : 1243 case ICMP_TIMXCEED : 1244 case ICMP_PARAMPROB : 1245 fin->fin_flx |= FI_ICMPERR; 1246 if (ipf_coalesce(fin) != 1) { 1247 LBUMPD(ipf_stats[fin->fin_out], fr_icmp_coalesce); 1248 return; 1249 } 1250 1251 /* 1252 * ICMP error packets should not be generated for IP 1253 * packets that are a fragment that isn't the first 1254 * fragment. 1255 */ 1256 oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN); 1257 if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0) { 1258 fin->fin_flx |= FI_BAD; 1259 DT2(ipf_fi_bad_icmp_err, fr_info_t, fin, u_int, (ntohs(oip->ip_off) & IP_OFFMASK)); 1260 } 1261 1262 /* 1263 * If the destination of this packet doesn't match the 1264 * source of the original packet then this packet is 1265 * not correct. 1266 */ 1267 if (oip->ip_src.s_addr != fin->fin_daddr) { 1268 fin->fin_flx |= FI_BAD; 1269 DT1(ipf_fi_bad_src_ne_dst, fr_info_t *, fin); 1270 } 1271 break; 1272 default : 1273 break; 1274 } 1275 1276 ipf_pr_short(fin, minicmpsz); 1277 1278 ipf_checkv4sum(fin); 1279 } 1280 1281 1282 /* ------------------------------------------------------------------------ */ 1283 /* Function: ipf_pr_tcpcommon */ 1284 /* Returns: int - 0 = header ok, 1 = bad packet, -1 = buffer error */ 1285 /* Parameters: fin(I) - pointer to packet information */ 1286 /* */ 1287 /* TCP header sanity checking. Look for bad combinations of TCP flags, */ 1288 /* and make some checks with how they interact with other fields. */ 1289 /* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is */ 1290 /* valid and mark the packet as bad if not. */ 1291 /* ------------------------------------------------------------------------ */ 1292 static inline int 1293 ipf_pr_tcpcommon(fr_info_t *fin) 1294 { 1295 ipf_main_softc_t *softc = fin->fin_main_soft; 1296 int flags, tlen; 1297 tcphdr_t *tcp; 1298 1299 fin->fin_flx |= FI_TCPUDP; 1300 if (fin->fin_off != 0) { 1301 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_frag); 1302 return (0); 1303 } 1304 1305 if (ipf_pr_pullup(fin, sizeof(*tcp)) == -1) { 1306 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup); 1307 return (-1); 1308 } 1309 1310 tcp = fin->fin_dp; 1311 if (fin->fin_dlen > 3) { 1312 fin->fin_sport = ntohs(tcp->th_sport); 1313 fin->fin_dport = ntohs(tcp->th_dport); 1314 } 1315 1316 if ((fin->fin_flx & FI_SHORT) != 0) { 1317 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_short); 1318 return (1); 1319 } 1320 1321 /* 1322 * Use of the TCP data offset *must* result in a value that is at 1323 * least the same size as the TCP header. 1324 */ 1325 tlen = TCP_OFF(tcp) << 2; 1326 if (tlen < sizeof(tcphdr_t)) { 1327 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_small); 1328 fin->fin_flx |= FI_BAD; 1329 DT3(ipf_fi_bad_tlen, fr_info_t, fin, u_int, tlen, u_int, sizeof(tcphdr_t)); 1330 return (1); 1331 } 1332 1333 flags = tcp->th_flags; 1334 fin->fin_tcpf = tcp->th_flags; 1335 1336 /* 1337 * If the urgent flag is set, then the urgent pointer must 1338 * also be set and vice versa. Good TCP packets do not have 1339 * just one of these set. 1340 */ 1341 if ((flags & TH_URG) != 0 && (tcp->th_urp == 0)) { 1342 fin->fin_flx |= FI_BAD; 1343 DT3(ipf_fi_bad_th_urg, fr_info_t*, fin, u_int, (flags & TH_URG), u_int, tcp->th_urp); 1344 #if 0 1345 } else if ((flags & TH_URG) == 0 && (tcp->th_urp != 0)) { 1346 /* 1347 * Ignore this case (#if 0) as it shows up in "real" 1348 * traffic with bogus values in the urgent pointer field. 1349 */ 1350 fin->fin_flx |= FI_BAD; 1351 DT3(ipf_fi_bad_th_urg0, fr_info_t *, fin, u_int, (flags & TH_URG), u_int, tcp->th_urp); 1352 #endif 1353 } else if (((flags & (TH_SYN|TH_FIN)) != 0) && 1354 ((flags & (TH_RST|TH_ACK)) == TH_RST)) { 1355 /* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */ 1356 fin->fin_flx |= FI_BAD; 1357 DT1(ipf_fi_bad_th_fin_rst_ack, fr_info_t, fin); 1358 #if 1 1359 } else if (((flags & TH_SYN) != 0) && 1360 ((flags & (TH_URG|TH_PUSH)) != 0)) { 1361 /* 1362 * SYN with URG and PUSH set is not for normal TCP but it is 1363 * possible(?) with T/TCP...but who uses T/TCP? 1364 */ 1365 fin->fin_flx |= FI_BAD; 1366 DT1(ipf_fi_bad_th_syn_urg_psh, fr_info_t *, fin); 1367 #endif 1368 } else if (!(flags & TH_ACK)) { 1369 /* 1370 * If the ack bit isn't set, then either the SYN or 1371 * RST bit must be set. If the SYN bit is set, then 1372 * we expect the ACK field to be 0. If the ACK is 1373 * not set and if URG, PSH or FIN are set, consdier 1374 * that to indicate a bad TCP packet. 1375 */ 1376 if ((flags == TH_SYN) && (tcp->th_ack != 0)) { 1377 /* 1378 * Cisco PIX sets the ACK field to a random value. 1379 * In light of this, do not set FI_BAD until a patch 1380 * is available from Cisco to ensure that 1381 * interoperability between existing systems is 1382 * achieved. 1383 */ 1384 /*fin->fin_flx |= FI_BAD*/; 1385 /*DT1(ipf_fi_bad_th_syn_ack, fr_info_t *, fin);*/ 1386 } else if (!(flags & (TH_RST|TH_SYN))) { 1387 fin->fin_flx |= FI_BAD; 1388 DT1(ipf_fi_bad_th_rst_syn, fr_info_t *, fin); 1389 } else if ((flags & (TH_URG|TH_PUSH|TH_FIN)) != 0) { 1390 fin->fin_flx |= FI_BAD; 1391 DT1(ipf_fi_bad_th_urg_push_fin, fr_info_t *, fin); 1392 } 1393 } 1394 if (fin->fin_flx & FI_BAD) { 1395 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_bad_flags); 1396 return (1); 1397 } 1398 1399 /* 1400 * At this point, it's not exactly clear what is to be gained by 1401 * marking up which TCP options are and are not present. The one we 1402 * are most interested in is the TCP window scale. This is only in 1403 * a SYN packet [RFC1323] so we don't need this here...? 1404 * Now if we were to analyse the header for passive fingerprinting, 1405 * then that might add some weight to adding this... 1406 */ 1407 if (tlen == sizeof(tcphdr_t)) { 1408 return (0); 1409 } 1410 1411 if (ipf_pr_pullup(fin, tlen) == -1) { 1412 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup); 1413 return (-1); 1414 } 1415 1416 #if 0 1417 tcp = fin->fin_dp; 1418 ip = fin->fin_ip; 1419 s = (u_char *)(tcp + 1); 1420 off = IP_HL(ip) << 2; 1421 # ifdef _KERNEL 1422 if (fin->fin_mp != NULL) { 1423 mb_t *m = *fin->fin_mp; 1424 1425 if (off + tlen > M_LEN(m)) 1426 return; 1427 } 1428 # endif 1429 for (tlen -= (int)sizeof(*tcp); tlen > 0; ) { 1430 opt = *s; 1431 if (opt == '\0') 1432 break; 1433 else if (opt == TCPOPT_NOP) 1434 ol = 1; 1435 else { 1436 if (tlen < 2) 1437 break; 1438 ol = (int)*(s + 1); 1439 if (ol < 2 || ol > tlen) 1440 break; 1441 } 1442 1443 for (i = 9, mv = 4; mv >= 0; ) { 1444 op = ipopts + i; 1445 if (opt == (u_char)op->ol_val) { 1446 optmsk |= op->ol_bit; 1447 break; 1448 } 1449 } 1450 tlen -= ol; 1451 s += ol; 1452 } 1453 #endif /* 0 */ 1454 1455 return (0); 1456 } 1457 1458 1459 1460 /* ------------------------------------------------------------------------ */ 1461 /* Function: ipf_pr_udpcommon */ 1462 /* Returns: int - 0 = header ok, 1 = bad packet */ 1463 /* Parameters: fin(I) - pointer to packet information */ 1464 /* */ 1465 /* Extract the UDP source and destination ports, if present. If compiled */ 1466 /* with IPFILTER_CKSUM, check to see if the UDP checksum is valid. */ 1467 /* ------------------------------------------------------------------------ */ 1468 static inline int 1469 ipf_pr_udpcommon(fr_info_t *fin) 1470 { 1471 udphdr_t *udp; 1472 1473 fin->fin_flx |= FI_TCPUDP; 1474 1475 if (!fin->fin_off && (fin->fin_dlen > 3)) { 1476 if (ipf_pr_pullup(fin, sizeof(*udp)) == -1) { 1477 ipf_main_softc_t *softc = fin->fin_main_soft; 1478 1479 fin->fin_flx |= FI_SHORT; 1480 LBUMPD(ipf_stats[fin->fin_out], fr_udp_pullup); 1481 return (1); 1482 } 1483 1484 udp = fin->fin_dp; 1485 1486 fin->fin_sport = ntohs(udp->uh_sport); 1487 fin->fin_dport = ntohs(udp->uh_dport); 1488 } 1489 1490 return (0); 1491 } 1492 1493 1494 /* ------------------------------------------------------------------------ */ 1495 /* Function: ipf_pr_tcp */ 1496 /* Returns: void */ 1497 /* Parameters: fin(I) - pointer to packet information */ 1498 /* */ 1499 /* IPv4 Only */ 1500 /* Analyse the packet for IPv4/TCP properties. */ 1501 /* ------------------------------------------------------------------------ */ 1502 static inline void 1503 ipf_pr_tcp(fr_info_t *fin) 1504 { 1505 1506 ipf_pr_short(fin, sizeof(tcphdr_t)); 1507 1508 if (ipf_pr_tcpcommon(fin) == 0) 1509 ipf_checkv4sum(fin); 1510 } 1511 1512 1513 /* ------------------------------------------------------------------------ */ 1514 /* Function: ipf_pr_udp */ 1515 /* Returns: void */ 1516 /* Parameters: fin(I) - pointer to packet information */ 1517 /* */ 1518 /* IPv4 Only */ 1519 /* Analyse the packet for IPv4/UDP properties. */ 1520 /* ------------------------------------------------------------------------ */ 1521 static inline void 1522 ipf_pr_udp(fr_info_t *fin) 1523 { 1524 1525 ipf_pr_short(fin, sizeof(udphdr_t)); 1526 1527 if (ipf_pr_udpcommon(fin) == 0) 1528 ipf_checkv4sum(fin); 1529 } 1530 1531 1532 /* ------------------------------------------------------------------------ */ 1533 /* Function: ipf_pr_esp */ 1534 /* Returns: void */ 1535 /* Parameters: fin(I) - pointer to packet information */ 1536 /* */ 1537 /* Analyse the packet for ESP properties. */ 1538 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ 1539 /* even though the newer ESP packets must also have a sequence number that */ 1540 /* is 32bits as well, it is not possible(?) to determine the version from a */ 1541 /* simple packet header. */ 1542 /* ------------------------------------------------------------------------ */ 1543 static inline void 1544 ipf_pr_esp(fr_info_t *fin) 1545 { 1546 1547 if (fin->fin_off == 0) { 1548 ipf_pr_short(fin, 8); 1549 if (ipf_pr_pullup(fin, 8) == -1) { 1550 ipf_main_softc_t *softc = fin->fin_main_soft; 1551 1552 LBUMPD(ipf_stats[fin->fin_out], fr_v4_esp_pullup); 1553 } 1554 } 1555 } 1556 1557 1558 /* ------------------------------------------------------------------------ */ 1559 /* Function: ipf_pr_ah */ 1560 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 1561 /* Parameters: fin(I) - pointer to packet information */ 1562 /* */ 1563 /* Analyse the packet for AH properties. */ 1564 /* The minimum length is taken to be the combination of all fields in the */ 1565 /* header being present and no authentication data (null algorithm used.) */ 1566 /* ------------------------------------------------------------------------ */ 1567 static inline int 1568 ipf_pr_ah(fr_info_t *fin) 1569 { 1570 ipf_main_softc_t *softc = fin->fin_main_soft; 1571 authhdr_t *ah; 1572 int len; 1573 1574 fin->fin_flx |= FI_AH; 1575 ipf_pr_short(fin, sizeof(*ah)); 1576 1577 if (((fin->fin_flx & FI_SHORT) != 0) || (fin->fin_off != 0)) { 1578 LBUMPD(ipf_stats[fin->fin_out], fr_v4_ah_bad); 1579 return (IPPROTO_NONE); 1580 } 1581 1582 if (ipf_pr_pullup(fin, sizeof(*ah)) == -1) { 1583 DT(fr_v4_ah_pullup_1); 1584 LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup); 1585 return (IPPROTO_NONE); 1586 } 1587 1588 ah = (authhdr_t *)fin->fin_dp; 1589 1590 len = (ah->ah_plen + 2) << 2; 1591 ipf_pr_short(fin, len); 1592 if (ipf_pr_pullup(fin, len) == -1) { 1593 DT(fr_v4_ah_pullup_2); 1594 LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup); 1595 return (IPPROTO_NONE); 1596 } 1597 1598 /* 1599 * Adjust fin_dp and fin_dlen for skipping over the authentication 1600 * header. 1601 */ 1602 fin->fin_dp = (char *)fin->fin_dp + len; 1603 fin->fin_dlen -= len; 1604 return (ah->ah_next); 1605 } 1606 1607 1608 /* ------------------------------------------------------------------------ */ 1609 /* Function: ipf_pr_gre */ 1610 /* Returns: void */ 1611 /* Parameters: fin(I) - pointer to packet information */ 1612 /* */ 1613 /* Analyse the packet for GRE properties. */ 1614 /* ------------------------------------------------------------------------ */ 1615 static inline void 1616 ipf_pr_gre(fr_info_t *fin) 1617 { 1618 ipf_main_softc_t *softc = fin->fin_main_soft; 1619 grehdr_t *gre; 1620 1621 ipf_pr_short(fin, sizeof(grehdr_t)); 1622 1623 if (fin->fin_off != 0) { 1624 LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_frag); 1625 return; 1626 } 1627 1628 if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) { 1629 LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_pullup); 1630 return; 1631 } 1632 1633 gre = fin->fin_dp; 1634 if (GRE_REV(gre->gr_flags) == 1) 1635 fin->fin_data[0] = gre->gr_call; 1636 } 1637 1638 1639 /* ------------------------------------------------------------------------ */ 1640 /* Function: ipf_pr_ipv4hdr */ 1641 /* Returns: void */ 1642 /* Parameters: fin(I) - pointer to packet information */ 1643 /* */ 1644 /* IPv4 Only */ 1645 /* Analyze the IPv4 header and set fields in the fr_info_t structure. */ 1646 /* Check all options present and flag their presence if any exist. */ 1647 /* ------------------------------------------------------------------------ */ 1648 static inline void 1649 ipf_pr_ipv4hdr(fr_info_t *fin) 1650 { 1651 u_short optmsk = 0, secmsk = 0, auth = 0; 1652 int hlen, ol, mv, p, i; 1653 const struct optlist *op; 1654 u_char *s, opt; 1655 u_short off; 1656 fr_ip_t *fi; 1657 ip_t *ip; 1658 1659 fi = &fin->fin_fi; 1660 hlen = fin->fin_hlen; 1661 1662 ip = fin->fin_ip; 1663 p = ip->ip_p; 1664 fi->fi_p = p; 1665 fin->fin_crc = p; 1666 fi->fi_tos = ip->ip_tos; 1667 fin->fin_id = ntohs(ip->ip_id); 1668 off = ntohs(ip->ip_off); 1669 1670 /* Get both TTL and protocol */ 1671 fi->fi_p = ip->ip_p; 1672 fi->fi_ttl = ip->ip_ttl; 1673 1674 /* Zero out bits not used in IPv6 address */ 1675 fi->fi_src.i6[1] = 0; 1676 fi->fi_src.i6[2] = 0; 1677 fi->fi_src.i6[3] = 0; 1678 fi->fi_dst.i6[1] = 0; 1679 fi->fi_dst.i6[2] = 0; 1680 fi->fi_dst.i6[3] = 0; 1681 1682 fi->fi_saddr = ip->ip_src.s_addr; 1683 fin->fin_crc += fi->fi_saddr; 1684 fi->fi_daddr = ip->ip_dst.s_addr; 1685 fin->fin_crc += fi->fi_daddr; 1686 if (IN_MULTICAST(ntohl(fi->fi_daddr))) 1687 fin->fin_flx |= FI_MULTICAST|FI_MBCAST; 1688 1689 /* 1690 * set packet attribute flags based on the offset and 1691 * calculate the byte offset that it represents. 1692 */ 1693 off &= IP_MF|IP_OFFMASK; 1694 if (off != 0) { 1695 int morefrag = off & IP_MF; 1696 1697 fi->fi_flx |= FI_FRAG; 1698 off &= IP_OFFMASK; 1699 if (off == 1 && p == IPPROTO_TCP) { 1700 fin->fin_flx |= FI_SHORT; /* RFC 3128 */ 1701 DT1(ipf_fi_tcp_frag_off_1, fr_info_t *, fin); 1702 } 1703 if (off != 0) { 1704 fin->fin_flx |= FI_FRAGBODY; 1705 off <<= 3; 1706 if ((off + fin->fin_dlen > 65535) || 1707 (fin->fin_dlen == 0) || 1708 ((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) { 1709 /* 1710 * The length of the packet, starting at its 1711 * offset cannot exceed 65535 (0xffff) as the 1712 * length of an IP packet is only 16 bits. 1713 * 1714 * Any fragment that isn't the last fragment 1715 * must have a length greater than 0 and it 1716 * must be an even multiple of 8. 1717 */ 1718 fi->fi_flx |= FI_BAD; 1719 DT1(ipf_fi_bad_fragbody_gt_65535, fr_info_t *, fin); 1720 } 1721 } 1722 } 1723 fin->fin_off = off; 1724 1725 /* 1726 * Call per-protocol setup and checking 1727 */ 1728 if (p == IPPROTO_AH) { 1729 /* 1730 * Treat AH differently because we expect there to be another 1731 * layer 4 header after it. 1732 */ 1733 p = ipf_pr_ah(fin); 1734 } 1735 1736 switch (p) 1737 { 1738 case IPPROTO_UDP : 1739 ipf_pr_udp(fin); 1740 break; 1741 case IPPROTO_TCP : 1742 ipf_pr_tcp(fin); 1743 break; 1744 case IPPROTO_ICMP : 1745 ipf_pr_icmp(fin); 1746 break; 1747 case IPPROTO_ESP : 1748 ipf_pr_esp(fin); 1749 break; 1750 case IPPROTO_GRE : 1751 ipf_pr_gre(fin); 1752 break; 1753 } 1754 1755 ip = fin->fin_ip; 1756 if (ip == NULL) 1757 return; 1758 1759 /* 1760 * If it is a standard IP header (no options), set the flag fields 1761 * which relate to options to 0. 1762 */ 1763 if (hlen == sizeof(*ip)) { 1764 fi->fi_optmsk = 0; 1765 fi->fi_secmsk = 0; 1766 fi->fi_auth = 0; 1767 return; 1768 } 1769 1770 /* 1771 * So the IP header has some IP options attached. Walk the entire 1772 * list of options present with this packet and set flags to indicate 1773 * which ones are here and which ones are not. For the somewhat out 1774 * of date and obscure security classification options, set a flag to 1775 * represent which classification is present. 1776 */ 1777 fi->fi_flx |= FI_OPTIONS; 1778 1779 for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) { 1780 opt = *s; 1781 if (opt == '\0') 1782 break; 1783 else if (opt == IPOPT_NOP) 1784 ol = 1; 1785 else { 1786 if (hlen < 2) 1787 break; 1788 ol = (int)*(s + 1); 1789 if (ol < 2 || ol > hlen) 1790 break; 1791 } 1792 for (i = 9, mv = 4; mv >= 0; ) { 1793 op = ipopts + i; 1794 1795 if ((opt == (u_char)op->ol_val) && (ol > 4)) { 1796 u_32_t doi; 1797 1798 switch (opt) 1799 { 1800 case IPOPT_SECURITY : 1801 if (optmsk & op->ol_bit) { 1802 fin->fin_flx |= FI_BAD; 1803 DT2(ipf_fi_bad_ipopt_security, fr_info_t *, fin, u_short, (optmsk & op->ol_bit)); 1804 } else { 1805 doi = ipf_checkripso(s); 1806 secmsk = doi >> 16; 1807 auth = doi & 0xffff; 1808 } 1809 break; 1810 1811 case IPOPT_CIPSO : 1812 1813 if (optmsk & op->ol_bit) { 1814 fin->fin_flx |= FI_BAD; 1815 DT2(ipf_fi_bad_ipopt_cipso, fr_info_t *, fin, u_short, (optmsk & op->ol_bit)); 1816 } else { 1817 doi = ipf_checkcipso(fin, 1818 s, ol); 1819 secmsk = doi >> 16; 1820 auth = doi & 0xffff; 1821 } 1822 break; 1823 } 1824 optmsk |= op->ol_bit; 1825 } 1826 1827 if (opt < op->ol_val) 1828 i -= mv; 1829 else 1830 i += mv; 1831 mv--; 1832 } 1833 hlen -= ol; 1834 s += ol; 1835 } 1836 1837 /* 1838 * 1839 */ 1840 if (auth && !(auth & 0x0100)) 1841 auth &= 0xff00; 1842 fi->fi_optmsk = optmsk; 1843 fi->fi_secmsk = secmsk; 1844 fi->fi_auth = auth; 1845 } 1846 1847 1848 /* ------------------------------------------------------------------------ */ 1849 /* Function: ipf_checkripso */ 1850 /* Returns: void */ 1851 /* Parameters: s(I) - pointer to start of RIPSO option */ 1852 /* */ 1853 /* ------------------------------------------------------------------------ */ 1854 static u_32_t 1855 ipf_checkripso(u_char *s) 1856 { 1857 const struct optlist *sp; 1858 u_short secmsk = 0, auth = 0; 1859 u_char sec; 1860 int j, m; 1861 1862 sec = *(s + 2); /* classification */ 1863 for (j = 3, m = 2; m >= 0; ) { 1864 sp = secopt + j; 1865 if (sec == sp->ol_val) { 1866 secmsk |= sp->ol_bit; 1867 auth = *(s + 3); 1868 auth *= 256; 1869 auth += *(s + 4); 1870 break; 1871 } 1872 if (sec < sp->ol_val) 1873 j -= m; 1874 else 1875 j += m; 1876 m--; 1877 } 1878 1879 return (secmsk << 16) | auth; 1880 } 1881 1882 1883 /* ------------------------------------------------------------------------ */ 1884 /* Function: ipf_checkcipso */ 1885 /* Returns: u_32_t - 0 = failure, else the doi from the header */ 1886 /* Parameters: fin(IO) - pointer to packet information */ 1887 /* s(I) - pointer to start of CIPSO option */ 1888 /* ol(I) - length of CIPSO option field */ 1889 /* */ 1890 /* This function returns the domain of integrity (DOI) field from the CIPSO */ 1891 /* header and returns that whilst also storing the highest sensitivity */ 1892 /* value found in the fr_info_t structure. */ 1893 /* */ 1894 /* No attempt is made to extract the category bitmaps as these are defined */ 1895 /* by the user (rather than the protocol) and can be rather numerous on the */ 1896 /* end nodes. */ 1897 /* ------------------------------------------------------------------------ */ 1898 static u_32_t 1899 ipf_checkcipso(fr_info_t *fin, u_char *s, int ol) 1900 { 1901 ipf_main_softc_t *softc = fin->fin_main_soft; 1902 fr_ip_t *fi; 1903 u_32_t doi; 1904 u_char *t, tag, tlen, sensitivity; 1905 int len; 1906 1907 if (ol < 6 || ol > 40) { 1908 LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_bad); 1909 fin->fin_flx |= FI_BAD; 1910 DT2(ipf_fi_bad_checkcipso_ol, fr_info_t *, fin, u_int, ol); 1911 return (0); 1912 } 1913 1914 fi = &fin->fin_fi; 1915 fi->fi_sensitivity = 0; 1916 /* 1917 * The DOI field MUST be there. 1918 */ 1919 bcopy(s + 2, &doi, sizeof(doi)); 1920 1921 t = (u_char *)s + 6; 1922 for (len = ol - 6; len >= 2; len -= tlen, t+= tlen) { 1923 tag = *t; 1924 tlen = *(t + 1); 1925 if (tlen > len || tlen < 4 || tlen > 34) { 1926 LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_tlen); 1927 fin->fin_flx |= FI_BAD; 1928 DT2(ipf_fi_bad_checkcipso_tlen, fr_info_t *, fin, u_int, tlen); 1929 return (0); 1930 } 1931 1932 sensitivity = 0; 1933 /* 1934 * Tag numbers 0, 1, 2, 5 are laid out in the CIPSO Internet 1935 * draft (16 July 1992) that has expired. 1936 */ 1937 if (tag == 0) { 1938 fin->fin_flx |= FI_BAD; 1939 DT2(ipf_fi_bad_checkcipso_tag, fr_info_t *, fin, u_int, tag); 1940 continue; 1941 } else if (tag == 1) { 1942 if (*(t + 2) != 0) { 1943 fin->fin_flx |= FI_BAD; 1944 DT2(ipf_fi_bad_checkcipso_tag1_t2, fr_info_t *, fin, u_int, (*t + 2)); 1945 continue; 1946 } 1947 sensitivity = *(t + 3); 1948 /* Category bitmap for categories 0-239 */ 1949 1950 } else if (tag == 4) { 1951 if (*(t + 2) != 0) { 1952 fin->fin_flx |= FI_BAD; 1953 DT2(ipf_fi_bad_checkcipso_tag4_t2, fr_info_t *, fin, u_int, (*t + 2)); 1954 continue; 1955 } 1956 sensitivity = *(t + 3); 1957 /* Enumerated categories, 16bits each, upto 15 */ 1958 1959 } else if (tag == 5) { 1960 if (*(t + 2) != 0) { 1961 fin->fin_flx |= FI_BAD; 1962 DT2(ipf_fi_bad_checkcipso_tag5_t2, fr_info_t *, fin, u_int, (*t + 2)); 1963 continue; 1964 } 1965 sensitivity = *(t + 3); 1966 /* Range of categories (2*16bits), up to 7 pairs */ 1967 1968 } else if (tag > 127) { 1969 /* Custom defined DOI */ 1970 ; 1971 } else { 1972 fin->fin_flx |= FI_BAD; 1973 DT2(ipf_fi_bad_checkcipso_tag127, fr_info_t *, fin, u_int, tag); 1974 continue; 1975 } 1976 1977 if (sensitivity > fi->fi_sensitivity) 1978 fi->fi_sensitivity = sensitivity; 1979 } 1980 1981 return (doi); 1982 } 1983 1984 1985 /* ------------------------------------------------------------------------ */ 1986 /* Function: ipf_makefrip */ 1987 /* Returns: int - 0 == packet ok, -1 == packet freed */ 1988 /* Parameters: hlen(I) - length of IP packet header */ 1989 /* ip(I) - pointer to the IP header */ 1990 /* fin(IO) - pointer to packet information */ 1991 /* */ 1992 /* Compact the IP header into a structure which contains just the info. */ 1993 /* which is useful for comparing IP headers with and store this information */ 1994 /* in the fr_info_t structure pointer to by fin. At present, it is assumed */ 1995 /* this function will be called with either an IPv4 or IPv6 packet. */ 1996 /* ------------------------------------------------------------------------ */ 1997 int 1998 ipf_makefrip(int hlen, ip_t *ip, fr_info_t *fin) 1999 { 2000 ipf_main_softc_t *softc = fin->fin_main_soft; 2001 int v; 2002 2003 fin->fin_depth = 0; 2004 fin->fin_hlen = (u_short)hlen; 2005 fin->fin_ip = ip; 2006 fin->fin_rule = 0xffffffff; 2007 fin->fin_group[0] = -1; 2008 fin->fin_group[1] = '\0'; 2009 fin->fin_dp = (char *)ip + hlen; 2010 2011 v = fin->fin_v; 2012 if (v == 4) { 2013 fin->fin_plen = ntohs(ip->ip_len); 2014 fin->fin_dlen = fin->fin_plen - hlen; 2015 ipf_pr_ipv4hdr(fin); 2016 #ifdef USE_INET6 2017 } else if (v == 6) { 2018 fin->fin_plen = ntohs(((ip6_t *)ip)->ip6_plen); 2019 fin->fin_dlen = fin->fin_plen; 2020 fin->fin_plen += hlen; 2021 2022 ipf_pr_ipv6hdr(fin); 2023 #endif 2024 } 2025 if (fin->fin_ip == NULL) { 2026 LBUMP(ipf_stats[fin->fin_out].fr_ip_freed); 2027 return (-1); 2028 } 2029 return (0); 2030 } 2031 2032 2033 /* ------------------------------------------------------------------------ */ 2034 /* Function: ipf_portcheck */ 2035 /* Returns: int - 1 == port matched, 0 == port match failed */ 2036 /* Parameters: frp(I) - pointer to port check `expression' */ 2037 /* pop(I) - port number to evaluate */ 2038 /* */ 2039 /* Perform a comparison of a port number against some other(s), using a */ 2040 /* structure with compare information stored in it. */ 2041 /* ------------------------------------------------------------------------ */ 2042 static inline int 2043 ipf_portcheck(frpcmp_t *frp, u_32_t pop) 2044 { 2045 int err = 1; 2046 u_32_t po; 2047 2048 po = frp->frp_port; 2049 2050 /* 2051 * Do opposite test to that required and continue if that succeeds. 2052 */ 2053 switch (frp->frp_cmp) 2054 { 2055 case FR_EQUAL : 2056 if (pop != po) /* EQUAL */ 2057 err = 0; 2058 break; 2059 case FR_NEQUAL : 2060 if (pop == po) /* NOTEQUAL */ 2061 err = 0; 2062 break; 2063 case FR_LESST : 2064 if (pop >= po) /* LESSTHAN */ 2065 err = 0; 2066 break; 2067 case FR_GREATERT : 2068 if (pop <= po) /* GREATERTHAN */ 2069 err = 0; 2070 break; 2071 case FR_LESSTE : 2072 if (pop > po) /* LT or EQ */ 2073 err = 0; 2074 break; 2075 case FR_GREATERTE : 2076 if (pop < po) /* GT or EQ */ 2077 err = 0; 2078 break; 2079 case FR_OUTRANGE : 2080 if (pop >= po && pop <= frp->frp_top) /* Out of range */ 2081 err = 0; 2082 break; 2083 case FR_INRANGE : 2084 if (pop <= po || pop >= frp->frp_top) /* In range */ 2085 err = 0; 2086 break; 2087 case FR_INCRANGE : 2088 if (pop < po || pop > frp->frp_top) /* Inclusive range */ 2089 err = 0; 2090 break; 2091 default : 2092 break; 2093 } 2094 return (err); 2095 } 2096 2097 2098 /* ------------------------------------------------------------------------ */ 2099 /* Function: ipf_tcpudpchk */ 2100 /* Returns: int - 1 == protocol matched, 0 == check failed */ 2101 /* Parameters: fda(I) - pointer to packet information */ 2102 /* ft(I) - pointer to structure with comparison data */ 2103 /* */ 2104 /* Compares the current pcket (assuming it is TCP/UDP) information with a */ 2105 /* structure containing information that we want to match against. */ 2106 /* ------------------------------------------------------------------------ */ 2107 int 2108 ipf_tcpudpchk(fr_ip_t *fi, frtuc_t *ft) 2109 { 2110 int err = 1; 2111 2112 /* 2113 * Both ports should *always* be in the first fragment. 2114 * So far, I cannot find any cases where they can not be. 2115 * 2116 * compare destination ports 2117 */ 2118 if (ft->ftu_dcmp) 2119 err = ipf_portcheck(&ft->ftu_dst, fi->fi_ports[1]); 2120 2121 /* 2122 * compare source ports 2123 */ 2124 if (err && ft->ftu_scmp) 2125 err = ipf_portcheck(&ft->ftu_src, fi->fi_ports[0]); 2126 2127 /* 2128 * If we don't have all the TCP/UDP header, then how can we 2129 * expect to do any sort of match on it ? If we were looking for 2130 * TCP flags, then NO match. If not, then match (which should 2131 * satisfy the "short" class too). 2132 */ 2133 if (err && (fi->fi_p == IPPROTO_TCP)) { 2134 if (fi->fi_flx & FI_SHORT) 2135 return (!(ft->ftu_tcpf | ft->ftu_tcpfm)); 2136 /* 2137 * Match the flags ? If not, abort this match. 2138 */ 2139 if (ft->ftu_tcpfm && 2140 ft->ftu_tcpf != (fi->fi_tcpf & ft->ftu_tcpfm)) { 2141 FR_DEBUG(("f. %#x & %#x != %#x\n", fi->fi_tcpf, 2142 ft->ftu_tcpfm, ft->ftu_tcpf)); 2143 err = 0; 2144 } 2145 } 2146 return (err); 2147 } 2148 2149 2150 /* ------------------------------------------------------------------------ */ 2151 /* Function: ipf_check_ipf */ 2152 /* Returns: int - 0 == match, else no match */ 2153 /* Parameters: fin(I) - pointer to packet information */ 2154 /* fr(I) - pointer to filter rule */ 2155 /* portcmp(I) - flag indicating whether to attempt matching on */ 2156 /* TCP/UDP port data. */ 2157 /* */ 2158 /* Check to see if a packet matches an IPFilter rule. Checks of addresses, */ 2159 /* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */ 2160 /* this function. */ 2161 /* ------------------------------------------------------------------------ */ 2162 static inline int 2163 ipf_check_ipf(fr_info_t *fin, frentry_t *fr, int portcmp) 2164 { 2165 u_32_t *ld, *lm, *lip; 2166 fripf_t *fri; 2167 fr_ip_t *fi; 2168 int i; 2169 2170 fi = &fin->fin_fi; 2171 fri = fr->fr_ipf; 2172 lip = (u_32_t *)fi; 2173 lm = (u_32_t *)&fri->fri_mip; 2174 ld = (u_32_t *)&fri->fri_ip; 2175 2176 /* 2177 * first 32 bits to check coversion: 2178 * IP version, TOS, TTL, protocol 2179 */ 2180 i = ((*lip & *lm) != *ld); 2181 FR_DEBUG(("0. %#08x & %#08x != %#08x\n", 2182 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2183 if (i) 2184 return (1); 2185 2186 /* 2187 * Next 32 bits is a constructed bitmask indicating which IP options 2188 * are present (if any) in this packet. 2189 */ 2190 lip++, lm++, ld++; 2191 i = ((*lip & *lm) != *ld); 2192 FR_DEBUG(("1. %#08x & %#08x != %#08x\n", 2193 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2194 if (i != 0) 2195 return (1); 2196 2197 lip++, lm++, ld++; 2198 /* 2199 * Unrolled loops (4 each, for 32 bits) for address checks. 2200 */ 2201 /* 2202 * Check the source address. 2203 */ 2204 if (fr->fr_satype == FRI_LOOKUP) { 2205 i = (*fr->fr_srcfunc)(fin->fin_main_soft, fr->fr_srcptr, 2206 fi->fi_v, lip, fin->fin_plen); 2207 if (i == -1) 2208 return (1); 2209 lip += 3; 2210 lm += 3; 2211 ld += 3; 2212 } else { 2213 i = ((*lip & *lm) != *ld); 2214 FR_DEBUG(("2a. %#08x & %#08x != %#08x\n", 2215 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2216 if (fi->fi_v == 6) { 2217 lip++, lm++, ld++; 2218 i |= ((*lip & *lm) != *ld); 2219 FR_DEBUG(("2b. %#08x & %#08x != %#08x\n", 2220 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2221 lip++, lm++, ld++; 2222 i |= ((*lip & *lm) != *ld); 2223 FR_DEBUG(("2c. %#08x & %#08x != %#08x\n", 2224 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2225 lip++, lm++, ld++; 2226 i |= ((*lip & *lm) != *ld); 2227 FR_DEBUG(("2d. %#08x & %#08x != %#08x\n", 2228 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2229 } else { 2230 lip += 3; 2231 lm += 3; 2232 ld += 3; 2233 } 2234 } 2235 i ^= (fr->fr_flags & FR_NOTSRCIP) >> 6; 2236 if (i != 0) 2237 return (1); 2238 2239 /* 2240 * Check the destination address. 2241 */ 2242 lip++, lm++, ld++; 2243 if (fr->fr_datype == FRI_LOOKUP) { 2244 i = (*fr->fr_dstfunc)(fin->fin_main_soft, fr->fr_dstptr, 2245 fi->fi_v, lip, fin->fin_plen); 2246 if (i == -1) 2247 return (1); 2248 lip += 3; 2249 lm += 3; 2250 ld += 3; 2251 } else { 2252 i = ((*lip & *lm) != *ld); 2253 FR_DEBUG(("3a. %#08x & %#08x != %#08x\n", 2254 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2255 if (fi->fi_v == 6) { 2256 lip++, lm++, ld++; 2257 i |= ((*lip & *lm) != *ld); 2258 FR_DEBUG(("3b. %#08x & %#08x != %#08x\n", 2259 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2260 lip++, lm++, ld++; 2261 i |= ((*lip & *lm) != *ld); 2262 FR_DEBUG(("3c. %#08x & %#08x != %#08x\n", 2263 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2264 lip++, lm++, ld++; 2265 i |= ((*lip & *lm) != *ld); 2266 FR_DEBUG(("3d. %#08x & %#08x != %#08x\n", 2267 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2268 } else { 2269 lip += 3; 2270 lm += 3; 2271 ld += 3; 2272 } 2273 } 2274 i ^= (fr->fr_flags & FR_NOTDSTIP) >> 7; 2275 if (i != 0) 2276 return (1); 2277 /* 2278 * IP addresses matched. The next 32bits contains: 2279 * mast of old IP header security & authentication bits. 2280 */ 2281 lip++, lm++, ld++; 2282 i = (*ld - (*lip & *lm)); 2283 FR_DEBUG(("4. %#08x & %#08x != %#08x\n", *lip, *lm, *ld)); 2284 2285 /* 2286 * Next we have 32 bits of packet flags. 2287 */ 2288 lip++, lm++, ld++; 2289 i |= (*ld - (*lip & *lm)); 2290 FR_DEBUG(("5. %#08x & %#08x != %#08x\n", *lip, *lm, *ld)); 2291 2292 if (i == 0) { 2293 /* 2294 * If a fragment, then only the first has what we're 2295 * looking for here... 2296 */ 2297 if (portcmp) { 2298 if (!ipf_tcpudpchk(&fin->fin_fi, &fr->fr_tuc)) 2299 i = 1; 2300 } else { 2301 if (fr->fr_dcmp || fr->fr_scmp || 2302 fr->fr_tcpf || fr->fr_tcpfm) 2303 i = 1; 2304 if (fr->fr_icmpm || fr->fr_icmp) { 2305 if (((fi->fi_p != IPPROTO_ICMP) && 2306 (fi->fi_p != IPPROTO_ICMPV6)) || 2307 fin->fin_off || (fin->fin_dlen < 2)) 2308 i = 1; 2309 else if ((fin->fin_data[0] & fr->fr_icmpm) != 2310 fr->fr_icmp) { 2311 FR_DEBUG(("i. %#x & %#x != %#x\n", 2312 fin->fin_data[0], 2313 fr->fr_icmpm, fr->fr_icmp)); 2314 i = 1; 2315 } 2316 } 2317 } 2318 } 2319 return (i); 2320 } 2321 2322 2323 /* ------------------------------------------------------------------------ */ 2324 /* Function: ipf_scanlist */ 2325 /* Returns: int - result flags of scanning filter list */ 2326 /* Parameters: fin(I) - pointer to packet information */ 2327 /* pass(I) - default result to return for filtering */ 2328 /* */ 2329 /* Check the input/output list of rules for a match to the current packet. */ 2330 /* If a match is found, the value of fr_flags from the rule becomes the */ 2331 /* return value and fin->fin_fr points to the matched rule. */ 2332 /* */ 2333 /* This function may be called recursively upto 16 times (limit inbuilt.) */ 2334 /* When unwinding, it should finish up with fin_depth as 0. */ 2335 /* */ 2336 /* Could be per interface, but this gets real nasty when you don't have, */ 2337 /* or can't easily change, the kernel source code to . */ 2338 /* ------------------------------------------------------------------------ */ 2339 int 2340 ipf_scanlist(fr_info_t *fin, u_32_t pass) 2341 { 2342 ipf_main_softc_t *softc = fin->fin_main_soft; 2343 int rulen, portcmp, off, skip; 2344 struct frentry *fr, *fnext; 2345 u_32_t passt, passo; 2346 2347 /* 2348 * Do not allow nesting deeper than 16 levels. 2349 */ 2350 if (fin->fin_depth >= 16) 2351 return (pass); 2352 2353 fr = fin->fin_fr; 2354 2355 /* 2356 * If there are no rules in this list, return now. 2357 */ 2358 if (fr == NULL) 2359 return (pass); 2360 2361 skip = 0; 2362 portcmp = 0; 2363 fin->fin_depth++; 2364 fin->fin_fr = NULL; 2365 off = fin->fin_off; 2366 2367 if ((fin->fin_flx & FI_TCPUDP) && (fin->fin_dlen > 3) && !off) 2368 portcmp = 1; 2369 2370 for (rulen = 0; fr; fr = fnext, rulen++) { 2371 fnext = fr->fr_next; 2372 if (skip != 0) { 2373 FR_VERBOSE(("SKIP %d (%#x)\n", skip, fr->fr_flags)); 2374 skip--; 2375 continue; 2376 } 2377 2378 /* 2379 * In all checks below, a null (zero) value in the 2380 * filter struture is taken to mean a wildcard. 2381 * 2382 * check that we are working for the right interface 2383 */ 2384 #ifdef _KERNEL 2385 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) 2386 continue; 2387 #else 2388 if (opts & (OPT_VERBOSE|OPT_DEBUG)) 2389 printf("\n"); 2390 FR_VERBOSE(("%c", FR_ISSKIP(pass) ? 's' : 2391 FR_ISPASS(pass) ? 'p' : 2392 FR_ISACCOUNT(pass) ? 'A' : 2393 FR_ISAUTH(pass) ? 'a' : 2394 (pass & FR_NOMATCH) ? 'n' :'b')); 2395 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) 2396 continue; 2397 FR_VERBOSE((":i")); 2398 #endif 2399 2400 switch (fr->fr_type) 2401 { 2402 case FR_T_IPF : 2403 case FR_T_IPF_BUILTIN : 2404 if (ipf_check_ipf(fin, fr, portcmp)) 2405 continue; 2406 break; 2407 #if defined(IPFILTER_BPF) 2408 case FR_T_BPFOPC : 2409 case FR_T_BPFOPC_BUILTIN : 2410 { 2411 u_char *mc; 2412 int wlen; 2413 2414 if (*fin->fin_mp == NULL) 2415 continue; 2416 if (fin->fin_family != fr->fr_family) 2417 continue; 2418 mc = (u_char *)fin->fin_m; 2419 wlen = fin->fin_dlen + fin->fin_hlen; 2420 if (!bpf_filter(fr->fr_data, mc, wlen, 0)) 2421 continue; 2422 break; 2423 } 2424 #endif 2425 case FR_T_CALLFUNC_BUILTIN : 2426 { 2427 frentry_t *f; 2428 2429 f = (*fr->fr_func)(fin, &pass); 2430 if (f != NULL) 2431 fr = f; 2432 else 2433 continue; 2434 break; 2435 } 2436 2437 case FR_T_IPFEXPR : 2438 case FR_T_IPFEXPR_BUILTIN : 2439 if (fin->fin_family != fr->fr_family) 2440 continue; 2441 if (ipf_fr_matcharray(fin, fr->fr_data) == 0) 2442 continue; 2443 break; 2444 2445 default : 2446 break; 2447 } 2448 2449 if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) { 2450 if (fin->fin_nattag == NULL) 2451 continue; 2452 if (ipf_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0) 2453 continue; 2454 } 2455 FR_VERBOSE(("=%d/%d.%d *", fr->fr_grhead, fr->fr_group, rulen)); 2456 2457 passt = fr->fr_flags; 2458 2459 /* 2460 * If the rule is a "call now" rule, then call the function 2461 * in the rule, if it exists and use the results from that. 2462 * If the function pointer is bad, just make like we ignore 2463 * it, except for increasing the hit counter. 2464 */ 2465 if ((passt & FR_CALLNOW) != 0) { 2466 frentry_t *frs; 2467 2468 ATOMIC_INC64(fr->fr_hits); 2469 if ((fr->fr_func == NULL) || 2470 (fr->fr_func == (ipfunc_t)-1)) 2471 continue; 2472 2473 frs = fin->fin_fr; 2474 fin->fin_fr = fr; 2475 fr = (*fr->fr_func)(fin, &passt); 2476 if (fr == NULL) { 2477 fin->fin_fr = frs; 2478 continue; 2479 } 2480 passt = fr->fr_flags; 2481 } 2482 fin->fin_fr = fr; 2483 2484 #ifdef IPFILTER_LOG 2485 /* 2486 * Just log this packet... 2487 */ 2488 if ((passt & FR_LOGMASK) == FR_LOG) { 2489 if (ipf_log_pkt(fin, passt) == -1) { 2490 if (passt & FR_LOGORBLOCK) { 2491 DT(frb_logfail); 2492 passt &= ~FR_CMDMASK; 2493 passt |= FR_BLOCK|FR_QUICK; 2494 fin->fin_reason = FRB_LOGFAIL; 2495 } 2496 } 2497 } 2498 #endif /* IPFILTER_LOG */ 2499 2500 MUTEX_ENTER(&fr->fr_lock); 2501 fr->fr_bytes += (U_QUAD_T)fin->fin_plen; 2502 fr->fr_hits++; 2503 MUTEX_EXIT(&fr->fr_lock); 2504 fin->fin_rule = rulen; 2505 2506 passo = pass; 2507 if (FR_ISSKIP(passt)) { 2508 skip = fr->fr_arg; 2509 continue; 2510 } else if (((passt & FR_LOGMASK) != FR_LOG) && 2511 ((passt & FR_LOGMASK) != FR_DECAPSULATE)) { 2512 pass = passt; 2513 } 2514 2515 if (passt & (FR_RETICMP|FR_FAKEICMP)) 2516 fin->fin_icode = fr->fr_icode; 2517 2518 if (fr->fr_group != -1) { 2519 (void) strncpy(fin->fin_group, 2520 FR_NAME(fr, fr_group), 2521 strlen(FR_NAME(fr, fr_group))); 2522 } else { 2523 fin->fin_group[0] = '\0'; 2524 } 2525 2526 FR_DEBUG(("pass %#x/%#x/%x\n", passo, pass, passt)); 2527 2528 if (fr->fr_grphead != NULL) { 2529 fin->fin_fr = fr->fr_grphead->fg_start; 2530 FR_VERBOSE(("group %s\n", FR_NAME(fr, fr_grhead))); 2531 2532 if (FR_ISDECAPS(passt)) 2533 passt = ipf_decaps(fin, pass, fr->fr_icode); 2534 else 2535 passt = ipf_scanlist(fin, pass); 2536 2537 if (fin->fin_fr == NULL) { 2538 fin->fin_rule = rulen; 2539 if (fr->fr_group != -1) 2540 (void) strncpy(fin->fin_group, 2541 fr->fr_names + 2542 fr->fr_group, 2543 strlen(fr->fr_names + 2544 fr->fr_group)); 2545 fin->fin_fr = fr; 2546 passt = pass; 2547 } 2548 pass = passt; 2549 } 2550 2551 if (pass & FR_QUICK) { 2552 /* 2553 * Finally, if we've asked to track state for this 2554 * packet, set it up. Add state for "quick" rules 2555 * here so that if the action fails we can consider 2556 * the rule to "not match" and keep on processing 2557 * filter rules. 2558 */ 2559 if ((pass & FR_KEEPSTATE) && !FR_ISAUTH(pass) && 2560 !(fin->fin_flx & FI_STATE)) { 2561 int out = fin->fin_out; 2562 2563 fin->fin_fr = fr; 2564 if (ipf_state_add(softc, fin, NULL, 0) == 0) { 2565 LBUMPD(ipf_stats[out], fr_ads); 2566 } else { 2567 LBUMPD(ipf_stats[out], fr_bads); 2568 pass = passo; 2569 continue; 2570 } 2571 } 2572 break; 2573 } 2574 } 2575 fin->fin_depth--; 2576 return (pass); 2577 } 2578 2579 2580 /* ------------------------------------------------------------------------ */ 2581 /* Function: ipf_acctpkt */ 2582 /* Returns: frentry_t* - always returns NULL */ 2583 /* Parameters: fin(I) - pointer to packet information */ 2584 /* passp(IO) - pointer to current/new filter decision (unused) */ 2585 /* */ 2586 /* Checks a packet against accounting rules, if there are any for the given */ 2587 /* IP protocol version. */ 2588 /* */ 2589 /* N.B.: this function returns NULL to match the prototype used by other */ 2590 /* functions called from the IPFilter "mainline" in ipf_check(). */ 2591 /* ------------------------------------------------------------------------ */ 2592 frentry_t * 2593 ipf_acctpkt(fr_info_t *fin, u_32_t *passp) 2594 { 2595 ipf_main_softc_t *softc = fin->fin_main_soft; 2596 char group[FR_GROUPLEN]; 2597 frentry_t *fr, *frsave; 2598 u_32_t pass, rulen; 2599 2600 passp = passp; 2601 fr = softc->ipf_acct[fin->fin_out][softc->ipf_active]; 2602 2603 if (fr != NULL) { 2604 frsave = fin->fin_fr; 2605 bcopy(fin->fin_group, group, FR_GROUPLEN); 2606 rulen = fin->fin_rule; 2607 fin->fin_fr = fr; 2608 pass = ipf_scanlist(fin, FR_NOMATCH); 2609 if (FR_ISACCOUNT(pass)) { 2610 LBUMPD(ipf_stats[0], fr_acct); 2611 } 2612 fin->fin_fr = frsave; 2613 bcopy(group, fin->fin_group, FR_GROUPLEN); 2614 fin->fin_rule = rulen; 2615 } 2616 return (NULL); 2617 } 2618 2619 2620 /* ------------------------------------------------------------------------ */ 2621 /* Function: ipf_firewall */ 2622 /* Returns: frentry_t* - returns pointer to matched rule, if no matches */ 2623 /* were found, returns NULL. */ 2624 /* Parameters: fin(I) - pointer to packet information */ 2625 /* passp(IO) - pointer to current/new filter decision (unused) */ 2626 /* */ 2627 /* Applies an appropriate set of firewall rules to the packet, to see if */ 2628 /* there are any matches. The first check is to see if a match can be seen */ 2629 /* in the cache. If not, then search an appropriate list of rules. Once a */ 2630 /* matching rule is found, take any appropriate actions as defined by the */ 2631 /* rule - except logging. */ 2632 /* ------------------------------------------------------------------------ */ 2633 static frentry_t * 2634 ipf_firewall(fr_info_t *fin, u_32_t *passp) 2635 { 2636 ipf_main_softc_t *softc = fin->fin_main_soft; 2637 frentry_t *fr; 2638 u_32_t pass; 2639 int out; 2640 2641 out = fin->fin_out; 2642 pass = *passp; 2643 2644 /* 2645 * This rule cache will only affect packets that are not being 2646 * statefully filtered. 2647 */ 2648 fin->fin_fr = softc->ipf_rules[out][softc->ipf_active]; 2649 if (fin->fin_fr != NULL) 2650 pass = ipf_scanlist(fin, softc->ipf_pass); 2651 2652 if ((pass & FR_NOMATCH)) { 2653 LBUMPD(ipf_stats[out], fr_nom); 2654 } 2655 fr = fin->fin_fr; 2656 2657 /* 2658 * Apply packets per second rate-limiting to a rule as required. 2659 */ 2660 if ((fr != NULL) && (fr->fr_pps != 0) && 2661 !ppsratecheck(&fr->fr_lastpkt, &fr->fr_curpps, fr->fr_pps)) { 2662 DT2(frb_ppsrate, fr_info_t *, fin, frentry_t *, fr); 2663 pass &= ~(FR_CMDMASK|FR_RETICMP|FR_RETRST); 2664 pass |= FR_BLOCK; 2665 LBUMPD(ipf_stats[out], fr_ppshit); 2666 fin->fin_reason = FRB_PPSRATE; 2667 } 2668 2669 /* 2670 * If we fail to add a packet to the authorization queue, then we 2671 * drop the packet later. However, if it was added then pretend 2672 * we've dropped it already. 2673 */ 2674 if (FR_ISAUTH(pass)) { 2675 if (ipf_auth_new(fin->fin_m, fin) != 0) { 2676 DT1(frb_authnew, fr_info_t *, fin); 2677 fin->fin_m = *fin->fin_mp = NULL; 2678 fin->fin_reason = FRB_AUTHNEW; 2679 fin->fin_error = 0; 2680 } else { 2681 IPFERROR(1); 2682 fin->fin_error = ENOSPC; 2683 } 2684 } 2685 2686 if ((fr != NULL) && (fr->fr_func != NULL) && 2687 (fr->fr_func != (ipfunc_t)-1) && !(pass & FR_CALLNOW)) 2688 (void) (*fr->fr_func)(fin, &pass); 2689 2690 /* 2691 * If a rule is a pre-auth rule, check again in the list of rules 2692 * loaded for authenticated use. It does not particulary matter 2693 * if this search fails because a "preauth" result, from a rule, 2694 * is treated as "not a pass", hence the packet is blocked. 2695 */ 2696 if (FR_ISPREAUTH(pass)) { 2697 pass = ipf_auth_pre_scanlist(softc, fin, pass); 2698 } 2699 2700 /* 2701 * If the rule has "keep frag" and the packet is actually a fragment, 2702 * then create a fragment state entry. 2703 */ 2704 if (pass & FR_KEEPFRAG) { 2705 if (fin->fin_flx & FI_FRAG) { 2706 if (ipf_frag_new(softc, fin, pass) == -1) { 2707 LBUMP(ipf_stats[out].fr_bnfr); 2708 } else { 2709 LBUMP(ipf_stats[out].fr_nfr); 2710 } 2711 } else { 2712 LBUMP(ipf_stats[out].fr_cfr); 2713 } 2714 } 2715 2716 fr = fin->fin_fr; 2717 *passp = pass; 2718 2719 return (fr); 2720 } 2721 2722 2723 /* ------------------------------------------------------------------------ */ 2724 /* Function: ipf_check */ 2725 /* Returns: int - 0 == packet allowed through, */ 2726 /* User space: */ 2727 /* -1 == packet blocked */ 2728 /* 1 == packet not matched */ 2729 /* -2 == requires authentication */ 2730 /* Kernel: */ 2731 /* > 0 == filter error # for packet */ 2732 /* Parameters: ctx(I) - pointer to the instance context */ 2733 /* ip(I) - pointer to start of IPv4/6 packet */ 2734 /* hlen(I) - length of header */ 2735 /* ifp(I) - pointer to interface this packet is on */ 2736 /* out(I) - 0 == packet going in, 1 == packet going out */ 2737 /* mp(IO) - pointer to caller's buffer pointer that holds this */ 2738 /* IP packet. */ 2739 /* Solaris: */ 2740 /* qpi(I) - pointer to STREAMS queue information for this */ 2741 /* interface & direction. */ 2742 /* */ 2743 /* ipf_check() is the master function for all IPFilter packet processing. */ 2744 /* It orchestrates: Network Address Translation (NAT), checking for packet */ 2745 /* authorisation (or pre-authorisation), presence of related state info., */ 2746 /* generating log entries, IP packet accounting, routing of packets as */ 2747 /* directed by firewall rules and of course whether or not to allow the */ 2748 /* packet to be further processed by the kernel. */ 2749 /* */ 2750 /* For packets blocked, the contents of "mp" will be NULL'd and the buffer */ 2751 /* freed. Packets passed may be returned with the pointer pointed to by */ 2752 /* by "mp" changed to a new buffer. */ 2753 /* ------------------------------------------------------------------------ */ 2754 int 2755 ipf_check(void *ctx, ip_t *ip, int hlen, struct ifnet *ifp, int out 2756 #if defined(_KERNEL) && SOLARIS 2757 , void* qif, mb_t **mp) 2758 #else 2759 , mb_t **mp) 2760 #endif 2761 { 2762 /* 2763 * The above really sucks, but short of writing a diff 2764 */ 2765 ipf_main_softc_t *softc = ctx; 2766 fr_info_t frinfo; 2767 fr_info_t *fin = &frinfo; 2768 u_32_t pass = softc->ipf_pass; 2769 frentry_t *fr = NULL; 2770 int v = IP_V(ip); 2771 mb_t *mc = NULL; 2772 mb_t *m; 2773 /* 2774 * The first part of ipf_check() deals with making sure that what goes 2775 * into the filtering engine makes some sense. Information about the 2776 * the packet is distilled, collected into a fr_info_t structure and 2777 * the an attempt to ensure the buffer the packet is in is big enough 2778 * to hold all the required packet headers. 2779 */ 2780 #ifdef _KERNEL 2781 # if SOLARIS 2782 qpktinfo_t *qpi = qif; 2783 2784 # ifdef __sparc 2785 if ((u_int)ip & 0x3) 2786 return (2); 2787 # endif 2788 # else 2789 SPL_INT(s); 2790 # endif 2791 2792 if (softc->ipf_running <= 0) { 2793 return (0); 2794 } 2795 2796 bzero((char *)fin, sizeof(*fin)); 2797 2798 # if SOLARIS 2799 if (qpi->qpi_flags & QF_BROADCAST) 2800 fin->fin_flx |= FI_MBCAST|FI_BROADCAST; 2801 if (qpi->qpi_flags & QF_MULTICAST) 2802 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2803 m = qpi->qpi_m; 2804 fin->fin_qfm = m; 2805 fin->fin_qpi = qpi; 2806 # else /* SOLARIS */ 2807 2808 m = *mp; 2809 2810 # if defined(M_MCAST) 2811 if ((m->m_flags & M_MCAST) != 0) 2812 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2813 # endif 2814 # if defined(M_MLOOP) 2815 if ((m->m_flags & M_MLOOP) != 0) 2816 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2817 # endif 2818 # if defined(M_BCAST) 2819 if ((m->m_flags & M_BCAST) != 0) 2820 fin->fin_flx |= FI_MBCAST|FI_BROADCAST; 2821 # endif 2822 # ifdef M_CANFASTFWD 2823 /* 2824 * XXX For now, IP Filter and fast-forwarding of cached flows 2825 * XXX are mutually exclusive. Eventually, IP Filter should 2826 * XXX get a "can-fast-forward" filter rule. 2827 */ 2828 m->m_flags &= ~M_CANFASTFWD; 2829 # endif /* M_CANFASTFWD */ 2830 # if defined(CSUM_DELAY_DATA) && !defined(__FreeBSD__) 2831 /* 2832 * disable delayed checksums. 2833 */ 2834 if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 2835 in_delayed_cksum(m); 2836 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 2837 } 2838 # endif /* CSUM_DELAY_DATA */ 2839 # endif /* SOLARIS */ 2840 #else 2841 bzero((char *)fin, sizeof(*fin)); 2842 m = *mp; 2843 # if defined(M_MCAST) 2844 if ((m->m_flags & M_MCAST) != 0) 2845 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2846 # endif 2847 # if defined(M_MLOOP) 2848 if ((m->m_flags & M_MLOOP) != 0) 2849 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2850 # endif 2851 # if defined(M_BCAST) 2852 if ((m->m_flags & M_BCAST) != 0) 2853 fin->fin_flx |= FI_MBCAST|FI_BROADCAST; 2854 # endif 2855 #endif /* _KERNEL */ 2856 2857 fin->fin_v = v; 2858 fin->fin_m = m; 2859 fin->fin_ip = ip; 2860 fin->fin_mp = mp; 2861 fin->fin_out = out; 2862 fin->fin_ifp = ifp; 2863 fin->fin_error = ENETUNREACH; 2864 fin->fin_hlen = (u_short)hlen; 2865 fin->fin_dp = (char *)ip + hlen; 2866 fin->fin_main_soft = softc; 2867 2868 fin->fin_ipoff = (char *)ip - MTOD(m, char *); 2869 2870 SPL_NET(s); 2871 2872 #ifdef USE_INET6 2873 if (v == 6) { 2874 LBUMP(ipf_stats[out].fr_ipv6); 2875 /* 2876 * Jumbo grams are quite likely too big for internal buffer 2877 * structures to handle comfortably, for now, so just drop 2878 * them. 2879 */ 2880 if (((ip6_t *)ip)->ip6_plen == 0) { 2881 DT1(frb_jumbo, ip6_t *, (ip6_t *)ip); 2882 pass = FR_BLOCK|FR_NOMATCH; 2883 fin->fin_reason = FRB_JUMBO; 2884 goto finished; 2885 } 2886 fin->fin_family = AF_INET6; 2887 } else 2888 #endif 2889 { 2890 fin->fin_family = AF_INET; 2891 } 2892 2893 if (ipf_makefrip(hlen, ip, fin) == -1) { 2894 DT1(frb_makefrip, fr_info_t *, fin); 2895 pass = FR_BLOCK|FR_NOMATCH; 2896 fin->fin_reason = FRB_MAKEFRIP; 2897 goto finished; 2898 } 2899 2900 /* 2901 * For at least IPv6 packets, if a m_pullup() fails then this pointer 2902 * becomes NULL and so we have no packet to free. 2903 */ 2904 if (*fin->fin_mp == NULL) 2905 goto finished; 2906 2907 if (!out) { 2908 if (v == 4) { 2909 if (softc->ipf_chksrc && !ipf_verifysrc(fin)) { 2910 LBUMPD(ipf_stats[0], fr_v4_badsrc); 2911 fin->fin_flx |= FI_BADSRC; 2912 } 2913 if (fin->fin_ip->ip_ttl < softc->ipf_minttl) { 2914 LBUMPD(ipf_stats[0], fr_v4_badttl); 2915 fin->fin_flx |= FI_LOWTTL; 2916 } 2917 } 2918 #ifdef USE_INET6 2919 else if (v == 6) { 2920 if (((ip6_t *)ip)->ip6_hlim < softc->ipf_minttl) { 2921 LBUMPD(ipf_stats[0], fr_v6_badttl); 2922 fin->fin_flx |= FI_LOWTTL; 2923 } 2924 } 2925 #endif 2926 } 2927 2928 if (fin->fin_flx & FI_SHORT) { 2929 LBUMPD(ipf_stats[out], fr_short); 2930 } 2931 2932 READ_ENTER(&softc->ipf_mutex); 2933 2934 if (!out) { 2935 switch (fin->fin_v) 2936 { 2937 case 4 : 2938 if (ipf_nat_checkin(fin, &pass) == -1) { 2939 goto filterdone; 2940 } 2941 break; 2942 #ifdef USE_INET6 2943 case 6 : 2944 if (ipf_nat6_checkin(fin, &pass) == -1) { 2945 goto filterdone; 2946 } 2947 break; 2948 #endif 2949 default : 2950 break; 2951 } 2952 } 2953 /* 2954 * Check auth now. 2955 * If a packet is found in the auth table, then skip checking 2956 * the access lists for permission but we do need to consider 2957 * the result as if it were from the ACL's. In addition, being 2958 * found in the auth table means it has been seen before, so do 2959 * not pass it through accounting (again), lest it be counted twice. 2960 */ 2961 fr = ipf_auth_check(fin, &pass); 2962 if (!out && (fr == NULL)) 2963 (void) ipf_acctpkt(fin, NULL); 2964 2965 if (fr == NULL) { 2966 if ((fin->fin_flx & FI_FRAG) != 0) 2967 fr = ipf_frag_known(fin, &pass); 2968 2969 if (fr == NULL) 2970 fr = ipf_state_check(fin, &pass); 2971 } 2972 2973 if ((pass & FR_NOMATCH) || (fr == NULL)) 2974 fr = ipf_firewall(fin, &pass); 2975 2976 /* 2977 * If we've asked to track state for this packet, set it up. 2978 * Here rather than ipf_firewall because ipf_checkauth may decide 2979 * to return a packet for "keep state" 2980 */ 2981 if ((pass & FR_KEEPSTATE) && (fin->fin_m != NULL) && 2982 !(fin->fin_flx & FI_STATE)) { 2983 if (ipf_state_add(softc, fin, NULL, 0) == 0) { 2984 LBUMP(ipf_stats[out].fr_ads); 2985 } else { 2986 LBUMP(ipf_stats[out].fr_bads); 2987 if (FR_ISPASS(pass)) { 2988 DT(frb_stateadd); 2989 pass &= ~FR_CMDMASK; 2990 pass |= FR_BLOCK; 2991 fin->fin_reason = FRB_STATEADD; 2992 } 2993 } 2994 } 2995 2996 fin->fin_fr = fr; 2997 if ((fr != NULL) && !(fin->fin_flx & FI_STATE)) { 2998 fin->fin_dif = &fr->fr_dif; 2999 fin->fin_tif = &fr->fr_tifs[fin->fin_rev]; 3000 } 3001 3002 /* 3003 * Only count/translate packets which will be passed on, out the 3004 * interface. 3005 */ 3006 if (out && FR_ISPASS(pass)) { 3007 (void) ipf_acctpkt(fin, NULL); 3008 3009 switch (fin->fin_v) 3010 { 3011 case 4 : 3012 if (ipf_nat_checkout(fin, &pass) == -1) { 3013 ; 3014 } else if ((softc->ipf_update_ipid != 0) && (v == 4)) { 3015 if (ipf_updateipid(fin) == -1) { 3016 DT(frb_updateipid); 3017 LBUMP(ipf_stats[1].fr_ipud); 3018 pass &= ~FR_CMDMASK; 3019 pass |= FR_BLOCK; 3020 fin->fin_reason = FRB_UPDATEIPID; 3021 } else { 3022 LBUMP(ipf_stats[0].fr_ipud); 3023 } 3024 } 3025 break; 3026 #ifdef USE_INET6 3027 case 6 : 3028 (void) ipf_nat6_checkout(fin, &pass); 3029 break; 3030 #endif 3031 default : 3032 break; 3033 } 3034 } 3035 3036 filterdone: 3037 #ifdef IPFILTER_LOG 3038 if ((softc->ipf_flags & FF_LOGGING) || (pass & FR_LOGMASK)) { 3039 (void) ipf_dolog(fin, &pass); 3040 } 3041 #endif 3042 3043 /* 3044 * The FI_STATE flag is cleared here so that calling ipf_state_check 3045 * will work when called from inside of fr_fastroute. Although 3046 * there is a similar flag, FI_NATED, for NAT, it does have the same 3047 * impact on code execution. 3048 */ 3049 fin->fin_flx &= ~FI_STATE; 3050 3051 #if defined(FASTROUTE_RECURSION) 3052 /* 3053 * Up the reference on fr_lock and exit ipf_mutex. The generation of 3054 * a packet below can sometimes cause a recursive call into IPFilter. 3055 * On those platforms where that does happen, we need to hang onto 3056 * the filter rule just in case someone decides to remove or flush it 3057 * in the meantime. 3058 */ 3059 if (fr != NULL) { 3060 MUTEX_ENTER(&fr->fr_lock); 3061 fr->fr_ref++; 3062 MUTEX_EXIT(&fr->fr_lock); 3063 } 3064 3065 RWLOCK_EXIT(&softc->ipf_mutex); 3066 #endif 3067 3068 if ((pass & FR_RETMASK) != 0) { 3069 /* 3070 * Should we return an ICMP packet to indicate error 3071 * status passing through the packet filter ? 3072 * WARNING: ICMP error packets AND TCP RST packets should 3073 * ONLY be sent in repsonse to incoming packets. Sending 3074 * them in response to outbound packets can result in a 3075 * panic on some operating systems. 3076 */ 3077 if (!out) { 3078 if (pass & FR_RETICMP) { 3079 int dst; 3080 3081 if ((pass & FR_RETMASK) == FR_FAKEICMP) 3082 dst = 1; 3083 else 3084 dst = 0; 3085 (void) ipf_send_icmp_err(ICMP_UNREACH, fin, 3086 dst); 3087 LBUMP(ipf_stats[0].fr_ret); 3088 } else if (((pass & FR_RETMASK) == FR_RETRST) && 3089 !(fin->fin_flx & FI_SHORT)) { 3090 if (((fin->fin_flx & FI_OOW) != 0) || 3091 (ipf_send_reset(fin) == 0)) { 3092 LBUMP(ipf_stats[1].fr_ret); 3093 } 3094 } 3095 3096 /* 3097 * When using return-* with auth rules, the auth code 3098 * takes over disposing of this packet. 3099 */ 3100 if (FR_ISAUTH(pass) && (fin->fin_m != NULL)) { 3101 DT1(frb_authcapture, fr_info_t *, fin); 3102 fin->fin_m = *fin->fin_mp = NULL; 3103 fin->fin_reason = FRB_AUTHCAPTURE; 3104 m = NULL; 3105 } 3106 } else { 3107 if (pass & FR_RETRST) { 3108 fin->fin_error = ECONNRESET; 3109 } 3110 } 3111 } 3112 3113 /* 3114 * After the above so that ICMP unreachables and TCP RSTs get 3115 * created properly. 3116 */ 3117 if (FR_ISBLOCK(pass) && (fin->fin_flx & FI_NEWNAT)) 3118 ipf_nat_uncreate(fin); 3119 3120 /* 3121 * If we didn't drop off the bottom of the list of rules (and thus 3122 * the 'current' rule fr is not NULL), then we may have some extra 3123 * instructions about what to do with a packet. 3124 * Once we're finished return to our caller, freeing the packet if 3125 * we are dropping it. 3126 */ 3127 if (fr != NULL) { 3128 frdest_t *fdp; 3129 3130 /* 3131 * Generate a duplicated packet first because ipf_fastroute 3132 * can lead to fin_m being free'd... not good. 3133 */ 3134 fdp = fin->fin_dif; 3135 if ((fdp != NULL) && (fdp->fd_ptr != NULL) && 3136 (fdp->fd_ptr != (void *)-1)) { 3137 mc = M_COPY(fin->fin_m); 3138 if (mc != NULL) 3139 ipf_fastroute(mc, &mc, fin, fdp); 3140 } 3141 3142 fdp = fin->fin_tif; 3143 if (!out && (pass & FR_FASTROUTE)) { 3144 /* 3145 * For fastroute rule, no destination interface defined 3146 * so pass NULL as the frdest_t parameter 3147 */ 3148 (void) ipf_fastroute(fin->fin_m, mp, fin, NULL); 3149 m = *mp = NULL; 3150 } else if ((fdp != NULL) && (fdp->fd_ptr != NULL) && 3151 (fdp->fd_ptr != (struct ifnet *)-1)) { 3152 /* this is for to rules: */ 3153 ipf_fastroute(fin->fin_m, mp, fin, fdp); 3154 m = *mp = NULL; 3155 } 3156 3157 #if defined(FASTROUTE_RECURSION) 3158 (void) ipf_derefrule(softc, &fr); 3159 #endif 3160 } 3161 #if !defined(FASTROUTE_RECURSION) 3162 RWLOCK_EXIT(&softc->ipf_mutex); 3163 #endif 3164 3165 finished: 3166 if (!FR_ISPASS(pass)) { 3167 LBUMP(ipf_stats[out].fr_block); 3168 if (*mp != NULL) { 3169 #ifdef _KERNEL 3170 FREE_MB_T(*mp); 3171 #endif 3172 m = *mp = NULL; 3173 } 3174 } else { 3175 LBUMP(ipf_stats[out].fr_pass); 3176 } 3177 3178 SPL_X(s); 3179 3180 if (fin->fin_m == NULL && fin->fin_flx & FI_BAD && 3181 fin->fin_reason == FRB_PULLUP) { 3182 /* m_pullup() has freed the mbuf */ 3183 LBUMP(ipf_stats[out].fr_blocked[fin->fin_reason]); 3184 return (-1); 3185 } 3186 3187 3188 #ifdef _KERNEL 3189 if (FR_ISPASS(pass)) 3190 return (0); 3191 LBUMP(ipf_stats[out].fr_blocked[fin->fin_reason]); 3192 return (fin->fin_error); 3193 #else /* _KERNEL */ 3194 if (*mp != NULL) 3195 (*mp)->mb_ifp = fin->fin_ifp; 3196 blockreason = fin->fin_reason; 3197 FR_VERBOSE(("fin_flx %#x pass %#x ", fin->fin_flx, pass)); 3198 /*if ((pass & FR_CMDMASK) == (softc->ipf_pass & FR_CMDMASK))*/ 3199 if ((pass & FR_NOMATCH) != 0) 3200 return (1); 3201 3202 if ((pass & FR_RETMASK) != 0) 3203 switch (pass & FR_RETMASK) 3204 { 3205 case FR_RETRST : 3206 return (3); 3207 case FR_RETICMP : 3208 return (4); 3209 case FR_FAKEICMP : 3210 return (5); 3211 } 3212 3213 switch (pass & FR_CMDMASK) 3214 { 3215 case FR_PASS : 3216 return (0); 3217 case FR_BLOCK : 3218 return (-1); 3219 case FR_AUTH : 3220 return (-2); 3221 case FR_ACCOUNT : 3222 return (-3); 3223 case FR_PREAUTH : 3224 return (-4); 3225 } 3226 return (2); 3227 #endif /* _KERNEL */ 3228 } 3229 3230 3231 #ifdef IPFILTER_LOG 3232 /* ------------------------------------------------------------------------ */ 3233 /* Function: ipf_dolog */ 3234 /* Returns: frentry_t* - returns contents of fin_fr (no change made) */ 3235 /* Parameters: fin(I) - pointer to packet information */ 3236 /* passp(IO) - pointer to current/new filter decision (unused) */ 3237 /* */ 3238 /* Checks flags set to see how a packet should be logged, if it is to be */ 3239 /* logged. Adjust statistics based on its success or not. */ 3240 /* ------------------------------------------------------------------------ */ 3241 frentry_t * 3242 ipf_dolog(fr_info_t *fin, u_32_t *passp) 3243 { 3244 ipf_main_softc_t *softc = fin->fin_main_soft; 3245 u_32_t pass; 3246 int out; 3247 3248 out = fin->fin_out; 3249 pass = *passp; 3250 3251 if ((softc->ipf_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) { 3252 pass |= FF_LOGNOMATCH; 3253 LBUMPD(ipf_stats[out], fr_npkl); 3254 goto logit; 3255 3256 } else if (((pass & FR_LOGMASK) == FR_LOGP) || 3257 (FR_ISPASS(pass) && (softc->ipf_flags & FF_LOGPASS))) { 3258 if ((pass & FR_LOGMASK) != FR_LOGP) 3259 pass |= FF_LOGPASS; 3260 LBUMPD(ipf_stats[out], fr_ppkl); 3261 goto logit; 3262 3263 } else if (((pass & FR_LOGMASK) == FR_LOGB) || 3264 (FR_ISBLOCK(pass) && (softc->ipf_flags & FF_LOGBLOCK))) { 3265 if ((pass & FR_LOGMASK) != FR_LOGB) 3266 pass |= FF_LOGBLOCK; 3267 LBUMPD(ipf_stats[out], fr_bpkl); 3268 3269 logit: 3270 if (ipf_log_pkt(fin, pass) == -1) { 3271 /* 3272 * If the "or-block" option has been used then 3273 * block the packet if we failed to log it. 3274 */ 3275 if ((pass & FR_LOGORBLOCK) && FR_ISPASS(pass)) { 3276 DT1(frb_logfail2, u_int, pass); 3277 pass &= ~FR_CMDMASK; 3278 pass |= FR_BLOCK; 3279 fin->fin_reason = FRB_LOGFAIL2; 3280 } 3281 } 3282 *passp = pass; 3283 } 3284 3285 return (fin->fin_fr); 3286 } 3287 #endif /* IPFILTER_LOG */ 3288 3289 3290 /* ------------------------------------------------------------------------ */ 3291 /* Function: ipf_cksum */ 3292 /* Returns: u_short - IP header checksum */ 3293 /* Parameters: addr(I) - pointer to start of buffer to checksum */ 3294 /* len(I) - length of buffer in bytes */ 3295 /* */ 3296 /* Calculate the two's complement 16 bit checksum of the buffer passed. */ 3297 /* */ 3298 /* N.B.: addr should be 16bit aligned. */ 3299 /* ------------------------------------------------------------------------ */ 3300 u_short 3301 ipf_cksum(u_short *addr, int len) 3302 { 3303 u_32_t sum = 0; 3304 3305 for (sum = 0; len > 1; len -= 2) 3306 sum += *addr++; 3307 3308 /* mop up an odd byte, if necessary */ 3309 if (len == 1) 3310 sum += *(u_char *)addr; 3311 3312 /* 3313 * add back carry outs from top 16 bits to low 16 bits 3314 */ 3315 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 3316 sum += (sum >> 16); /* add carry */ 3317 return (u_short)(~sum); 3318 } 3319 3320 3321 /* ------------------------------------------------------------------------ */ 3322 /* Function: fr_cksum */ 3323 /* Returns: u_short - layer 4 checksum */ 3324 /* Parameters: fin(I) - pointer to packet information */ 3325 /* ip(I) - pointer to IP header */ 3326 /* l4proto(I) - protocol to caclulate checksum for */ 3327 /* l4hdr(I) - pointer to layer 4 header */ 3328 /* */ 3329 /* Calculates the TCP checksum for the packet held in "m", using the data */ 3330 /* in the IP header "ip" to seed it. */ 3331 /* */ 3332 /* NB: This function assumes we've pullup'd enough for all of the IP header */ 3333 /* and the TCP header. We also assume that data blocks aren't allocated in */ 3334 /* odd sizes. */ 3335 /* */ 3336 /* Expects ip_len and ip_off to be in network byte order when called. */ 3337 /* ------------------------------------------------------------------------ */ 3338 u_short 3339 fr_cksum(fr_info_t *fin, ip_t *ip, int l4proto, void *l4hdr) 3340 { 3341 u_short *sp, slen, sumsave, *csump; 3342 u_int sum, sum2; 3343 int hlen; 3344 int off; 3345 #ifdef USE_INET6 3346 ip6_t *ip6; 3347 #endif 3348 3349 csump = NULL; 3350 sumsave = 0; 3351 sp = NULL; 3352 slen = 0; 3353 hlen = 0; 3354 sum = 0; 3355 3356 sum = htons((u_short)l4proto); 3357 /* 3358 * Add up IP Header portion 3359 */ 3360 #ifdef USE_INET6 3361 if (IP_V(ip) == 4) { 3362 #endif 3363 hlen = IP_HL(ip) << 2; 3364 off = hlen; 3365 sp = (u_short *)&ip->ip_src; 3366 sum += *sp++; /* ip_src */ 3367 sum += *sp++; 3368 sum += *sp++; /* ip_dst */ 3369 sum += *sp++; 3370 slen = fin->fin_plen - off; 3371 sum += htons(slen); 3372 #ifdef USE_INET6 3373 } else if (IP_V(ip) == 6) { 3374 mb_t *m; 3375 3376 m = fin->fin_m; 3377 ip6 = (ip6_t *)ip; 3378 off = ((caddr_t)ip6 - m->m_data) + sizeof(struct ip6_hdr); 3379 int len = ntohs(ip6->ip6_plen) - (off - sizeof(*ip6)); 3380 return (ipf_pcksum6(m, ip6, off, len)); 3381 } else { 3382 return (0xffff); 3383 } 3384 #endif 3385 3386 switch (l4proto) 3387 { 3388 case IPPROTO_UDP : 3389 csump = &((udphdr_t *)l4hdr)->uh_sum; 3390 break; 3391 3392 case IPPROTO_TCP : 3393 csump = &((tcphdr_t *)l4hdr)->th_sum; 3394 break; 3395 case IPPROTO_ICMP : 3396 csump = &((icmphdr_t *)l4hdr)->icmp_cksum; 3397 sum = 0; /* Pseudo-checksum is not included */ 3398 break; 3399 #ifdef USE_INET6 3400 case IPPROTO_ICMPV6 : 3401 csump = &((struct icmp6_hdr *)l4hdr)->icmp6_cksum; 3402 break; 3403 #endif 3404 default : 3405 break; 3406 } 3407 3408 if (csump != NULL) { 3409 sumsave = *csump; 3410 *csump = 0; 3411 } 3412 3413 sum2 = ipf_pcksum(fin, off, sum); 3414 if (csump != NULL) 3415 *csump = sumsave; 3416 return (sum2); 3417 } 3418 3419 3420 /* ------------------------------------------------------------------------ */ 3421 /* Function: ipf_findgroup */ 3422 /* Returns: frgroup_t * - NULL = group not found, else pointer to group */ 3423 /* Parameters: softc(I) - pointer to soft context main structure */ 3424 /* group(I) - group name to search for */ 3425 /* unit(I) - device to which this group belongs */ 3426 /* set(I) - which set of rules (inactive/inactive) this is */ 3427 /* fgpp(O) - pointer to place to store pointer to the pointer */ 3428 /* to where to add the next (last) group or where */ 3429 /* to delete group from. */ 3430 /* */ 3431 /* Search amongst the defined groups for a particular group number. */ 3432 /* ------------------------------------------------------------------------ */ 3433 frgroup_t * 3434 ipf_findgroup(ipf_main_softc_t *softc, char *group, minor_t unit, int set, 3435 frgroup_t ***fgpp) 3436 { 3437 frgroup_t *fg, **fgp; 3438 3439 /* 3440 * Which list of groups to search in is dependent on which list of 3441 * rules are being operated on. 3442 */ 3443 fgp = &softc->ipf_groups[unit][set]; 3444 3445 while ((fg = *fgp) != NULL) { 3446 if (strncmp(group, fg->fg_name, FR_GROUPLEN) == 0) 3447 break; 3448 else 3449 fgp = &fg->fg_next; 3450 } 3451 if (fgpp != NULL) 3452 *fgpp = fgp; 3453 return (fg); 3454 } 3455 3456 3457 /* ------------------------------------------------------------------------ */ 3458 /* Function: ipf_group_add */ 3459 /* Returns: frgroup_t * - NULL == did not create group, */ 3460 /* != NULL == pointer to the group */ 3461 /* Parameters: softc(I) - pointer to soft context main structure */ 3462 /* num(I) - group number to add */ 3463 /* head(I) - rule pointer that is using this as the head */ 3464 /* flags(I) - rule flags which describe the type of rule it is */ 3465 /* unit(I) - device to which this group will belong to */ 3466 /* set(I) - which set of rules (inactive/inactive) this is */ 3467 /* Write Locks: ipf_mutex */ 3468 /* */ 3469 /* Add a new group head, or if it already exists, increase the reference */ 3470 /* count to it. */ 3471 /* ------------------------------------------------------------------------ */ 3472 frgroup_t * 3473 ipf_group_add(ipf_main_softc_t *softc, char *group, void *head, u_32_t flags, 3474 minor_t unit, int set) 3475 { 3476 frgroup_t *fg, **fgp; 3477 u_32_t gflags; 3478 3479 if (group == NULL) 3480 return (NULL); 3481 3482 if (unit == IPL_LOGIPF && *group == '\0') 3483 return (NULL); 3484 3485 fgp = NULL; 3486 gflags = flags & FR_INOUT; 3487 3488 fg = ipf_findgroup(softc, group, unit, set, &fgp); 3489 if (fg != NULL) { 3490 if (fg->fg_head == NULL && head != NULL) 3491 fg->fg_head = head; 3492 if (fg->fg_flags == 0) 3493 fg->fg_flags = gflags; 3494 else if (gflags != fg->fg_flags) 3495 return (NULL); 3496 fg->fg_ref++; 3497 return (fg); 3498 } 3499 3500 KMALLOC(fg, frgroup_t *); 3501 if (fg != NULL) { 3502 fg->fg_head = head; 3503 fg->fg_start = NULL; 3504 fg->fg_next = *fgp; 3505 bcopy(group, fg->fg_name, strlen(group) + 1); 3506 fg->fg_flags = gflags; 3507 fg->fg_ref = 1; 3508 fg->fg_set = &softc->ipf_groups[unit][set]; 3509 *fgp = fg; 3510 } 3511 return (fg); 3512 } 3513 3514 3515 /* ------------------------------------------------------------------------ */ 3516 /* Function: ipf_group_del */ 3517 /* Returns: int - number of rules deleted */ 3518 /* Parameters: softc(I) - pointer to soft context main structure */ 3519 /* group(I) - group name to delete */ 3520 /* fr(I) - filter rule from which group is referenced */ 3521 /* Write Locks: ipf_mutex */ 3522 /* */ 3523 /* This function is called whenever a reference to a group is to be dropped */ 3524 /* and thus its reference count needs to be lowered and the group free'd if */ 3525 /* the reference count reaches zero. Passing in fr is really for the sole */ 3526 /* purpose of knowing when the head rule is being deleted. */ 3527 /* ------------------------------------------------------------------------ */ 3528 void 3529 ipf_group_del(ipf_main_softc_t *softc, frgroup_t *group, frentry_t *fr) 3530 { 3531 3532 if (group->fg_head == fr) 3533 group->fg_head = NULL; 3534 3535 group->fg_ref--; 3536 if ((group->fg_ref == 0) && (group->fg_start == NULL)) 3537 ipf_group_free(group); 3538 } 3539 3540 3541 /* ------------------------------------------------------------------------ */ 3542 /* Function: ipf_group_free */ 3543 /* Returns: Nil */ 3544 /* Parameters: group(I) - pointer to filter rule group */ 3545 /* */ 3546 /* Remove the group from the list of groups and free it. */ 3547 /* ------------------------------------------------------------------------ */ 3548 static void 3549 ipf_group_free(frgroup_t *group) 3550 { 3551 frgroup_t **gp; 3552 3553 for (gp = group->fg_set; *gp != NULL; gp = &(*gp)->fg_next) { 3554 if (*gp == group) { 3555 *gp = group->fg_next; 3556 break; 3557 } 3558 } 3559 KFREE(group); 3560 } 3561 3562 3563 /* ------------------------------------------------------------------------ */ 3564 /* Function: ipf_group_flush */ 3565 /* Returns: int - number of rules flush from group */ 3566 /* Parameters: softc(I) - pointer to soft context main structure */ 3567 /* Parameters: group(I) - pointer to filter rule group */ 3568 /* */ 3569 /* Remove all of the rules that currently are listed under the given group. */ 3570 /* ------------------------------------------------------------------------ */ 3571 static int 3572 ipf_group_flush(ipf_main_softc_t *softc, frgroup_t *group) 3573 { 3574 int gone = 0; 3575 3576 (void) ipf_flushlist(softc, &gone, &group->fg_start); 3577 3578 return (gone); 3579 } 3580 3581 3582 /* ------------------------------------------------------------------------ */ 3583 /* Function: ipf_getrulen */ 3584 /* Returns: frentry_t * - NULL == not found, else pointer to rule n */ 3585 /* Parameters: softc(I) - pointer to soft context main structure */ 3586 /* Parameters: unit(I) - device for which to count the rule's number */ 3587 /* flags(I) - which set of rules to find the rule in */ 3588 /* group(I) - group name */ 3589 /* n(I) - rule number to find */ 3590 /* */ 3591 /* Find rule # n in group # g and return a pointer to it. Return NULl if */ 3592 /* group # g doesn't exist or there are less than n rules in the group. */ 3593 /* ------------------------------------------------------------------------ */ 3594 frentry_t * 3595 ipf_getrulen(ipf_main_softc_t *softc, int unit, char *group, u_32_t n) 3596 { 3597 frentry_t *fr; 3598 frgroup_t *fg; 3599 3600 fg = ipf_findgroup(softc, group, unit, softc->ipf_active, NULL); 3601 if (fg == NULL) 3602 return (NULL); 3603 for (fr = fg->fg_start; fr && n; fr = fr->fr_next, n--) 3604 ; 3605 if (n != 0) 3606 return (NULL); 3607 return (fr); 3608 } 3609 3610 3611 /* ------------------------------------------------------------------------ */ 3612 /* Function: ipf_flushlist */ 3613 /* Returns: int - >= 0 - number of flushed rules */ 3614 /* Parameters: softc(I) - pointer to soft context main structure */ 3615 /* nfreedp(O) - pointer to int where flush count is stored */ 3616 /* listp(I) - pointer to list to flush pointer */ 3617 /* Write Locks: ipf_mutex */ 3618 /* */ 3619 /* Recursively flush rules from the list, descending groups as they are */ 3620 /* encountered. if a rule is the head of a group and it has lost all its */ 3621 /* group members, then also delete the group reference. nfreedp is needed */ 3622 /* to store the accumulating count of rules removed, whereas the returned */ 3623 /* value is just the number removed from the current list. The latter is */ 3624 /* needed to correctly adjust reference counts on rules that define groups. */ 3625 /* */ 3626 /* NOTE: Rules not loaded from user space cannot be flushed. */ 3627 /* ------------------------------------------------------------------------ */ 3628 static int 3629 ipf_flushlist(ipf_main_softc_t *softc, int *nfreedp, frentry_t **listp) 3630 { 3631 int freed = 0; 3632 frentry_t *fp; 3633 3634 while ((fp = *listp) != NULL) { 3635 if ((fp->fr_type & FR_T_BUILTIN) || 3636 !(fp->fr_flags & FR_COPIED)) { 3637 listp = &fp->fr_next; 3638 continue; 3639 } 3640 *listp = fp->fr_next; 3641 if (fp->fr_next != NULL) 3642 fp->fr_next->fr_pnext = fp->fr_pnext; 3643 fp->fr_pnext = NULL; 3644 3645 if (fp->fr_grphead != NULL) { 3646 freed += ipf_group_flush(softc, fp->fr_grphead); 3647 fp->fr_names[fp->fr_grhead] = '\0'; 3648 } 3649 3650 if (fp->fr_icmpgrp != NULL) { 3651 freed += ipf_group_flush(softc, fp->fr_icmpgrp); 3652 fp->fr_names[fp->fr_icmphead] = '\0'; 3653 } 3654 3655 if (fp->fr_srctrack.ht_max_nodes) 3656 ipf_rb_ht_flush(&fp->fr_srctrack); 3657 3658 fp->fr_next = NULL; 3659 3660 ASSERT(fp->fr_ref > 0); 3661 if (ipf_derefrule(softc, &fp) == 0) 3662 freed++; 3663 } 3664 *nfreedp += freed; 3665 return (freed); 3666 } 3667 3668 3669 /* ------------------------------------------------------------------------ */ 3670 /* Function: ipf_flush */ 3671 /* Returns: int - >= 0 - number of flushed rules */ 3672 /* Parameters: softc(I) - pointer to soft context main structure */ 3673 /* unit(I) - device for which to flush rules */ 3674 /* flags(I) - which set of rules to flush */ 3675 /* */ 3676 /* Calls flushlist() for all filter rules (accounting, firewall - both IPv4 */ 3677 /* and IPv6) as defined by the value of flags. */ 3678 /* ------------------------------------------------------------------------ */ 3679 int 3680 ipf_flush(ipf_main_softc_t *softc, minor_t unit, int flags) 3681 { 3682 int flushed = 0, set; 3683 3684 WRITE_ENTER(&softc->ipf_mutex); 3685 3686 set = softc->ipf_active; 3687 if ((flags & FR_INACTIVE) == FR_INACTIVE) 3688 set = 1 - set; 3689 3690 if (flags & FR_OUTQUE) { 3691 ipf_flushlist(softc, &flushed, &softc->ipf_rules[1][set]); 3692 ipf_flushlist(softc, &flushed, &softc->ipf_acct[1][set]); 3693 } 3694 if (flags & FR_INQUE) { 3695 ipf_flushlist(softc, &flushed, &softc->ipf_rules[0][set]); 3696 ipf_flushlist(softc, &flushed, &softc->ipf_acct[0][set]); 3697 } 3698 3699 flushed += ipf_flush_groups(softc, &softc->ipf_groups[unit][set], 3700 flags & (FR_INQUE|FR_OUTQUE)); 3701 3702 RWLOCK_EXIT(&softc->ipf_mutex); 3703 3704 if (unit == IPL_LOGIPF) { 3705 int tmp; 3706 3707 tmp = ipf_flush(softc, IPL_LOGCOUNT, flags); 3708 if (tmp >= 0) 3709 flushed += tmp; 3710 } 3711 return (flushed); 3712 } 3713 3714 3715 /* ------------------------------------------------------------------------ */ 3716 /* Function: ipf_flush_groups */ 3717 /* Returns: int - >= 0 - number of flushed rules */ 3718 /* Parameters: softc(I) - soft context pointerto work with */ 3719 /* grhead(I) - pointer to the start of the group list to flush */ 3720 /* flags(I) - which set of rules to flush */ 3721 /* */ 3722 /* Walk through all of the groups under the given group head and remove all */ 3723 /* of those that match the flags passed in. The for loop here is bit more */ 3724 /* complicated than usual because the removal of a rule with ipf_derefrule */ 3725 /* may end up removing not only the structure pointed to by "fg" but also */ 3726 /* what is fg_next and fg_next after that. So if a filter rule is actually */ 3727 /* removed from the group then it is necessary to start again. */ 3728 /* ------------------------------------------------------------------------ */ 3729 static int 3730 ipf_flush_groups(ipf_main_softc_t *softc, frgroup_t **grhead, int flags) 3731 { 3732 frentry_t *fr, **frp; 3733 frgroup_t *fg, **fgp; 3734 int flushed = 0; 3735 int removed = 0; 3736 3737 for (fgp = grhead; (fg = *fgp) != NULL; ) { 3738 while ((fg != NULL) && ((fg->fg_flags & flags) == 0)) 3739 fg = fg->fg_next; 3740 if (fg == NULL) 3741 break; 3742 removed = 0; 3743 frp = &fg->fg_start; 3744 while ((removed == 0) && ((fr = *frp) != NULL)) { 3745 if ((fr->fr_flags & flags) == 0) { 3746 frp = &fr->fr_next; 3747 } else { 3748 if (fr->fr_next != NULL) 3749 fr->fr_next->fr_pnext = fr->fr_pnext; 3750 *frp = fr->fr_next; 3751 fr->fr_pnext = NULL; 3752 fr->fr_next = NULL; 3753 (void) ipf_derefrule(softc, &fr); 3754 flushed++; 3755 removed++; 3756 } 3757 } 3758 if (removed == 0) 3759 fgp = &fg->fg_next; 3760 } 3761 return (flushed); 3762 } 3763 3764 3765 /* ------------------------------------------------------------------------ */ 3766 /* Function: memstr */ 3767 /* Returns: char * - NULL if failed, != NULL pointer to matching bytes */ 3768 /* Parameters: src(I) - pointer to byte sequence to match */ 3769 /* dst(I) - pointer to byte sequence to search */ 3770 /* slen(I) - match length */ 3771 /* dlen(I) - length available to search in */ 3772 /* */ 3773 /* Search dst for a sequence of bytes matching those at src and extend for */ 3774 /* slen bytes. */ 3775 /* ------------------------------------------------------------------------ */ 3776 char * 3777 memstr(const char *src, char *dst, size_t slen, size_t dlen) 3778 { 3779 char *s = NULL; 3780 3781 while (dlen >= slen) { 3782 if (bcmp(src, dst, slen) == 0) { 3783 s = dst; 3784 break; 3785 } 3786 dst++; 3787 dlen--; 3788 } 3789 return (s); 3790 } 3791 /* ------------------------------------------------------------------------ */ 3792 /* Function: ipf_fixskip */ 3793 /* Returns: Nil */ 3794 /* Parameters: listp(IO) - pointer to start of list with skip rule */ 3795 /* rp(I) - rule added/removed with skip in it. */ 3796 /* addremove(I) - adjustment (-1/+1) to make to skip count, */ 3797 /* depending on whether a rule was just added */ 3798 /* or removed. */ 3799 /* */ 3800 /* Adjust all the rules in a list which would have skip'd past the position */ 3801 /* where we are inserting to skip to the right place given the change. */ 3802 /* ------------------------------------------------------------------------ */ 3803 void 3804 ipf_fixskip(frentry_t **listp, frentry_t *rp, int addremove) 3805 { 3806 int rules, rn; 3807 frentry_t *fp; 3808 3809 rules = 0; 3810 for (fp = *listp; (fp != NULL) && (fp != rp); fp = fp->fr_next) 3811 rules++; 3812 3813 if (fp == NULL) 3814 return; 3815 3816 for (rn = 0, fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++) 3817 if (FR_ISSKIP(fp->fr_flags) && (rn + fp->fr_arg >= rules)) 3818 fp->fr_arg += addremove; 3819 } 3820 3821 3822 #ifdef _KERNEL 3823 /* ------------------------------------------------------------------------ */ 3824 /* Function: count4bits */ 3825 /* Returns: int - >= 0 - number of consecutive bits in input */ 3826 /* Parameters: ip(I) - 32bit IP address */ 3827 /* */ 3828 /* IPv4 ONLY */ 3829 /* count consecutive 1's in bit mask. If the mask generated by counting */ 3830 /* consecutive 1's is different to that passed, return -1, else return # */ 3831 /* of bits. */ 3832 /* ------------------------------------------------------------------------ */ 3833 int 3834 count4bits(u_32_t ip) 3835 { 3836 u_32_t ipn; 3837 int cnt = 0, i, j; 3838 3839 ip = ipn = ntohl(ip); 3840 for (i = 32; i; i--, ipn *= 2) 3841 if (ipn & 0x80000000) 3842 cnt++; 3843 else 3844 break; 3845 ipn = 0; 3846 for (i = 32, j = cnt; i; i--, j--) { 3847 ipn *= 2; 3848 if (j > 0) 3849 ipn++; 3850 } 3851 if (ipn == ip) 3852 return (cnt); 3853 return (-1); 3854 } 3855 3856 3857 /* ------------------------------------------------------------------------ */ 3858 /* Function: count6bits */ 3859 /* Returns: int - >= 0 - number of consecutive bits in input */ 3860 /* Parameters: msk(I) - pointer to start of IPv6 bitmask */ 3861 /* */ 3862 /* IPv6 ONLY */ 3863 /* count consecutive 1's in bit mask. */ 3864 /* ------------------------------------------------------------------------ */ 3865 # ifdef USE_INET6 3866 int 3867 count6bits(u_32_t *msk) 3868 { 3869 int i = 0, k; 3870 u_32_t j; 3871 3872 for (k = 3; k >= 0; k--) 3873 if (msk[k] == 0xffffffff) 3874 i += 32; 3875 else { 3876 for (j = msk[k]; j; j <<= 1) 3877 if (j & 0x80000000) 3878 i++; 3879 } 3880 return (i); 3881 } 3882 # endif 3883 #endif /* _KERNEL */ 3884 3885 3886 /* ------------------------------------------------------------------------ */ 3887 /* Function: ipf_synclist */ 3888 /* Returns: int - 0 = no failures, else indication of first failure */ 3889 /* Parameters: fr(I) - start of filter list to sync interface names for */ 3890 /* ifp(I) - interface pointer for limiting sync lookups */ 3891 /* Write Locks: ipf_mutex */ 3892 /* */ 3893 /* Walk through a list of filter rules and resolve any interface names into */ 3894 /* pointers. Where dynamic addresses are used, also update the IP address */ 3895 /* used in the rule. The interface pointer is used to limit the lookups to */ 3896 /* a specific set of matching names if it is non-NULL. */ 3897 /* Errors can occur when resolving the destination name of to/dup-to fields */ 3898 /* when the name points to a pool and that pool doest not exist. If this */ 3899 /* does happen then it is necessary to check if there are any lookup refs */ 3900 /* that need to be dropped before returning with an error. */ 3901 /* ------------------------------------------------------------------------ */ 3902 static int 3903 ipf_synclist(ipf_main_softc_t *softc, frentry_t *fr, void *ifp) 3904 { 3905 frentry_t *frt, *start = fr; 3906 frdest_t *fdp; 3907 char *name; 3908 int error; 3909 void *ifa; 3910 int v, i; 3911 3912 error = 0; 3913 3914 for (; fr; fr = fr->fr_next) { 3915 if (fr->fr_family == AF_INET) 3916 v = 4; 3917 else if (fr->fr_family == AF_INET6) 3918 v = 6; 3919 else 3920 v = 0; 3921 3922 /* 3923 * Lookup all the interface names that are part of the rule. 3924 */ 3925 for (i = 0; i < FR_NUM(fr->fr_ifas); i++) { 3926 if ((ifp != NULL) && (fr->fr_ifas[i] != ifp)) 3927 continue; 3928 if (fr->fr_ifnames[i] == -1) 3929 continue; 3930 name = FR_NAME(fr, fr_ifnames[i]); 3931 fr->fr_ifas[i] = ipf_resolvenic(softc, name, v); 3932 } 3933 3934 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) { 3935 if (fr->fr_satype != FRI_NORMAL && 3936 fr->fr_satype != FRI_LOOKUP) { 3937 ifa = ipf_resolvenic(softc, fr->fr_names + 3938 fr->fr_sifpidx, v); 3939 ipf_ifpaddr(softc, v, fr->fr_satype, ifa, 3940 &fr->fr_src6, &fr->fr_smsk6); 3941 } 3942 if (fr->fr_datype != FRI_NORMAL && 3943 fr->fr_datype != FRI_LOOKUP) { 3944 ifa = ipf_resolvenic(softc, fr->fr_names + 3945 fr->fr_sifpidx, v); 3946 ipf_ifpaddr(softc, v, fr->fr_datype, ifa, 3947 &fr->fr_dst6, &fr->fr_dmsk6); 3948 } 3949 } 3950 3951 fdp = &fr->fr_tifs[0]; 3952 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) { 3953 error = ipf_resolvedest(softc, fr->fr_names, fdp, v); 3954 if (error != 0) 3955 goto unwind; 3956 } 3957 3958 fdp = &fr->fr_tifs[1]; 3959 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) { 3960 error = ipf_resolvedest(softc, fr->fr_names, fdp, v); 3961 if (error != 0) 3962 goto unwind; 3963 } 3964 3965 fdp = &fr->fr_dif; 3966 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) { 3967 error = ipf_resolvedest(softc, fr->fr_names, fdp, v); 3968 if (error != 0) 3969 goto unwind; 3970 } 3971 3972 if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 3973 (fr->fr_satype == FRI_LOOKUP) && (fr->fr_srcptr == NULL)) { 3974 fr->fr_srcptr = ipf_lookup_res_num(softc, 3975 fr->fr_srctype, 3976 IPL_LOGIPF, 3977 fr->fr_srcnum, 3978 &fr->fr_srcfunc); 3979 } 3980 if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 3981 (fr->fr_datype == FRI_LOOKUP) && (fr->fr_dstptr == NULL)) { 3982 fr->fr_dstptr = ipf_lookup_res_num(softc, 3983 fr->fr_dsttype, 3984 IPL_LOGIPF, 3985 fr->fr_dstnum, 3986 &fr->fr_dstfunc); 3987 } 3988 } 3989 return (0); 3990 3991 unwind: 3992 for (frt = start; frt != fr; fr = fr->fr_next) { 3993 if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 3994 (frt->fr_satype == FRI_LOOKUP) && (frt->fr_srcptr != NULL)) 3995 ipf_lookup_deref(softc, frt->fr_srctype, 3996 frt->fr_srcptr); 3997 if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 3998 (frt->fr_datype == FRI_LOOKUP) && (frt->fr_dstptr != NULL)) 3999 ipf_lookup_deref(softc, frt->fr_dsttype, 4000 frt->fr_dstptr); 4001 } 4002 return (error); 4003 } 4004 4005 4006 /* ------------------------------------------------------------------------ */ 4007 /* Function: ipf_sync */ 4008 /* Returns: void */ 4009 /* Parameters: Nil */ 4010 /* */ 4011 /* ipf_sync() is called when we suspect that the interface list or */ 4012 /* information about interfaces (like IP#) has changed. Go through all */ 4013 /* filter rules, NAT entries and the state table and check if anything */ 4014 /* needs to be changed/updated. */ 4015 /* ------------------------------------------------------------------------ */ 4016 int 4017 ipf_sync(ipf_main_softc_t *softc, void *ifp) 4018 { 4019 int i; 4020 4021 #if !SOLARIS 4022 ipf_nat_sync(softc, ifp); 4023 ipf_state_sync(softc, ifp); 4024 ipf_lookup_sync(softc, ifp); 4025 #endif 4026 4027 WRITE_ENTER(&softc->ipf_mutex); 4028 (void) ipf_synclist(softc, softc->ipf_acct[0][softc->ipf_active], ifp); 4029 (void) ipf_synclist(softc, softc->ipf_acct[1][softc->ipf_active], ifp); 4030 (void) ipf_synclist(softc, softc->ipf_rules[0][softc->ipf_active], ifp); 4031 (void) ipf_synclist(softc, softc->ipf_rules[1][softc->ipf_active], ifp); 4032 4033 for (i = 0; i < IPL_LOGSIZE; i++) { 4034 frgroup_t *g; 4035 4036 for (g = softc->ipf_groups[i][0]; g != NULL; g = g->fg_next) 4037 (void) ipf_synclist(softc, g->fg_start, ifp); 4038 for (g = softc->ipf_groups[i][1]; g != NULL; g = g->fg_next) 4039 (void) ipf_synclist(softc, g->fg_start, ifp); 4040 } 4041 RWLOCK_EXIT(&softc->ipf_mutex); 4042 4043 return (0); 4044 } 4045 4046 4047 /* 4048 * In the functions below, bcopy() is called because the pointer being 4049 * copied _from_ in this instance is a pointer to a char buf (which could 4050 * end up being unaligned) and on the kernel's local stack. 4051 */ 4052 /* ------------------------------------------------------------------------ */ 4053 /* Function: copyinptr */ 4054 /* Returns: int - 0 = success, else failure */ 4055 /* Parameters: src(I) - pointer to the source address */ 4056 /* dst(I) - destination address */ 4057 /* size(I) - number of bytes to copy */ 4058 /* */ 4059 /* Copy a block of data in from user space, given a pointer to the pointer */ 4060 /* to start copying from (src) and a pointer to where to store it (dst). */ 4061 /* NB: src - pointer to user space pointer, dst - kernel space pointer */ 4062 /* ------------------------------------------------------------------------ */ 4063 int 4064 copyinptr(ipf_main_softc_t *softc, void *src, void *dst, size_t size) 4065 { 4066 caddr_t ca; 4067 int error; 4068 4069 #if SOLARIS 4070 error = COPYIN(src, &ca, sizeof(ca)); 4071 if (error != 0) 4072 return (error); 4073 #else 4074 bcopy(src, (caddr_t)&ca, sizeof(ca)); 4075 #endif 4076 error = COPYIN(ca, dst, size); 4077 if (error != 0) { 4078 IPFERROR(3); 4079 error = EFAULT; 4080 } 4081 return (error); 4082 } 4083 4084 4085 /* ------------------------------------------------------------------------ */ 4086 /* Function: copyoutptr */ 4087 /* Returns: int - 0 = success, else failure */ 4088 /* Parameters: src(I) - pointer to the source address */ 4089 /* dst(I) - destination address */ 4090 /* size(I) - number of bytes to copy */ 4091 /* */ 4092 /* Copy a block of data out to user space, given a pointer to the pointer */ 4093 /* to start copying from (src) and a pointer to where to store it (dst). */ 4094 /* NB: src - kernel space pointer, dst - pointer to user space pointer. */ 4095 /* ------------------------------------------------------------------------ */ 4096 int 4097 copyoutptr(ipf_main_softc_t *softc, void *src, void *dst, size_t size) 4098 { 4099 caddr_t ca; 4100 int error; 4101 4102 bcopy(dst, (caddr_t)&ca, sizeof(ca)); 4103 error = COPYOUT(src, ca, size); 4104 if (error != 0) { 4105 IPFERROR(4); 4106 error = EFAULT; 4107 } 4108 return (error); 4109 } 4110 4111 4112 /* ------------------------------------------------------------------------ */ 4113 /* Function: ipf_lock */ 4114 /* Returns: int - 0 = success, else error */ 4115 /* Parameters: data(I) - pointer to lock value to set */ 4116 /* lockp(O) - pointer to location to store old lock value */ 4117 /* */ 4118 /* Get the new value for the lock integer, set it and return the old value */ 4119 /* in *lockp. */ 4120 /* ------------------------------------------------------------------------ */ 4121 int 4122 ipf_lock(caddr_t data, int *lockp) 4123 { 4124 int arg, err; 4125 4126 err = BCOPYIN(data, &arg, sizeof(arg)); 4127 if (err != 0) 4128 return (EFAULT); 4129 err = BCOPYOUT(lockp, data, sizeof(*lockp)); 4130 if (err != 0) 4131 return (EFAULT); 4132 *lockp = arg; 4133 return (0); 4134 } 4135 4136 4137 /* ------------------------------------------------------------------------ */ 4138 /* Function: ipf_getstat */ 4139 /* Returns: Nil */ 4140 /* Parameters: softc(I) - pointer to soft context main structure */ 4141 /* fiop(I) - pointer to ipfilter stats structure */ 4142 /* rev(I) - version claim by program doing ioctl */ 4143 /* */ 4144 /* Stores a copy of current pointers, counters, etc, in the friostat */ 4145 /* structure. */ 4146 /* If IPFILTER_COMPAT is compiled, we pretend to be whatever version the */ 4147 /* program is looking for. This ensure that validation of the version it */ 4148 /* expects will always succeed. Thus kernels with IPFILTER_COMPAT will */ 4149 /* allow older binaries to work but kernels without it will not. */ 4150 /* ------------------------------------------------------------------------ */ 4151 /*ARGSUSED*/ 4152 static void 4153 ipf_getstat(ipf_main_softc_t *softc, friostat_t *fiop, int rev) 4154 { 4155 int i; 4156 4157 bcopy((char *)softc->ipf_stats, (char *)fiop->f_st, 4158 sizeof(ipf_statistics_t) * 2); 4159 fiop->f_locks[IPL_LOGSTATE] = -1; 4160 fiop->f_locks[IPL_LOGNAT] = -1; 4161 fiop->f_locks[IPL_LOGIPF] = -1; 4162 fiop->f_locks[IPL_LOGAUTH] = -1; 4163 4164 fiop->f_ipf[0][0] = softc->ipf_rules[0][0]; 4165 fiop->f_acct[0][0] = softc->ipf_acct[0][0]; 4166 fiop->f_ipf[0][1] = softc->ipf_rules[0][1]; 4167 fiop->f_acct[0][1] = softc->ipf_acct[0][1]; 4168 fiop->f_ipf[1][0] = softc->ipf_rules[1][0]; 4169 fiop->f_acct[1][0] = softc->ipf_acct[1][0]; 4170 fiop->f_ipf[1][1] = softc->ipf_rules[1][1]; 4171 fiop->f_acct[1][1] = softc->ipf_acct[1][1]; 4172 4173 fiop->f_ticks = softc->ipf_ticks; 4174 fiop->f_active = softc->ipf_active; 4175 fiop->f_froute[0] = softc->ipf_frouteok[0]; 4176 fiop->f_froute[1] = softc->ipf_frouteok[1]; 4177 fiop->f_rb_no_mem = softc->ipf_rb_no_mem; 4178 fiop->f_rb_node_max = softc->ipf_rb_node_max; 4179 4180 fiop->f_running = softc->ipf_running; 4181 for (i = 0; i < IPL_LOGSIZE; i++) { 4182 fiop->f_groups[i][0] = softc->ipf_groups[i][0]; 4183 fiop->f_groups[i][1] = softc->ipf_groups[i][1]; 4184 } 4185 #ifdef IPFILTER_LOG 4186 fiop->f_log_ok = ipf_log_logok(softc, IPL_LOGIPF); 4187 fiop->f_log_fail = ipf_log_failures(softc, IPL_LOGIPF); 4188 fiop->f_logging = 1; 4189 #else 4190 fiop->f_log_ok = 0; 4191 fiop->f_log_fail = 0; 4192 fiop->f_logging = 0; 4193 #endif 4194 fiop->f_defpass = softc->ipf_pass; 4195 fiop->f_features = ipf_features; 4196 4197 #ifdef IPFILTER_COMPAT 4198 snprintf(fiop->f_version, sizeof(friostat.f_version), "IP Filter: v%d.%d.%d", 4199 (rev / 1000000) % 100, 4200 (rev / 10000) % 100, 4201 (rev / 100) % 100); 4202 #else 4203 rev = rev; 4204 (void) strncpy(fiop->f_version, ipfilter_version, 4205 sizeof(fiop->f_version)); 4206 #endif 4207 } 4208 4209 4210 #ifdef USE_INET6 4211 int icmptoicmp6types[ICMP_MAXTYPE+1] = { 4212 ICMP6_ECHO_REPLY, /* 0: ICMP_ECHOREPLY */ 4213 -1, /* 1: UNUSED */ 4214 -1, /* 2: UNUSED */ 4215 ICMP6_DST_UNREACH, /* 3: ICMP_UNREACH */ 4216 -1, /* 4: ICMP_SOURCEQUENCH */ 4217 ND_REDIRECT, /* 5: ICMP_REDIRECT */ 4218 -1, /* 6: UNUSED */ 4219 -1, /* 7: UNUSED */ 4220 ICMP6_ECHO_REQUEST, /* 8: ICMP_ECHO */ 4221 -1, /* 9: UNUSED */ 4222 -1, /* 10: UNUSED */ 4223 ICMP6_TIME_EXCEEDED, /* 11: ICMP_TIMXCEED */ 4224 ICMP6_PARAM_PROB, /* 12: ICMP_PARAMPROB */ 4225 -1, /* 13: ICMP_TSTAMP */ 4226 -1, /* 14: ICMP_TSTAMPREPLY */ 4227 -1, /* 15: ICMP_IREQ */ 4228 -1, /* 16: ICMP_IREQREPLY */ 4229 -1, /* 17: ICMP_MASKREQ */ 4230 -1, /* 18: ICMP_MASKREPLY */ 4231 }; 4232 4233 4234 int icmptoicmp6unreach[ICMP_MAX_UNREACH] = { 4235 ICMP6_DST_UNREACH_ADDR, /* 0: ICMP_UNREACH_NET */ 4236 ICMP6_DST_UNREACH_ADDR, /* 1: ICMP_UNREACH_HOST */ 4237 -1, /* 2: ICMP_UNREACH_PROTOCOL */ 4238 ICMP6_DST_UNREACH_NOPORT, /* 3: ICMP_UNREACH_PORT */ 4239 -1, /* 4: ICMP_UNREACH_NEEDFRAG */ 4240 ICMP6_DST_UNREACH_NOTNEIGHBOR, /* 5: ICMP_UNREACH_SRCFAIL */ 4241 ICMP6_DST_UNREACH_ADDR, /* 6: ICMP_UNREACH_NET_UNKNOWN */ 4242 ICMP6_DST_UNREACH_ADDR, /* 7: ICMP_UNREACH_HOST_UNKNOWN */ 4243 -1, /* 8: ICMP_UNREACH_ISOLATED */ 4244 ICMP6_DST_UNREACH_ADMIN, /* 9: ICMP_UNREACH_NET_PROHIB */ 4245 ICMP6_DST_UNREACH_ADMIN, /* 10: ICMP_UNREACH_HOST_PROHIB */ 4246 -1, /* 11: ICMP_UNREACH_TOSNET */ 4247 -1, /* 12: ICMP_UNREACH_TOSHOST */ 4248 ICMP6_DST_UNREACH_ADMIN, /* 13: ICMP_UNREACH_ADMIN_PROHIBIT */ 4249 }; 4250 int icmpreplytype6[ICMP6_MAXTYPE + 1]; 4251 #endif 4252 4253 int icmpreplytype4[ICMP_MAXTYPE + 1]; 4254 4255 4256 /* ------------------------------------------------------------------------ */ 4257 /* Function: ipf_matchicmpqueryreply */ 4258 /* Returns: int - 1 if "icmp" is a valid reply to "ic" else 0. */ 4259 /* Parameters: v(I) - IP protocol version (4 or 6) */ 4260 /* ic(I) - ICMP information */ 4261 /* icmp(I) - ICMP packet header */ 4262 /* rev(I) - direction (0 = forward/1 = reverse) of packet */ 4263 /* */ 4264 /* Check if the ICMP packet defined by the header pointed to by icmp is a */ 4265 /* reply to one as described by what's in ic. If it is a match, return 1, */ 4266 /* else return 0 for no match. */ 4267 /* ------------------------------------------------------------------------ */ 4268 int 4269 ipf_matchicmpqueryreply(int v, icmpinfo_t *ic, icmphdr_t *icmp, int rev) 4270 { 4271 int ictype; 4272 4273 ictype = ic->ici_type; 4274 4275 if (v == 4) { 4276 /* 4277 * If we matched its type on the way in, then when going out 4278 * it will still be the same type. 4279 */ 4280 if ((!rev && (icmp->icmp_type == ictype)) || 4281 (rev && (icmpreplytype4[ictype] == icmp->icmp_type))) { 4282 if (icmp->icmp_type != ICMP_ECHOREPLY) 4283 return (1); 4284 if (icmp->icmp_id == ic->ici_id) 4285 return (1); 4286 } 4287 } 4288 #ifdef USE_INET6 4289 else if (v == 6) { 4290 if ((!rev && (icmp->icmp_type == ictype)) || 4291 (rev && (icmpreplytype6[ictype] == icmp->icmp_type))) { 4292 if (icmp->icmp_type != ICMP6_ECHO_REPLY) 4293 return (1); 4294 if (icmp->icmp_id == ic->ici_id) 4295 return (1); 4296 } 4297 } 4298 #endif 4299 return (0); 4300 } 4301 4302 4303 /* 4304 * IFNAMES are located in the variable length field starting at 4305 * frentry.fr_names. As pointers within the struct cannot be passed 4306 * to the kernel from ipf(8), an offset is used. An offset of -1 means it 4307 * is unused (invalid). If it is used (valid) it is an offset to the 4308 * character string of an interface name or a comment. The following 4309 * macros will assist those who follow to understand the code. 4310 */ 4311 #define IPF_IFNAME_VALID(_a) (_a != -1) 4312 #define IPF_IFNAME_INVALID(_a) (_a == -1) 4313 #define IPF_IFNAMES_DIFFERENT(_a) \ 4314 !((IPF_IFNAME_INVALID(fr1->_a) && \ 4315 IPF_IFNAME_INVALID(fr2->_a)) || \ 4316 (IPF_IFNAME_VALID(fr1->_a) && \ 4317 IPF_IFNAME_VALID(fr2->_a) && \ 4318 !strcmp(FR_NAME(fr1, _a), FR_NAME(fr2, _a)))) 4319 #define IPF_FRDEST_DIFFERENT(_a) \ 4320 (memcmp(&fr1->_a.fd_addr, &fr2->_a.fd_addr, \ 4321 offsetof(frdest_t, fd_name) - offsetof(frdest_t, fd_addr)) || \ 4322 IPF_IFNAMES_DIFFERENT(_a.fd_name)) 4323 4324 4325 /* ------------------------------------------------------------------------ */ 4326 /* Function: ipf_rule_compare */ 4327 /* Parameters: fr1(I) - first rule structure to compare */ 4328 /* fr2(I) - second rule structure to compare */ 4329 /* Returns: int - 0 == rules are the same, else mismatch */ 4330 /* */ 4331 /* Compare two rules and return 0 if they match or a number indicating */ 4332 /* which of the individual checks failed. */ 4333 /* ------------------------------------------------------------------------ */ 4334 static int 4335 ipf_rule_compare(frentry_t *fr1, frentry_t *fr2) 4336 { 4337 int i; 4338 4339 if (fr1->fr_cksum != fr2->fr_cksum) 4340 return (1); 4341 if (fr1->fr_size != fr2->fr_size) 4342 return (2); 4343 if (fr1->fr_dsize != fr2->fr_dsize) 4344 return (3); 4345 if (bcmp((char *)&fr1->fr_func, (char *)&fr2->fr_func, FR_CMPSIZ) 4346 != 0) 4347 return (4); 4348 /* 4349 * XXX: There is still a bug here as different rules with the 4350 * the same interfaces but in a different order will compare 4351 * differently. But since multiple interfaces in a rule doesn't 4352 * work anyway a simple straightforward compare is performed 4353 * here. Ultimately frentry_t creation will need to be 4354 * revisited in ipf_y.y. While the other issue, recognition 4355 * of only the first interface in a list of interfaces will 4356 * need to be separately addressed along with why only four. 4357 */ 4358 for (i = 0; i < FR_NUM(fr1->fr_ifnames); i++) { 4359 /* 4360 * XXX: It's either the same index or uninitialized. 4361 * We assume this because multiple interfaces 4362 * referenced by the same rule doesn't work anyway. 4363 */ 4364 if (IPF_IFNAMES_DIFFERENT(fr_ifnames[i])) 4365 return (5); 4366 } 4367 4368 if (IPF_FRDEST_DIFFERENT(fr_tif)) 4369 return (6); 4370 if (IPF_FRDEST_DIFFERENT(fr_rif)) 4371 return (7); 4372 if (IPF_FRDEST_DIFFERENT(fr_dif)) 4373 return (8); 4374 if (!fr1->fr_data && !fr2->fr_data) 4375 return (0); /* move along, nothing to see here */ 4376 if (fr1->fr_data && fr2->fr_data) { 4377 if (bcmp(fr1->fr_caddr, fr2->fr_caddr, fr1->fr_dsize) == 0) 4378 return (0); /* same */ 4379 } 4380 return (9); 4381 } 4382 4383 4384 /* ------------------------------------------------------------------------ */ 4385 /* Function: frrequest */ 4386 /* Returns: int - 0 == success, > 0 == errno value */ 4387 /* Parameters: unit(I) - device for which this is for */ 4388 /* req(I) - ioctl command (SIOC*) */ 4389 /* data(I) - pointr to ioctl data */ 4390 /* set(I) - 1 or 0 (filter set) */ 4391 /* makecopy(I) - flag indicating whether data points to a rule */ 4392 /* in kernel space & hence doesn't need copying. */ 4393 /* */ 4394 /* This function handles all the requests which operate on the list of */ 4395 /* filter rules. This includes adding, deleting, insertion. It is also */ 4396 /* responsible for creating groups when a "head" rule is loaded. Interface */ 4397 /* names are resolved here and other sanity checks are made on the content */ 4398 /* of the rule structure being loaded. If a rule has user defined timeouts */ 4399 /* then make sure they are created and initialised before exiting. */ 4400 /* ------------------------------------------------------------------------ */ 4401 int 4402 frrequest(ipf_main_softc_t *softc, int unit, ioctlcmd_t req, caddr_t data, 4403 int set, int makecopy) 4404 { 4405 int error = 0, in, family, need_free = 0; 4406 enum { OP_ADD, /* add rule */ 4407 OP_REM, /* remove rule */ 4408 OP_ZERO /* zero statistics and counters */ } 4409 addrem = OP_ADD; 4410 frentry_t frd, *fp, *f, **fprev, **ftail; 4411 void *ptr, *uptr, *cptr; 4412 u_int *p, *pp; 4413 frgroup_t *fg; 4414 char *group; 4415 4416 ptr = NULL; 4417 cptr = NULL; 4418 fg = NULL; 4419 fp = &frd; 4420 if (makecopy != 0) { 4421 bzero(fp, sizeof(frd)); 4422 error = ipf_inobj(softc, data, NULL, fp, IPFOBJ_FRENTRY); 4423 if (error) { 4424 return (error); 4425 } 4426 if ((fp->fr_type & FR_T_BUILTIN) != 0) { 4427 IPFERROR(6); 4428 return (EINVAL); 4429 } 4430 KMALLOCS(f, frentry_t *, fp->fr_size); 4431 if (f == NULL) { 4432 IPFERROR(131); 4433 return (ENOMEM); 4434 } 4435 bzero(f, fp->fr_size); 4436 error = ipf_inobjsz(softc, data, f, IPFOBJ_FRENTRY, 4437 fp->fr_size); 4438 if (error) { 4439 KFREES(f, fp->fr_size); 4440 return (error); 4441 } 4442 4443 fp = f; 4444 f = NULL; 4445 fp->fr_next = NULL; 4446 fp->fr_dnext = NULL; 4447 fp->fr_pnext = NULL; 4448 fp->fr_pdnext = NULL; 4449 fp->fr_grp = NULL; 4450 fp->fr_grphead = NULL; 4451 fp->fr_icmpgrp = NULL; 4452 fp->fr_isc = (void *)-1; 4453 fp->fr_ptr = NULL; 4454 fp->fr_ref = 0; 4455 fp->fr_flags |= FR_COPIED; 4456 } else { 4457 fp = (frentry_t *)data; 4458 if ((fp->fr_type & FR_T_BUILTIN) == 0) { 4459 IPFERROR(7); 4460 return (EINVAL); 4461 } 4462 fp->fr_flags &= ~FR_COPIED; 4463 } 4464 4465 if (((fp->fr_dsize == 0) && (fp->fr_data != NULL)) || 4466 ((fp->fr_dsize != 0) && (fp->fr_data == NULL))) { 4467 IPFERROR(8); 4468 error = EINVAL; 4469 goto donenolock; 4470 } 4471 4472 family = fp->fr_family; 4473 uptr = fp->fr_data; 4474 4475 if (req == (ioctlcmd_t)SIOCINAFR || req == (ioctlcmd_t)SIOCINIFR || 4476 req == (ioctlcmd_t)SIOCADAFR || req == (ioctlcmd_t)SIOCADIFR) 4477 addrem = OP_ADD; /* Add rule */ 4478 else if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR) 4479 addrem = OP_REM; /* Remove rule */ 4480 else if (req == (ioctlcmd_t)SIOCZRLST) 4481 addrem = OP_ZERO; /* Zero statistics and counters */ 4482 else { 4483 IPFERROR(9); 4484 error = EINVAL; 4485 goto donenolock; 4486 } 4487 4488 /* 4489 * Only filter rules for IPv4 or IPv6 are accepted. 4490 */ 4491 if (family == AF_INET) { 4492 /*EMPTY*/; 4493 #ifdef USE_INET6 4494 } else if (family == AF_INET6) { 4495 /*EMPTY*/; 4496 #endif 4497 } else if (family != 0) { 4498 IPFERROR(10); 4499 error = EINVAL; 4500 goto donenolock; 4501 } 4502 4503 /* 4504 * If the rule is being loaded from user space, i.e. we had to copy it 4505 * into kernel space, then do not trust the function pointer in the 4506 * rule. 4507 */ 4508 if ((makecopy == 1) && (fp->fr_func != NULL)) { 4509 if (ipf_findfunc(fp->fr_func) == NULL) { 4510 IPFERROR(11); 4511 error = ESRCH; 4512 goto donenolock; 4513 } 4514 4515 if (addrem == OP_ADD) { 4516 error = ipf_funcinit(softc, fp); 4517 if (error != 0) 4518 goto donenolock; 4519 } 4520 } 4521 if ((fp->fr_flags & FR_CALLNOW) && 4522 ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) { 4523 IPFERROR(142); 4524 error = ESRCH; 4525 goto donenolock; 4526 } 4527 if (((fp->fr_flags & FR_CMDMASK) == FR_CALL) && 4528 ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) { 4529 IPFERROR(143); 4530 error = ESRCH; 4531 goto donenolock; 4532 } 4533 4534 ptr = NULL; 4535 cptr = NULL; 4536 4537 if (FR_ISACCOUNT(fp->fr_flags)) 4538 unit = IPL_LOGCOUNT; 4539 4540 /* 4541 * Check that each group name in the rule has a start index that 4542 * is valid. 4543 */ 4544 if (fp->fr_icmphead != -1) { 4545 if ((fp->fr_icmphead < 0) || 4546 (fp->fr_icmphead >= fp->fr_namelen)) { 4547 IPFERROR(136); 4548 error = EINVAL; 4549 goto donenolock; 4550 } 4551 if (!strcmp(FR_NAME(fp, fr_icmphead), "0")) 4552 fp->fr_names[fp->fr_icmphead] = '\0'; 4553 } 4554 4555 if (fp->fr_grhead != -1) { 4556 if ((fp->fr_grhead < 0) || 4557 (fp->fr_grhead >= fp->fr_namelen)) { 4558 IPFERROR(137); 4559 error = EINVAL; 4560 goto donenolock; 4561 } 4562 if (!strcmp(FR_NAME(fp, fr_grhead), "0")) 4563 fp->fr_names[fp->fr_grhead] = '\0'; 4564 } 4565 4566 if (fp->fr_group != -1) { 4567 if ((fp->fr_group < 0) || 4568 (fp->fr_group >= fp->fr_namelen)) { 4569 IPFERROR(138); 4570 error = EINVAL; 4571 goto donenolock; 4572 } 4573 if ((req != (int)SIOCZRLST) && (fp->fr_group != -1)) { 4574 /* 4575 * Allow loading rules that are in groups to cause 4576 * them to be created if they don't already exit. 4577 */ 4578 group = FR_NAME(fp, fr_group); 4579 if (addrem == OP_ADD) { 4580 fg = ipf_group_add(softc, group, NULL, 4581 fp->fr_flags, unit, set); 4582 fp->fr_grp = fg; 4583 } else { 4584 fg = ipf_findgroup(softc, group, unit, 4585 set, NULL); 4586 if (fg == NULL) { 4587 IPFERROR(12); 4588 error = ESRCH; 4589 goto donenolock; 4590 } 4591 } 4592 4593 if (fg->fg_flags == 0) { 4594 fg->fg_flags = fp->fr_flags & FR_INOUT; 4595 } else if (fg->fg_flags != (fp->fr_flags & FR_INOUT)) { 4596 IPFERROR(13); 4597 error = ESRCH; 4598 goto donenolock; 4599 } 4600 } 4601 } else { 4602 /* 4603 * If a rule is going to be part of a group then it does 4604 * not matter whether it is an in or out rule, but if it 4605 * isn't in a group, then it does... 4606 */ 4607 if ((fp->fr_flags & (FR_INQUE|FR_OUTQUE)) == 0) { 4608 IPFERROR(14); 4609 error = EINVAL; 4610 goto donenolock; 4611 } 4612 } 4613 in = (fp->fr_flags & FR_INQUE) ? 0 : 1; 4614 4615 /* 4616 * Work out which rule list this change is being applied to. 4617 */ 4618 ftail = NULL; 4619 fprev = NULL; 4620 if (unit == IPL_LOGAUTH) { 4621 if ((fp->fr_tifs[0].fd_ptr != NULL) || 4622 (fp->fr_tifs[1].fd_ptr != NULL) || 4623 (fp->fr_dif.fd_ptr != NULL) || 4624 (fp->fr_flags & FR_FASTROUTE)) { 4625 softc->ipf_interror = 145; 4626 error = EINVAL; 4627 goto donenolock; 4628 } 4629 fprev = ipf_auth_rulehead(softc); 4630 } else { 4631 if (FR_ISACCOUNT(fp->fr_flags)) 4632 fprev = &softc->ipf_acct[in][set]; 4633 else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0) 4634 fprev = &softc->ipf_rules[in][set]; 4635 } 4636 if (fprev == NULL) { 4637 IPFERROR(15); 4638 error = ESRCH; 4639 goto donenolock; 4640 } 4641 4642 if (fg != NULL) 4643 fprev = &fg->fg_start; 4644 4645 /* 4646 * Copy in extra data for the rule. 4647 */ 4648 if (fp->fr_dsize != 0) { 4649 if (makecopy != 0) { 4650 KMALLOCS(ptr, void *, fp->fr_dsize); 4651 if (ptr == NULL) { 4652 IPFERROR(16); 4653 error = ENOMEM; 4654 goto donenolock; 4655 } 4656 4657 /* 4658 * The bcopy case is for when the data is appended 4659 * to the rule by ipf_in_compat(). 4660 */ 4661 if (uptr >= (void *)fp && 4662 uptr < (void *)((char *)fp + fp->fr_size)) { 4663 bcopy(uptr, ptr, fp->fr_dsize); 4664 error = 0; 4665 } else { 4666 error = COPYIN(uptr, ptr, fp->fr_dsize); 4667 if (error != 0) { 4668 IPFERROR(17); 4669 error = EFAULT; 4670 goto donenolock; 4671 } 4672 } 4673 } else { 4674 ptr = uptr; 4675 } 4676 fp->fr_data = ptr; 4677 } else { 4678 fp->fr_data = NULL; 4679 } 4680 4681 /* 4682 * Perform per-rule type sanity checks of their members. 4683 * All code after this needs to be aware that allocated memory 4684 * may need to be free'd before exiting. 4685 */ 4686 switch (fp->fr_type & ~FR_T_BUILTIN) 4687 { 4688 #if defined(IPFILTER_BPF) 4689 case FR_T_BPFOPC : 4690 if (fp->fr_dsize == 0) { 4691 IPFERROR(19); 4692 error = EINVAL; 4693 break; 4694 } 4695 if (!bpf_validate(ptr, fp->fr_dsize/sizeof(struct bpf_insn))) { 4696 IPFERROR(20); 4697 error = EINVAL; 4698 break; 4699 } 4700 break; 4701 #endif 4702 case FR_T_IPF : 4703 /* 4704 * Preparation for error case at the bottom of this function. 4705 */ 4706 if (fp->fr_datype == FRI_LOOKUP) 4707 fp->fr_dstptr = NULL; 4708 if (fp->fr_satype == FRI_LOOKUP) 4709 fp->fr_srcptr = NULL; 4710 4711 if (fp->fr_dsize != sizeof(fripf_t)) { 4712 IPFERROR(21); 4713 error = EINVAL; 4714 break; 4715 } 4716 4717 /* 4718 * Allowing a rule with both "keep state" and "with oow" is 4719 * pointless because adding a state entry to the table will 4720 * fail with the out of window (oow) flag set. 4721 */ 4722 if ((fp->fr_flags & FR_KEEPSTATE) && (fp->fr_flx & FI_OOW)) { 4723 IPFERROR(22); 4724 error = EINVAL; 4725 break; 4726 } 4727 4728 switch (fp->fr_satype) 4729 { 4730 case FRI_BROADCAST : 4731 case FRI_DYNAMIC : 4732 case FRI_NETWORK : 4733 case FRI_NETMASKED : 4734 case FRI_PEERADDR : 4735 if (fp->fr_sifpidx < 0) { 4736 IPFERROR(23); 4737 error = EINVAL; 4738 } 4739 break; 4740 case FRI_LOOKUP : 4741 fp->fr_srcptr = ipf_findlookup(softc, unit, fp, 4742 &fp->fr_src6, 4743 &fp->fr_smsk6); 4744 if (fp->fr_srcfunc == NULL) { 4745 IPFERROR(132); 4746 error = ESRCH; 4747 break; 4748 } 4749 break; 4750 case FRI_NORMAL : 4751 break; 4752 default : 4753 IPFERROR(133); 4754 error = EINVAL; 4755 break; 4756 } 4757 if (error != 0) 4758 break; 4759 4760 switch (fp->fr_datype) 4761 { 4762 case FRI_BROADCAST : 4763 case FRI_DYNAMIC : 4764 case FRI_NETWORK : 4765 case FRI_NETMASKED : 4766 case FRI_PEERADDR : 4767 if (fp->fr_difpidx < 0) { 4768 IPFERROR(24); 4769 error = EINVAL; 4770 } 4771 break; 4772 case FRI_LOOKUP : 4773 fp->fr_dstptr = ipf_findlookup(softc, unit, fp, 4774 &fp->fr_dst6, 4775 &fp->fr_dmsk6); 4776 if (fp->fr_dstfunc == NULL) { 4777 IPFERROR(134); 4778 error = ESRCH; 4779 } 4780 break; 4781 case FRI_NORMAL : 4782 break; 4783 default : 4784 IPFERROR(135); 4785 error = EINVAL; 4786 } 4787 break; 4788 4789 case FR_T_NONE : 4790 case FR_T_CALLFUNC : 4791 case FR_T_COMPIPF : 4792 break; 4793 4794 case FR_T_IPFEXPR : 4795 if (ipf_matcharray_verify(fp->fr_data, fp->fr_dsize) == -1) { 4796 IPFERROR(25); 4797 error = EINVAL; 4798 } 4799 break; 4800 4801 default : 4802 IPFERROR(26); 4803 error = EINVAL; 4804 break; 4805 } 4806 if (error != 0) 4807 goto donenolock; 4808 4809 if (fp->fr_tif.fd_name != -1) { 4810 if ((fp->fr_tif.fd_name < 0) || 4811 (fp->fr_tif.fd_name >= fp->fr_namelen)) { 4812 IPFERROR(139); 4813 error = EINVAL; 4814 goto donenolock; 4815 } 4816 } 4817 4818 if (fp->fr_dif.fd_name != -1) { 4819 if ((fp->fr_dif.fd_name < 0) || 4820 (fp->fr_dif.fd_name >= fp->fr_namelen)) { 4821 IPFERROR(140); 4822 error = EINVAL; 4823 goto donenolock; 4824 } 4825 } 4826 4827 if (fp->fr_rif.fd_name != -1) { 4828 if ((fp->fr_rif.fd_name < 0) || 4829 (fp->fr_rif.fd_name >= fp->fr_namelen)) { 4830 IPFERROR(141); 4831 error = EINVAL; 4832 goto donenolock; 4833 } 4834 } 4835 4836 /* 4837 * Lookup all the interface names that are part of the rule. 4838 */ 4839 error = ipf_synclist(softc, fp, NULL); 4840 if (error != 0) 4841 goto donenolock; 4842 fp->fr_statecnt = 0; 4843 if (fp->fr_srctrack.ht_max_nodes != 0) 4844 ipf_rb_ht_init(&fp->fr_srctrack); 4845 4846 /* 4847 * Look for an existing matching filter rule, but don't include the 4848 * next or interface pointer in the comparison (fr_next, fr_ifa). 4849 * This elminates rules which are indentical being loaded. Checksum 4850 * the constant part of the filter rule to make comparisons quicker 4851 * (this meaning no pointers are included). 4852 */ 4853 pp = (u_int *)(fp->fr_caddr + fp->fr_dsize); 4854 for (fp->fr_cksum = 0, p = (u_int *)fp->fr_data; p < pp; p++) 4855 fp->fr_cksum += *p; 4856 4857 WRITE_ENTER(&softc->ipf_mutex); 4858 4859 /* 4860 * Now that the filter rule lists are locked, we can walk the 4861 * chain of them without fear. 4862 */ 4863 ftail = fprev; 4864 for (f = *ftail; (f = *ftail) != NULL; ftail = &f->fr_next) { 4865 if (fp->fr_collect <= f->fr_collect) { 4866 ftail = fprev; 4867 f = NULL; 4868 break; 4869 } 4870 fprev = ftail; 4871 } 4872 4873 for (; (f = *ftail) != NULL; ftail = &f->fr_next) { 4874 if (ipf_rule_compare(fp, f) == 0) 4875 break; 4876 } 4877 4878 /* 4879 * If zero'ing statistics, copy current to caller and zero. 4880 */ 4881 if (addrem == OP_ZERO) { 4882 if (f == NULL) { 4883 IPFERROR(27); 4884 error = ESRCH; 4885 } else { 4886 /* 4887 * Copy and reduce lock because of impending copyout. 4888 * Well we should, but if we do then the atomicity of 4889 * this call and the correctness of fr_hits and 4890 * fr_bytes cannot be guaranteed. As it is, this code 4891 * only resets them to 0 if they are successfully 4892 * copied out into user space. 4893 */ 4894 bcopy((char *)f, (char *)fp, f->fr_size); 4895 /* MUTEX_DOWNGRADE(&softc->ipf_mutex); */ 4896 4897 /* 4898 * When we copy this rule back out, set the data 4899 * pointer to be what it was in user space. 4900 */ 4901 fp->fr_data = uptr; 4902 error = ipf_outobj(softc, data, fp, IPFOBJ_FRENTRY); 4903 4904 if (error == 0) { 4905 if ((f->fr_dsize != 0) && (uptr != NULL)) { 4906 error = COPYOUT(f->fr_data, uptr, 4907 f->fr_dsize); 4908 if (error == 0) { 4909 f->fr_hits = 0; 4910 f->fr_bytes = 0; 4911 } else { 4912 IPFERROR(28); 4913 error = EFAULT; 4914 } 4915 } 4916 } 4917 } 4918 4919 if (makecopy != 0) { 4920 if (ptr != NULL) { 4921 KFREES(ptr, fp->fr_dsize); 4922 } 4923 KFREES(fp, fp->fr_size); 4924 } 4925 RWLOCK_EXIT(&softc->ipf_mutex); 4926 return (error); 4927 } 4928 4929 if (f == NULL) { 4930 /* 4931 * At the end of this, ftail must point to the place where the 4932 * new rule is to be saved/inserted/added. 4933 * For SIOCAD*FR, this should be the last rule in the group of 4934 * rules that have equal fr_collect fields. 4935 * For SIOCIN*FR, ... 4936 */ 4937 if (req == (ioctlcmd_t)SIOCADAFR || 4938 req == (ioctlcmd_t)SIOCADIFR) { 4939 4940 for (ftail = fprev; (f = *ftail) != NULL; ) { 4941 if (f->fr_collect > fp->fr_collect) 4942 break; 4943 ftail = &f->fr_next; 4944 fprev = ftail; 4945 } 4946 ftail = fprev; 4947 f = NULL; 4948 ptr = NULL; 4949 } else if (req == (ioctlcmd_t)SIOCINAFR || 4950 req == (ioctlcmd_t)SIOCINIFR) { 4951 while ((f = *fprev) != NULL) { 4952 if (f->fr_collect >= fp->fr_collect) 4953 break; 4954 fprev = &f->fr_next; 4955 } 4956 ftail = fprev; 4957 if (fp->fr_hits != 0) { 4958 while (fp->fr_hits && (f = *ftail)) { 4959 if (f->fr_collect != fp->fr_collect) 4960 break; 4961 fprev = ftail; 4962 ftail = &f->fr_next; 4963 fp->fr_hits--; 4964 } 4965 } 4966 f = NULL; 4967 ptr = NULL; 4968 } 4969 } 4970 4971 /* 4972 * Request to remove a rule. 4973 */ 4974 if (addrem == OP_REM) { 4975 if (f == NULL) { 4976 IPFERROR(29); 4977 error = ESRCH; 4978 } else { 4979 /* 4980 * Do not allow activity from user space to interfere 4981 * with rules not loaded that way. 4982 */ 4983 if ((makecopy == 1) && !(f->fr_flags & FR_COPIED)) { 4984 IPFERROR(30); 4985 error = EPERM; 4986 goto done; 4987 } 4988 4989 /* 4990 * Return EBUSY if the rule is being reference by 4991 * something else (eg state information.) 4992 */ 4993 if (f->fr_ref > 1) { 4994 IPFERROR(31); 4995 error = EBUSY; 4996 goto done; 4997 } 4998 #ifdef IPFILTER_SCAN 4999 if (f->fr_isctag != -1 && 5000 (f->fr_isc != (struct ipscan *)-1)) 5001 ipf_scan_detachfr(f); 5002 #endif 5003 5004 if (unit == IPL_LOGAUTH) { 5005 error = ipf_auth_precmd(softc, req, f, ftail); 5006 goto done; 5007 } 5008 5009 ipf_rule_delete(softc, f, unit, set); 5010 5011 need_free = makecopy; 5012 } 5013 } else { 5014 /* 5015 * Not removing, so we must be adding/inserting a rule. 5016 */ 5017 if (f != NULL) { 5018 IPFERROR(32); 5019 error = EEXIST; 5020 goto done; 5021 } 5022 if (unit == IPL_LOGAUTH) { 5023 error = ipf_auth_precmd(softc, req, fp, ftail); 5024 goto done; 5025 } 5026 5027 MUTEX_NUKE(&fp->fr_lock); 5028 MUTEX_INIT(&fp->fr_lock, "filter rule lock"); 5029 if (fp->fr_die != 0) 5030 ipf_rule_expire_insert(softc, fp, set); 5031 5032 fp->fr_hits = 0; 5033 if (makecopy != 0) 5034 fp->fr_ref = 1; 5035 fp->fr_pnext = ftail; 5036 fp->fr_next = *ftail; 5037 if (fp->fr_next != NULL) 5038 fp->fr_next->fr_pnext = &fp->fr_next; 5039 *ftail = fp; 5040 ipf_fixskip(ftail, fp, 1); 5041 5042 fp->fr_icmpgrp = NULL; 5043 if (fp->fr_icmphead != -1) { 5044 group = FR_NAME(fp, fr_icmphead); 5045 fg = ipf_group_add(softc, group, fp, 0, unit, set); 5046 fp->fr_icmpgrp = fg; 5047 } 5048 5049 fp->fr_grphead = NULL; 5050 if (fp->fr_grhead != -1) { 5051 group = FR_NAME(fp, fr_grhead); 5052 fg = ipf_group_add(softc, group, fp, fp->fr_flags, 5053 unit, set); 5054 fp->fr_grphead = fg; 5055 } 5056 } 5057 done: 5058 RWLOCK_EXIT(&softc->ipf_mutex); 5059 donenolock: 5060 if (need_free || (error != 0)) { 5061 if ((fp->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) { 5062 if ((fp->fr_satype == FRI_LOOKUP) && 5063 (fp->fr_srcptr != NULL)) 5064 ipf_lookup_deref(softc, fp->fr_srctype, 5065 fp->fr_srcptr); 5066 if ((fp->fr_datype == FRI_LOOKUP) && 5067 (fp->fr_dstptr != NULL)) 5068 ipf_lookup_deref(softc, fp->fr_dsttype, 5069 fp->fr_dstptr); 5070 } 5071 if (fp->fr_grp != NULL) { 5072 WRITE_ENTER(&softc->ipf_mutex); 5073 ipf_group_del(softc, fp->fr_grp, fp); 5074 RWLOCK_EXIT(&softc->ipf_mutex); 5075 } 5076 if ((ptr != NULL) && (makecopy != 0)) { 5077 KFREES(ptr, fp->fr_dsize); 5078 } 5079 KFREES(fp, fp->fr_size); 5080 } 5081 return (error); 5082 } 5083 5084 5085 /* ------------------------------------------------------------------------ */ 5086 /* Function: ipf_rule_delete */ 5087 /* Returns: Nil */ 5088 /* Parameters: softc(I) - pointer to soft context main structure */ 5089 /* f(I) - pointer to the rule being deleted */ 5090 /* ftail(I) - pointer to the pointer to f */ 5091 /* unit(I) - device for which this is for */ 5092 /* set(I) - 1 or 0 (filter set) */ 5093 /* */ 5094 /* This function attempts to do what it can to delete a filter rule: remove */ 5095 /* it from any linked lists and remove any groups it is responsible for. */ 5096 /* But in the end, removing a rule can only drop the reference count - we */ 5097 /* must use that as the guide for whether or not it can be freed. */ 5098 /* ------------------------------------------------------------------------ */ 5099 static void 5100 ipf_rule_delete(ipf_main_softc_t *softc, frentry_t *f, int unit, int set) 5101 { 5102 5103 /* 5104 * If fr_pdnext is set, then the rule is on the expire list, so 5105 * remove it from there. 5106 */ 5107 if (f->fr_pdnext != NULL) { 5108 *f->fr_pdnext = f->fr_dnext; 5109 if (f->fr_dnext != NULL) 5110 f->fr_dnext->fr_pdnext = f->fr_pdnext; 5111 f->fr_pdnext = NULL; 5112 f->fr_dnext = NULL; 5113 } 5114 5115 ipf_fixskip(f->fr_pnext, f, -1); 5116 if (f->fr_pnext != NULL) 5117 *f->fr_pnext = f->fr_next; 5118 if (f->fr_next != NULL) 5119 f->fr_next->fr_pnext = f->fr_pnext; 5120 f->fr_pnext = NULL; 5121 f->fr_next = NULL; 5122 5123 (void) ipf_derefrule(softc, &f); 5124 } 5125 5126 /* ------------------------------------------------------------------------ */ 5127 /* Function: ipf_rule_expire_insert */ 5128 /* Returns: Nil */ 5129 /* Parameters: softc(I) - pointer to soft context main structure */ 5130 /* f(I) - pointer to rule to be added to expire list */ 5131 /* set(I) - 1 or 0 (filter set) */ 5132 /* */ 5133 /* If the new rule has a given expiration time, insert it into the list of */ 5134 /* expiring rules with the ones to be removed first added to the front of */ 5135 /* the list. The insertion is O(n) but it is kept sorted for quick scans at */ 5136 /* expiration interval checks. */ 5137 /* ------------------------------------------------------------------------ */ 5138 static void 5139 ipf_rule_expire_insert(ipf_main_softc_t *softc, frentry_t *f, int set) 5140 { 5141 frentry_t *fr; 5142 5143 /* 5144 */ 5145 5146 f->fr_die = softc->ipf_ticks + IPF_TTLVAL(f->fr_die); 5147 for (fr = softc->ipf_rule_explist[set]; fr != NULL; 5148 fr = fr->fr_dnext) { 5149 if (f->fr_die < fr->fr_die) 5150 break; 5151 if (fr->fr_dnext == NULL) { 5152 /* 5153 * We've got to the last rule and everything 5154 * wanted to be expired before this new node, 5155 * so we have to tack it on the end... 5156 */ 5157 fr->fr_dnext = f; 5158 f->fr_pdnext = &fr->fr_dnext; 5159 fr = NULL; 5160 break; 5161 } 5162 } 5163 5164 if (softc->ipf_rule_explist[set] == NULL) { 5165 softc->ipf_rule_explist[set] = f; 5166 f->fr_pdnext = &softc->ipf_rule_explist[set]; 5167 } else if (fr != NULL) { 5168 f->fr_dnext = fr; 5169 f->fr_pdnext = fr->fr_pdnext; 5170 fr->fr_pdnext = &f->fr_dnext; 5171 } 5172 } 5173 5174 5175 /* ------------------------------------------------------------------------ */ 5176 /* Function: ipf_findlookup */ 5177 /* Returns: NULL = failure, else success */ 5178 /* Parameters: softc(I) - pointer to soft context main structure */ 5179 /* unit(I) - ipf device we want to find match for */ 5180 /* fp(I) - rule for which lookup is for */ 5181 /* addrp(I) - pointer to lookup information in address struct */ 5182 /* maskp(O) - pointer to lookup information for storage */ 5183 /* */ 5184 /* When using pools and hash tables to store addresses for matching in */ 5185 /* rules, it is necessary to resolve both the object referred to by the */ 5186 /* name or address (and return that pointer) and also provide the means by */ 5187 /* which to determine if an address belongs to that object to make the */ 5188 /* packet matching quicker. */ 5189 /* ------------------------------------------------------------------------ */ 5190 static void * 5191 ipf_findlookup(ipf_main_softc_t *softc, int unit, frentry_t *fr, 5192 i6addr_t *addrp, i6addr_t *maskp) 5193 { 5194 void *ptr = NULL; 5195 5196 switch (addrp->iplookupsubtype) 5197 { 5198 case 0 : 5199 ptr = ipf_lookup_res_num(softc, unit, addrp->iplookuptype, 5200 addrp->iplookupnum, 5201 &maskp->iplookupfunc); 5202 break; 5203 case 1 : 5204 if (addrp->iplookupname < 0) 5205 break; 5206 if (addrp->iplookupname >= fr->fr_namelen) 5207 break; 5208 ptr = ipf_lookup_res_name(softc, unit, addrp->iplookuptype, 5209 fr->fr_names + addrp->iplookupname, 5210 &maskp->iplookupfunc); 5211 break; 5212 default : 5213 break; 5214 } 5215 5216 return (ptr); 5217 } 5218 5219 5220 /* ------------------------------------------------------------------------ */ 5221 /* Function: ipf_funcinit */ 5222 /* Returns: int - 0 == success, else ESRCH: cannot resolve rule details */ 5223 /* Parameters: softc(I) - pointer to soft context main structure */ 5224 /* fr(I) - pointer to filter rule */ 5225 /* */ 5226 /* If a rule is a call rule, then check if the function it points to needs */ 5227 /* an init function to be called now the rule has been loaded. */ 5228 /* ------------------------------------------------------------------------ */ 5229 static int 5230 ipf_funcinit(ipf_main_softc_t *softc, frentry_t *fr) 5231 { 5232 ipfunc_resolve_t *ft; 5233 int err; 5234 5235 IPFERROR(34); 5236 err = ESRCH; 5237 5238 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5239 if (ft->ipfu_addr == fr->fr_func) { 5240 err = 0; 5241 if (ft->ipfu_init != NULL) 5242 err = (*ft->ipfu_init)(softc, fr); 5243 break; 5244 } 5245 return (err); 5246 } 5247 5248 5249 /* ------------------------------------------------------------------------ */ 5250 /* Function: ipf_funcfini */ 5251 /* Returns: Nil */ 5252 /* Parameters: softc(I) - pointer to soft context main structure */ 5253 /* fr(I) - pointer to filter rule */ 5254 /* */ 5255 /* For a given filter rule, call the matching "fini" function if the rule */ 5256 /* is using a known function that would have resulted in the "init" being */ 5257 /* called for ealier. */ 5258 /* ------------------------------------------------------------------------ */ 5259 static void 5260 ipf_funcfini(ipf_main_softc_t *softc, frentry_t *fr) 5261 { 5262 ipfunc_resolve_t *ft; 5263 5264 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5265 if (ft->ipfu_addr == fr->fr_func) { 5266 if (ft->ipfu_fini != NULL) 5267 (void) (*ft->ipfu_fini)(softc, fr); 5268 break; 5269 } 5270 } 5271 5272 5273 /* ------------------------------------------------------------------------ */ 5274 /* Function: ipf_findfunc */ 5275 /* Returns: ipfunc_t - pointer to function if found, else NULL */ 5276 /* Parameters: funcptr(I) - function pointer to lookup */ 5277 /* */ 5278 /* Look for a function in the table of known functions. */ 5279 /* ------------------------------------------------------------------------ */ 5280 static ipfunc_t 5281 ipf_findfunc(ipfunc_t funcptr) 5282 { 5283 ipfunc_resolve_t *ft; 5284 5285 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5286 if (ft->ipfu_addr == funcptr) 5287 return (funcptr); 5288 return (NULL); 5289 } 5290 5291 5292 /* ------------------------------------------------------------------------ */ 5293 /* Function: ipf_resolvefunc */ 5294 /* Returns: int - 0 == success, else error */ 5295 /* Parameters: data(IO) - ioctl data pointer to ipfunc_resolve_t struct */ 5296 /* */ 5297 /* Copy in a ipfunc_resolve_t structure and then fill in the missing field. */ 5298 /* This will either be the function name (if the pointer is set) or the */ 5299 /* function pointer if the name is set. When found, fill in the other one */ 5300 /* so that the entire, complete, structure can be copied back to user space.*/ 5301 /* ------------------------------------------------------------------------ */ 5302 int 5303 ipf_resolvefunc(ipf_main_softc_t *softc, void *data) 5304 { 5305 ipfunc_resolve_t res, *ft; 5306 int error; 5307 5308 error = BCOPYIN(data, &res, sizeof(res)); 5309 if (error != 0) { 5310 IPFERROR(123); 5311 return (EFAULT); 5312 } 5313 5314 if (res.ipfu_addr == NULL && res.ipfu_name[0] != '\0') { 5315 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5316 if (strncmp(res.ipfu_name, ft->ipfu_name, 5317 sizeof(res.ipfu_name)) == 0) { 5318 res.ipfu_addr = ft->ipfu_addr; 5319 res.ipfu_init = ft->ipfu_init; 5320 if (COPYOUT(&res, data, sizeof(res)) != 0) { 5321 IPFERROR(35); 5322 return (EFAULT); 5323 } 5324 return (0); 5325 } 5326 } 5327 if (res.ipfu_addr != NULL && res.ipfu_name[0] == '\0') { 5328 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5329 if (ft->ipfu_addr == res.ipfu_addr) { 5330 (void) strncpy(res.ipfu_name, ft->ipfu_name, 5331 sizeof(res.ipfu_name)); 5332 res.ipfu_init = ft->ipfu_init; 5333 if (COPYOUT(&res, data, sizeof(res)) != 0) { 5334 IPFERROR(36); 5335 return (EFAULT); 5336 } 5337 return (0); 5338 } 5339 } 5340 IPFERROR(37); 5341 return (ESRCH); 5342 } 5343 5344 5345 #if !defined(_KERNEL) || SOLARIS 5346 /* 5347 * From: NetBSD 5348 * ppsratecheck(): packets (or events) per second limitation. 5349 */ 5350 int 5351 ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps) 5352 /* maxpps: maximum pps allowed */ 5353 { 5354 struct timeval tv, delta; 5355 int rv; 5356 5357 GETKTIME(&tv); 5358 5359 delta.tv_sec = tv.tv_sec - lasttime->tv_sec; 5360 delta.tv_usec = tv.tv_usec - lasttime->tv_usec; 5361 if (delta.tv_usec < 0) { 5362 delta.tv_sec--; 5363 delta.tv_usec += 1000000; 5364 } 5365 5366 /* 5367 * check for 0,0 is so that the message will be seen at least once. 5368 * if more than one second have passed since the last update of 5369 * lasttime, reset the counter. 5370 * 5371 * we do increment *curpps even in *curpps < maxpps case, as some may 5372 * try to use *curpps for stat purposes as well. 5373 */ 5374 if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) || 5375 delta.tv_sec >= 1) { 5376 *lasttime = tv; 5377 *curpps = 0; 5378 rv = 1; 5379 } else if (maxpps < 0) 5380 rv = 1; 5381 else if (*curpps < maxpps) 5382 rv = 1; 5383 else 5384 rv = 0; 5385 *curpps = *curpps + 1; 5386 5387 return (rv); 5388 } 5389 #endif 5390 5391 5392 /* ------------------------------------------------------------------------ */ 5393 /* Function: ipf_derefrule */ 5394 /* Returns: int - 0 == rule freed up, else rule not freed */ 5395 /* Parameters: fr(I) - pointer to filter rule */ 5396 /* */ 5397 /* Decrement the reference counter to a rule by one. If it reaches zero, */ 5398 /* free it and any associated storage space being used by it. */ 5399 /* ------------------------------------------------------------------------ */ 5400 int 5401 ipf_derefrule(ipf_main_softc_t *softc, frentry_t **frp) 5402 { 5403 frentry_t *fr; 5404 frdest_t *fdp; 5405 5406 fr = *frp; 5407 *frp = NULL; 5408 5409 MUTEX_ENTER(&fr->fr_lock); 5410 fr->fr_ref--; 5411 if (fr->fr_ref == 0) { 5412 MUTEX_EXIT(&fr->fr_lock); 5413 MUTEX_DESTROY(&fr->fr_lock); 5414 5415 ipf_funcfini(softc, fr); 5416 5417 fdp = &fr->fr_tif; 5418 if (fdp->fd_type == FRD_DSTLIST) 5419 ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr); 5420 5421 fdp = &fr->fr_rif; 5422 if (fdp->fd_type == FRD_DSTLIST) 5423 ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr); 5424 5425 fdp = &fr->fr_dif; 5426 if (fdp->fd_type == FRD_DSTLIST) 5427 ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr); 5428 5429 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF && 5430 fr->fr_satype == FRI_LOOKUP) 5431 ipf_lookup_deref(softc, fr->fr_srctype, fr->fr_srcptr); 5432 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF && 5433 fr->fr_datype == FRI_LOOKUP) 5434 ipf_lookup_deref(softc, fr->fr_dsttype, fr->fr_dstptr); 5435 5436 if (fr->fr_grp != NULL) 5437 ipf_group_del(softc, fr->fr_grp, fr); 5438 5439 if (fr->fr_grphead != NULL) 5440 ipf_group_del(softc, fr->fr_grphead, fr); 5441 5442 if (fr->fr_icmpgrp != NULL) 5443 ipf_group_del(softc, fr->fr_icmpgrp, fr); 5444 5445 if ((fr->fr_flags & FR_COPIED) != 0) { 5446 if (fr->fr_dsize) { 5447 KFREES(fr->fr_data, fr->fr_dsize); 5448 } 5449 KFREES(fr, fr->fr_size); 5450 return (0); 5451 } 5452 return (1); 5453 } else { 5454 MUTEX_EXIT(&fr->fr_lock); 5455 } 5456 return (-1); 5457 } 5458 5459 5460 /* ------------------------------------------------------------------------ */ 5461 /* Function: ipf_grpmapinit */ 5462 /* Returns: int - 0 == success, else ESRCH because table entry not found*/ 5463 /* Parameters: fr(I) - pointer to rule to find hash table for */ 5464 /* */ 5465 /* Looks for group hash table fr_arg and stores a pointer to it in fr_ptr. */ 5466 /* fr_ptr is later used by ipf_srcgrpmap and ipf_dstgrpmap. */ 5467 /* ------------------------------------------------------------------------ */ 5468 static int 5469 ipf_grpmapinit(ipf_main_softc_t *softc, frentry_t *fr) 5470 { 5471 char name[FR_GROUPLEN]; 5472 iphtable_t *iph; 5473 5474 (void) snprintf(name, sizeof(name), "%d", fr->fr_arg); 5475 iph = ipf_lookup_find_htable(softc, IPL_LOGIPF, name); 5476 if (iph == NULL) { 5477 IPFERROR(38); 5478 return (ESRCH); 5479 } 5480 if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT)) { 5481 IPFERROR(39); 5482 return (ESRCH); 5483 } 5484 iph->iph_ref++; 5485 fr->fr_ptr = iph; 5486 return (0); 5487 } 5488 5489 5490 /* ------------------------------------------------------------------------ */ 5491 /* Function: ipf_grpmapfini */ 5492 /* Returns: int - 0 == success, else ESRCH because table entry not found*/ 5493 /* Parameters: softc(I) - pointer to soft context main structure */ 5494 /* fr(I) - pointer to rule to release hash table for */ 5495 /* */ 5496 /* For rules that have had ipf_grpmapinit called, ipf_lookup_deref needs to */ 5497 /* be called to undo what ipf_grpmapinit caused to be done. */ 5498 /* ------------------------------------------------------------------------ */ 5499 static int 5500 ipf_grpmapfini(ipf_main_softc_t *softc, frentry_t *fr) 5501 { 5502 iphtable_t *iph; 5503 iph = fr->fr_ptr; 5504 if (iph != NULL) 5505 ipf_lookup_deref(softc, IPLT_HASH, iph); 5506 return (0); 5507 } 5508 5509 5510 /* ------------------------------------------------------------------------ */ 5511 /* Function: ipf_srcgrpmap */ 5512 /* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ 5513 /* Parameters: fin(I) - pointer to packet information */ 5514 /* passp(IO) - pointer to current/new filter decision (unused) */ 5515 /* */ 5516 /* Look for a rule group head in a hash table, using the source address as */ 5517 /* the key, and descend into that group and continue matching rules against */ 5518 /* the packet. */ 5519 /* ------------------------------------------------------------------------ */ 5520 frentry_t * 5521 ipf_srcgrpmap(fr_info_t *fin, u_32_t *passp) 5522 { 5523 frgroup_t *fg; 5524 void *rval; 5525 5526 rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr, 5527 &fin->fin_src); 5528 if (rval == NULL) 5529 return (NULL); 5530 5531 fg = rval; 5532 fin->fin_fr = fg->fg_start; 5533 (void) ipf_scanlist(fin, *passp); 5534 return (fin->fin_fr); 5535 } 5536 5537 5538 /* ------------------------------------------------------------------------ */ 5539 /* Function: ipf_dstgrpmap */ 5540 /* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ 5541 /* Parameters: fin(I) - pointer to packet information */ 5542 /* passp(IO) - pointer to current/new filter decision (unused) */ 5543 /* */ 5544 /* Look for a rule group head in a hash table, using the destination */ 5545 /* address as the key, and descend into that group and continue matching */ 5546 /* rules against the packet. */ 5547 /* ------------------------------------------------------------------------ */ 5548 frentry_t * 5549 ipf_dstgrpmap(fr_info_t *fin, u_32_t *passp) 5550 { 5551 frgroup_t *fg; 5552 void *rval; 5553 5554 rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr, 5555 &fin->fin_dst); 5556 if (rval == NULL) 5557 return (NULL); 5558 5559 fg = rval; 5560 fin->fin_fr = fg->fg_start; 5561 (void) ipf_scanlist(fin, *passp); 5562 return (fin->fin_fr); 5563 } 5564 5565 /* 5566 * Queue functions 5567 * =============== 5568 * These functions manage objects on queues for efficient timeouts. There 5569 * are a number of system defined queues as well as user defined timeouts. 5570 * It is expected that a lock is held in the domain in which the queue 5571 * belongs (i.e. either state or NAT) when calling any of these functions 5572 * that prevents ipf_freetimeoutqueue() from being called at the same time 5573 * as any other. 5574 */ 5575 5576 5577 /* ------------------------------------------------------------------------ */ 5578 /* Function: ipf_addtimeoutqueue */ 5579 /* Returns: struct ifqtq * - NULL if malloc fails, else pointer to */ 5580 /* timeout queue with given interval. */ 5581 /* Parameters: parent(I) - pointer to pointer to parent node of this list */ 5582 /* of interface queues. */ 5583 /* seconds(I) - timeout value in seconds for this queue. */ 5584 /* */ 5585 /* This routine first looks for a timeout queue that matches the interval */ 5586 /* being requested. If it finds one, increments the reference counter and */ 5587 /* returns a pointer to it. If none are found, it allocates a new one and */ 5588 /* inserts it at the top of the list. */ 5589 /* */ 5590 /* Locking. */ 5591 /* It is assumed that the caller of this function has an appropriate lock */ 5592 /* held (exclusively) in the domain that encompases 'parent'. */ 5593 /* ------------------------------------------------------------------------ */ 5594 ipftq_t * 5595 ipf_addtimeoutqueue(ipf_main_softc_t *softc, ipftq_t **parent, u_int seconds) 5596 { 5597 ipftq_t *ifq; 5598 u_int period; 5599 5600 period = seconds * IPF_HZ_DIVIDE; 5601 5602 MUTEX_ENTER(&softc->ipf_timeoutlock); 5603 for (ifq = *parent; ifq != NULL; ifq = ifq->ifq_next) { 5604 if (ifq->ifq_ttl == period) { 5605 /* 5606 * Reset the delete flag, if set, so the structure 5607 * gets reused rather than freed and reallocated. 5608 */ 5609 MUTEX_ENTER(&ifq->ifq_lock); 5610 ifq->ifq_flags &= ~IFQF_DELETE; 5611 ifq->ifq_ref++; 5612 MUTEX_EXIT(&ifq->ifq_lock); 5613 MUTEX_EXIT(&softc->ipf_timeoutlock); 5614 5615 return (ifq); 5616 } 5617 } 5618 5619 KMALLOC(ifq, ipftq_t *); 5620 if (ifq != NULL) { 5621 MUTEX_NUKE(&ifq->ifq_lock); 5622 IPFTQ_INIT(ifq, period, "ipftq mutex"); 5623 ifq->ifq_next = *parent; 5624 ifq->ifq_pnext = parent; 5625 ifq->ifq_flags = IFQF_USER; 5626 ifq->ifq_ref++; 5627 *parent = ifq; 5628 softc->ipf_userifqs++; 5629 } 5630 MUTEX_EXIT(&softc->ipf_timeoutlock); 5631 return (ifq); 5632 } 5633 5634 5635 /* ------------------------------------------------------------------------ */ 5636 /* Function: ipf_deletetimeoutqueue */ 5637 /* Returns: int - new reference count value of the timeout queue */ 5638 /* Parameters: ifq(I) - timeout queue which is losing a reference. */ 5639 /* Locks: ifq->ifq_lock */ 5640 /* */ 5641 /* This routine must be called when we're discarding a pointer to a timeout */ 5642 /* queue object, taking care of the reference counter. */ 5643 /* */ 5644 /* Now that this just sets a DELETE flag, it requires the expire code to */ 5645 /* check the list of user defined timeout queues and call the free function */ 5646 /* below (currently commented out) to stop memory leaking. It is done this */ 5647 /* way because the locking may not be sufficient to safely do a free when */ 5648 /* this function is called. */ 5649 /* ------------------------------------------------------------------------ */ 5650 int 5651 ipf_deletetimeoutqueue(ipftq_t *ifq) 5652 { 5653 5654 ifq->ifq_ref--; 5655 if ((ifq->ifq_ref == 0) && ((ifq->ifq_flags & IFQF_USER) != 0)) { 5656 ifq->ifq_flags |= IFQF_DELETE; 5657 } 5658 5659 return (ifq->ifq_ref); 5660 } 5661 5662 5663 /* ------------------------------------------------------------------------ */ 5664 /* Function: ipf_freetimeoutqueue */ 5665 /* Parameters: ifq(I) - timeout queue which is losing a reference. */ 5666 /* Returns: Nil */ 5667 /* */ 5668 /* Locking: */ 5669 /* It is assumed that the caller of this function has an appropriate lock */ 5670 /* held (exclusively) in the domain that encompases the callers "domain". */ 5671 /* The ifq_lock for this structure should not be held. */ 5672 /* */ 5673 /* Remove a user defined timeout queue from the list of queues it is in and */ 5674 /* tidy up after this is done. */ 5675 /* ------------------------------------------------------------------------ */ 5676 void 5677 ipf_freetimeoutqueue(ipf_main_softc_t *softc, ipftq_t *ifq) 5678 { 5679 5680 if (((ifq->ifq_flags & IFQF_DELETE) == 0) || (ifq->ifq_ref != 0) || 5681 ((ifq->ifq_flags & IFQF_USER) == 0)) { 5682 printf("ipf_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n", 5683 (u_long)ifq, ifq->ifq_flags, ifq->ifq_ttl, 5684 ifq->ifq_ref); 5685 return; 5686 } 5687 5688 /* 5689 * Remove from its position in the list. 5690 */ 5691 *ifq->ifq_pnext = ifq->ifq_next; 5692 if (ifq->ifq_next != NULL) 5693 ifq->ifq_next->ifq_pnext = ifq->ifq_pnext; 5694 ifq->ifq_next = NULL; 5695 ifq->ifq_pnext = NULL; 5696 5697 MUTEX_DESTROY(&ifq->ifq_lock); 5698 ATOMIC_DEC(softc->ipf_userifqs); 5699 KFREE(ifq); 5700 } 5701 5702 5703 /* ------------------------------------------------------------------------ */ 5704 /* Function: ipf_deletequeueentry */ 5705 /* Returns: Nil */ 5706 /* Parameters: tqe(I) - timeout queue entry to delete */ 5707 /* */ 5708 /* Remove a tail queue entry from its queue and make it an orphan. */ 5709 /* ipf_deletetimeoutqueue is called to make sure the reference count on the */ 5710 /* queue is correct. We can't, however, call ipf_freetimeoutqueue because */ 5711 /* the correct lock(s) may not be held that would make it safe to do so. */ 5712 /* ------------------------------------------------------------------------ */ 5713 void 5714 ipf_deletequeueentry(ipftqent_t *tqe) 5715 { 5716 ipftq_t *ifq; 5717 5718 ifq = tqe->tqe_ifq; 5719 5720 MUTEX_ENTER(&ifq->ifq_lock); 5721 5722 if (tqe->tqe_pnext != NULL) { 5723 *tqe->tqe_pnext = tqe->tqe_next; 5724 if (tqe->tqe_next != NULL) 5725 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5726 else /* we must be the tail anyway */ 5727 ifq->ifq_tail = tqe->tqe_pnext; 5728 5729 tqe->tqe_pnext = NULL; 5730 tqe->tqe_ifq = NULL; 5731 } 5732 5733 (void) ipf_deletetimeoutqueue(ifq); 5734 ASSERT(ifq->ifq_ref > 0); 5735 5736 MUTEX_EXIT(&ifq->ifq_lock); 5737 } 5738 5739 5740 /* ------------------------------------------------------------------------ */ 5741 /* Function: ipf_queuefront */ 5742 /* Returns: Nil */ 5743 /* Parameters: tqe(I) - pointer to timeout queue entry */ 5744 /* */ 5745 /* Move a queue entry to the front of the queue, if it isn't already there. */ 5746 /* ------------------------------------------------------------------------ */ 5747 void 5748 ipf_queuefront(ipftqent_t *tqe) 5749 { 5750 ipftq_t *ifq; 5751 5752 ifq = tqe->tqe_ifq; 5753 if (ifq == NULL) 5754 return; 5755 5756 MUTEX_ENTER(&ifq->ifq_lock); 5757 if (ifq->ifq_head != tqe) { 5758 *tqe->tqe_pnext = tqe->tqe_next; 5759 if (tqe->tqe_next) 5760 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5761 else 5762 ifq->ifq_tail = tqe->tqe_pnext; 5763 5764 tqe->tqe_next = ifq->ifq_head; 5765 ifq->ifq_head->tqe_pnext = &tqe->tqe_next; 5766 ifq->ifq_head = tqe; 5767 tqe->tqe_pnext = &ifq->ifq_head; 5768 } 5769 MUTEX_EXIT(&ifq->ifq_lock); 5770 } 5771 5772 5773 /* ------------------------------------------------------------------------ */ 5774 /* Function: ipf_queueback */ 5775 /* Returns: Nil */ 5776 /* Parameters: ticks(I) - ipf tick time to use with this call */ 5777 /* tqe(I) - pointer to timeout queue entry */ 5778 /* */ 5779 /* Move a queue entry to the back of the queue, if it isn't already there. */ 5780 /* We use use ticks to calculate the expiration and mark for when we last */ 5781 /* touched the structure. */ 5782 /* ------------------------------------------------------------------------ */ 5783 void 5784 ipf_queueback(u_long ticks, ipftqent_t *tqe) 5785 { 5786 ipftq_t *ifq; 5787 5788 ifq = tqe->tqe_ifq; 5789 if (ifq == NULL) 5790 return; 5791 tqe->tqe_die = ticks + ifq->ifq_ttl; 5792 tqe->tqe_touched = ticks; 5793 5794 MUTEX_ENTER(&ifq->ifq_lock); 5795 if (tqe->tqe_next != NULL) { /* at the end already ? */ 5796 /* 5797 * Remove from list 5798 */ 5799 *tqe->tqe_pnext = tqe->tqe_next; 5800 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5801 5802 /* 5803 * Make it the last entry. 5804 */ 5805 tqe->tqe_next = NULL; 5806 tqe->tqe_pnext = ifq->ifq_tail; 5807 *ifq->ifq_tail = tqe; 5808 ifq->ifq_tail = &tqe->tqe_next; 5809 } 5810 MUTEX_EXIT(&ifq->ifq_lock); 5811 } 5812 5813 5814 /* ------------------------------------------------------------------------ */ 5815 /* Function: ipf_queueappend */ 5816 /* Returns: Nil */ 5817 /* Parameters: ticks(I) - ipf tick time to use with this call */ 5818 /* tqe(I) - pointer to timeout queue entry */ 5819 /* ifq(I) - pointer to timeout queue */ 5820 /* parent(I) - owing object pointer */ 5821 /* */ 5822 /* Add a new item to this queue and put it on the very end. */ 5823 /* We use use ticks to calculate the expiration and mark for when we last */ 5824 /* touched the structure. */ 5825 /* ------------------------------------------------------------------------ */ 5826 void 5827 ipf_queueappend(u_long ticks, ipftqent_t *tqe, ipftq_t *ifq, void *parent) 5828 { 5829 5830 MUTEX_ENTER(&ifq->ifq_lock); 5831 tqe->tqe_parent = parent; 5832 tqe->tqe_pnext = ifq->ifq_tail; 5833 *ifq->ifq_tail = tqe; 5834 ifq->ifq_tail = &tqe->tqe_next; 5835 tqe->tqe_next = NULL; 5836 tqe->tqe_ifq = ifq; 5837 tqe->tqe_die = ticks + ifq->ifq_ttl; 5838 tqe->tqe_touched = ticks; 5839 ifq->ifq_ref++; 5840 MUTEX_EXIT(&ifq->ifq_lock); 5841 } 5842 5843 5844 /* ------------------------------------------------------------------------ */ 5845 /* Function: ipf_movequeue */ 5846 /* Returns: Nil */ 5847 /* Parameters: tq(I) - pointer to timeout queue information */ 5848 /* oifp(I) - old timeout queue entry was on */ 5849 /* nifp(I) - new timeout queue to put entry on */ 5850 /* */ 5851 /* Move a queue entry from one timeout queue to another timeout queue. */ 5852 /* If it notices that the current entry is already last and does not need */ 5853 /* to move queue, the return. */ 5854 /* ------------------------------------------------------------------------ */ 5855 void 5856 ipf_movequeue(u_long ticks, ipftqent_t *tqe, ipftq_t *oifq, ipftq_t *nifq) 5857 { 5858 5859 /* 5860 * If the queue hasn't changed and we last touched this entry at the 5861 * same ipf time, then we're not going to achieve anything by either 5862 * changing the ttl or moving it on the queue. 5863 */ 5864 if (oifq == nifq && tqe->tqe_touched == ticks) 5865 return; 5866 5867 /* 5868 * For any of this to be outside the lock, there is a risk that two 5869 * packets entering simultaneously, with one changing to a different 5870 * queue and one not, could end up with things in a bizarre state. 5871 */ 5872 MUTEX_ENTER(&oifq->ifq_lock); 5873 5874 tqe->tqe_touched = ticks; 5875 tqe->tqe_die = ticks + nifq->ifq_ttl; 5876 /* 5877 * Is the operation here going to be a no-op ? 5878 */ 5879 if (oifq == nifq) { 5880 if ((tqe->tqe_next == NULL) || 5881 (tqe->tqe_next->tqe_die == tqe->tqe_die)) { 5882 MUTEX_EXIT(&oifq->ifq_lock); 5883 return; 5884 } 5885 } 5886 5887 /* 5888 * Remove from the old queue 5889 */ 5890 *tqe->tqe_pnext = tqe->tqe_next; 5891 if (tqe->tqe_next) 5892 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5893 else 5894 oifq->ifq_tail = tqe->tqe_pnext; 5895 tqe->tqe_next = NULL; 5896 5897 /* 5898 * If we're moving from one queue to another, release the 5899 * lock on the old queue and get a lock on the new queue. 5900 * For user defined queues, if we're moving off it, call 5901 * delete in case it can now be freed. 5902 */ 5903 if (oifq != nifq) { 5904 tqe->tqe_ifq = NULL; 5905 5906 (void) ipf_deletetimeoutqueue(oifq); 5907 5908 MUTEX_EXIT(&oifq->ifq_lock); 5909 5910 MUTEX_ENTER(&nifq->ifq_lock); 5911 5912 tqe->tqe_ifq = nifq; 5913 nifq->ifq_ref++; 5914 } 5915 5916 /* 5917 * Add to the bottom of the new queue 5918 */ 5919 tqe->tqe_pnext = nifq->ifq_tail; 5920 *nifq->ifq_tail = tqe; 5921 nifq->ifq_tail = &tqe->tqe_next; 5922 MUTEX_EXIT(&nifq->ifq_lock); 5923 } 5924 5925 5926 /* ------------------------------------------------------------------------ */ 5927 /* Function: ipf_updateipid */ 5928 /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 5929 /* Parameters: fin(I) - pointer to packet information */ 5930 /* */ 5931 /* When we are doing NAT, change the IP of every packet to represent a */ 5932 /* single sequence of packets coming from the host, hiding any host */ 5933 /* specific sequencing that might otherwise be revealed. If the packet is */ 5934 /* a fragment, then store the 'new' IPid in the fragment cache and look up */ 5935 /* the fragment cache for non-leading fragments. If a non-leading fragment */ 5936 /* has no match in the cache, return an error. */ 5937 /* ------------------------------------------------------------------------ */ 5938 static int 5939 ipf_updateipid(fr_info_t *fin) 5940 { 5941 u_short id, ido, sums; 5942 u_32_t sumd, sum; 5943 ip_t *ip; 5944 5945 ip = fin->fin_ip; 5946 ido = ntohs(ip->ip_id); 5947 if (fin->fin_off != 0) { 5948 sum = ipf_frag_ipidknown(fin); 5949 if (sum == 0xffffffff) 5950 return (-1); 5951 sum &= 0xffff; 5952 id = (u_short)sum; 5953 ip->ip_id = htons(id); 5954 } else { 5955 ip_fillid(ip); 5956 id = ntohs(ip->ip_id); 5957 if ((fin->fin_flx & FI_FRAG) != 0) 5958 (void) ipf_frag_ipidnew(fin, (u_32_t)id); 5959 } 5960 5961 if (id == ido) 5962 return (0); 5963 CALC_SUMD(ido, id, sumd); /* DESTRUCTIVE MACRO! id,ido change */ 5964 sum = (~ntohs(ip->ip_sum)) & 0xffff; 5965 sum += sumd; 5966 sum = (sum >> 16) + (sum & 0xffff); 5967 sum = (sum >> 16) + (sum & 0xffff); 5968 sums = ~(u_short)sum; 5969 ip->ip_sum = htons(sums); 5970 return (0); 5971 } 5972 5973 5974 #ifdef NEED_FRGETIFNAME 5975 /* ------------------------------------------------------------------------ */ 5976 /* Function: ipf_getifname */ 5977 /* Returns: char * - pointer to interface name */ 5978 /* Parameters: ifp(I) - pointer to network interface */ 5979 /* buffer(O) - pointer to where to store interface name */ 5980 /* */ 5981 /* Constructs an interface name in the buffer passed. The buffer passed is */ 5982 /* expected to be at least LIFNAMSIZ in bytes big. If buffer is passed in */ 5983 /* as a NULL pointer then return a pointer to a static array. */ 5984 /* ------------------------------------------------------------------------ */ 5985 char * 5986 ipf_getifname(struct ifnet *ifp, char *buffer) 5987 { 5988 static char namebuf[LIFNAMSIZ]; 5989 # if SOLARIS || defined(__FreeBSD__) 5990 int unit, space; 5991 char temp[20]; 5992 char *s; 5993 # endif 5994 5995 if (buffer == NULL) 5996 buffer = namebuf; 5997 (void) strncpy(buffer, ifp->if_name, LIFNAMSIZ); 5998 buffer[LIFNAMSIZ - 1] = '\0'; 5999 # if SOLARIS || defined(__FreeBSD__) 6000 for (s = buffer; *s; s++) 6001 ; 6002 unit = ifp->if_unit; 6003 space = LIFNAMSIZ - (s - buffer); 6004 if ((space > 0) && (unit >= 0)) { 6005 (void) snprintf(temp, sizeof(name), "%d", unit); 6006 (void) strncpy(s, temp, space); 6007 } 6008 # endif 6009 return (buffer); 6010 } 6011 #endif 6012 6013 6014 /* ------------------------------------------------------------------------ */ 6015 /* Function: ipf_ioctlswitch */ 6016 /* Returns: int - -1 continue processing, else ioctl return value */ 6017 /* Parameters: unit(I) - device unit opened */ 6018 /* data(I) - pointer to ioctl data */ 6019 /* cmd(I) - ioctl command */ 6020 /* mode(I) - mode value */ 6021 /* uid(I) - uid making the ioctl call */ 6022 /* ctx(I) - pointer to context data */ 6023 /* */ 6024 /* Based on the value of unit, call the appropriate ioctl handler or return */ 6025 /* EIO if ipfilter is not running. Also checks if write perms are req'd */ 6026 /* for the device in order to execute the ioctl. A special case is made */ 6027 /* SIOCIPFINTERROR so that the same code isn't required in every handler. */ 6028 /* The context data pointer is passed through as this is used as the key */ 6029 /* for locating a matching token for continued access for walking lists, */ 6030 /* etc. */ 6031 /* ------------------------------------------------------------------------ */ 6032 int 6033 ipf_ioctlswitch(ipf_main_softc_t *softc, int unit, void *data, ioctlcmd_t cmd, 6034 int mode, int uid, void *ctx) 6035 { 6036 int error = 0; 6037 6038 switch (cmd) 6039 { 6040 case SIOCIPFINTERROR : 6041 error = BCOPYOUT(&softc->ipf_interror, data, 6042 sizeof(softc->ipf_interror)); 6043 if (error != 0) { 6044 IPFERROR(40); 6045 error = EFAULT; 6046 } 6047 return (error); 6048 default : 6049 break; 6050 } 6051 6052 switch (unit) 6053 { 6054 case IPL_LOGIPF : 6055 error = ipf_ipf_ioctl(softc, data, cmd, mode, uid, ctx); 6056 break; 6057 case IPL_LOGNAT : 6058 if (softc->ipf_running > 0) { 6059 error = ipf_nat_ioctl(softc, data, cmd, mode, 6060 uid, ctx); 6061 } else { 6062 IPFERROR(42); 6063 error = EIO; 6064 } 6065 break; 6066 case IPL_LOGSTATE : 6067 if (softc->ipf_running > 0) { 6068 error = ipf_state_ioctl(softc, data, cmd, mode, 6069 uid, ctx); 6070 } else { 6071 IPFERROR(43); 6072 error = EIO; 6073 } 6074 break; 6075 case IPL_LOGAUTH : 6076 if (softc->ipf_running > 0) { 6077 error = ipf_auth_ioctl(softc, data, cmd, mode, 6078 uid, ctx); 6079 } else { 6080 IPFERROR(44); 6081 error = EIO; 6082 } 6083 break; 6084 case IPL_LOGSYNC : 6085 if (softc->ipf_running > 0) { 6086 error = ipf_sync_ioctl(softc, data, cmd, mode, 6087 uid, ctx); 6088 } else { 6089 error = EIO; 6090 IPFERROR(45); 6091 } 6092 break; 6093 case IPL_LOGSCAN : 6094 #ifdef IPFILTER_SCAN 6095 if (softc->ipf_running > 0) 6096 error = ipf_scan_ioctl(softc, data, cmd, mode, 6097 uid, ctx); 6098 else 6099 #endif 6100 { 6101 error = EIO; 6102 IPFERROR(46); 6103 } 6104 break; 6105 case IPL_LOGLOOKUP : 6106 if (softc->ipf_running > 0) { 6107 error = ipf_lookup_ioctl(softc, data, cmd, mode, 6108 uid, ctx); 6109 } else { 6110 error = EIO; 6111 IPFERROR(47); 6112 } 6113 break; 6114 default : 6115 IPFERROR(48); 6116 error = EIO; 6117 break; 6118 } 6119 6120 return (error); 6121 } 6122 6123 6124 /* 6125 * This array defines the expected size of objects coming into the kernel 6126 * for the various recognised object types. The first column is flags (see 6127 * below), 2nd column is current size, 3rd column is the version number of 6128 * when the current size became current. 6129 * Flags: 6130 * 1 = minimum size, not absolute size 6131 */ 6132 static const int ipf_objbytes[IPFOBJ_COUNT][3] = { 6133 { 1, sizeof(struct frentry), 5010000 }, /* 0 */ 6134 { 1, sizeof(struct friostat), 5010000 }, 6135 { 0, sizeof(struct fr_info), 5010000 }, 6136 { 0, sizeof(struct ipf_authstat), 4010100 }, 6137 { 0, sizeof(struct ipfrstat), 5010000 }, 6138 { 1, sizeof(struct ipnat), 5010000 }, /* 5 */ 6139 { 0, sizeof(struct natstat), 5010000 }, 6140 { 0, sizeof(struct ipstate_save), 5010000 }, 6141 { 1, sizeof(struct nat_save), 5010000 }, 6142 { 0, sizeof(struct natlookup), 5010000 }, 6143 { 1, sizeof(struct ipstate), 5010000 }, /* 10 */ 6144 { 0, sizeof(struct ips_stat), 5010000 }, 6145 { 0, sizeof(struct frauth), 5010000 }, 6146 { 0, sizeof(struct ipftune), 4010100 }, 6147 { 0, sizeof(struct nat), 5010000 }, 6148 { 0, sizeof(struct ipfruleiter), 4011400 }, /* 15 */ 6149 { 0, sizeof(struct ipfgeniter), 4011400 }, 6150 { 0, sizeof(struct ipftable), 4011400 }, 6151 { 0, sizeof(struct ipflookupiter), 4011400 }, 6152 { 0, sizeof(struct ipftq) * IPF_TCP_NSTATES }, 6153 { 1, 0, 0 }, /* IPFEXPR */ 6154 { 0, 0, 0 }, /* PROXYCTL */ 6155 { 0, sizeof (struct fripf), 5010000 } 6156 }; 6157 6158 6159 /* ------------------------------------------------------------------------ */ 6160 /* Function: ipf_inobj */ 6161 /* Returns: int - 0 = success, else failure */ 6162 /* Parameters: softc(I) - soft context pointerto work with */ 6163 /* data(I) - pointer to ioctl data */ 6164 /* objp(O) - where to store ipfobj structure */ 6165 /* ptr(I) - pointer to data to copy out */ 6166 /* type(I) - type of structure being moved */ 6167 /* */ 6168 /* Copy in the contents of what the ipfobj_t points to. In future, we */ 6169 /* add things to check for version numbers, sizes, etc, to make it backward */ 6170 /* compatible at the ABI for user land. */ 6171 /* If objp is not NULL then we assume that the caller wants to see what is */ 6172 /* in the ipfobj_t structure being copied in. As an example, this can tell */ 6173 /* the caller what version of ipfilter the ioctl program was written to. */ 6174 /* ------------------------------------------------------------------------ */ 6175 int 6176 ipf_inobj(ipf_main_softc_t *softc, void *data, ipfobj_t *objp, void *ptr, 6177 int type) 6178 { 6179 ipfobj_t obj; 6180 int error; 6181 int size; 6182 6183 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6184 IPFERROR(49); 6185 return (EINVAL); 6186 } 6187 6188 if (objp == NULL) 6189 objp = &obj; 6190 error = BCOPYIN(data, objp, sizeof(*objp)); 6191 if (error != 0) { 6192 IPFERROR(124); 6193 return (EFAULT); 6194 } 6195 6196 if (objp->ipfo_type != type) { 6197 IPFERROR(50); 6198 return (EINVAL); 6199 } 6200 6201 if (objp->ipfo_rev >= ipf_objbytes[type][2]) { 6202 if ((ipf_objbytes[type][0] & 1) != 0) { 6203 if (objp->ipfo_size < ipf_objbytes[type][1]) { 6204 IPFERROR(51); 6205 return (EINVAL); 6206 } 6207 size = ipf_objbytes[type][1]; 6208 } else if (objp->ipfo_size == ipf_objbytes[type][1]) { 6209 size = objp->ipfo_size; 6210 } else { 6211 IPFERROR(52); 6212 return (EINVAL); 6213 } 6214 error = COPYIN(objp->ipfo_ptr, ptr, size); 6215 if (error != 0) { 6216 IPFERROR(55); 6217 error = EFAULT; 6218 } 6219 } else { 6220 #ifdef IPFILTER_COMPAT 6221 error = ipf_in_compat(softc, objp, ptr, 0); 6222 #else 6223 IPFERROR(54); 6224 error = EINVAL; 6225 #endif 6226 } 6227 return (error); 6228 } 6229 6230 6231 /* ------------------------------------------------------------------------ */ 6232 /* Function: ipf_inobjsz */ 6233 /* Returns: int - 0 = success, else failure */ 6234 /* Parameters: softc(I) - soft context pointerto work with */ 6235 /* data(I) - pointer to ioctl data */ 6236 /* ptr(I) - pointer to store real data in */ 6237 /* type(I) - type of structure being moved */ 6238 /* sz(I) - size of data to copy */ 6239 /* */ 6240 /* As per ipf_inobj, except the size of the object to copy in is passed in */ 6241 /* but it must not be smaller than the size defined for the type and the */ 6242 /* type must allow for varied sized objects. The extra requirement here is */ 6243 /* that sz must match the size of the object being passed in - this is not */ 6244 /* not possible nor required in ipf_inobj(). */ 6245 /* ------------------------------------------------------------------------ */ 6246 int 6247 ipf_inobjsz(ipf_main_softc_t *softc, void *data, void *ptr, int type, int sz) 6248 { 6249 ipfobj_t obj; 6250 int error; 6251 6252 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6253 IPFERROR(56); 6254 return (EINVAL); 6255 } 6256 6257 error = BCOPYIN(data, &obj, sizeof(obj)); 6258 if (error != 0) { 6259 IPFERROR(125); 6260 return (EFAULT); 6261 } 6262 6263 if (obj.ipfo_type != type) { 6264 IPFERROR(58); 6265 return (EINVAL); 6266 } 6267 6268 if (obj.ipfo_rev >= ipf_objbytes[type][2]) { 6269 if (((ipf_objbytes[type][0] & 1) == 0) || 6270 (sz < ipf_objbytes[type][1])) { 6271 IPFERROR(57); 6272 return (EINVAL); 6273 } 6274 error = COPYIN(obj.ipfo_ptr, ptr, sz); 6275 if (error != 0) { 6276 IPFERROR(61); 6277 error = EFAULT; 6278 } 6279 } else { 6280 #ifdef IPFILTER_COMPAT 6281 error = ipf_in_compat(softc, &obj, ptr, sz); 6282 #else 6283 IPFERROR(60); 6284 error = EINVAL; 6285 #endif 6286 } 6287 return (error); 6288 } 6289 6290 6291 /* ------------------------------------------------------------------------ */ 6292 /* Function: ipf_outobjsz */ 6293 /* Returns: int - 0 = success, else failure */ 6294 /* Parameters: data(I) - pointer to ioctl data */ 6295 /* ptr(I) - pointer to store real data in */ 6296 /* type(I) - type of structure being moved */ 6297 /* sz(I) - size of data to copy */ 6298 /* */ 6299 /* As per ipf_outobj, except the size of the object to copy out is passed in*/ 6300 /* but it must not be smaller than the size defined for the type and the */ 6301 /* type must allow for varied sized objects. The extra requirement here is */ 6302 /* that sz must match the size of the object being passed in - this is not */ 6303 /* not possible nor required in ipf_outobj(). */ 6304 /* ------------------------------------------------------------------------ */ 6305 int 6306 ipf_outobjsz(ipf_main_softc_t *softc, void *data, void *ptr, int type, int sz) 6307 { 6308 ipfobj_t obj; 6309 int error; 6310 6311 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6312 IPFERROR(62); 6313 return (EINVAL); 6314 } 6315 6316 error = BCOPYIN(data, &obj, sizeof(obj)); 6317 if (error != 0) { 6318 IPFERROR(127); 6319 return (EFAULT); 6320 } 6321 6322 if (obj.ipfo_type != type) { 6323 IPFERROR(63); 6324 return (EINVAL); 6325 } 6326 6327 if (obj.ipfo_rev >= ipf_objbytes[type][2]) { 6328 if (((ipf_objbytes[type][0] & 1) == 0) || 6329 (sz < ipf_objbytes[type][1])) { 6330 IPFERROR(146); 6331 return (EINVAL); 6332 } 6333 error = COPYOUT(ptr, obj.ipfo_ptr, sz); 6334 if (error != 0) { 6335 IPFERROR(66); 6336 error = EFAULT; 6337 } 6338 } else { 6339 #ifdef IPFILTER_COMPAT 6340 error = ipf_out_compat(softc, &obj, ptr); 6341 #else 6342 IPFERROR(65); 6343 error = EINVAL; 6344 #endif 6345 } 6346 return (error); 6347 } 6348 6349 6350 /* ------------------------------------------------------------------------ */ 6351 /* Function: ipf_outobj */ 6352 /* Returns: int - 0 = success, else failure */ 6353 /* Parameters: data(I) - pointer to ioctl data */ 6354 /* ptr(I) - pointer to store real data in */ 6355 /* type(I) - type of structure being moved */ 6356 /* */ 6357 /* Copy out the contents of what ptr is to where ipfobj points to. In */ 6358 /* future, we add things to check for version numbers, sizes, etc, to make */ 6359 /* it backward compatible at the ABI for user land. */ 6360 /* ------------------------------------------------------------------------ */ 6361 int 6362 ipf_outobj(ipf_main_softc_t *softc, void *data, void *ptr, int type) 6363 { 6364 ipfobj_t obj; 6365 int error; 6366 6367 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6368 IPFERROR(67); 6369 return (EINVAL); 6370 } 6371 6372 error = BCOPYIN(data, &obj, sizeof(obj)); 6373 if (error != 0) { 6374 IPFERROR(126); 6375 return (EFAULT); 6376 } 6377 6378 if (obj.ipfo_type != type) { 6379 IPFERROR(68); 6380 return (EINVAL); 6381 } 6382 6383 if (obj.ipfo_rev >= ipf_objbytes[type][2]) { 6384 if ((ipf_objbytes[type][0] & 1) != 0) { 6385 if (obj.ipfo_size < ipf_objbytes[type][1]) { 6386 IPFERROR(69); 6387 return (EINVAL); 6388 } 6389 } else if (obj.ipfo_size != ipf_objbytes[type][1]) { 6390 IPFERROR(70); 6391 return (EINVAL); 6392 } 6393 6394 error = COPYOUT(ptr, obj.ipfo_ptr, obj.ipfo_size); 6395 if (error != 0) { 6396 IPFERROR(73); 6397 error = EFAULT; 6398 } 6399 } else { 6400 #ifdef IPFILTER_COMPAT 6401 error = ipf_out_compat(softc, &obj, ptr); 6402 #else 6403 IPFERROR(72); 6404 error = EINVAL; 6405 #endif 6406 } 6407 return (error); 6408 } 6409 6410 6411 /* ------------------------------------------------------------------------ */ 6412 /* Function: ipf_outobjk */ 6413 /* Returns: int - 0 = success, else failure */ 6414 /* Parameters: obj(I) - pointer to data description structure */ 6415 /* ptr(I) - pointer to kernel data to copy out */ 6416 /* */ 6417 /* In the above functions, the ipfobj_t structure is copied into the kernel,*/ 6418 /* telling ipfilter how to copy out data. In this instance, the ipfobj_t is */ 6419 /* already populated with information and now we just need to use it. */ 6420 /* There is no need for this function to have a "type" parameter as there */ 6421 /* is no point in validating information that comes from the kernel with */ 6422 /* itself. */ 6423 /* ------------------------------------------------------------------------ */ 6424 int 6425 ipf_outobjk(ipf_main_softc_t *softc, ipfobj_t *obj, void *ptr) 6426 { 6427 int type = obj->ipfo_type; 6428 int error; 6429 6430 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6431 IPFERROR(147); 6432 return (EINVAL); 6433 } 6434 6435 if (obj->ipfo_rev >= ipf_objbytes[type][2]) { 6436 if ((ipf_objbytes[type][0] & 1) != 0) { 6437 if (obj->ipfo_size < ipf_objbytes[type][1]) { 6438 IPFERROR(148); 6439 return (EINVAL); 6440 } 6441 6442 } else if (obj->ipfo_size != ipf_objbytes[type][1]) { 6443 IPFERROR(149); 6444 return (EINVAL); 6445 } 6446 6447 error = COPYOUT(ptr, obj->ipfo_ptr, obj->ipfo_size); 6448 if (error != 0) { 6449 IPFERROR(150); 6450 error = EFAULT; 6451 } 6452 } else { 6453 #ifdef IPFILTER_COMPAT 6454 error = ipf_out_compat(softc, obj, ptr); 6455 #else 6456 IPFERROR(151); 6457 error = EINVAL; 6458 #endif 6459 } 6460 return (error); 6461 } 6462 6463 6464 /* ------------------------------------------------------------------------ */ 6465 /* Function: ipf_checkl4sum */ 6466 /* Returns: int - 0 = good, -1 = bad, 1 = cannot check */ 6467 /* Parameters: fin(I) - pointer to packet information */ 6468 /* */ 6469 /* If possible, calculate the layer 4 checksum for the packet. If this is */ 6470 /* not possible, return without indicating a failure or success but in a */ 6471 /* way that is ditinguishable. This function should only be called by the */ 6472 /* ipf_checkv6sum() for each platform. */ 6473 /* ------------------------------------------------------------------------ */ 6474 inline int 6475 ipf_checkl4sum(fr_info_t *fin) 6476 { 6477 u_short sum, hdrsum, *csump; 6478 udphdr_t *udp; 6479 int dosum; 6480 6481 /* 6482 * If the TCP packet isn't a fragment, isn't too short and otherwise 6483 * isn't already considered "bad", then validate the checksum. If 6484 * this check fails then considered the packet to be "bad". 6485 */ 6486 if ((fin->fin_flx & (FI_FRAG|FI_SHORT|FI_BAD)) != 0) 6487 return (1); 6488 6489 DT2(l4sumo, int, fin->fin_out, int, (int)fin->fin_p); 6490 if (fin->fin_out == 1) { 6491 fin->fin_cksum = FI_CK_SUMOK; 6492 return (0); 6493 } 6494 6495 csump = NULL; 6496 hdrsum = 0; 6497 dosum = 0; 6498 sum = 0; 6499 6500 switch (fin->fin_p) 6501 { 6502 case IPPROTO_TCP : 6503 csump = &((tcphdr_t *)fin->fin_dp)->th_sum; 6504 dosum = 1; 6505 break; 6506 6507 case IPPROTO_UDP : 6508 udp = fin->fin_dp; 6509 if (udp->uh_sum != 0) { 6510 csump = &udp->uh_sum; 6511 dosum = 1; 6512 } 6513 break; 6514 6515 #ifdef USE_INET6 6516 case IPPROTO_ICMPV6 : 6517 csump = &((struct icmp6_hdr *)fin->fin_dp)->icmp6_cksum; 6518 dosum = 1; 6519 break; 6520 #endif 6521 6522 case IPPROTO_ICMP : 6523 csump = &((struct icmp *)fin->fin_dp)->icmp_cksum; 6524 dosum = 1; 6525 break; 6526 6527 default : 6528 return (1); 6529 /*NOTREACHED*/ 6530 } 6531 6532 if (csump != NULL) { 6533 hdrsum = *csump; 6534 if (fin->fin_p == IPPROTO_UDP && hdrsum == 0xffff) 6535 hdrsum = 0x0000; 6536 } 6537 6538 if (dosum) { 6539 sum = fr_cksum(fin, fin->fin_ip, fin->fin_p, fin->fin_dp); 6540 } 6541 #if !defined(_KERNEL) 6542 if (sum == hdrsum) { 6543 FR_DEBUG(("checkl4sum: %hx == %hx\n", sum, hdrsum)); 6544 } else { 6545 FR_DEBUG(("checkl4sum: %hx != %hx\n", sum, hdrsum)); 6546 } 6547 #endif 6548 DT3(l4sums, u_short, hdrsum, u_short, sum, fr_info_t *, fin); 6549 #ifdef USE_INET6 6550 if (hdrsum == sum || (sum == 0 && IP_V(fin->fin_ip) == 6)) { 6551 #else 6552 if (hdrsum == sum) { 6553 #endif 6554 fin->fin_cksum = FI_CK_SUMOK; 6555 return (0); 6556 } 6557 fin->fin_cksum = FI_CK_BAD; 6558 return (-1); 6559 } 6560 6561 6562 /* ------------------------------------------------------------------------ */ 6563 /* Function: ipf_ifpfillv4addr */ 6564 /* Returns: int - 0 = address update, -1 = address not updated */ 6565 /* Parameters: atype(I) - type of network address update to perform */ 6566 /* sin(I) - pointer to source of address information */ 6567 /* mask(I) - pointer to source of netmask information */ 6568 /* inp(I) - pointer to destination address store */ 6569 /* inpmask(I) - pointer to destination netmask store */ 6570 /* */ 6571 /* Given a type of network address update (atype) to perform, copy */ 6572 /* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ 6573 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ 6574 /* which case the operation fails. For all values of atype other than */ 6575 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ 6576 /* value. */ 6577 /* ------------------------------------------------------------------------ */ 6578 int 6579 ipf_ifpfillv4addr(int atype, struct sockaddr_in *sin, struct sockaddr_in *mask, 6580 struct in_addr *inp, struct in_addr *inpmask) 6581 { 6582 if (inpmask != NULL && atype != FRI_NETMASKED) 6583 inpmask->s_addr = 0xffffffff; 6584 6585 if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { 6586 if (atype == FRI_NETMASKED) { 6587 if (inpmask == NULL) 6588 return (-1); 6589 inpmask->s_addr = mask->sin_addr.s_addr; 6590 } 6591 inp->s_addr = sin->sin_addr.s_addr & mask->sin_addr.s_addr; 6592 } else { 6593 inp->s_addr = sin->sin_addr.s_addr; 6594 } 6595 return (0); 6596 } 6597 6598 6599 #ifdef USE_INET6 6600 /* ------------------------------------------------------------------------ */ 6601 /* Function: ipf_ifpfillv6addr */ 6602 /* Returns: int - 0 = address update, -1 = address not updated */ 6603 /* Parameters: atype(I) - type of network address update to perform */ 6604 /* sin(I) - pointer to source of address information */ 6605 /* mask(I) - pointer to source of netmask information */ 6606 /* inp(I) - pointer to destination address store */ 6607 /* inpmask(I) - pointer to destination netmask store */ 6608 /* */ 6609 /* Given a type of network address update (atype) to perform, copy */ 6610 /* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ 6611 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ 6612 /* which case the operation fails. For all values of atype other than */ 6613 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ 6614 /* value. */ 6615 /* ------------------------------------------------------------------------ */ 6616 int 6617 ipf_ifpfillv6addr(int atype, struct sockaddr_in6 *sin, 6618 struct sockaddr_in6 *mask, i6addr_t *inp, i6addr_t *inpmask) 6619 { 6620 i6addr_t *src, *and; 6621 6622 src = (i6addr_t *)&sin->sin6_addr; 6623 and = (i6addr_t *)&mask->sin6_addr; 6624 6625 if (inpmask != NULL && atype != FRI_NETMASKED) { 6626 inpmask->i6[0] = 0xffffffff; 6627 inpmask->i6[1] = 0xffffffff; 6628 inpmask->i6[2] = 0xffffffff; 6629 inpmask->i6[3] = 0xffffffff; 6630 } 6631 6632 if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { 6633 if (atype == FRI_NETMASKED) { 6634 if (inpmask == NULL) 6635 return (-1); 6636 inpmask->i6[0] = and->i6[0]; 6637 inpmask->i6[1] = and->i6[1]; 6638 inpmask->i6[2] = and->i6[2]; 6639 inpmask->i6[3] = and->i6[3]; 6640 } 6641 6642 inp->i6[0] = src->i6[0] & and->i6[0]; 6643 inp->i6[1] = src->i6[1] & and->i6[1]; 6644 inp->i6[2] = src->i6[2] & and->i6[2]; 6645 inp->i6[3] = src->i6[3] & and->i6[3]; 6646 } else { 6647 inp->i6[0] = src->i6[0]; 6648 inp->i6[1] = src->i6[1]; 6649 inp->i6[2] = src->i6[2]; 6650 inp->i6[3] = src->i6[3]; 6651 } 6652 return (0); 6653 } 6654 #endif 6655 6656 6657 /* ------------------------------------------------------------------------ */ 6658 /* Function: ipf_matchtag */ 6659 /* Returns: 0 == mismatch, 1 == match. */ 6660 /* Parameters: tag1(I) - pointer to first tag to compare */ 6661 /* tag2(I) - pointer to second tag to compare */ 6662 /* */ 6663 /* Returns true (non-zero) or false(0) if the two tag structures can be */ 6664 /* considered to be a match or not match, respectively. The tag is 16 */ 6665 /* bytes long (16 characters) but that is overlayed with 4 32bit ints so */ 6666 /* compare the ints instead, for speed. tag1 is the master of the */ 6667 /* comparison. This function should only be called with both tag1 and tag2 */ 6668 /* as non-NULL pointers. */ 6669 /* ------------------------------------------------------------------------ */ 6670 int 6671 ipf_matchtag(ipftag_t *tag1, ipftag_t *tag2) 6672 { 6673 if (tag1 == tag2) 6674 return (1); 6675 6676 if ((tag1->ipt_num[0] == 0) && (tag2->ipt_num[0] == 0)) 6677 return (1); 6678 6679 if ((tag1->ipt_num[0] == tag2->ipt_num[0]) && 6680 (tag1->ipt_num[1] == tag2->ipt_num[1]) && 6681 (tag1->ipt_num[2] == tag2->ipt_num[2]) && 6682 (tag1->ipt_num[3] == tag2->ipt_num[3])) 6683 return (1); 6684 return (0); 6685 } 6686 6687 6688 /* ------------------------------------------------------------------------ */ 6689 /* Function: ipf_coalesce */ 6690 /* Returns: 1 == success, -1 == failure, 0 == no change */ 6691 /* Parameters: fin(I) - pointer to packet information */ 6692 /* */ 6693 /* Attempt to get all of the packet data into a single, contiguous buffer. */ 6694 /* If this call returns a failure then the buffers have also been freed. */ 6695 /* ------------------------------------------------------------------------ */ 6696 int 6697 ipf_coalesce(fr_info_t *fin) 6698 { 6699 6700 if ((fin->fin_flx & FI_COALESCE) != 0) 6701 return (1); 6702 6703 /* 6704 * If the mbuf pointers indicate that there is no mbuf to work with, 6705 * return but do not indicate success or failure. 6706 */ 6707 if (fin->fin_m == NULL || fin->fin_mp == NULL) 6708 return (0); 6709 6710 #if defined(_KERNEL) 6711 if (ipf_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) { 6712 ipf_main_softc_t *softc = fin->fin_main_soft; 6713 6714 DT1(frb_coalesce, fr_info_t *, fin); 6715 LBUMP(ipf_stats[fin->fin_out].fr_badcoalesces); 6716 # if SOLARIS 6717 FREE_MB_T(*fin->fin_mp); 6718 # endif 6719 fin->fin_reason = FRB_COALESCE; 6720 *fin->fin_mp = NULL; 6721 fin->fin_m = NULL; 6722 return (-1); 6723 } 6724 #else 6725 fin = fin; /* LINT */ 6726 #endif 6727 return (1); 6728 } 6729 6730 6731 /* 6732 * The following table lists all of the tunable variables that can be 6733 * accessed via SIOCIPFGET/SIOCIPFSET/SIOCIPFGETNEXt. The format of each row 6734 * in the table below is as follows: 6735 * 6736 * pointer to value, name of value, minimum, maximum, size of the value's 6737 * container, value attribute flags 6738 * 6739 * For convienience, IPFT_RDONLY means the value is read-only, IPFT_WRDISABLED 6740 * means the value can only be written to when IPFilter is loaded but disabled. 6741 * The obvious implication is if neither of these are set then the value can be 6742 * changed at any time without harm. 6743 */ 6744 6745 6746 /* ------------------------------------------------------------------------ */ 6747 /* Function: ipf_tune_findbycookie */ 6748 /* Returns: NULL = search failed, else pointer to tune struct */ 6749 /* Parameters: cookie(I) - cookie value to search for amongst tuneables */ 6750 /* next(O) - pointer to place to store the cookie for the */ 6751 /* "next" tuneable, if it is desired. */ 6752 /* */ 6753 /* This function is used to walk through all of the existing tunables with */ 6754 /* successive calls. It searches the known tunables for the one which has */ 6755 /* a matching value for "cookie" - ie its address. When returning a match, */ 6756 /* the next one to be found may be returned inside next. */ 6757 /* ------------------------------------------------------------------------ */ 6758 static ipftuneable_t * 6759 ipf_tune_findbycookie(ipftuneable_t **ptop, void *cookie, void **next) 6760 { 6761 ipftuneable_t *ta, **tap; 6762 6763 for (ta = *ptop; ta->ipft_name != NULL; ta++) 6764 if (ta == cookie) { 6765 if (next != NULL) { 6766 /* 6767 * If the next entry in the array has a name 6768 * present, then return a pointer to it for 6769 * where to go next, else return a pointer to 6770 * the dynaminc list as a key to search there 6771 * next. This facilitates a weak linking of 6772 * the two "lists" together. 6773 */ 6774 if ((ta + 1)->ipft_name != NULL) 6775 *next = ta + 1; 6776 else 6777 *next = ptop; 6778 } 6779 return (ta); 6780 } 6781 6782 for (tap = ptop; (ta = *tap) != NULL; tap = &ta->ipft_next) 6783 if (tap == cookie) { 6784 if (next != NULL) 6785 *next = &ta->ipft_next; 6786 return (ta); 6787 } 6788 6789 if (next != NULL) 6790 *next = NULL; 6791 return (NULL); 6792 } 6793 6794 6795 /* ------------------------------------------------------------------------ */ 6796 /* Function: ipf_tune_findbyname */ 6797 /* Returns: NULL = search failed, else pointer to tune struct */ 6798 /* Parameters: name(I) - name of the tuneable entry to find. */ 6799 /* */ 6800 /* Search the static array of tuneables and the list of dynamic tuneables */ 6801 /* for an entry with a matching name. If we can find one, return a pointer */ 6802 /* to the matching structure. */ 6803 /* ------------------------------------------------------------------------ */ 6804 static ipftuneable_t * 6805 ipf_tune_findbyname(ipftuneable_t *top, const char *name) 6806 { 6807 ipftuneable_t *ta; 6808 6809 for (ta = top; ta != NULL; ta = ta->ipft_next) 6810 if (!strcmp(ta->ipft_name, name)) { 6811 return (ta); 6812 } 6813 6814 return (NULL); 6815 } 6816 6817 6818 /* ------------------------------------------------------------------------ */ 6819 /* Function: ipf_tune_add_array */ 6820 /* Returns: int - 0 == success, else failure */ 6821 /* Parameters: newtune - pointer to new tune array to add to tuneables */ 6822 /* */ 6823 /* Appends tune structures from the array passed in (newtune) to the end of */ 6824 /* the current list of "dynamic" tuneable parameters. */ 6825 /* If any entry to be added is already present (by name) then the operation */ 6826 /* is aborted - entries that have been added are removed before returning. */ 6827 /* An entry with no name (NULL) is used as the indication that the end of */ 6828 /* the array has been reached. */ 6829 /* ------------------------------------------------------------------------ */ 6830 int 6831 ipf_tune_add_array(ipf_main_softc_t *softc, ipftuneable_t *newtune) 6832 { 6833 ipftuneable_t *nt, *dt; 6834 int error = 0; 6835 6836 for (nt = newtune; nt->ipft_name != NULL; nt++) { 6837 error = ipf_tune_add(softc, nt); 6838 if (error != 0) { 6839 for (dt = newtune; dt != nt; dt++) { 6840 (void) ipf_tune_del(softc, dt); 6841 } 6842 } 6843 } 6844 6845 return (error); 6846 } 6847 6848 6849 /* ------------------------------------------------------------------------ */ 6850 /* Function: ipf_tune_array_link */ 6851 /* Returns: 0 == success, -1 == failure */ 6852 /* Parameters: softc(I) - soft context pointerto work with */ 6853 /* array(I) - pointer to an array of tuneables */ 6854 /* */ 6855 /* Given an array of tunables (array), append them to the current list of */ 6856 /* tuneables for this context (softc->ipf_tuners.) To properly prepare the */ 6857 /* the array for being appended to the list, initialise all of the next */ 6858 /* pointers so we don't need to walk parts of it with ++ and others with */ 6859 /* next. The array is expected to have an entry with a NULL name as the */ 6860 /* terminator. Trying to add an array with no non-NULL names will return as */ 6861 /* a failure. */ 6862 /* ------------------------------------------------------------------------ */ 6863 int 6864 ipf_tune_array_link(ipf_main_softc_t *softc, ipftuneable_t *array) 6865 { 6866 ipftuneable_t *t, **p; 6867 6868 t = array; 6869 if (t->ipft_name == NULL) 6870 return (-1); 6871 6872 for (; t[1].ipft_name != NULL; t++) 6873 t[0].ipft_next = &t[1]; 6874 t->ipft_next = NULL; 6875 6876 /* 6877 * Since a pointer to the last entry isn't kept, we need to find it 6878 * each time we want to add new variables to the list. 6879 */ 6880 for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next) 6881 if (t->ipft_name == NULL) 6882 break; 6883 *p = array; 6884 6885 return (0); 6886 } 6887 6888 6889 /* ------------------------------------------------------------------------ */ 6890 /* Function: ipf_tune_array_unlink */ 6891 /* Returns: 0 == success, -1 == failure */ 6892 /* Parameters: softc(I) - soft context pointerto work with */ 6893 /* array(I) - pointer to an array of tuneables */ 6894 /* */ 6895 /* ------------------------------------------------------------------------ */ 6896 int 6897 ipf_tune_array_unlink(ipf_main_softc_t *softc, ipftuneable_t *array) 6898 { 6899 ipftuneable_t *t, **p; 6900 6901 for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next) 6902 if (t == array) 6903 break; 6904 if (t == NULL) 6905 return (-1); 6906 6907 for (; t[1].ipft_name != NULL; t++) 6908 ; 6909 6910 *p = t->ipft_next; 6911 6912 return (0); 6913 } 6914 6915 6916 /* ------------------------------------------------------------------------ */ 6917 /* Function: ipf_tune_array_copy */ 6918 /* Returns: NULL = failure, else pointer to new array */ 6919 /* Parameters: base(I) - pointer to structure base */ 6920 /* size(I) - size of the array at template */ 6921 /* template(I) - original array to copy */ 6922 /* */ 6923 /* Allocate memory for a new set of tuneable values and copy everything */ 6924 /* from template into the new region of memory. The new region is full of */ 6925 /* uninitialised pointers (ipft_next) so set them up. Now, ipftp_offset... */ 6926 /* */ 6927 /* NOTE: the following assumes that sizeof(long) == sizeof(void *) */ 6928 /* In the array template, ipftp_offset is the offset (in bytes) of the */ 6929 /* location of the tuneable value inside the structure pointed to by base. */ 6930 /* As ipftp_offset is a union over the pointers to the tuneable values, if */ 6931 /* we add base to the copy's ipftp_offset, copy ends up with a pointer in */ 6932 /* ipftp_void that points to the stored value. */ 6933 /* ------------------------------------------------------------------------ */ 6934 ipftuneable_t * 6935 ipf_tune_array_copy(void *base, size_t size, ipftuneable_t *template) 6936 { 6937 ipftuneable_t *copy; 6938 int i; 6939 6940 6941 KMALLOCS(copy, ipftuneable_t *, size); 6942 if (copy == NULL) { 6943 return (NULL); 6944 } 6945 bcopy(template, copy, size); 6946 6947 for (i = 0; copy[i].ipft_name; i++) { 6948 copy[i].ipft_una.ipftp_offset += (u_long)base; 6949 copy[i].ipft_next = copy + i + 1; 6950 } 6951 6952 return (copy); 6953 } 6954 6955 6956 /* ------------------------------------------------------------------------ */ 6957 /* Function: ipf_tune_add */ 6958 /* Returns: int - 0 == success, else failure */ 6959 /* Parameters: newtune - pointer to new tune entry to add to tuneables */ 6960 /* */ 6961 /* Appends tune structures from the array passed in (newtune) to the end of */ 6962 /* the current list of "dynamic" tuneable parameters. Once added, the */ 6963 /* owner of the object is not expected to ever change "ipft_next". */ 6964 /* ------------------------------------------------------------------------ */ 6965 int 6966 ipf_tune_add(ipf_main_softc_t *softc, ipftuneable_t *newtune) 6967 { 6968 ipftuneable_t *ta, **tap; 6969 6970 ta = ipf_tune_findbyname(softc->ipf_tuners, newtune->ipft_name); 6971 if (ta != NULL) { 6972 IPFERROR(74); 6973 return (EEXIST); 6974 } 6975 6976 for (tap = &softc->ipf_tuners; *tap != NULL; tap = &(*tap)->ipft_next) 6977 ; 6978 6979 newtune->ipft_next = NULL; 6980 *tap = newtune; 6981 return (0); 6982 } 6983 6984 6985 /* ------------------------------------------------------------------------ */ 6986 /* Function: ipf_tune_del */ 6987 /* Returns: int - 0 == success, else failure */ 6988 /* Parameters: oldtune - pointer to tune entry to remove from the list of */ 6989 /* current dynamic tuneables */ 6990 /* */ 6991 /* Search for the tune structure, by pointer, in the list of those that are */ 6992 /* dynamically added at run time. If found, adjust the list so that this */ 6993 /* structure is no longer part of it. */ 6994 /* ------------------------------------------------------------------------ */ 6995 int 6996 ipf_tune_del(ipf_main_softc_t *softc, ipftuneable_t *oldtune) 6997 { 6998 ipftuneable_t *ta, **tap; 6999 int error = 0; 7000 7001 for (tap = &softc->ipf_tuners; (ta = *tap) != NULL; 7002 tap = &ta->ipft_next) { 7003 if (ta == oldtune) { 7004 *tap = oldtune->ipft_next; 7005 oldtune->ipft_next = NULL; 7006 break; 7007 } 7008 } 7009 7010 if (ta == NULL) { 7011 error = ESRCH; 7012 IPFERROR(75); 7013 } 7014 return (error); 7015 } 7016 7017 7018 /* ------------------------------------------------------------------------ */ 7019 /* Function: ipf_tune_del_array */ 7020 /* Returns: int - 0 == success, else failure */ 7021 /* Parameters: oldtune - pointer to tuneables array */ 7022 /* */ 7023 /* Remove each tuneable entry in the array from the list of "dynamic" */ 7024 /* tunables. If one entry should fail to be found, an error will be */ 7025 /* returned and no further ones removed. */ 7026 /* An entry with a NULL name is used as the indicator of the last entry in */ 7027 /* the array. */ 7028 /* ------------------------------------------------------------------------ */ 7029 int 7030 ipf_tune_del_array(ipf_main_softc_t *softc, ipftuneable_t *oldtune) 7031 { 7032 ipftuneable_t *ot; 7033 int error = 0; 7034 7035 for (ot = oldtune; ot->ipft_name != NULL; ot++) { 7036 error = ipf_tune_del(softc, ot); 7037 if (error != 0) 7038 break; 7039 } 7040 7041 return (error); 7042 7043 } 7044 7045 7046 /* ------------------------------------------------------------------------ */ 7047 /* Function: ipf_tune */ 7048 /* Returns: int - 0 == success, else failure */ 7049 /* Parameters: cmd(I) - ioctl command number */ 7050 /* data(I) - pointer to ioctl data structure */ 7051 /* */ 7052 /* Implement handling of SIOCIPFGETNEXT, SIOCIPFGET and SIOCIPFSET. These */ 7053 /* three ioctls provide the means to access and control global variables */ 7054 /* within IPFilter, allowing (for example) timeouts and table sizes to be */ 7055 /* changed without rebooting, reloading or recompiling. The initialisation */ 7056 /* and 'destruction' routines of the various components of ipfilter are all */ 7057 /* each responsible for handling their own values being too big. */ 7058 /* ------------------------------------------------------------------------ */ 7059 int 7060 ipf_ipftune(ipf_main_softc_t *softc, ioctlcmd_t cmd, void *data) 7061 { 7062 ipftuneable_t *ta; 7063 ipftune_t tu; 7064 void *cookie; 7065 int error; 7066 7067 error = ipf_inobj(softc, data, NULL, &tu, IPFOBJ_TUNEABLE); 7068 if (error != 0) 7069 return (error); 7070 7071 tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0'; 7072 cookie = tu.ipft_cookie; 7073 ta = NULL; 7074 7075 switch (cmd) 7076 { 7077 case SIOCIPFGETNEXT : 7078 /* 7079 * If cookie is non-NULL, assume it to be a pointer to the last 7080 * entry we looked at, so find it (if possible) and return a 7081 * pointer to the next one after it. The last entry in the 7082 * the table is a NULL entry, so when we get to it, set cookie 7083 * to NULL and return that, indicating end of list, erstwhile 7084 * if we come in with cookie set to NULL, we are starting anew 7085 * at the front of the list. 7086 */ 7087 if (cookie != NULL) { 7088 ta = ipf_tune_findbycookie(&softc->ipf_tuners, 7089 cookie, &tu.ipft_cookie); 7090 } else { 7091 ta = softc->ipf_tuners; 7092 tu.ipft_cookie = ta + 1; 7093 } 7094 if (ta != NULL) { 7095 /* 7096 * Entry found, but does the data pointed to by that 7097 * row fit in what we can return? 7098 */ 7099 if (ta->ipft_sz > sizeof(tu.ipft_un)) { 7100 IPFERROR(76); 7101 return (EINVAL); 7102 } 7103 7104 tu.ipft_vlong = 0; 7105 if (ta->ipft_sz == sizeof(u_long)) 7106 tu.ipft_vlong = *ta->ipft_plong; 7107 else if (ta->ipft_sz == sizeof(u_int)) 7108 tu.ipft_vint = *ta->ipft_pint; 7109 else if (ta->ipft_sz == sizeof(u_short)) 7110 tu.ipft_vshort = *ta->ipft_pshort; 7111 else if (ta->ipft_sz == sizeof(u_char)) 7112 tu.ipft_vchar = *ta->ipft_pchar; 7113 7114 tu.ipft_sz = ta->ipft_sz; 7115 tu.ipft_min = ta->ipft_min; 7116 tu.ipft_max = ta->ipft_max; 7117 tu.ipft_flags = ta->ipft_flags; 7118 bcopy(ta->ipft_name, tu.ipft_name, 7119 MIN(sizeof(tu.ipft_name), 7120 strlen(ta->ipft_name) + 1)); 7121 } 7122 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE); 7123 break; 7124 7125 case SIOCIPFGET : 7126 case SIOCIPFSET : 7127 /* 7128 * Search by name or by cookie value for a particular entry 7129 * in the tuning parameter table. 7130 */ 7131 IPFERROR(77); 7132 error = ESRCH; 7133 if (cookie != NULL) { 7134 ta = ipf_tune_findbycookie(&softc->ipf_tuners, 7135 cookie, NULL); 7136 if (ta != NULL) 7137 error = 0; 7138 } else if (tu.ipft_name[0] != '\0') { 7139 ta = ipf_tune_findbyname(softc->ipf_tuners, 7140 tu.ipft_name); 7141 if (ta != NULL) 7142 error = 0; 7143 } 7144 if (error != 0) 7145 break; 7146 7147 if (cmd == (ioctlcmd_t)SIOCIPFGET) { 7148 /* 7149 * Fetch the tuning parameters for a particular value 7150 */ 7151 tu.ipft_vlong = 0; 7152 if (ta->ipft_sz == sizeof(u_long)) 7153 tu.ipft_vlong = *ta->ipft_plong; 7154 else if (ta->ipft_sz == sizeof(u_int)) 7155 tu.ipft_vint = *ta->ipft_pint; 7156 else if (ta->ipft_sz == sizeof(u_short)) 7157 tu.ipft_vshort = *ta->ipft_pshort; 7158 else if (ta->ipft_sz == sizeof(u_char)) 7159 tu.ipft_vchar = *ta->ipft_pchar; 7160 tu.ipft_cookie = ta; 7161 tu.ipft_sz = ta->ipft_sz; 7162 tu.ipft_min = ta->ipft_min; 7163 tu.ipft_max = ta->ipft_max; 7164 tu.ipft_flags = ta->ipft_flags; 7165 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE); 7166 7167 } else if (cmd == (ioctlcmd_t)SIOCIPFSET) { 7168 /* 7169 * Set an internal parameter. The hard part here is 7170 * getting the new value safely and correctly out of 7171 * the kernel (given we only know its size, not type.) 7172 */ 7173 u_long in; 7174 7175 if (((ta->ipft_flags & IPFT_WRDISABLED) != 0) && 7176 (softc->ipf_running > 0)) { 7177 IPFERROR(78); 7178 error = EBUSY; 7179 break; 7180 } 7181 7182 in = tu.ipft_vlong; 7183 if (in < ta->ipft_min || in > ta->ipft_max) { 7184 IPFERROR(79); 7185 error = EINVAL; 7186 break; 7187 } 7188 7189 if (ta->ipft_func != NULL) { 7190 SPL_INT(s); 7191 7192 SPL_NET(s); 7193 error = (*ta->ipft_func)(softc, ta, 7194 &tu.ipft_un); 7195 SPL_X(s); 7196 7197 } else if (ta->ipft_sz == sizeof(u_long)) { 7198 tu.ipft_vlong = *ta->ipft_plong; 7199 *ta->ipft_plong = in; 7200 7201 } else if (ta->ipft_sz == sizeof(u_int)) { 7202 tu.ipft_vint = *ta->ipft_pint; 7203 *ta->ipft_pint = (u_int)(in & 0xffffffff); 7204 7205 } else if (ta->ipft_sz == sizeof(u_short)) { 7206 tu.ipft_vshort = *ta->ipft_pshort; 7207 *ta->ipft_pshort = (u_short)(in & 0xffff); 7208 7209 } else if (ta->ipft_sz == sizeof(u_char)) { 7210 tu.ipft_vchar = *ta->ipft_pchar; 7211 *ta->ipft_pchar = (u_char)(in & 0xff); 7212 } 7213 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE); 7214 } 7215 break; 7216 7217 default : 7218 IPFERROR(80); 7219 error = EINVAL; 7220 break; 7221 } 7222 7223 return (error); 7224 } 7225 7226 7227 /* ------------------------------------------------------------------------ */ 7228 /* Function: ipf_zerostats */ 7229 /* Returns: int - 0 = success, else failure */ 7230 /* Parameters: data(O) - pointer to pointer for copying data back to */ 7231 /* */ 7232 /* Copies the current statistics out to userspace and then zero's the */ 7233 /* current ones in the kernel. The lock is only held across the bzero() as */ 7234 /* the copyout may result in paging (ie network activity.) */ 7235 /* ------------------------------------------------------------------------ */ 7236 int 7237 ipf_zerostats(ipf_main_softc_t *softc, caddr_t data) 7238 { 7239 friostat_t fio; 7240 ipfobj_t obj; 7241 int error; 7242 7243 error = ipf_inobj(softc, data, &obj, &fio, IPFOBJ_IPFSTAT); 7244 if (error != 0) 7245 return (error); 7246 ipf_getstat(softc, &fio, obj.ipfo_rev); 7247 error = ipf_outobj(softc, data, &fio, IPFOBJ_IPFSTAT); 7248 if (error != 0) 7249 return (error); 7250 7251 WRITE_ENTER(&softc->ipf_mutex); 7252 bzero(&softc->ipf_stats, sizeof(softc->ipf_stats)); 7253 RWLOCK_EXIT(&softc->ipf_mutex); 7254 7255 return (0); 7256 } 7257 7258 7259 /* ------------------------------------------------------------------------ */ 7260 /* Function: ipf_resolvedest */ 7261 /* Returns: Nil */ 7262 /* Parameters: softc(I) - pointer to soft context main structure */ 7263 /* base(I) - where strings are stored */ 7264 /* fdp(IO) - pointer to destination information to resolve */ 7265 /* v(I) - IP protocol version to match */ 7266 /* */ 7267 /* Looks up an interface name in the frdest structure pointed to by fdp and */ 7268 /* if a matching name can be found for the particular IP protocol version */ 7269 /* then store the interface pointer in the frdest struct. If no match is */ 7270 /* found, then set the interface pointer to be -1 as NULL is considered to */ 7271 /* indicate there is no information at all in the structure. */ 7272 /* ------------------------------------------------------------------------ */ 7273 int 7274 ipf_resolvedest(ipf_main_softc_t *softc, char *base, frdest_t *fdp, int v) 7275 { 7276 int errval = 0; 7277 void *ifp; 7278 7279 ifp = NULL; 7280 7281 if (fdp->fd_name != -1) { 7282 if (fdp->fd_type == FRD_DSTLIST) { 7283 ifp = ipf_lookup_res_name(softc, IPL_LOGIPF, 7284 IPLT_DSTLIST, 7285 base + fdp->fd_name, 7286 NULL); 7287 if (ifp == NULL) { 7288 IPFERROR(144); 7289 errval = ESRCH; 7290 } 7291 } else { 7292 ifp = GETIFP(base + fdp->fd_name, v); 7293 if (ifp == NULL) 7294 ifp = (void *)-1; 7295 } 7296 } 7297 fdp->fd_ptr = ifp; 7298 7299 return (errval); 7300 } 7301 7302 7303 /* ------------------------------------------------------------------------ */ 7304 /* Function: ipf_resolvenic */ 7305 /* Returns: void* - NULL = wildcard name, -1 = failed to find NIC, else */ 7306 /* pointer to interface structure for NIC */ 7307 /* Parameters: softc(I)- pointer to soft context main structure */ 7308 /* name(I) - complete interface name */ 7309 /* v(I) - IP protocol version */ 7310 /* */ 7311 /* Look for a network interface structure that firstly has a matching name */ 7312 /* to that passed in and that is also being used for that IP protocol */ 7313 /* version (necessary on some platforms where there are separate listings */ 7314 /* for both IPv4 and IPv6 on the same physical NIC. */ 7315 /* ------------------------------------------------------------------------ */ 7316 void * 7317 ipf_resolvenic(ipf_main_softc_t *softc, char *name, int v) 7318 { 7319 void *nic; 7320 7321 softc = softc; /* gcc -Wextra */ 7322 if (name[0] == '\0') 7323 return (NULL); 7324 7325 if ((name[1] == '\0') && ((name[0] == '-') || (name[0] == '*'))) { 7326 return (NULL); 7327 } 7328 7329 nic = GETIFP(name, v); 7330 if (nic == NULL) 7331 nic = (void *)-1; 7332 return (nic); 7333 } 7334 7335 7336 /* ------------------------------------------------------------------------ */ 7337 /* Function: ipf_token_expire */ 7338 /* Returns: None. */ 7339 /* Parameters: softc(I) - pointer to soft context main structure */ 7340 /* */ 7341 /* This function is run every ipf tick to see if there are any tokens that */ 7342 /* have been held for too long and need to be freed up. */ 7343 /* ------------------------------------------------------------------------ */ 7344 void 7345 ipf_token_expire(ipf_main_softc_t *softc) 7346 { 7347 ipftoken_t *it; 7348 7349 WRITE_ENTER(&softc->ipf_tokens); 7350 while ((it = softc->ipf_token_head) != NULL) { 7351 if (it->ipt_die > softc->ipf_ticks) 7352 break; 7353 7354 ipf_token_deref(softc, it); 7355 } 7356 RWLOCK_EXIT(&softc->ipf_tokens); 7357 } 7358 7359 7360 /* ------------------------------------------------------------------------ */ 7361 /* Function: ipf_token_flush */ 7362 /* Returns: None. */ 7363 /* Parameters: softc(I) - pointer to soft context main structure */ 7364 /* */ 7365 /* Loop through all of the existing tokens and call deref to see if they */ 7366 /* can be freed. Normally a function like this might just loop on */ 7367 /* ipf_token_head but there is a chance that a token might have a ref count */ 7368 /* of greater than one and in that case the reference would drop twice */ 7369 /* by code that is only entitled to drop it once. */ 7370 /* ------------------------------------------------------------------------ */ 7371 static void 7372 ipf_token_flush(ipf_main_softc_t *softc) 7373 { 7374 ipftoken_t *it, *next; 7375 7376 WRITE_ENTER(&softc->ipf_tokens); 7377 for (it = softc->ipf_token_head; it != NULL; it = next) { 7378 next = it->ipt_next; 7379 (void) ipf_token_deref(softc, it); 7380 } 7381 RWLOCK_EXIT(&softc->ipf_tokens); 7382 } 7383 7384 7385 /* ------------------------------------------------------------------------ */ 7386 /* Function: ipf_token_del */ 7387 /* Returns: int - 0 = success, else error */ 7388 /* Parameters: softc(I)- pointer to soft context main structure */ 7389 /* type(I) - the token type to match */ 7390 /* uid(I) - uid owning the token */ 7391 /* ptr(I) - context pointer for the token */ 7392 /* */ 7393 /* This function looks for a token in the current list that matches up */ 7394 /* the fields (type, uid, ptr). If none is found, ESRCH is returned, else */ 7395 /* call ipf_token_dewref() to remove it from the list. In the event that */ 7396 /* the token has a reference held elsewhere, setting ipt_complete to 2 */ 7397 /* enables debugging to distinguish between the two paths that ultimately */ 7398 /* lead to a token to be deleted. */ 7399 /* ------------------------------------------------------------------------ */ 7400 int 7401 ipf_token_del(ipf_main_softc_t *softc, int type, int uid, void *ptr) 7402 { 7403 ipftoken_t *it; 7404 int error; 7405 7406 IPFERROR(82); 7407 error = ESRCH; 7408 7409 WRITE_ENTER(&softc->ipf_tokens); 7410 for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) { 7411 if (ptr == it->ipt_ctx && type == it->ipt_type && 7412 uid == it->ipt_uid) { 7413 it->ipt_complete = 2; 7414 ipf_token_deref(softc, it); 7415 error = 0; 7416 break; 7417 } 7418 } 7419 RWLOCK_EXIT(&softc->ipf_tokens); 7420 7421 return (error); 7422 } 7423 7424 7425 /* ------------------------------------------------------------------------ */ 7426 /* Function: ipf_token_mark_complete */ 7427 /* Returns: None. */ 7428 /* Parameters: token(I) - pointer to token structure */ 7429 /* */ 7430 /* Mark a token as being ineligable for being found with ipf_token_find. */ 7431 /* ------------------------------------------------------------------------ */ 7432 void 7433 ipf_token_mark_complete(ipftoken_t *token) 7434 { 7435 if (token->ipt_complete == 0) 7436 token->ipt_complete = 1; 7437 } 7438 7439 7440 /* ------------------------------------------------------------------------ */ 7441 /* Function: ipf_token_find */ 7442 /* Returns: ipftoken_t * - NULL if no memory, else pointer to token */ 7443 /* Parameters: softc(I)- pointer to soft context main structure */ 7444 /* type(I) - the token type to match */ 7445 /* uid(I) - uid owning the token */ 7446 /* ptr(I) - context pointer for the token */ 7447 /* */ 7448 /* This function looks for a live token in the list of current tokens that */ 7449 /* matches the tuple (type, uid, ptr). If one cannot be found then one is */ 7450 /* allocated. If one is found then it is moved to the top of the list of */ 7451 /* currently active tokens. */ 7452 /* ------------------------------------------------------------------------ */ 7453 ipftoken_t * 7454 ipf_token_find(ipf_main_softc_t *softc, int type, int uid, void *ptr) 7455 { 7456 ipftoken_t *it, *new; 7457 7458 WRITE_ENTER(&softc->ipf_tokens); 7459 for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) { 7460 if ((ptr == it->ipt_ctx) && (type == it->ipt_type) && 7461 (uid == it->ipt_uid) && (it->ipt_complete < 2)) 7462 break; 7463 } 7464 7465 if (it == NULL) { 7466 KMALLOC(new, ipftoken_t *); 7467 if (new != NULL) 7468 bzero((char *)new, sizeof(*new)); 7469 7470 it = new; 7471 new = NULL; 7472 if (it == NULL) { 7473 RWLOCK_EXIT(&softc->ipf_tokens); 7474 return (NULL); 7475 } 7476 it->ipt_ctx = ptr; 7477 it->ipt_uid = uid; 7478 it->ipt_type = type; 7479 it->ipt_ref = 1; 7480 } else { 7481 if (it->ipt_complete > 0) 7482 it = NULL; 7483 else 7484 ipf_token_unlink(softc, it); 7485 } 7486 7487 if (it != NULL) { 7488 it->ipt_pnext = softc->ipf_token_tail; 7489 *softc->ipf_token_tail = it; 7490 softc->ipf_token_tail = &it->ipt_next; 7491 it->ipt_next = NULL; 7492 it->ipt_ref++; 7493 7494 it->ipt_die = softc->ipf_ticks + 20; 7495 } 7496 7497 RWLOCK_EXIT(&softc->ipf_tokens); 7498 7499 return (it); 7500 } 7501 7502 7503 /* ------------------------------------------------------------------------ */ 7504 /* Function: ipf_token_unlink */ 7505 /* Returns: None. */ 7506 /* Parameters: softc(I) - pointer to soft context main structure */ 7507 /* token(I) - pointer to token structure */ 7508 /* Write Locks: ipf_tokens */ 7509 /* */ 7510 /* This function unlinks a token structure from the linked list of tokens */ 7511 /* that "own" it. The head pointer never needs to be explicitly adjusted */ 7512 /* but the tail does due to the linked list implementation. */ 7513 /* ------------------------------------------------------------------------ */ 7514 static void 7515 ipf_token_unlink(ipf_main_softc_t *softc, ipftoken_t *token) 7516 { 7517 7518 if (softc->ipf_token_tail == &token->ipt_next) 7519 softc->ipf_token_tail = token->ipt_pnext; 7520 7521 *token->ipt_pnext = token->ipt_next; 7522 if (token->ipt_next != NULL) 7523 token->ipt_next->ipt_pnext = token->ipt_pnext; 7524 token->ipt_next = NULL; 7525 token->ipt_pnext = NULL; 7526 } 7527 7528 7529 /* ------------------------------------------------------------------------ */ 7530 /* Function: ipf_token_deref */ 7531 /* Returns: int - 0 == token freed, else reference count */ 7532 /* Parameters: softc(I) - pointer to soft context main structure */ 7533 /* token(I) - pointer to token structure */ 7534 /* Write Locks: ipf_tokens */ 7535 /* */ 7536 /* Drop the reference count on the token structure and if it drops to zero, */ 7537 /* call the dereference function for the token type because it is then */ 7538 /* possible to free the token data structure. */ 7539 /* ------------------------------------------------------------------------ */ 7540 int 7541 ipf_token_deref(ipf_main_softc_t *softc, ipftoken_t *token) 7542 { 7543 void *data, **datap; 7544 7545 ASSERT(token->ipt_ref > 0); 7546 token->ipt_ref--; 7547 if (token->ipt_ref > 0) 7548 return (token->ipt_ref); 7549 7550 data = token->ipt_data; 7551 datap = &data; 7552 7553 if ((data != NULL) && (data != (void *)-1)) { 7554 switch (token->ipt_type) 7555 { 7556 case IPFGENITER_IPF : 7557 (void) ipf_derefrule(softc, (frentry_t **)datap); 7558 break; 7559 case IPFGENITER_IPNAT : 7560 WRITE_ENTER(&softc->ipf_nat); 7561 ipf_nat_rule_deref(softc, (ipnat_t **)datap); 7562 RWLOCK_EXIT(&softc->ipf_nat); 7563 break; 7564 case IPFGENITER_NAT : 7565 ipf_nat_deref(softc, (nat_t **)datap); 7566 break; 7567 case IPFGENITER_STATE : 7568 ipf_state_deref(softc, (ipstate_t **)datap); 7569 break; 7570 case IPFGENITER_FRAG : 7571 ipf_frag_pkt_deref(softc, (ipfr_t **)datap); 7572 break; 7573 case IPFGENITER_NATFRAG : 7574 ipf_frag_nat_deref(softc, (ipfr_t **)datap); 7575 break; 7576 case IPFGENITER_HOSTMAP : 7577 WRITE_ENTER(&softc->ipf_nat); 7578 ipf_nat_hostmapdel(softc, (hostmap_t **)datap); 7579 RWLOCK_EXIT(&softc->ipf_nat); 7580 break; 7581 default : 7582 ipf_lookup_iterderef(softc, token->ipt_type, data); 7583 break; 7584 } 7585 } 7586 7587 ipf_token_unlink(softc, token); 7588 KFREE(token); 7589 return (0); 7590 } 7591 7592 7593 /* ------------------------------------------------------------------------ */ 7594 /* Function: ipf_nextrule */ 7595 /* Returns: frentry_t * - NULL == no more rules, else pointer to next */ 7596 /* Parameters: softc(I) - pointer to soft context main structure */ 7597 /* fr(I) - pointer to filter rule */ 7598 /* out(I) - 1 == out rules, 0 == input rules */ 7599 /* */ 7600 /* Starting with "fr", find the next rule to visit. This includes visiting */ 7601 /* the list of rule groups if either fr is NULL (empty list) or it is the */ 7602 /* last rule in the list. When walking rule lists, it is either input or */ 7603 /* output rules that are returned, never both. */ 7604 /* ------------------------------------------------------------------------ */ 7605 static frentry_t * 7606 ipf_nextrule(ipf_main_softc_t *softc, int active, int unit, frentry_t *fr, 7607 int out) 7608 { 7609 frentry_t *next; 7610 frgroup_t *fg; 7611 7612 if (fr != NULL && fr->fr_group != -1) { 7613 fg = ipf_findgroup(softc, fr->fr_names + fr->fr_group, 7614 unit, active, NULL); 7615 if (fg != NULL) 7616 fg = fg->fg_next; 7617 } else { 7618 fg = softc->ipf_groups[unit][active]; 7619 } 7620 7621 while (fg != NULL) { 7622 next = fg->fg_start; 7623 while (next != NULL) { 7624 if (out) { 7625 if (next->fr_flags & FR_OUTQUE) 7626 return (next); 7627 } else if (next->fr_flags & FR_INQUE) { 7628 return (next); 7629 } 7630 next = next->fr_next; 7631 } 7632 if (next == NULL) 7633 fg = fg->fg_next; 7634 } 7635 7636 return (NULL); 7637 } 7638 7639 /* ------------------------------------------------------------------------ */ 7640 /* Function: ipf_getnextrule */ 7641 /* Returns: int - 0 = success, else error */ 7642 /* Parameters: softc(I)- pointer to soft context main structure */ 7643 /* t(I) - pointer to destination information to resolve */ 7644 /* ptr(I) - pointer to ipfobj_t to copyin from user space */ 7645 /* */ 7646 /* This function's first job is to bring in the ipfruleiter_t structure via */ 7647 /* the ipfobj_t structure to determine what should be the next rule to */ 7648 /* return. Once the ipfruleiter_t has been brought in, it then tries to */ 7649 /* find the 'next rule'. This may include searching rule group lists or */ 7650 /* just be as simple as looking at the 'next' field in the rule structure. */ 7651 /* When we have found the rule to return, increase its reference count and */ 7652 /* if we used an existing rule to get here, decrease its reference count. */ 7653 /* ------------------------------------------------------------------------ */ 7654 int 7655 ipf_getnextrule(ipf_main_softc_t *softc, ipftoken_t *t, void *ptr) 7656 { 7657 frentry_t *fr, *next, zero; 7658 ipfruleiter_t it; 7659 int error, out; 7660 frgroup_t *fg; 7661 ipfobj_t obj; 7662 int predict; 7663 char *dst; 7664 int unit; 7665 7666 if (t == NULL || ptr == NULL) { 7667 IPFERROR(84); 7668 return (EFAULT); 7669 } 7670 7671 error = ipf_inobj(softc, ptr, &obj, &it, IPFOBJ_IPFITER); 7672 if (error != 0) 7673 return (error); 7674 7675 if ((it.iri_inout < 0) || (it.iri_inout > 3)) { 7676 IPFERROR(85); 7677 return (EINVAL); 7678 } 7679 if ((it.iri_active != 0) && (it.iri_active != 1)) { 7680 IPFERROR(86); 7681 return (EINVAL); 7682 } 7683 if (it.iri_nrules == 0) { 7684 IPFERROR(87); 7685 return (ENOSPC); 7686 } 7687 if (it.iri_rule == NULL) { 7688 IPFERROR(88); 7689 return (EFAULT); 7690 } 7691 7692 fg = NULL; 7693 fr = t->ipt_data; 7694 if ((it.iri_inout & F_OUT) != 0) 7695 out = 1; 7696 else 7697 out = 0; 7698 if ((it.iri_inout & F_ACIN) != 0) 7699 unit = IPL_LOGCOUNT; 7700 else 7701 unit = IPL_LOGIPF; 7702 7703 READ_ENTER(&softc->ipf_mutex); 7704 if (fr == NULL) { 7705 if (*it.iri_group == '\0') { 7706 if (unit == IPL_LOGCOUNT) { 7707 next = softc->ipf_acct[out][it.iri_active]; 7708 } else { 7709 next = softc->ipf_rules[out][it.iri_active]; 7710 } 7711 if (next == NULL) 7712 next = ipf_nextrule(softc, it.iri_active, 7713 unit, NULL, out); 7714 } else { 7715 fg = ipf_findgroup(softc, it.iri_group, unit, 7716 it.iri_active, NULL); 7717 if (fg != NULL) 7718 next = fg->fg_start; 7719 else 7720 next = NULL; 7721 } 7722 } else { 7723 next = fr->fr_next; 7724 if (next == NULL) 7725 next = ipf_nextrule(softc, it.iri_active, unit, 7726 fr, out); 7727 } 7728 7729 if (next != NULL && next->fr_next != NULL) 7730 predict = 1; 7731 else if (ipf_nextrule(softc, it.iri_active, unit, next, out) != NULL) 7732 predict = 1; 7733 else 7734 predict = 0; 7735 7736 if (fr != NULL) 7737 (void) ipf_derefrule(softc, &fr); 7738 7739 obj.ipfo_type = IPFOBJ_FRENTRY; 7740 dst = (char *)it.iri_rule; 7741 7742 if (next != NULL) { 7743 obj.ipfo_size = next->fr_size; 7744 MUTEX_ENTER(&next->fr_lock); 7745 next->fr_ref++; 7746 MUTEX_EXIT(&next->fr_lock); 7747 t->ipt_data = next; 7748 } else { 7749 obj.ipfo_size = sizeof(frentry_t); 7750 bzero(&zero, sizeof(zero)); 7751 next = &zero; 7752 t->ipt_data = NULL; 7753 } 7754 it.iri_rule = predict ? next : NULL; 7755 if (predict == 0) 7756 ipf_token_mark_complete(t); 7757 7758 RWLOCK_EXIT(&softc->ipf_mutex); 7759 7760 obj.ipfo_ptr = dst; 7761 error = ipf_outobjk(softc, &obj, next); 7762 if (error == 0 && t->ipt_data != NULL) { 7763 dst += obj.ipfo_size; 7764 if (next->fr_data != NULL) { 7765 ipfobj_t dobj; 7766 7767 if (next->fr_type == FR_T_IPFEXPR) 7768 dobj.ipfo_type = IPFOBJ_IPFEXPR; 7769 else 7770 dobj.ipfo_type = IPFOBJ_FRIPF; 7771 dobj.ipfo_size = next->fr_dsize; 7772 dobj.ipfo_rev = obj.ipfo_rev; 7773 dobj.ipfo_ptr = dst; 7774 error = ipf_outobjk(softc, &dobj, next->fr_data); 7775 } 7776 } 7777 7778 if ((fr != NULL) && (next == &zero)) 7779 (void) ipf_derefrule(softc, &fr); 7780 7781 return (error); 7782 } 7783 7784 7785 /* ------------------------------------------------------------------------ */ 7786 /* Function: ipf_frruleiter */ 7787 /* Returns: int - 0 = success, else error */ 7788 /* Parameters: softc(I)- pointer to soft context main structure */ 7789 /* data(I) - the token type to match */ 7790 /* uid(I) - uid owning the token */ 7791 /* ptr(I) - context pointer for the token */ 7792 /* */ 7793 /* This function serves as a stepping stone between ipf_ipf_ioctl and */ 7794 /* ipf_getnextrule. It's role is to find the right token in the kernel for */ 7795 /* the process doing the ioctl and use that to ask for the next rule. */ 7796 /* ------------------------------------------------------------------------ */ 7797 static int 7798 ipf_frruleiter(ipf_main_softc_t *softc, void *data, int uid, void *ctx) 7799 { 7800 ipftoken_t *token; 7801 ipfruleiter_t it; 7802 ipfobj_t obj; 7803 int error; 7804 7805 token = ipf_token_find(softc, IPFGENITER_IPF, uid, ctx); 7806 if (token != NULL) { 7807 error = ipf_getnextrule(softc, token, data); 7808 WRITE_ENTER(&softc->ipf_tokens); 7809 ipf_token_deref(softc, token); 7810 RWLOCK_EXIT(&softc->ipf_tokens); 7811 } else { 7812 error = ipf_inobj(softc, data, &obj, &it, IPFOBJ_IPFITER); 7813 if (error != 0) 7814 return (error); 7815 it.iri_rule = NULL; 7816 error = ipf_outobj(softc, data, &it, IPFOBJ_IPFITER); 7817 } 7818 7819 return (error); 7820 } 7821 7822 7823 /* ------------------------------------------------------------------------ */ 7824 /* Function: ipf_geniter */ 7825 /* Returns: int - 0 = success, else error */ 7826 /* Parameters: softc(I) - pointer to soft context main structure */ 7827 /* token(I) - pointer to ipftoken_t structure */ 7828 /* itp(I) - pointer to iterator data */ 7829 /* */ 7830 /* Decide which iterator function to call using information passed through */ 7831 /* the ipfgeniter_t structure at itp. */ 7832 /* ------------------------------------------------------------------------ */ 7833 static int 7834 ipf_geniter(ipf_main_softc_t *softc, ipftoken_t *token, ipfgeniter_t *itp) 7835 { 7836 int error; 7837 7838 switch (itp->igi_type) 7839 { 7840 case IPFGENITER_FRAG : 7841 error = ipf_frag_pkt_next(softc, token, itp); 7842 break; 7843 default : 7844 IPFERROR(92); 7845 error = EINVAL; 7846 break; 7847 } 7848 7849 return (error); 7850 } 7851 7852 7853 /* ------------------------------------------------------------------------ */ 7854 /* Function: ipf_genericiter */ 7855 /* Returns: int - 0 = success, else error */ 7856 /* Parameters: softc(I)- pointer to soft context main structure */ 7857 /* data(I) - the token type to match */ 7858 /* uid(I) - uid owning the token */ 7859 /* ptr(I) - context pointer for the token */ 7860 /* */ 7861 /* Handle the SIOCGENITER ioctl for the ipfilter device. The primary role */ 7862 /* ------------------------------------------------------------------------ */ 7863 int 7864 ipf_genericiter(ipf_main_softc_t *softc, void *data, int uid, void *ctx) 7865 { 7866 ipftoken_t *token; 7867 ipfgeniter_t iter; 7868 int error; 7869 7870 error = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_GENITER); 7871 if (error != 0) 7872 return (error); 7873 7874 token = ipf_token_find(softc, iter.igi_type, uid, ctx); 7875 if (token != NULL) { 7876 token->ipt_subtype = iter.igi_type; 7877 error = ipf_geniter(softc, token, &iter); 7878 WRITE_ENTER(&softc->ipf_tokens); 7879 ipf_token_deref(softc, token); 7880 RWLOCK_EXIT(&softc->ipf_tokens); 7881 } else { 7882 IPFERROR(93); 7883 error = 0; 7884 } 7885 7886 return (error); 7887 } 7888 7889 7890 /* ------------------------------------------------------------------------ */ 7891 /* Function: ipf_ipf_ioctl */ 7892 /* Returns: int - 0 = success, else error */ 7893 /* Parameters: softc(I)- pointer to soft context main structure */ 7894 /* data(I) - the token type to match */ 7895 /* cmd(I) - the ioctl command number */ 7896 /* mode(I) - mode flags for the ioctl */ 7897 /* uid(I) - uid owning the token */ 7898 /* ptr(I) - context pointer for the token */ 7899 /* */ 7900 /* This function handles all of the ioctl command that are actually isssued */ 7901 /* to the /dev/ipl device. */ 7902 /* ------------------------------------------------------------------------ */ 7903 int 7904 ipf_ipf_ioctl(ipf_main_softc_t *softc, caddr_t data, ioctlcmd_t cmd, int mode, 7905 int uid, void *ctx) 7906 { 7907 friostat_t fio; 7908 int error, tmp; 7909 ipfobj_t obj; 7910 SPL_INT(s); 7911 7912 switch (cmd) 7913 { 7914 case SIOCFRENB : 7915 if (!(mode & FWRITE)) { 7916 IPFERROR(94); 7917 error = EPERM; 7918 } else { 7919 error = BCOPYIN(data, &tmp, sizeof(tmp)); 7920 if (error != 0) { 7921 IPFERROR(95); 7922 error = EFAULT; 7923 break; 7924 } 7925 7926 WRITE_ENTER(&softc->ipf_global); 7927 if (tmp) { 7928 if (softc->ipf_running > 0) 7929 error = 0; 7930 else 7931 error = ipfattach(softc); 7932 if (error == 0) 7933 softc->ipf_running = 1; 7934 else 7935 (void) ipfdetach(softc); 7936 } else { 7937 if (softc->ipf_running == 1) 7938 error = ipfdetach(softc); 7939 else 7940 error = 0; 7941 if (error == 0) 7942 softc->ipf_running = -1; 7943 } 7944 RWLOCK_EXIT(&softc->ipf_global); 7945 } 7946 break; 7947 7948 case SIOCIPFSET : 7949 if (!(mode & FWRITE)) { 7950 IPFERROR(96); 7951 error = EPERM; 7952 break; 7953 } 7954 /* FALLTHRU */ 7955 case SIOCIPFGETNEXT : 7956 case SIOCIPFGET : 7957 error = ipf_ipftune(softc, cmd, (void *)data); 7958 break; 7959 7960 case SIOCSETFF : 7961 if (!(mode & FWRITE)) { 7962 IPFERROR(97); 7963 error = EPERM; 7964 } else { 7965 error = BCOPYIN(data, &softc->ipf_flags, 7966 sizeof(softc->ipf_flags)); 7967 if (error != 0) { 7968 IPFERROR(98); 7969 error = EFAULT; 7970 } 7971 } 7972 break; 7973 7974 case SIOCGETFF : 7975 error = BCOPYOUT(&softc->ipf_flags, data, 7976 sizeof(softc->ipf_flags)); 7977 if (error != 0) { 7978 IPFERROR(99); 7979 error = EFAULT; 7980 } 7981 break; 7982 7983 case SIOCFUNCL : 7984 error = ipf_resolvefunc(softc, (void *)data); 7985 break; 7986 7987 case SIOCINAFR : 7988 case SIOCRMAFR : 7989 case SIOCADAFR : 7990 case SIOCZRLST : 7991 if (!(mode & FWRITE)) { 7992 IPFERROR(100); 7993 error = EPERM; 7994 } else { 7995 error = frrequest(softc, IPL_LOGIPF, cmd, (caddr_t)data, 7996 softc->ipf_active, 1); 7997 } 7998 break; 7999 8000 case SIOCINIFR : 8001 case SIOCRMIFR : 8002 case SIOCADIFR : 8003 if (!(mode & FWRITE)) { 8004 IPFERROR(101); 8005 error = EPERM; 8006 } else { 8007 error = frrequest(softc, IPL_LOGIPF, cmd, (caddr_t)data, 8008 1 - softc->ipf_active, 1); 8009 } 8010 break; 8011 8012 case SIOCSWAPA : 8013 if (!(mode & FWRITE)) { 8014 IPFERROR(102); 8015 error = EPERM; 8016 } else { 8017 WRITE_ENTER(&softc->ipf_mutex); 8018 error = BCOPYOUT(&softc->ipf_active, data, 8019 sizeof(softc->ipf_active)); 8020 if (error != 0) { 8021 IPFERROR(103); 8022 error = EFAULT; 8023 } else { 8024 softc->ipf_active = 1 - softc->ipf_active; 8025 } 8026 RWLOCK_EXIT(&softc->ipf_mutex); 8027 } 8028 break; 8029 8030 case SIOCGETFS : 8031 error = ipf_inobj(softc, (void *)data, &obj, &fio, 8032 IPFOBJ_IPFSTAT); 8033 if (error != 0) 8034 break; 8035 ipf_getstat(softc, &fio, obj.ipfo_rev); 8036 error = ipf_outobj(softc, (void *)data, &fio, IPFOBJ_IPFSTAT); 8037 break; 8038 8039 case SIOCFRZST : 8040 if (!(mode & FWRITE)) { 8041 IPFERROR(104); 8042 error = EPERM; 8043 } else 8044 error = ipf_zerostats(softc, (caddr_t)data); 8045 break; 8046 8047 case SIOCIPFFL : 8048 if (!(mode & FWRITE)) { 8049 IPFERROR(105); 8050 error = EPERM; 8051 } else { 8052 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8053 if (!error) { 8054 tmp = ipf_flush(softc, IPL_LOGIPF, tmp); 8055 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8056 if (error != 0) { 8057 IPFERROR(106); 8058 error = EFAULT; 8059 } 8060 } else { 8061 IPFERROR(107); 8062 error = EFAULT; 8063 } 8064 } 8065 break; 8066 8067 #ifdef USE_INET6 8068 case SIOCIPFL6 : 8069 if (!(mode & FWRITE)) { 8070 IPFERROR(108); 8071 error = EPERM; 8072 } else { 8073 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8074 if (!error) { 8075 tmp = ipf_flush(softc, IPL_LOGIPF, tmp); 8076 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8077 if (error != 0) { 8078 IPFERROR(109); 8079 error = EFAULT; 8080 } 8081 } else { 8082 IPFERROR(110); 8083 error = EFAULT; 8084 } 8085 } 8086 break; 8087 #endif 8088 8089 case SIOCSTLCK : 8090 if (!(mode & FWRITE)) { 8091 IPFERROR(122); 8092 error = EPERM; 8093 } else { 8094 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8095 if (error == 0) { 8096 ipf_state_setlock(softc->ipf_state_soft, tmp); 8097 ipf_nat_setlock(softc->ipf_nat_soft, tmp); 8098 ipf_frag_setlock(softc->ipf_frag_soft, tmp); 8099 ipf_auth_setlock(softc->ipf_auth_soft, tmp); 8100 } else { 8101 IPFERROR(111); 8102 error = EFAULT; 8103 } 8104 } 8105 break; 8106 8107 #ifdef IPFILTER_LOG 8108 case SIOCIPFFB : 8109 if (!(mode & FWRITE)) { 8110 IPFERROR(112); 8111 error = EPERM; 8112 } else { 8113 tmp = ipf_log_clear(softc, IPL_LOGIPF); 8114 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8115 if (error) { 8116 IPFERROR(113); 8117 error = EFAULT; 8118 } 8119 } 8120 break; 8121 #endif /* IPFILTER_LOG */ 8122 8123 case SIOCFRSYN : 8124 if (!(mode & FWRITE)) { 8125 IPFERROR(114); 8126 error = EPERM; 8127 } else { 8128 WRITE_ENTER(&softc->ipf_global); 8129 #if (SOLARIS && defined(_KERNEL)) && !defined(INSTANCES) 8130 error = ipfsync(); 8131 #else 8132 ipf_sync(softc, NULL); 8133 error = 0; 8134 #endif 8135 RWLOCK_EXIT(&softc->ipf_global); 8136 8137 } 8138 break; 8139 8140 case SIOCGFRST : 8141 error = ipf_outobj(softc, (void *)data, 8142 ipf_frag_stats(softc->ipf_frag_soft), 8143 IPFOBJ_FRAGSTAT); 8144 break; 8145 8146 #ifdef IPFILTER_LOG 8147 case FIONREAD : 8148 tmp = ipf_log_bytesused(softc, IPL_LOGIPF); 8149 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8150 break; 8151 #endif 8152 8153 case SIOCIPFITER : 8154 SPL_SCHED(s); 8155 error = ipf_frruleiter(softc, data, uid, ctx); 8156 SPL_X(s); 8157 break; 8158 8159 case SIOCGENITER : 8160 SPL_SCHED(s); 8161 error = ipf_genericiter(softc, data, uid, ctx); 8162 SPL_X(s); 8163 break; 8164 8165 case SIOCIPFDELTOK : 8166 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8167 if (error == 0) { 8168 SPL_SCHED(s); 8169 error = ipf_token_del(softc, tmp, uid, ctx); 8170 SPL_X(s); 8171 } 8172 break; 8173 8174 default : 8175 IPFERROR(115); 8176 error = EINVAL; 8177 break; 8178 } 8179 8180 return (error); 8181 } 8182 8183 8184 /* ------------------------------------------------------------------------ */ 8185 /* Function: ipf_decaps */ 8186 /* Returns: int - -1 == decapsulation failed, else bit mask of */ 8187 /* flags indicating packet filtering decision. */ 8188 /* Parameters: fin(I) - pointer to packet information */ 8189 /* pass(I) - IP protocol version to match */ 8190 /* l5proto(I) - layer 5 protocol to decode UDP data as. */ 8191 /* */ 8192 /* This function is called for packets that are wrapt up in other packets, */ 8193 /* for example, an IP packet that is the entire data segment for another IP */ 8194 /* packet. If the basic constraints for this are satisfied, change the */ 8195 /* buffer to point to the start of the inner packet and start processing */ 8196 /* rules belonging to the head group this rule specifies. */ 8197 /* ------------------------------------------------------------------------ */ 8198 u_32_t 8199 ipf_decaps(fr_info_t *fin, u_32_t pass, int l5proto) 8200 { 8201 fr_info_t fin2, *fino = NULL; 8202 int elen, hlen, nh; 8203 grehdr_t gre; 8204 ip_t *ip; 8205 mb_t *m; 8206 8207 if ((fin->fin_flx & FI_COALESCE) == 0) 8208 if (ipf_coalesce(fin) == -1) 8209 goto cantdecaps; 8210 8211 m = fin->fin_m; 8212 hlen = fin->fin_hlen; 8213 8214 switch (fin->fin_p) 8215 { 8216 case IPPROTO_UDP : 8217 /* 8218 * In this case, the specific protocol being decapsulated 8219 * inside UDP frames comes from the rule. 8220 */ 8221 nh = fin->fin_fr->fr_icode; 8222 break; 8223 8224 case IPPROTO_GRE : /* 47 */ 8225 bcopy(fin->fin_dp, (char *)&gre, sizeof(gre)); 8226 hlen += sizeof(grehdr_t); 8227 if (gre.gr_R|gre.gr_s) 8228 goto cantdecaps; 8229 if (gre.gr_C) 8230 hlen += 4; 8231 if (gre.gr_K) 8232 hlen += 4; 8233 if (gre.gr_S) 8234 hlen += 4; 8235 8236 nh = IPPROTO_IP; 8237 8238 /* 8239 * If the routing options flag is set, validate that it is 8240 * there and bounce over it. 8241 */ 8242 #if 0 8243 /* This is really heavy weight and lots of room for error, */ 8244 /* so for now, put it off and get the simple stuff right. */ 8245 if (gre.gr_R) { 8246 u_char off, len, *s; 8247 u_short af; 8248 int end; 8249 8250 end = 0; 8251 s = fin->fin_dp; 8252 s += hlen; 8253 aplen = fin->fin_plen - hlen; 8254 while (aplen > 3) { 8255 af = (s[0] << 8) | s[1]; 8256 off = s[2]; 8257 len = s[3]; 8258 aplen -= 4; 8259 s += 4; 8260 if (af == 0 && len == 0) { 8261 end = 1; 8262 break; 8263 } 8264 if (aplen < len) 8265 break; 8266 s += len; 8267 aplen -= len; 8268 } 8269 if (end != 1) 8270 goto cantdecaps; 8271 hlen = s - (u_char *)fin->fin_dp; 8272 } 8273 #endif 8274 break; 8275 8276 #ifdef IPPROTO_IPIP 8277 case IPPROTO_IPIP : /* 4 */ 8278 #endif 8279 nh = IPPROTO_IP; 8280 break; 8281 8282 default : /* Includes ESP, AH is special for IPv4 */ 8283 goto cantdecaps; 8284 } 8285 8286 switch (nh) 8287 { 8288 case IPPROTO_IP : 8289 case IPPROTO_IPV6 : 8290 break; 8291 default : 8292 goto cantdecaps; 8293 } 8294 8295 bcopy((char *)fin, (char *)&fin2, sizeof(fin2)); 8296 fino = fin; 8297 fin = &fin2; 8298 elen = hlen; 8299 #if SOLARIS && defined(_KERNEL) 8300 m->b_rptr += elen; 8301 #else 8302 m->m_data += elen; 8303 m->m_len -= elen; 8304 #endif 8305 fin->fin_plen -= elen; 8306 8307 ip = (ip_t *)((char *)fin->fin_ip + elen); 8308 8309 /* 8310 * Make sure we have at least enough data for the network layer 8311 * header. 8312 */ 8313 if (IP_V(ip) == 4) 8314 hlen = IP_HL(ip) << 2; 8315 #ifdef USE_INET6 8316 else if (IP_V(ip) == 6) 8317 hlen = sizeof(ip6_t); 8318 #endif 8319 else 8320 goto cantdecaps2; 8321 8322 if (fin->fin_plen < hlen) 8323 goto cantdecaps2; 8324 8325 fin->fin_dp = (char *)ip + hlen; 8326 8327 if (IP_V(ip) == 4) { 8328 /* 8329 * Perform IPv4 header checksum validation. 8330 */ 8331 if (ipf_cksum((u_short *)ip, hlen)) 8332 goto cantdecaps2; 8333 } 8334 8335 if (ipf_makefrip(hlen, ip, fin) == -1) { 8336 cantdecaps2: 8337 if (m != NULL) { 8338 #if SOLARIS && defined(_KERNEL) 8339 m->b_rptr -= elen; 8340 #else 8341 m->m_data -= elen; 8342 m->m_len += elen; 8343 #endif 8344 } 8345 cantdecaps: 8346 DT1(frb_decapfrip, fr_info_t *, fin); 8347 pass &= ~FR_CMDMASK; 8348 pass |= FR_BLOCK|FR_QUICK; 8349 fin->fin_reason = FRB_DECAPFRIP; 8350 return (-1); 8351 } 8352 8353 pass = ipf_scanlist(fin, pass); 8354 8355 /* 8356 * Copy the packet filter "result" fields out of the fr_info_t struct 8357 * that is local to the decapsulation processing and back into the 8358 * one we were called with. 8359 */ 8360 fino->fin_flx = fin->fin_flx; 8361 fino->fin_rev = fin->fin_rev; 8362 fino->fin_icode = fin->fin_icode; 8363 fino->fin_rule = fin->fin_rule; 8364 (void) strncpy(fino->fin_group, fin->fin_group, FR_GROUPLEN); 8365 fino->fin_fr = fin->fin_fr; 8366 fino->fin_error = fin->fin_error; 8367 fino->fin_mp = fin->fin_mp; 8368 fino->fin_m = fin->fin_m; 8369 m = fin->fin_m; 8370 if (m != NULL) { 8371 #if SOLARIS && defined(_KERNEL) 8372 m->b_rptr -= elen; 8373 #else 8374 m->m_data -= elen; 8375 m->m_len += elen; 8376 #endif 8377 } 8378 return (pass); 8379 } 8380 8381 8382 /* ------------------------------------------------------------------------ */ 8383 /* Function: ipf_matcharray_load */ 8384 /* Returns: int - 0 = success, else error */ 8385 /* Parameters: softc(I) - pointer to soft context main structure */ 8386 /* data(I) - pointer to ioctl data */ 8387 /* objp(I) - ipfobj_t structure to load data into */ 8388 /* arrayptr(I) - pointer to location to store array pointer */ 8389 /* */ 8390 /* This function loads in a mathing array through the ipfobj_t struct that */ 8391 /* describes it. Sanity checking and array size limitations are enforced */ 8392 /* in this function to prevent userspace from trying to load in something */ 8393 /* that is insanely big. Once the size of the array is known, the memory */ 8394 /* required is malloc'd and returned through changing *arrayptr. The */ 8395 /* contents of the array are verified before returning. Only in the event */ 8396 /* of a successful call is the caller required to free up the malloc area. */ 8397 /* ------------------------------------------------------------------------ */ 8398 int 8399 ipf_matcharray_load(ipf_main_softc_t *softc, caddr_t data, ipfobj_t *objp, 8400 int **arrayptr) 8401 { 8402 int arraysize, *array, error; 8403 8404 *arrayptr = NULL; 8405 8406 error = BCOPYIN(data, objp, sizeof(*objp)); 8407 if (error != 0) { 8408 IPFERROR(116); 8409 return (EFAULT); 8410 } 8411 8412 if (objp->ipfo_type != IPFOBJ_IPFEXPR) { 8413 IPFERROR(117); 8414 return (EINVAL); 8415 } 8416 8417 if (((objp->ipfo_size & 3) != 0) || (objp->ipfo_size == 0) || 8418 (objp->ipfo_size > 1024)) { 8419 IPFERROR(118); 8420 return (EINVAL); 8421 } 8422 8423 arraysize = objp->ipfo_size * sizeof(*array); 8424 KMALLOCS(array, int *, arraysize); 8425 if (array == NULL) { 8426 IPFERROR(119); 8427 return (ENOMEM); 8428 } 8429 8430 error = COPYIN(objp->ipfo_ptr, array, arraysize); 8431 if (error != 0) { 8432 KFREES(array, arraysize); 8433 IPFERROR(120); 8434 return (EFAULT); 8435 } 8436 8437 if (ipf_matcharray_verify(array, arraysize) != 0) { 8438 KFREES(array, arraysize); 8439 IPFERROR(121); 8440 return (EINVAL); 8441 } 8442 8443 *arrayptr = array; 8444 return (0); 8445 } 8446 8447 8448 /* ------------------------------------------------------------------------ */ 8449 /* Function: ipf_matcharray_verify */ 8450 /* Returns: Nil */ 8451 /* Parameters: array(I) - pointer to matching array */ 8452 /* arraysize(I) - number of elements in the array */ 8453 /* */ 8454 /* Verify the contents of a matching array by stepping through each element */ 8455 /* in it. The actual commands in the array are not verified for */ 8456 /* correctness, only that all of the sizes are correctly within limits. */ 8457 /* ------------------------------------------------------------------------ */ 8458 int 8459 ipf_matcharray_verify(int *array, int arraysize) 8460 { 8461 int i, nelem, maxidx; 8462 ipfexp_t *e; 8463 8464 nelem = arraysize / sizeof(*array); 8465 8466 /* 8467 * Currently, it makes no sense to have an array less than 6 8468 * elements long - the initial size at the from, a single operation 8469 * (minimum 4 in length) and a trailer, for a total of 6. 8470 */ 8471 if ((array[0] < 6) || (arraysize < 24) || (arraysize > 4096)) { 8472 return (-1); 8473 } 8474 8475 /* 8476 * Verify the size of data pointed to by array with how long 8477 * the array claims to be itself. 8478 */ 8479 if (array[0] * sizeof(*array) != arraysize) { 8480 return (-1); 8481 } 8482 8483 maxidx = nelem - 1; 8484 /* 8485 * The last opcode in this array should be an IPF_EXP_END. 8486 */ 8487 if (array[maxidx] != IPF_EXP_END) { 8488 return (-1); 8489 } 8490 8491 for (i = 1; i < maxidx; ) { 8492 e = (ipfexp_t *)(array + i); 8493 8494 /* 8495 * The length of the bits to check must be at least 1 8496 * (or else there is nothing to comapre with!) and it 8497 * cannot exceed the length of the data present. 8498 */ 8499 if ((e->ipfe_size < 1 ) || 8500 (e->ipfe_size + i > maxidx)) { 8501 return (-1); 8502 } 8503 i += e->ipfe_size; 8504 } 8505 return (0); 8506 } 8507 8508 8509 /* ------------------------------------------------------------------------ */ 8510 /* Function: ipf_fr_matcharray */ 8511 /* Returns: int - 0 = match failed, else positive match */ 8512 /* Parameters: fin(I) - pointer to packet information */ 8513 /* array(I) - pointer to matching array */ 8514 /* */ 8515 /* This function is used to apply a matching array against a packet and */ 8516 /* return an indication of whether or not the packet successfully matches */ 8517 /* all of the commands in it. */ 8518 /* ------------------------------------------------------------------------ */ 8519 static int 8520 ipf_fr_matcharray(fr_info_t *fin, int *array) 8521 { 8522 int i, n, *x, rv, p; 8523 ipfexp_t *e; 8524 8525 rv = 0; 8526 n = array[0]; 8527 x = array + 1; 8528 8529 for (; n > 0; x += 3 + x[3], rv = 0) { 8530 e = (ipfexp_t *)x; 8531 if (e->ipfe_cmd == IPF_EXP_END) 8532 break; 8533 n -= e->ipfe_size; 8534 8535 /* 8536 * The upper 16 bits currently store the protocol value. 8537 * This is currently used with TCP and UDP port compares and 8538 * allows "tcp.port = 80" without requiring an explicit 8539 " "ip.pr = tcp" first. 8540 */ 8541 p = e->ipfe_cmd >> 16; 8542 if ((p != 0) && (p != fin->fin_p)) 8543 break; 8544 8545 switch (e->ipfe_cmd) 8546 { 8547 case IPF_EXP_IP_PR : 8548 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8549 rv |= (fin->fin_p == e->ipfe_arg0[i]); 8550 } 8551 break; 8552 8553 case IPF_EXP_IP_SRCADDR : 8554 if (fin->fin_v != 4) 8555 break; 8556 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8557 rv |= ((fin->fin_saddr & 8558 e->ipfe_arg0[i * 2 + 1]) == 8559 e->ipfe_arg0[i * 2]); 8560 } 8561 break; 8562 8563 case IPF_EXP_IP_DSTADDR : 8564 if (fin->fin_v != 4) 8565 break; 8566 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8567 rv |= ((fin->fin_daddr & 8568 e->ipfe_arg0[i * 2 + 1]) == 8569 e->ipfe_arg0[i * 2]); 8570 } 8571 break; 8572 8573 case IPF_EXP_IP_ADDR : 8574 if (fin->fin_v != 4) 8575 break; 8576 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8577 rv |= ((fin->fin_saddr & 8578 e->ipfe_arg0[i * 2 + 1]) == 8579 e->ipfe_arg0[i * 2]) || 8580 ((fin->fin_daddr & 8581 e->ipfe_arg0[i * 2 + 1]) == 8582 e->ipfe_arg0[i * 2]); 8583 } 8584 break; 8585 8586 #ifdef USE_INET6 8587 case IPF_EXP_IP6_SRCADDR : 8588 if (fin->fin_v != 6) 8589 break; 8590 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8591 rv |= IP6_MASKEQ(&fin->fin_src6, 8592 &e->ipfe_arg0[i * 8 + 4], 8593 &e->ipfe_arg0[i * 8]); 8594 } 8595 break; 8596 8597 case IPF_EXP_IP6_DSTADDR : 8598 if (fin->fin_v != 6) 8599 break; 8600 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8601 rv |= IP6_MASKEQ(&fin->fin_dst6, 8602 &e->ipfe_arg0[i * 8 + 4], 8603 &e->ipfe_arg0[i * 8]); 8604 } 8605 break; 8606 8607 case IPF_EXP_IP6_ADDR : 8608 if (fin->fin_v != 6) 8609 break; 8610 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8611 rv |= IP6_MASKEQ(&fin->fin_src6, 8612 &e->ipfe_arg0[i * 8 + 4], 8613 &e->ipfe_arg0[i * 8]) || 8614 IP6_MASKEQ(&fin->fin_dst6, 8615 &e->ipfe_arg0[i * 8 + 4], 8616 &e->ipfe_arg0[i * 8]); 8617 } 8618 break; 8619 #endif 8620 8621 case IPF_EXP_UDP_PORT : 8622 case IPF_EXP_TCP_PORT : 8623 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8624 rv |= (fin->fin_sport == e->ipfe_arg0[i]) || 8625 (fin->fin_dport == e->ipfe_arg0[i]); 8626 } 8627 break; 8628 8629 case IPF_EXP_UDP_SPORT : 8630 case IPF_EXP_TCP_SPORT : 8631 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8632 rv |= (fin->fin_sport == e->ipfe_arg0[i]); 8633 } 8634 break; 8635 8636 case IPF_EXP_UDP_DPORT : 8637 case IPF_EXP_TCP_DPORT : 8638 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8639 rv |= (fin->fin_dport == e->ipfe_arg0[i]); 8640 } 8641 break; 8642 8643 case IPF_EXP_TCP_FLAGS : 8644 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8645 rv |= ((fin->fin_tcpf & 8646 e->ipfe_arg0[i * 2 + 1]) == 8647 e->ipfe_arg0[i * 2]); 8648 } 8649 break; 8650 } 8651 rv ^= e->ipfe_not; 8652 8653 if (rv == 0) 8654 break; 8655 } 8656 8657 return (rv); 8658 } 8659 8660 8661 /* ------------------------------------------------------------------------ */ 8662 /* Function: ipf_queueflush */ 8663 /* Returns: int - number of entries flushed (0 = none) */ 8664 /* Parameters: softc(I) - pointer to soft context main structure */ 8665 /* deletefn(I) - function to call to delete entry */ 8666 /* ipfqs(I) - top of the list of ipf internal queues */ 8667 /* userqs(I) - top of the list of user defined timeouts */ 8668 /* */ 8669 /* This fucntion gets called when the state/NAT hash tables fill up and we */ 8670 /* need to try a bit harder to free up some space. The algorithm used here */ 8671 /* split into two parts but both halves have the same goal: to reduce the */ 8672 /* number of connections considered to be "active" to the low watermark. */ 8673 /* There are two steps in doing this: */ 8674 /* 1) Remove any TCP connections that are already considered to be "closed" */ 8675 /* but have not yet been removed from the state table. The two states */ 8676 /* TCPS_TIME_WAIT and TCPS_CLOSED are considered to be the perfect */ 8677 /* candidates for this style of removal. If freeing up entries in */ 8678 /* CLOSED or both CLOSED and TIME_WAIT brings us to the low watermark, */ 8679 /* we do not go on to step 2. */ 8680 /* */ 8681 /* 2) Look for the oldest entries on each timeout queue and free them if */ 8682 /* they are within the given window we are considering. Where the */ 8683 /* window starts and the steps taken to increase its size depend upon */ 8684 /* how long ipf has been running (ipf_ticks.) Anything modified in the */ 8685 /* last 30 seconds is not touched. */ 8686 /* touched */ 8687 /* die ipf_ticks 30*1.5 1800*1.5 | 43200*1.5 */ 8688 /* | | | | | | */ 8689 /* future <--+----------+--------+-----------+-----+-----+-----------> past */ 8690 /* now \_int=30s_/ \_int=1hr_/ \_int=12hr */ 8691 /* */ 8692 /* Points to note: */ 8693 /* - tqe_die is the time, in the future, when entries die. */ 8694 /* - tqe_die - ipf_ticks is how long left the connection has to live in ipf */ 8695 /* ticks. */ 8696 /* - tqe_touched is when the entry was last used by NAT/state */ 8697 /* - the closer tqe_touched is to ipf_ticks, the further tqe_die will be */ 8698 /* ipf_ticks any given timeout queue and vice versa. */ 8699 /* - both tqe_die and tqe_touched increase over time */ 8700 /* - timeout queues are sorted with the highest value of tqe_die at the */ 8701 /* bottom and therefore the smallest values of each are at the top */ 8702 /* - the pointer passed in as ipfqs should point to an array of timeout */ 8703 /* queues representing each of the TCP states */ 8704 /* */ 8705 /* We start by setting up a maximum range to scan for things to move of */ 8706 /* iend (newest) to istart (oldest) in chunks of "interval". If nothing is */ 8707 /* found in that range, "interval" is adjusted (so long as it isn't 30) and */ 8708 /* we start again with a new value for "iend" and "istart". This is */ 8709 /* continued until we either finish the scan of 30 second intervals or the */ 8710 /* low water mark is reached. */ 8711 /* ------------------------------------------------------------------------ */ 8712 int 8713 ipf_queueflush(ipf_main_softc_t *softc, ipftq_delete_fn_t deletefn, 8714 ipftq_t *ipfqs, ipftq_t *userqs, u_int *activep, int size, int low) 8715 { 8716 u_long interval, istart, iend; 8717 ipftq_t *ifq, *ifqnext; 8718 ipftqent_t *tqe, *tqn; 8719 int removed = 0; 8720 8721 for (tqn = ipfqs[IPF_TCPS_CLOSED].ifq_head; ((tqe = tqn) != NULL); ) { 8722 tqn = tqe->tqe_next; 8723 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8724 removed++; 8725 } 8726 if ((*activep * 100 / size) > low) { 8727 for (tqn = ipfqs[IPF_TCPS_TIME_WAIT].ifq_head; 8728 ((tqe = tqn) != NULL); ) { 8729 tqn = tqe->tqe_next; 8730 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8731 removed++; 8732 } 8733 } 8734 8735 if ((*activep * 100 / size) <= low) { 8736 return (removed); 8737 } 8738 8739 /* 8740 * NOTE: Use of "* 15 / 10" is required here because if "* 1.5" is 8741 * used then the operations are upgraded to floating point 8742 * and kernels don't like floating point... 8743 */ 8744 if (softc->ipf_ticks > IPF_TTLVAL(43200 * 15 / 10)) { 8745 istart = IPF_TTLVAL(86400 * 4); 8746 interval = IPF_TTLVAL(43200); 8747 } else if (softc->ipf_ticks > IPF_TTLVAL(1800 * 15 / 10)) { 8748 istart = IPF_TTLVAL(43200); 8749 interval = IPF_TTLVAL(1800); 8750 } else if (softc->ipf_ticks > IPF_TTLVAL(30 * 15 / 10)) { 8751 istart = IPF_TTLVAL(1800); 8752 interval = IPF_TTLVAL(30); 8753 } else { 8754 return (0); 8755 } 8756 if (istart > softc->ipf_ticks) { 8757 if (softc->ipf_ticks - interval < interval) 8758 istart = interval; 8759 else 8760 istart = (softc->ipf_ticks / interval) * interval; 8761 } 8762 8763 iend = softc->ipf_ticks - interval; 8764 8765 while ((*activep * 100 / size) > low) { 8766 u_long try; 8767 8768 try = softc->ipf_ticks - istart; 8769 8770 for (ifq = ipfqs; ifq != NULL; ifq = ifq->ifq_next) { 8771 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { 8772 if (try < tqe->tqe_touched) 8773 break; 8774 tqn = tqe->tqe_next; 8775 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8776 removed++; 8777 } 8778 } 8779 8780 for (ifq = userqs; ifq != NULL; ifq = ifqnext) { 8781 ifqnext = ifq->ifq_next; 8782 8783 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { 8784 if (try < tqe->tqe_touched) 8785 break; 8786 tqn = tqe->tqe_next; 8787 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8788 removed++; 8789 } 8790 } 8791 8792 if (try >= iend) { 8793 if (interval == IPF_TTLVAL(43200)) { 8794 interval = IPF_TTLVAL(1800); 8795 } else if (interval == IPF_TTLVAL(1800)) { 8796 interval = IPF_TTLVAL(30); 8797 } else { 8798 break; 8799 } 8800 if (interval >= softc->ipf_ticks) 8801 break; 8802 8803 iend = softc->ipf_ticks - interval; 8804 } 8805 istart -= interval; 8806 } 8807 8808 return (removed); 8809 } 8810 8811 8812 /* ------------------------------------------------------------------------ */ 8813 /* Function: ipf_deliverlocal */ 8814 /* Returns: int - 1 = local address, 0 = non-local address */ 8815 /* Parameters: softc(I) - pointer to soft context main structure */ 8816 /* ipversion(I) - IP protocol version (4 or 6) */ 8817 /* ifp(I) - network interface pointer */ 8818 /* ipaddr(I) - IPv4/6 destination address */ 8819 /* */ 8820 /* This fucntion is used to determine in the address "ipaddr" belongs to */ 8821 /* the network interface represented by ifp. */ 8822 /* ------------------------------------------------------------------------ */ 8823 int 8824 ipf_deliverlocal(ipf_main_softc_t *softc, int ipversion, void *ifp, 8825 i6addr_t *ipaddr) 8826 { 8827 i6addr_t addr; 8828 int islocal = 0; 8829 8830 if (ipversion == 4) { 8831 if (ipf_ifpaddr(softc, 4, FRI_NORMAL, ifp, &addr, NULL) == 0) { 8832 if (addr.in4.s_addr == ipaddr->in4.s_addr) 8833 islocal = 1; 8834 } 8835 8836 #ifdef USE_INET6 8837 } else if (ipversion == 6) { 8838 if (ipf_ifpaddr(softc, 6, FRI_NORMAL, ifp, &addr, NULL) == 0) { 8839 if (IP6_EQ(&addr, ipaddr)) 8840 islocal = 1; 8841 } 8842 #endif 8843 } 8844 8845 return (islocal); 8846 } 8847 8848 8849 /* ------------------------------------------------------------------------ */ 8850 /* Function: ipf_settimeout */ 8851 /* Returns: int - 0 = success, -1 = failure */ 8852 /* Parameters: softc(I) - pointer to soft context main structure */ 8853 /* t(I) - pointer to tuneable array entry */ 8854 /* p(I) - pointer to values passed in to apply */ 8855 /* */ 8856 /* This function is called to set the timeout values for each distinct */ 8857 /* queue timeout that is available. When called, it calls into both the */ 8858 /* state and NAT code, telling them to update their timeout queues. */ 8859 /* ------------------------------------------------------------------------ */ 8860 static int 8861 ipf_settimeout(struct ipf_main_softc_s *softc, ipftuneable_t *t, 8862 ipftuneval_t *p) 8863 { 8864 8865 /* 8866 * ipf_interror should be set by the functions called here, not 8867 * by this function - it's just a middle man. 8868 */ 8869 if (ipf_state_settimeout(softc, t, p) == -1) 8870 return (-1); 8871 if (ipf_nat_settimeout(softc, t, p) == -1) 8872 return (-1); 8873 return (0); 8874 } 8875 8876 8877 /* ------------------------------------------------------------------------ */ 8878 /* Function: ipf_apply_timeout */ 8879 /* Returns: int - 0 = success, -1 = failure */ 8880 /* Parameters: head(I) - pointer to tuneable array entry */ 8881 /* seconds(I) - pointer to values passed in to apply */ 8882 /* */ 8883 /* This function applies a timeout of "seconds" to the timeout queue that */ 8884 /* is pointed to by "head". All entries on this list have an expiration */ 8885 /* set to be the current tick value of ipf plus the ttl. Given that this */ 8886 /* function should only be called when the delta is non-zero, the task is */ 8887 /* to walk the entire list and apply the change. The sort order will not */ 8888 /* change. The only catch is that this is O(n) across the list, so if the */ 8889 /* queue has lots of entries (10s of thousands or 100s of thousands), it */ 8890 /* could take a relatively long time to work through them all. */ 8891 /* ------------------------------------------------------------------------ */ 8892 void 8893 ipf_apply_timeout(ipftq_t *head, u_int seconds) 8894 { 8895 u_int oldtimeout, newtimeout; 8896 ipftqent_t *tqe; 8897 int delta; 8898 8899 MUTEX_ENTER(&head->ifq_lock); 8900 oldtimeout = head->ifq_ttl; 8901 newtimeout = IPF_TTLVAL(seconds); 8902 delta = oldtimeout - newtimeout; 8903 8904 head->ifq_ttl = newtimeout; 8905 8906 for (tqe = head->ifq_head; tqe != NULL; tqe = tqe->tqe_next) { 8907 tqe->tqe_die += delta; 8908 } 8909 MUTEX_EXIT(&head->ifq_lock); 8910 } 8911 8912 8913 /* ------------------------------------------------------------------------ */ 8914 /* Function: ipf_settimeout_tcp */ 8915 /* Returns: int - 0 = successfully applied, -1 = failed */ 8916 /* Parameters: t(I) - pointer to tuneable to change */ 8917 /* p(I) - pointer to new timeout information */ 8918 /* tab(I) - pointer to table of TCP queues */ 8919 /* */ 8920 /* This function applies the new timeout (p) to the TCP tunable (t) and */ 8921 /* updates all of the entries on the relevant timeout queue by calling */ 8922 /* ipf_apply_timeout(). */ 8923 /* ------------------------------------------------------------------------ */ 8924 int 8925 ipf_settimeout_tcp(ipftuneable_t *t, ipftuneval_t *p, ipftq_t *tab) 8926 { 8927 if (!strcmp(t->ipft_name, "tcp_idle_timeout") || 8928 !strcmp(t->ipft_name, "tcp_established")) { 8929 ipf_apply_timeout(&tab[IPF_TCPS_ESTABLISHED], p->ipftu_int); 8930 } else if (!strcmp(t->ipft_name, "tcp_close_wait")) { 8931 ipf_apply_timeout(&tab[IPF_TCPS_CLOSE_WAIT], p->ipftu_int); 8932 } else if (!strcmp(t->ipft_name, "tcp_last_ack")) { 8933 ipf_apply_timeout(&tab[IPF_TCPS_LAST_ACK], p->ipftu_int); 8934 } else if (!strcmp(t->ipft_name, "tcp_timeout")) { 8935 ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int); 8936 ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int); 8937 ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int); 8938 } else if (!strcmp(t->ipft_name, "tcp_listen")) { 8939 ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int); 8940 } else if (!strcmp(t->ipft_name, "tcp_half_established")) { 8941 ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int); 8942 } else if (!strcmp(t->ipft_name, "tcp_closing")) { 8943 ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int); 8944 } else if (!strcmp(t->ipft_name, "tcp_syn_received")) { 8945 ipf_apply_timeout(&tab[IPF_TCPS_SYN_RECEIVED], p->ipftu_int); 8946 } else if (!strcmp(t->ipft_name, "tcp_syn_sent")) { 8947 ipf_apply_timeout(&tab[IPF_TCPS_SYN_SENT], p->ipftu_int); 8948 } else if (!strcmp(t->ipft_name, "tcp_closed")) { 8949 ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int); 8950 } else if (!strcmp(t->ipft_name, "tcp_half_closed")) { 8951 ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int); 8952 } else if (!strcmp(t->ipft_name, "tcp_time_wait")) { 8953 ipf_apply_timeout(&tab[IPF_TCPS_TIME_WAIT], p->ipftu_int); 8954 } else { 8955 /* 8956 * ipf_interror isn't set here because it should be set 8957 * by whatever called this function. 8958 */ 8959 return (-1); 8960 } 8961 return (0); 8962 } 8963 8964 8965 /* ------------------------------------------------------------------------ */ 8966 /* Function: ipf_main_soft_create */ 8967 /* Returns: NULL = failure, else success */ 8968 /* Parameters: arg(I) - pointer to soft context structure if already allocd */ 8969 /* */ 8970 /* Create the foundation soft context structure. In circumstances where it */ 8971 /* is not required to dynamically allocate the context, a pointer can be */ 8972 /* passed in (rather than NULL) to a structure to be initialised. */ 8973 /* The main thing of interest is that a number of locks are initialised */ 8974 /* here instead of in the where might be expected - in the relevant create */ 8975 /* function elsewhere. This is done because the current locking design has */ 8976 /* some areas where these locks are used outside of their module. */ 8977 /* Possibly the most important exercise that is done here is setting of all */ 8978 /* the timeout values, allowing them to be changed before init(). */ 8979 /* ------------------------------------------------------------------------ */ 8980 void * 8981 ipf_main_soft_create(void *arg) 8982 { 8983 ipf_main_softc_t *softc; 8984 8985 if (arg == NULL) { 8986 KMALLOC(softc, ipf_main_softc_t *); 8987 if (softc == NULL) 8988 return (NULL); 8989 } else { 8990 softc = arg; 8991 } 8992 8993 bzero((char *)softc, sizeof(*softc)); 8994 8995 /* 8996 * This serves as a flag as to whether or not the softc should be 8997 * free'd when _destroy is called. 8998 */ 8999 softc->ipf_dynamic_softc = (arg == NULL) ? 1 : 0; 9000 9001 softc->ipf_tuners = ipf_tune_array_copy(softc, 9002 sizeof(ipf_main_tuneables), 9003 ipf_main_tuneables); 9004 if (softc->ipf_tuners == NULL) { 9005 ipf_main_soft_destroy(softc); 9006 return (NULL); 9007 } 9008 9009 MUTEX_INIT(&softc->ipf_rw, "ipf rw mutex"); 9010 MUTEX_INIT(&softc->ipf_timeoutlock, "ipf timeout lock"); 9011 RWLOCK_INIT(&softc->ipf_global, "ipf filter load/unload mutex"); 9012 RWLOCK_INIT(&softc->ipf_mutex, "ipf filter rwlock"); 9013 RWLOCK_INIT(&softc->ipf_tokens, "ipf token rwlock"); 9014 RWLOCK_INIT(&softc->ipf_state, "ipf state rwlock"); 9015 RWLOCK_INIT(&softc->ipf_nat, "ipf IP NAT rwlock"); 9016 RWLOCK_INIT(&softc->ipf_poolrw, "ipf pool rwlock"); 9017 RWLOCK_INIT(&softc->ipf_frag, "ipf frag rwlock"); 9018 9019 softc->ipf_token_head = NULL; 9020 softc->ipf_token_tail = &softc->ipf_token_head; 9021 9022 softc->ipf_tcpidletimeout = FIVE_DAYS; 9023 softc->ipf_tcpclosewait = IPF_TTLVAL(2 * TCP_MSL); 9024 softc->ipf_tcplastack = IPF_TTLVAL(30); 9025 softc->ipf_tcptimewait = IPF_TTLVAL(2 * TCP_MSL); 9026 softc->ipf_tcptimeout = IPF_TTLVAL(2 * TCP_MSL); 9027 softc->ipf_tcpsynsent = IPF_TTLVAL(2 * TCP_MSL); 9028 softc->ipf_tcpsynrecv = IPF_TTLVAL(2 * TCP_MSL); 9029 softc->ipf_tcpclosed = IPF_TTLVAL(30); 9030 softc->ipf_tcphalfclosed = IPF_TTLVAL(2 * 3600); 9031 softc->ipf_udptimeout = IPF_TTLVAL(120); 9032 softc->ipf_udpacktimeout = IPF_TTLVAL(12); 9033 softc->ipf_icmptimeout = IPF_TTLVAL(60); 9034 softc->ipf_icmpacktimeout = IPF_TTLVAL(6); 9035 softc->ipf_iptimeout = IPF_TTLVAL(60); 9036 9037 #if defined(IPFILTER_DEFAULT_BLOCK) 9038 softc->ipf_pass = FR_BLOCK|FR_NOMATCH; 9039 #else 9040 softc->ipf_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH; 9041 #endif 9042 softc->ipf_minttl = 4; 9043 softc->ipf_icmpminfragmtu = 68; 9044 softc->ipf_flags = IPF_LOGGING; 9045 9046 #ifdef LARGE_NAT 9047 softc->ipf_large_nat = 1; 9048 #endif 9049 ipf_fbsd_kenv_get(softc); 9050 9051 return (softc); 9052 } 9053 9054 /* ------------------------------------------------------------------------ */ 9055 /* Function: ipf_main_soft_init */ 9056 /* Returns: 0 = success, -1 = failure */ 9057 /* Parameters: softc(I) - pointer to soft context main structure */ 9058 /* */ 9059 /* A null-op function that exists as a placeholder so that the flow in */ 9060 /* other functions is obvious. */ 9061 /* ------------------------------------------------------------------------ */ 9062 /*ARGSUSED*/ 9063 int 9064 ipf_main_soft_init(ipf_main_softc_t *softc) 9065 { 9066 return (0); 9067 } 9068 9069 9070 /* ------------------------------------------------------------------------ */ 9071 /* Function: ipf_main_soft_destroy */ 9072 /* Returns: void */ 9073 /* Parameters: softc(I) - pointer to soft context main structure */ 9074 /* */ 9075 /* Undo everything that we did in ipf_main_soft_create. */ 9076 /* */ 9077 /* The most important check that needs to be made here is whether or not */ 9078 /* the structure was allocated by ipf_main_soft_create() by checking what */ 9079 /* value is stored in ipf_dynamic_main. */ 9080 /* ------------------------------------------------------------------------ */ 9081 /*ARGSUSED*/ 9082 void 9083 ipf_main_soft_destroy(ipf_main_softc_t *softc) 9084 { 9085 9086 RW_DESTROY(&softc->ipf_frag); 9087 RW_DESTROY(&softc->ipf_poolrw); 9088 RW_DESTROY(&softc->ipf_nat); 9089 RW_DESTROY(&softc->ipf_state); 9090 RW_DESTROY(&softc->ipf_tokens); 9091 RW_DESTROY(&softc->ipf_mutex); 9092 RW_DESTROY(&softc->ipf_global); 9093 MUTEX_DESTROY(&softc->ipf_timeoutlock); 9094 MUTEX_DESTROY(&softc->ipf_rw); 9095 9096 if (softc->ipf_tuners != NULL) { 9097 KFREES(softc->ipf_tuners, sizeof(ipf_main_tuneables)); 9098 } 9099 if (softc->ipf_dynamic_softc == 1) { 9100 KFREE(softc); 9101 } 9102 } 9103 9104 9105 /* ------------------------------------------------------------------------ */ 9106 /* Function: ipf_main_soft_fini */ 9107 /* Returns: 0 = success, -1 = failure */ 9108 /* Parameters: softc(I) - pointer to soft context main structure */ 9109 /* */ 9110 /* Clean out the rules which have been added since _init was last called, */ 9111 /* the only dynamic part of the mainline. */ 9112 /* ------------------------------------------------------------------------ */ 9113 int 9114 ipf_main_soft_fini(ipf_main_softc_t *softc) 9115 { 9116 (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE|FR_INACTIVE); 9117 (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE); 9118 (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE|FR_INACTIVE); 9119 (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE); 9120 9121 return (0); 9122 } 9123 9124 9125 /* ------------------------------------------------------------------------ */ 9126 /* Function: ipf_main_load */ 9127 /* Returns: 0 = success, -1 = failure */ 9128 /* Parameters: none */ 9129 /* */ 9130 /* Handle global initialisation that needs to be done for the base part of */ 9131 /* IPFilter. At present this just amounts to initialising some ICMP lookup */ 9132 /* arrays that get used by the state/NAT code. */ 9133 /* ------------------------------------------------------------------------ */ 9134 int 9135 ipf_main_load(void) 9136 { 9137 int i; 9138 9139 /* fill icmp reply type table */ 9140 for (i = 0; i <= ICMP_MAXTYPE; i++) 9141 icmpreplytype4[i] = -1; 9142 icmpreplytype4[ICMP_ECHO] = ICMP_ECHOREPLY; 9143 icmpreplytype4[ICMP_TSTAMP] = ICMP_TSTAMPREPLY; 9144 icmpreplytype4[ICMP_IREQ] = ICMP_IREQREPLY; 9145 icmpreplytype4[ICMP_MASKREQ] = ICMP_MASKREPLY; 9146 9147 #ifdef USE_INET6 9148 /* fill icmp reply type table */ 9149 for (i = 0; i <= ICMP6_MAXTYPE; i++) 9150 icmpreplytype6[i] = -1; 9151 icmpreplytype6[ICMP6_ECHO_REQUEST] = ICMP6_ECHO_REPLY; 9152 icmpreplytype6[ICMP6_MEMBERSHIP_QUERY] = ICMP6_MEMBERSHIP_REPORT; 9153 icmpreplytype6[ICMP6_NI_QUERY] = ICMP6_NI_REPLY; 9154 icmpreplytype6[ND_ROUTER_SOLICIT] = ND_ROUTER_ADVERT; 9155 icmpreplytype6[ND_NEIGHBOR_SOLICIT] = ND_NEIGHBOR_ADVERT; 9156 #endif 9157 9158 return (0); 9159 } 9160 9161 9162 /* ------------------------------------------------------------------------ */ 9163 /* Function: ipf_main_unload */ 9164 /* Returns: 0 = success, -1 = failure */ 9165 /* Parameters: none */ 9166 /* */ 9167 /* A null-op function that exists as a placeholder so that the flow in */ 9168 /* other functions is obvious. */ 9169 /* ------------------------------------------------------------------------ */ 9170 int 9171 ipf_main_unload(void) 9172 { 9173 return (0); 9174 } 9175 9176 9177 /* ------------------------------------------------------------------------ */ 9178 /* Function: ipf_load_all */ 9179 /* Returns: 0 = success, -1 = failure */ 9180 /* Parameters: none */ 9181 /* */ 9182 /* Work through all of the subsystems inside IPFilter and call the load */ 9183 /* function for each in an order that won't lead to a crash :) */ 9184 /* ------------------------------------------------------------------------ */ 9185 int 9186 ipf_load_all(void) 9187 { 9188 if (ipf_main_load() == -1) 9189 return (-1); 9190 9191 if (ipf_state_main_load() == -1) 9192 return (-1); 9193 9194 if (ipf_nat_main_load() == -1) 9195 return (-1); 9196 9197 if (ipf_frag_main_load() == -1) 9198 return (-1); 9199 9200 if (ipf_auth_main_load() == -1) 9201 return (-1); 9202 9203 if (ipf_proxy_main_load() == -1) 9204 return (-1); 9205 9206 return (0); 9207 } 9208 9209 9210 /* ------------------------------------------------------------------------ */ 9211 /* Function: ipf_unload_all */ 9212 /* Returns: 0 = success, -1 = failure */ 9213 /* Parameters: none */ 9214 /* */ 9215 /* Work through all of the subsystems inside IPFilter and call the unload */ 9216 /* function for each in an order that won't lead to a crash :) */ 9217 /* ------------------------------------------------------------------------ */ 9218 int 9219 ipf_unload_all(void) 9220 { 9221 if (ipf_proxy_main_unload() == -1) 9222 return (-1); 9223 9224 if (ipf_auth_main_unload() == -1) 9225 return (-1); 9226 9227 if (ipf_frag_main_unload() == -1) 9228 return (-1); 9229 9230 if (ipf_nat_main_unload() == -1) 9231 return (-1); 9232 9233 if (ipf_state_main_unload() == -1) 9234 return (-1); 9235 9236 if (ipf_main_unload() == -1) 9237 return (-1); 9238 9239 return (0); 9240 } 9241 9242 9243 /* ------------------------------------------------------------------------ */ 9244 /* Function: ipf_create_all */ 9245 /* Returns: NULL = failure, else success */ 9246 /* Parameters: arg(I) - pointer to soft context main structure */ 9247 /* */ 9248 /* Work through all of the subsystems inside IPFilter and call the create */ 9249 /* function for each in an order that won't lead to a crash :) */ 9250 /* ------------------------------------------------------------------------ */ 9251 ipf_main_softc_t * 9252 ipf_create_all(void *arg) 9253 { 9254 ipf_main_softc_t *softc; 9255 9256 softc = ipf_main_soft_create(arg); 9257 if (softc == NULL) 9258 return (NULL); 9259 9260 #ifdef IPFILTER_LOG 9261 softc->ipf_log_soft = ipf_log_soft_create(softc); 9262 if (softc->ipf_log_soft == NULL) { 9263 ipf_destroy_all(softc); 9264 return (NULL); 9265 } 9266 #endif 9267 9268 softc->ipf_lookup_soft = ipf_lookup_soft_create(softc); 9269 if (softc->ipf_lookup_soft == NULL) { 9270 ipf_destroy_all(softc); 9271 return (NULL); 9272 } 9273 9274 softc->ipf_sync_soft = ipf_sync_soft_create(softc); 9275 if (softc->ipf_sync_soft == NULL) { 9276 ipf_destroy_all(softc); 9277 return (NULL); 9278 } 9279 9280 softc->ipf_state_soft = ipf_state_soft_create(softc); 9281 if (softc->ipf_state_soft == NULL) { 9282 ipf_destroy_all(softc); 9283 return (NULL); 9284 } 9285 9286 softc->ipf_nat_soft = ipf_nat_soft_create(softc); 9287 if (softc->ipf_nat_soft == NULL) { 9288 ipf_destroy_all(softc); 9289 return (NULL); 9290 } 9291 9292 softc->ipf_frag_soft = ipf_frag_soft_create(softc); 9293 if (softc->ipf_frag_soft == NULL) { 9294 ipf_destroy_all(softc); 9295 return (NULL); 9296 } 9297 9298 softc->ipf_auth_soft = ipf_auth_soft_create(softc); 9299 if (softc->ipf_auth_soft == NULL) { 9300 ipf_destroy_all(softc); 9301 return (NULL); 9302 } 9303 9304 softc->ipf_proxy_soft = ipf_proxy_soft_create(softc); 9305 if (softc->ipf_proxy_soft == NULL) { 9306 ipf_destroy_all(softc); 9307 return (NULL); 9308 } 9309 9310 return (softc); 9311 } 9312 9313 9314 /* ------------------------------------------------------------------------ */ 9315 /* Function: ipf_destroy_all */ 9316 /* Returns: void */ 9317 /* Parameters: softc(I) - pointer to soft context main structure */ 9318 /* */ 9319 /* Work through all of the subsystems inside IPFilter and call the destroy */ 9320 /* function for each in an order that won't lead to a crash :) */ 9321 /* */ 9322 /* Every one of these functions is expected to succeed, so there is no */ 9323 /* checking of return values. */ 9324 /* ------------------------------------------------------------------------ */ 9325 void 9326 ipf_destroy_all(ipf_main_softc_t *softc) 9327 { 9328 9329 if (softc->ipf_state_soft != NULL) { 9330 ipf_state_soft_destroy(softc, softc->ipf_state_soft); 9331 softc->ipf_state_soft = NULL; 9332 } 9333 9334 if (softc->ipf_nat_soft != NULL) { 9335 ipf_nat_soft_destroy(softc, softc->ipf_nat_soft); 9336 softc->ipf_nat_soft = NULL; 9337 } 9338 9339 if (softc->ipf_frag_soft != NULL) { 9340 ipf_frag_soft_destroy(softc, softc->ipf_frag_soft); 9341 softc->ipf_frag_soft = NULL; 9342 } 9343 9344 if (softc->ipf_auth_soft != NULL) { 9345 ipf_auth_soft_destroy(softc, softc->ipf_auth_soft); 9346 softc->ipf_auth_soft = NULL; 9347 } 9348 9349 if (softc->ipf_proxy_soft != NULL) { 9350 ipf_proxy_soft_destroy(softc, softc->ipf_proxy_soft); 9351 softc->ipf_proxy_soft = NULL; 9352 } 9353 9354 if (softc->ipf_sync_soft != NULL) { 9355 ipf_sync_soft_destroy(softc, softc->ipf_sync_soft); 9356 softc->ipf_sync_soft = NULL; 9357 } 9358 9359 if (softc->ipf_lookup_soft != NULL) { 9360 ipf_lookup_soft_destroy(softc, softc->ipf_lookup_soft); 9361 softc->ipf_lookup_soft = NULL; 9362 } 9363 9364 #ifdef IPFILTER_LOG 9365 if (softc->ipf_log_soft != NULL) { 9366 ipf_log_soft_destroy(softc, softc->ipf_log_soft); 9367 softc->ipf_log_soft = NULL; 9368 } 9369 #endif 9370 9371 ipf_main_soft_destroy(softc); 9372 } 9373 9374 9375 /* ------------------------------------------------------------------------ */ 9376 /* Function: ipf_init_all */ 9377 /* Returns: 0 = success, -1 = failure */ 9378 /* Parameters: softc(I) - pointer to soft context main structure */ 9379 /* */ 9380 /* Work through all of the subsystems inside IPFilter and call the init */ 9381 /* function for each in an order that won't lead to a crash :) */ 9382 /* ------------------------------------------------------------------------ */ 9383 int 9384 ipf_init_all(ipf_main_softc_t *softc) 9385 { 9386 9387 if (ipf_main_soft_init(softc) == -1) 9388 return (-1); 9389 9390 #ifdef IPFILTER_LOG 9391 if (ipf_log_soft_init(softc, softc->ipf_log_soft) == -1) 9392 return (-1); 9393 #endif 9394 9395 if (ipf_lookup_soft_init(softc, softc->ipf_lookup_soft) == -1) 9396 return (-1); 9397 9398 if (ipf_sync_soft_init(softc, softc->ipf_sync_soft) == -1) 9399 return (-1); 9400 9401 if (ipf_state_soft_init(softc, softc->ipf_state_soft) == -1) 9402 return (-1); 9403 9404 if (ipf_nat_soft_init(softc, softc->ipf_nat_soft) == -1) 9405 return (-1); 9406 9407 if (ipf_frag_soft_init(softc, softc->ipf_frag_soft) == -1) 9408 return (-1); 9409 9410 if (ipf_auth_soft_init(softc, softc->ipf_auth_soft) == -1) 9411 return (-1); 9412 9413 if (ipf_proxy_soft_init(softc, softc->ipf_proxy_soft) == -1) 9414 return (-1); 9415 9416 return (0); 9417 } 9418 9419 9420 /* ------------------------------------------------------------------------ */ 9421 /* Function: ipf_fini_all */ 9422 /* Returns: 0 = success, -1 = failure */ 9423 /* Parameters: softc(I) - pointer to soft context main structure */ 9424 /* */ 9425 /* Work through all of the subsystems inside IPFilter and call the fini */ 9426 /* function for each in an order that won't lead to a crash :) */ 9427 /* ------------------------------------------------------------------------ */ 9428 int 9429 ipf_fini_all(ipf_main_softc_t *softc) 9430 { 9431 9432 ipf_token_flush(softc); 9433 9434 if (ipf_proxy_soft_fini(softc, softc->ipf_proxy_soft) == -1) 9435 return (-1); 9436 9437 if (ipf_auth_soft_fini(softc, softc->ipf_auth_soft) == -1) 9438 return (-1); 9439 9440 if (ipf_frag_soft_fini(softc, softc->ipf_frag_soft) == -1) 9441 return (-1); 9442 9443 if (ipf_nat_soft_fini(softc, softc->ipf_nat_soft) == -1) 9444 return (-1); 9445 9446 if (ipf_state_soft_fini(softc, softc->ipf_state_soft) == -1) 9447 return (-1); 9448 9449 if (ipf_sync_soft_fini(softc, softc->ipf_sync_soft) == -1) 9450 return (-1); 9451 9452 if (ipf_lookup_soft_fini(softc, softc->ipf_lookup_soft) == -1) 9453 return (-1); 9454 9455 #ifdef IPFILTER_LOG 9456 if (ipf_log_soft_fini(softc, softc->ipf_log_soft) == -1) 9457 return (-1); 9458 #endif 9459 9460 if (ipf_main_soft_fini(softc) == -1) 9461 return (-1); 9462 9463 return (0); 9464 } 9465 9466 9467 /* ------------------------------------------------------------------------ */ 9468 /* Function: ipf_rule_expire */ 9469 /* Returns: Nil */ 9470 /* Parameters: softc(I) - pointer to soft context main structure */ 9471 /* */ 9472 /* At present this function exists just to support temporary addition of */ 9473 /* firewall rules. Both inactive and active lists are scanned for items to */ 9474 /* purge, as by rights, the expiration is computed as soon as the rule is */ 9475 /* loaded in. */ 9476 /* ------------------------------------------------------------------------ */ 9477 void 9478 ipf_rule_expire(ipf_main_softc_t *softc) 9479 { 9480 frentry_t *fr; 9481 9482 if ((softc->ipf_rule_explist[0] == NULL) && 9483 (softc->ipf_rule_explist[1] == NULL)) 9484 return; 9485 9486 WRITE_ENTER(&softc->ipf_mutex); 9487 9488 while ((fr = softc->ipf_rule_explist[0]) != NULL) { 9489 /* 9490 * Because the list is kept sorted on insertion, the fist 9491 * one that dies in the future means no more work to do. 9492 */ 9493 if (fr->fr_die > softc->ipf_ticks) 9494 break; 9495 ipf_rule_delete(softc, fr, IPL_LOGIPF, 0); 9496 } 9497 9498 while ((fr = softc->ipf_rule_explist[1]) != NULL) { 9499 /* 9500 * Because the list is kept sorted on insertion, the fist 9501 * one that dies in the future means no more work to do. 9502 */ 9503 if (fr->fr_die > softc->ipf_ticks) 9504 break; 9505 ipf_rule_delete(softc, fr, IPL_LOGIPF, 1); 9506 } 9507 9508 RWLOCK_EXIT(&softc->ipf_mutex); 9509 } 9510 9511 9512 static int ipf_ht_node_cmp(struct host_node_s *, struct host_node_s *); 9513 static void ipf_ht_node_make_key(host_track_t *, host_node_t *, int, 9514 i6addr_t *); 9515 9516 host_node_t RBI_ZERO(ipf_rb); 9517 RBI_CODE(ipf_rb, host_node_t, hn_entry, ipf_ht_node_cmp) 9518 9519 9520 /* ------------------------------------------------------------------------ */ 9521 /* Function: ipf_ht_node_cmp */ 9522 /* Returns: int - 0 == nodes are the same, .. */ 9523 /* Parameters: k1(I) - pointer to first key to compare */ 9524 /* k2(I) - pointer to second key to compare */ 9525 /* */ 9526 /* The "key" for the node is a combination of two fields: the address */ 9527 /* family and the address itself. */ 9528 /* */ 9529 /* Because we're not actually interpreting the address data, it isn't */ 9530 /* necessary to convert them to/from network/host byte order. The mask is */ 9531 /* just used to remove bits that aren't significant - it doesn't matter */ 9532 /* where they are, as long as they're always in the same place. */ 9533 /* */ 9534 /* As with IP6_EQ, comparing IPv6 addresses starts at the bottom because */ 9535 /* this is where individual ones will differ the most - but not true for */ 9536 /* for /48's, etc. */ 9537 /* ------------------------------------------------------------------------ */ 9538 static int 9539 ipf_ht_node_cmp(struct host_node_s *k1, struct host_node_s *k2) 9540 { 9541 int i; 9542 9543 i = (k2->hn_addr.adf_family - k1->hn_addr.adf_family); 9544 if (i != 0) 9545 return (i); 9546 9547 if (k1->hn_addr.adf_family == AF_INET) 9548 return (k2->hn_addr.adf_addr.in4.s_addr - 9549 k1->hn_addr.adf_addr.in4.s_addr); 9550 9551 i = k2->hn_addr.adf_addr.i6[3] - k1->hn_addr.adf_addr.i6[3]; 9552 if (i != 0) 9553 return (i); 9554 i = k2->hn_addr.adf_addr.i6[2] - k1->hn_addr.adf_addr.i6[2]; 9555 if (i != 0) 9556 return (i); 9557 i = k2->hn_addr.adf_addr.i6[1] - k1->hn_addr.adf_addr.i6[1]; 9558 if (i != 0) 9559 return (i); 9560 i = k2->hn_addr.adf_addr.i6[0] - k1->hn_addr.adf_addr.i6[0]; 9561 return (i); 9562 } 9563 9564 9565 /* ------------------------------------------------------------------------ */ 9566 /* Function: ipf_ht_node_make_key */ 9567 /* Returns: Nil */ 9568 /* parameters: htp(I) - pointer to address tracking structure */ 9569 /* key(I) - where to store masked address for lookup */ 9570 /* family(I) - protocol family of address */ 9571 /* addr(I) - pointer to network address */ 9572 /* */ 9573 /* Using the "netmask" (number of bits) stored parent host tracking struct, */ 9574 /* copy the address passed in into the key structure whilst masking out the */ 9575 /* bits that we don't want. */ 9576 /* */ 9577 /* Because the parser will set ht_netmask to 128 if there is no protocol */ 9578 /* specified (the parser doesn't know if it should be a v4 or v6 rule), we */ 9579 /* have to be wary of that and not allow 32-128 to happen. */ 9580 /* ------------------------------------------------------------------------ */ 9581 static void 9582 ipf_ht_node_make_key(host_track_t *htp, host_node_t *key, int family, 9583 i6addr_t *addr) 9584 { 9585 key->hn_addr.adf_family = family; 9586 if (family == AF_INET) { 9587 u_32_t mask; 9588 int bits; 9589 9590 key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in4); 9591 bits = htp->ht_netmask; 9592 if (bits >= 32) { 9593 mask = 0xffffffff; 9594 } else { 9595 mask = htonl(0xffffffff << (32 - bits)); 9596 } 9597 key->hn_addr.adf_addr.in4.s_addr = addr->in4.s_addr & mask; 9598 #ifdef USE_INET6 9599 } else { 9600 int bits = htp->ht_netmask; 9601 9602 key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in6); 9603 if (bits > 96) { 9604 key->hn_addr.adf_addr.i6[3] = addr->i6[3] & 9605 htonl(0xffffffff << (128 - bits)); 9606 key->hn_addr.adf_addr.i6[2] = addr->i6[2]; 9607 key->hn_addr.adf_addr.i6[1] = addr->i6[2]; 9608 key->hn_addr.adf_addr.i6[0] = addr->i6[2]; 9609 } else if (bits > 64) { 9610 key->hn_addr.adf_addr.i6[3] = 0; 9611 key->hn_addr.adf_addr.i6[2] = addr->i6[2] & 9612 htonl(0xffffffff << (96 - bits)); 9613 key->hn_addr.adf_addr.i6[1] = addr->i6[1]; 9614 key->hn_addr.adf_addr.i6[0] = addr->i6[0]; 9615 } else if (bits > 32) { 9616 key->hn_addr.adf_addr.i6[3] = 0; 9617 key->hn_addr.adf_addr.i6[2] = 0; 9618 key->hn_addr.adf_addr.i6[1] = addr->i6[1] & 9619 htonl(0xffffffff << (64 - bits)); 9620 key->hn_addr.adf_addr.i6[0] = addr->i6[0]; 9621 } else { 9622 key->hn_addr.adf_addr.i6[3] = 0; 9623 key->hn_addr.adf_addr.i6[2] = 0; 9624 key->hn_addr.adf_addr.i6[1] = 0; 9625 key->hn_addr.adf_addr.i6[0] = addr->i6[0] & 9626 htonl(0xffffffff << (32 - bits)); 9627 } 9628 #endif 9629 } 9630 } 9631 9632 9633 /* ------------------------------------------------------------------------ */ 9634 /* Function: ipf_ht_node_add */ 9635 /* Returns: int - 0 == success, -1 == failure */ 9636 /* Parameters: softc(I) - pointer to soft context main structure */ 9637 /* htp(I) - pointer to address tracking structure */ 9638 /* family(I) - protocol family of address */ 9639 /* addr(I) - pointer to network address */ 9640 /* */ 9641 /* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS */ 9642 /* ipf_ht_node_del FROM RUNNING CONCURRENTLY ON THE SAME htp. */ 9643 /* */ 9644 /* After preparing the key with the address information to find, look in */ 9645 /* the red-black tree to see if the address is known. A successful call to */ 9646 /* this function can mean one of two things: a new node was added to the */ 9647 /* tree or a matching node exists and we're able to bump up its activity. */ 9648 /* ------------------------------------------------------------------------ */ 9649 int 9650 ipf_ht_node_add(ipf_main_softc_t *softc, host_track_t *htp, int family, 9651 i6addr_t *addr) 9652 { 9653 host_node_t *h; 9654 host_node_t k; 9655 9656 ipf_ht_node_make_key(htp, &k, family, addr); 9657 9658 h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k); 9659 if (h == NULL) { 9660 if (htp->ht_cur_nodes >= htp->ht_max_nodes) 9661 return (-1); 9662 KMALLOC(h, host_node_t *); 9663 if (h == NULL) { 9664 DT(ipf_rb_no_mem); 9665 LBUMP(ipf_rb_no_mem); 9666 return (-1); 9667 } 9668 9669 /* 9670 * If there was a macro to initialise the RB node then that 9671 * would get used here, but there isn't... 9672 */ 9673 bzero((char *)h, sizeof(*h)); 9674 h->hn_addr = k.hn_addr; 9675 h->hn_addr.adf_family = k.hn_addr.adf_family; 9676 RBI_INSERT(ipf_rb, &htp->ht_root, h); 9677 htp->ht_cur_nodes++; 9678 } else { 9679 if ((htp->ht_max_per_node != 0) && 9680 (h->hn_active >= htp->ht_max_per_node)) { 9681 DT(ipf_rb_node_max); 9682 LBUMP(ipf_rb_node_max); 9683 return (-1); 9684 } 9685 } 9686 9687 h->hn_active++; 9688 9689 return (0); 9690 } 9691 9692 9693 /* ------------------------------------------------------------------------ */ 9694 /* Function: ipf_ht_node_del */ 9695 /* Returns: int - 0 == success, -1 == failure */ 9696 /* parameters: htp(I) - pointer to address tracking structure */ 9697 /* family(I) - protocol family of address */ 9698 /* addr(I) - pointer to network address */ 9699 /* */ 9700 /* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS */ 9701 /* ipf_ht_node_add FROM RUNNING CONCURRENTLY ON THE SAME htp. */ 9702 /* */ 9703 /* Try and find the address passed in amongst the leavese on this tree to */ 9704 /* be friend. If found then drop the active account for that node drops by */ 9705 /* one. If that count reaches 0, it is time to free it all up. */ 9706 /* ------------------------------------------------------------------------ */ 9707 int 9708 ipf_ht_node_del(host_track_t *htp, int family, i6addr_t *addr) 9709 { 9710 host_node_t *h; 9711 host_node_t k; 9712 9713 ipf_ht_node_make_key(htp, &k, family, addr); 9714 9715 h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k); 9716 if (h == NULL) { 9717 return (-1); 9718 } else { 9719 h->hn_active--; 9720 if (h->hn_active == 0) { 9721 (void) RBI_DELETE(ipf_rb, &htp->ht_root, h); 9722 htp->ht_cur_nodes--; 9723 KFREE(h); 9724 } 9725 } 9726 9727 return (0); 9728 } 9729 9730 9731 /* ------------------------------------------------------------------------ */ 9732 /* Function: ipf_rb_ht_init */ 9733 /* Returns: Nil */ 9734 /* Parameters: head(I) - pointer to host tracking structure */ 9735 /* */ 9736 /* Initialise the host tracking structure to be ready for use above. */ 9737 /* ------------------------------------------------------------------------ */ 9738 void 9739 ipf_rb_ht_init(host_track_t *head) 9740 { 9741 RBI_INIT(ipf_rb, &head->ht_root); 9742 } 9743 9744 9745 /* ------------------------------------------------------------------------ */ 9746 /* Function: ipf_rb_ht_freenode */ 9747 /* Returns: Nil */ 9748 /* Parameters: head(I) - pointer to host tracking structure */ 9749 /* arg(I) - additional argument from walk caller */ 9750 /* */ 9751 /* Free an actual host_node_t structure. */ 9752 /* ------------------------------------------------------------------------ */ 9753 void 9754 ipf_rb_ht_freenode(host_node_t *node, void *arg) 9755 { 9756 KFREE(node); 9757 } 9758 9759 9760 /* ------------------------------------------------------------------------ */ 9761 /* Function: ipf_rb_ht_flush */ 9762 /* Returns: Nil */ 9763 /* Parameters: head(I) - pointer to host tracking structure */ 9764 /* */ 9765 /* Remove all of the nodes in the tree tracking hosts by calling a walker */ 9766 /* and free'ing each one. */ 9767 /* ------------------------------------------------------------------------ */ 9768 void 9769 ipf_rb_ht_flush(host_track_t *head) 9770 { 9771 RBI_WALK(ipf_rb, &head->ht_root, ipf_rb_ht_freenode, NULL); 9772 } 9773 9774 9775 /* ------------------------------------------------------------------------ */ 9776 /* Function: ipf_slowtimer */ 9777 /* Returns: Nil */ 9778 /* Parameters: ptr(I) - pointer to main ipf soft context structure */ 9779 /* */ 9780 /* Slowly expire held state for fragments. Timeouts are set * in */ 9781 /* expectation of this being called twice per second. */ 9782 /* ------------------------------------------------------------------------ */ 9783 void 9784 ipf_slowtimer(ipf_main_softc_t *softc) 9785 { 9786 9787 ipf_token_expire(softc); 9788 ipf_frag_expire(softc); 9789 ipf_state_expire(softc); 9790 ipf_nat_expire(softc); 9791 ipf_auth_expire(softc); 9792 ipf_lookup_expire(softc); 9793 ipf_rule_expire(softc); 9794 ipf_sync_expire(softc); 9795 softc->ipf_ticks++; 9796 } 9797 9798 9799 /* ------------------------------------------------------------------------ */ 9800 /* Function: ipf_inet_mask_add */ 9801 /* Returns: Nil */ 9802 /* Parameters: bits(I) - pointer to nat context information */ 9803 /* mtab(I) - pointer to mask hash table structure */ 9804 /* */ 9805 /* When called, bits represents the mask of a new NAT rule that has just */ 9806 /* been added. This function inserts a bitmask into the array of masks to */ 9807 /* search when searching for a matching NAT rule for a packet. */ 9808 /* Prevention of duplicate masks is achieved by checking the use count for */ 9809 /* a given netmask. */ 9810 /* ------------------------------------------------------------------------ */ 9811 void 9812 ipf_inet_mask_add(int bits, ipf_v4_masktab_t *mtab) 9813 { 9814 u_32_t mask; 9815 int i, j; 9816 9817 mtab->imt4_masks[bits]++; 9818 if (mtab->imt4_masks[bits] > 1) 9819 return; 9820 9821 if (bits == 0) 9822 mask = 0; 9823 else 9824 mask = 0xffffffff << (32 - bits); 9825 9826 for (i = 0; i < 33; i++) { 9827 if (ntohl(mtab->imt4_active[i]) < mask) { 9828 for (j = 32; j > i; j--) 9829 mtab->imt4_active[j] = mtab->imt4_active[j - 1]; 9830 mtab->imt4_active[i] = htonl(mask); 9831 break; 9832 } 9833 } 9834 mtab->imt4_max++; 9835 } 9836 9837 9838 /* ------------------------------------------------------------------------ */ 9839 /* Function: ipf_inet_mask_del */ 9840 /* Returns: Nil */ 9841 /* Parameters: bits(I) - number of bits set in the netmask */ 9842 /* mtab(I) - pointer to mask hash table structure */ 9843 /* */ 9844 /* Remove the 32bit bitmask represented by "bits" from the collection of */ 9845 /* netmasks stored inside of mtab. */ 9846 /* ------------------------------------------------------------------------ */ 9847 void 9848 ipf_inet_mask_del(int bits, ipf_v4_masktab_t *mtab) 9849 { 9850 u_32_t mask; 9851 int i, j; 9852 9853 mtab->imt4_masks[bits]--; 9854 if (mtab->imt4_masks[bits] > 0) 9855 return; 9856 9857 mask = htonl(0xffffffff << (32 - bits)); 9858 for (i = 0; i < 33; i++) { 9859 if (mtab->imt4_active[i] == mask) { 9860 for (j = i + 1; j < 33; j++) 9861 mtab->imt4_active[j - 1] = mtab->imt4_active[j]; 9862 break; 9863 } 9864 } 9865 mtab->imt4_max--; 9866 ASSERT(mtab->imt4_max >= 0); 9867 } 9868 9869 9870 #ifdef USE_INET6 9871 /* ------------------------------------------------------------------------ */ 9872 /* Function: ipf_inet6_mask_add */ 9873 /* Returns: Nil */ 9874 /* Parameters: bits(I) - number of bits set in mask */ 9875 /* mask(I) - pointer to mask to add */ 9876 /* mtab(I) - pointer to mask hash table structure */ 9877 /* */ 9878 /* When called, bitcount represents the mask of a IPv6 NAT map rule that */ 9879 /* has just been added. This function inserts a bitmask into the array of */ 9880 /* masks to search when searching for a matching NAT rule for a packet. */ 9881 /* Prevention of duplicate masks is achieved by checking the use count for */ 9882 /* a given netmask. */ 9883 /* ------------------------------------------------------------------------ */ 9884 void 9885 ipf_inet6_mask_add(int bits, i6addr_t *mask, ipf_v6_masktab_t *mtab) 9886 { 9887 i6addr_t zero; 9888 int i, j; 9889 9890 mtab->imt6_masks[bits]++; 9891 if (mtab->imt6_masks[bits] > 1) 9892 return; 9893 9894 if (bits == 0) { 9895 mask = &zero; 9896 zero.i6[0] = 0; 9897 zero.i6[1] = 0; 9898 zero.i6[2] = 0; 9899 zero.i6[3] = 0; 9900 } 9901 9902 for (i = 0; i < 129; i++) { 9903 if (IP6_LT(&mtab->imt6_active[i], mask)) { 9904 for (j = 128; j > i; j--) 9905 mtab->imt6_active[j] = mtab->imt6_active[j - 1]; 9906 mtab->imt6_active[i] = *mask; 9907 break; 9908 } 9909 } 9910 mtab->imt6_max++; 9911 } 9912 9913 9914 /* ------------------------------------------------------------------------ */ 9915 /* Function: ipf_inet6_mask_del */ 9916 /* Returns: Nil */ 9917 /* Parameters: bits(I) - number of bits set in mask */ 9918 /* mask(I) - pointer to mask to remove */ 9919 /* mtab(I) - pointer to mask hash table structure */ 9920 /* */ 9921 /* Remove the 128bit bitmask represented by "bits" from the collection of */ 9922 /* netmasks stored inside of mtab. */ 9923 /* ------------------------------------------------------------------------ */ 9924 void 9925 ipf_inet6_mask_del(int bits, i6addr_t *mask, ipf_v6_masktab_t *mtab) 9926 { 9927 i6addr_t zero; 9928 int i, j; 9929 9930 mtab->imt6_masks[bits]--; 9931 if (mtab->imt6_masks[bits] > 0) 9932 return; 9933 9934 if (bits == 0) 9935 mask = &zero; 9936 zero.i6[0] = 0; 9937 zero.i6[1] = 0; 9938 zero.i6[2] = 0; 9939 zero.i6[3] = 0; 9940 9941 for (i = 0; i < 129; i++) { 9942 if (IP6_EQ(&mtab->imt6_active[i], mask)) { 9943 for (j = i + 1; j < 129; j++) { 9944 mtab->imt6_active[j - 1] = mtab->imt6_active[j]; 9945 if (IP6_EQ(&mtab->imt6_active[j - 1], &zero)) 9946 break; 9947 } 9948 break; 9949 } 9950 } 9951 mtab->imt6_max--; 9952 ASSERT(mtab->imt6_max >= 0); 9953 } 9954 #endif 9955