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 /* 240 * Internal errors set by ipf_check_names_string(). 241 */ 242 static const int interr_tbl[3] = { 152, 156, 153 }; 243 244 char ipfilter_version[] = IPL_VERSION; 245 246 int ipf_features = 0 247 #ifdef IPFILTER_LKM 248 | IPF_FEAT_LKM 249 #endif 250 #ifdef IPFILTER_LOG 251 | IPF_FEAT_LOG 252 #endif 253 | IPF_FEAT_LOOKUP 254 #ifdef IPFILTER_BPF 255 | IPF_FEAT_BPF 256 #endif 257 #ifdef IPFILTER_COMPILED 258 | IPF_FEAT_COMPILED 259 #endif 260 #ifdef IPFILTER_CKSUM 261 | IPF_FEAT_CKSUM 262 #endif 263 | IPF_FEAT_SYNC 264 #ifdef IPFILTER_SCAN 265 | IPF_FEAT_SCAN 266 #endif 267 #ifdef USE_INET6 268 | IPF_FEAT_IPV6 269 #endif 270 ; 271 272 273 /* 274 * Table of functions available for use with call rules. 275 */ 276 static ipfunc_resolve_t ipf_availfuncs[] = { 277 { "srcgrpmap", ipf_srcgrpmap, ipf_grpmapinit, ipf_grpmapfini }, 278 { "dstgrpmap", ipf_dstgrpmap, ipf_grpmapinit, ipf_grpmapfini }, 279 { "", NULL, NULL, NULL } 280 }; 281 282 static ipftuneable_t ipf_main_tuneables[] = { 283 { { (void *)offsetof(struct ipf_main_softc_s, ipf_flags) }, 284 "ipf_flags", 0, 0xffffffff, 285 stsizeof(ipf_main_softc_t, ipf_flags), 286 0, NULL, NULL }, 287 { { (void *)offsetof(struct ipf_main_softc_s, ipf_active) }, 288 "active", 0, 0, 289 stsizeof(ipf_main_softc_t, ipf_active), 290 IPFT_RDONLY, NULL, NULL }, 291 { { (void *)offsetof(ipf_main_softc_t, ipf_control_forwarding) }, 292 "control_forwarding", 0, 1, 293 stsizeof(ipf_main_softc_t, ipf_control_forwarding), 294 0, NULL, NULL }, 295 { { (void *)offsetof(ipf_main_softc_t, ipf_update_ipid) }, 296 "update_ipid", 0, 1, 297 stsizeof(ipf_main_softc_t, ipf_update_ipid), 298 0, NULL, NULL }, 299 { { (void *)offsetof(ipf_main_softc_t, ipf_chksrc) }, 300 "chksrc", 0, 1, 301 stsizeof(ipf_main_softc_t, ipf_chksrc), 302 0, NULL, NULL }, 303 { { (void *)offsetof(ipf_main_softc_t, ipf_minttl) }, 304 "min_ttl", 0, 1, 305 stsizeof(ipf_main_softc_t, ipf_minttl), 306 0, NULL, NULL }, 307 { { (void *)offsetof(ipf_main_softc_t, ipf_icmpminfragmtu) }, 308 "icmp_minfragmtu", 0, 1, 309 stsizeof(ipf_main_softc_t, ipf_icmpminfragmtu), 310 0, NULL, NULL }, 311 { { (void *)offsetof(ipf_main_softc_t, ipf_pass) }, 312 "default_pass", 0, 0xffffffff, 313 stsizeof(ipf_main_softc_t, ipf_pass), 314 0, NULL, NULL }, 315 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpidletimeout) }, 316 "tcp_idle_timeout", 1, 0x7fffffff, 317 stsizeof(ipf_main_softc_t, ipf_tcpidletimeout), 318 0, NULL, ipf_settimeout }, 319 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosewait) }, 320 "tcp_close_wait", 1, 0x7fffffff, 321 stsizeof(ipf_main_softc_t, ipf_tcpclosewait), 322 0, NULL, ipf_settimeout }, 323 { { (void *)offsetof(ipf_main_softc_t, ipf_tcplastack) }, 324 "tcp_last_ack", 1, 0x7fffffff, 325 stsizeof(ipf_main_softc_t, ipf_tcplastack), 326 0, NULL, ipf_settimeout }, 327 { { (void *)offsetof(ipf_main_softc_t, ipf_tcptimeout) }, 328 "tcp_timeout", 1, 0x7fffffff, 329 stsizeof(ipf_main_softc_t, ipf_tcptimeout), 330 0, NULL, ipf_settimeout }, 331 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynsent) }, 332 "tcp_syn_sent", 1, 0x7fffffff, 333 stsizeof(ipf_main_softc_t, ipf_tcpsynsent), 334 0, NULL, ipf_settimeout }, 335 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynrecv) }, 336 "tcp_syn_received", 1, 0x7fffffff, 337 stsizeof(ipf_main_softc_t, ipf_tcpsynrecv), 338 0, NULL, ipf_settimeout }, 339 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosed) }, 340 "tcp_closed", 1, 0x7fffffff, 341 stsizeof(ipf_main_softc_t, ipf_tcpclosed), 342 0, NULL, ipf_settimeout }, 343 { { (void *)offsetof(ipf_main_softc_t, ipf_tcphalfclosed) }, 344 "tcp_half_closed", 1, 0x7fffffff, 345 stsizeof(ipf_main_softc_t, ipf_tcphalfclosed), 346 0, NULL, ipf_settimeout }, 347 { { (void *)offsetof(ipf_main_softc_t, ipf_tcptimewait) }, 348 "tcp_time_wait", 1, 0x7fffffff, 349 stsizeof(ipf_main_softc_t, ipf_tcptimewait), 350 0, NULL, ipf_settimeout }, 351 { { (void *)offsetof(ipf_main_softc_t, ipf_udptimeout) }, 352 "udp_timeout", 1, 0x7fffffff, 353 stsizeof(ipf_main_softc_t, ipf_udptimeout), 354 0, NULL, ipf_settimeout }, 355 { { (void *)offsetof(ipf_main_softc_t, ipf_udpacktimeout) }, 356 "udp_ack_timeout", 1, 0x7fffffff, 357 stsizeof(ipf_main_softc_t, ipf_udpacktimeout), 358 0, NULL, ipf_settimeout }, 359 { { (void *)offsetof(ipf_main_softc_t, ipf_icmptimeout) }, 360 "icmp_timeout", 1, 0x7fffffff, 361 stsizeof(ipf_main_softc_t, ipf_icmptimeout), 362 0, NULL, ipf_settimeout }, 363 { { (void *)offsetof(ipf_main_softc_t, ipf_icmpacktimeout) }, 364 "icmp_ack_timeout", 1, 0x7fffffff, 365 stsizeof(ipf_main_softc_t, ipf_icmpacktimeout), 366 0, NULL, ipf_settimeout }, 367 { { (void *)offsetof(ipf_main_softc_t, ipf_iptimeout) }, 368 "ip_timeout", 1, 0x7fffffff, 369 stsizeof(ipf_main_softc_t, ipf_iptimeout), 370 0, NULL, ipf_settimeout }, 371 { { (void *)offsetof(ipf_main_softc_t, ipf_max_namelen) }, 372 "max_namelen", 0, 0x7fffffff, 373 stsizeof(ipf_main_softc_t, ipf_max_namelen), 374 0, NULL, NULL }, 375 #if defined(INSTANCES) && defined(_KERNEL) 376 { { (void *)offsetof(ipf_main_softc_t, ipf_get_loopback) }, 377 "intercept_loopback", 0, 1, 378 stsizeof(ipf_main_softc_t, ipf_get_loopback), 379 0, NULL, ipf_set_loopback }, 380 #endif 381 { { 0 }, 382 NULL, 0, 0, 383 0, 384 0, NULL, NULL } 385 }; 386 387 388 /* 389 * The next section of code is a collection of small routines that set 390 * fields in the fr_info_t structure passed based on properties of the 391 * current packet. There are different routines for the same protocol 392 * for each of IPv4 and IPv6. Adding a new protocol, for which there 393 * will "special" inspection for setup, is now more easily done by adding 394 * a new routine and expanding the ipf_pr_ipinit*() function rather than by 395 * adding more code to a growing switch statement. 396 */ 397 #ifdef USE_INET6 398 static inline int ipf_pr_ah6(fr_info_t *); 399 static inline void ipf_pr_esp6(fr_info_t *); 400 static inline void ipf_pr_gre6(fr_info_t *); 401 static inline void ipf_pr_udp6(fr_info_t *); 402 static inline void ipf_pr_tcp6(fr_info_t *); 403 static inline void ipf_pr_icmp6(fr_info_t *); 404 static inline void ipf_pr_ipv6hdr(fr_info_t *); 405 static inline void ipf_pr_short6(fr_info_t *, int); 406 static inline int ipf_pr_hopopts6(fr_info_t *); 407 static inline int ipf_pr_mobility6(fr_info_t *); 408 static inline int ipf_pr_routing6(fr_info_t *); 409 static inline int ipf_pr_dstopts6(fr_info_t *); 410 static inline int ipf_pr_fragment6(fr_info_t *); 411 static inline struct ip6_ext *ipf_pr_ipv6exthdr(fr_info_t *, int, int); 412 413 414 /* ------------------------------------------------------------------------ */ 415 /* Function: ipf_pr_short6 */ 416 /* Returns: void */ 417 /* Parameters: fin(I) - pointer to packet information */ 418 /* xmin(I) - minimum header size */ 419 /* */ 420 /* IPv6 Only */ 421 /* This is function enforces the 'is a packet too short to be legit' rule */ 422 /* for IPv6 and marks the packet with FI_SHORT if so. See function comment */ 423 /* for ipf_pr_short() for more details. */ 424 /* ------------------------------------------------------------------------ */ 425 static inline void 426 ipf_pr_short6(fr_info_t *fin, int xmin) 427 { 428 429 if (fin->fin_dlen < xmin) 430 fin->fin_flx |= FI_SHORT; 431 } 432 433 434 /* ------------------------------------------------------------------------ */ 435 /* Function: ipf_pr_ipv6hdr */ 436 /* Returns: void */ 437 /* Parameters: fin(I) - pointer to packet information */ 438 /* */ 439 /* IPv6 Only */ 440 /* Copy values from the IPv6 header into the fr_info_t struct and call the */ 441 /* per-protocol analyzer if it exists. In validating the packet, a protocol*/ 442 /* analyzer may pullup or free the packet itself so we need to be vigiliant */ 443 /* of that possibility arising. */ 444 /* ------------------------------------------------------------------------ */ 445 static inline void 446 ipf_pr_ipv6hdr(fr_info_t *fin) 447 { 448 ip6_t *ip6 = (ip6_t *)fin->fin_ip; 449 int p, go = 1, i; 450 fr_ip_t *fi = &fin->fin_fi; 451 452 fin->fin_off = 0; 453 454 fi->fi_tos = 0; 455 fi->fi_optmsk = 0; 456 fi->fi_secmsk = 0; 457 fi->fi_auth = 0; 458 459 p = ip6->ip6_nxt; 460 fin->fin_crc = p; 461 fi->fi_ttl = ip6->ip6_hlim; 462 fi->fi_src.in6 = ip6->ip6_src; 463 fin->fin_crc += fi->fi_src.i6[0]; 464 fin->fin_crc += fi->fi_src.i6[1]; 465 fin->fin_crc += fi->fi_src.i6[2]; 466 fin->fin_crc += fi->fi_src.i6[3]; 467 fi->fi_dst.in6 = ip6->ip6_dst; 468 fin->fin_crc += fi->fi_dst.i6[0]; 469 fin->fin_crc += fi->fi_dst.i6[1]; 470 fin->fin_crc += fi->fi_dst.i6[2]; 471 fin->fin_crc += fi->fi_dst.i6[3]; 472 fin->fin_id = 0; 473 if (IN6_IS_ADDR_MULTICAST(&fi->fi_dst.in6)) 474 fin->fin_flx |= FI_MULTICAST|FI_MBCAST; 475 476 while (go && !(fin->fin_flx & FI_SHORT)) { 477 switch (p) 478 { 479 case IPPROTO_UDP : 480 ipf_pr_udp6(fin); 481 go = 0; 482 break; 483 484 case IPPROTO_TCP : 485 ipf_pr_tcp6(fin); 486 go = 0; 487 break; 488 489 case IPPROTO_ICMPV6 : 490 ipf_pr_icmp6(fin); 491 go = 0; 492 break; 493 494 case IPPROTO_GRE : 495 ipf_pr_gre6(fin); 496 go = 0; 497 break; 498 499 case IPPROTO_HOPOPTS : 500 p = ipf_pr_hopopts6(fin); 501 break; 502 503 case IPPROTO_MOBILITY : 504 p = ipf_pr_mobility6(fin); 505 break; 506 507 case IPPROTO_DSTOPTS : 508 p = ipf_pr_dstopts6(fin); 509 break; 510 511 case IPPROTO_ROUTING : 512 p = ipf_pr_routing6(fin); 513 break; 514 515 case IPPROTO_AH : 516 p = ipf_pr_ah6(fin); 517 break; 518 519 case IPPROTO_ESP : 520 ipf_pr_esp6(fin); 521 go = 0; 522 break; 523 524 case IPPROTO_IPV6 : 525 for (i = 0; ip6exthdr[i].ol_bit != 0; i++) 526 if (ip6exthdr[i].ol_val == p) { 527 fin->fin_flx |= ip6exthdr[i].ol_bit; 528 break; 529 } 530 go = 0; 531 break; 532 533 case IPPROTO_NONE : 534 go = 0; 535 break; 536 537 case IPPROTO_FRAGMENT : 538 p = ipf_pr_fragment6(fin); 539 /* 540 * Given that the only fragments we want to let through 541 * (where fin_off != 0) are those where the non-first 542 * fragments only have data, we can safely stop looking 543 * at headers if this is a non-leading fragment. 544 */ 545 if (fin->fin_off != 0) 546 go = 0; 547 break; 548 549 default : 550 go = 0; 551 break; 552 } 553 554 /* 555 * It is important to note that at this point, for the 556 * extension headers (go != 0), the entire header may not have 557 * been pulled up when the code gets to this point. This is 558 * only done for "go != 0" because the other header handlers 559 * will all pullup their complete header. The other indicator 560 * of an incomplete packet is that this was just an extension 561 * header. 562 */ 563 if ((go != 0) && (p != IPPROTO_NONE) && 564 (ipf_pr_pullup(fin, 0) == -1)) { 565 p = IPPROTO_NONE; 566 break; 567 } 568 } 569 570 /* 571 * Some of the above functions, like ipf_pr_esp6(), can call ipf_pullup 572 * and destroy whatever packet was here. The caller of this function 573 * expects us to return if there is a problem with ipf_pullup. 574 */ 575 if (fin->fin_m == NULL) { 576 ipf_main_softc_t *softc = fin->fin_main_soft; 577 578 LBUMPD(ipf_stats[fin->fin_out], fr_v6_bad); 579 return; 580 } 581 582 fi->fi_p = p; 583 584 /* 585 * IPv6 fragment case 1 - see comment for ipf_pr_fragment6(). 586 * "go != 0" implies the above loop hasn't arrived at a layer 4 header. 587 */ 588 if ((go != 0) && (fin->fin_flx & FI_FRAG) && (fin->fin_off == 0)) { 589 ipf_main_softc_t *softc = fin->fin_main_soft; 590 591 fin->fin_flx |= FI_BAD; 592 DT2(ipf_fi_bad_ipv6_frag_1, fr_info_t *, fin, int, go); 593 LBUMPD(ipf_stats[fin->fin_out], fr_v6_badfrag); 594 LBUMP(ipf_stats[fin->fin_out].fr_v6_bad); 595 } 596 } 597 598 599 /* ------------------------------------------------------------------------ */ 600 /* Function: ipf_pr_ipv6exthdr */ 601 /* Returns: struct ip6_ext * - pointer to the start of the next header */ 602 /* or NULL if there is a prolblem. */ 603 /* Parameters: fin(I) - pointer to packet information */ 604 /* multiple(I) - flag indicating yes/no if multiple occurances */ 605 /* of this extension header are allowed. */ 606 /* proto(I) - protocol number for this extension header */ 607 /* */ 608 /* IPv6 Only */ 609 /* This function embodies a number of common checks that all IPv6 extension */ 610 /* headers must be subjected to. For example, making sure the packet is */ 611 /* big enough for it to be in, checking if it is repeated and setting a */ 612 /* flag to indicate its presence. */ 613 /* ------------------------------------------------------------------------ */ 614 static inline struct ip6_ext * 615 ipf_pr_ipv6exthdr(fr_info_t *fin, int multiple, int proto) 616 { 617 ipf_main_softc_t *softc = fin->fin_main_soft; 618 struct ip6_ext *hdr; 619 u_short shift; 620 int i; 621 622 fin->fin_flx |= FI_V6EXTHDR; 623 624 /* 8 is default length of extension hdr */ 625 if ((fin->fin_dlen - 8) < 0) { 626 fin->fin_flx |= FI_SHORT; 627 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_short); 628 return (NULL); 629 } 630 631 if (ipf_pr_pullup(fin, 8) == -1) { 632 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_pullup); 633 return (NULL); 634 } 635 636 hdr = fin->fin_dp; 637 switch (proto) 638 { 639 case IPPROTO_FRAGMENT : 640 shift = 8; 641 break; 642 default : 643 shift = 8 + (hdr->ip6e_len << 3); 644 break; 645 } 646 647 if (shift > fin->fin_dlen) { /* Nasty extension header length? */ 648 fin->fin_flx |= FI_BAD; 649 DT3(ipf_fi_bad_pr_ipv6exthdr_len, fr_info_t *, fin, u_short, shift, u_short, fin->fin_dlen); 650 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_hlen); 651 return (NULL); 652 } 653 654 fin->fin_dp = (char *)fin->fin_dp + shift; 655 fin->fin_dlen -= shift; 656 657 /* 658 * If we have seen a fragment header, do not set any flags to indicate 659 * the presence of this extension header as it has no impact on the 660 * end result until after it has been defragmented. 661 */ 662 if (fin->fin_flx & FI_FRAG) 663 return (hdr); 664 665 for (i = 0; ip6exthdr[i].ol_bit != 0; i++) 666 if (ip6exthdr[i].ol_val == proto) { 667 /* 668 * Most IPv6 extension headers are only allowed once. 669 */ 670 if ((multiple == 0) && 671 ((fin->fin_optmsk & ip6exthdr[i].ol_bit) != 0)) { 672 fin->fin_flx |= FI_BAD; 673 DT2(ipf_fi_bad_ipv6exthdr_once, fr_info_t *, fin, u_int, (fin->fin_optmsk & ip6exthdr[i].ol_bit)); 674 } else 675 fin->fin_optmsk |= ip6exthdr[i].ol_bit; 676 break; 677 } 678 679 return (hdr); 680 } 681 682 683 /* ------------------------------------------------------------------------ */ 684 /* Function: ipf_pr_hopopts6 */ 685 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 686 /* Parameters: fin(I) - pointer to packet information */ 687 /* */ 688 /* IPv6 Only */ 689 /* This is function checks pending hop by hop options extension header */ 690 /* ------------------------------------------------------------------------ */ 691 static inline int 692 ipf_pr_hopopts6(fr_info_t *fin) 693 { 694 struct ip6_ext *hdr; 695 696 hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS); 697 if (hdr == NULL) 698 return (IPPROTO_NONE); 699 return (hdr->ip6e_nxt); 700 } 701 702 703 /* ------------------------------------------------------------------------ */ 704 /* Function: ipf_pr_mobility6 */ 705 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 706 /* Parameters: fin(I) - pointer to packet information */ 707 /* */ 708 /* IPv6 Only */ 709 /* This is function checks the IPv6 mobility extension header */ 710 /* ------------------------------------------------------------------------ */ 711 static inline int 712 ipf_pr_mobility6(fr_info_t *fin) 713 { 714 struct ip6_ext *hdr; 715 716 hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_MOBILITY); 717 if (hdr == NULL) 718 return (IPPROTO_NONE); 719 return (hdr->ip6e_nxt); 720 } 721 722 723 /* ------------------------------------------------------------------------ */ 724 /* Function: ipf_pr_routing6 */ 725 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 726 /* Parameters: fin(I) - pointer to packet information */ 727 /* */ 728 /* IPv6 Only */ 729 /* This is function checks pending routing extension header */ 730 /* ------------------------------------------------------------------------ */ 731 static inline int 732 ipf_pr_routing6(fr_info_t *fin) 733 { 734 struct ip6_routing *hdr; 735 736 hdr = (struct ip6_routing *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_ROUTING); 737 if (hdr == NULL) 738 return (IPPROTO_NONE); 739 740 switch (hdr->ip6r_type) 741 { 742 case 0 : 743 /* 744 * Nasty extension header length? 745 */ 746 if (((hdr->ip6r_len >> 1) < hdr->ip6r_segleft) || 747 (hdr->ip6r_segleft && (hdr->ip6r_len & 1))) { 748 ipf_main_softc_t *softc = fin->fin_main_soft; 749 750 fin->fin_flx |= FI_BAD; 751 DT1(ipf_fi_bad_routing6, fr_info_t *, fin); 752 LBUMPD(ipf_stats[fin->fin_out], fr_v6_rh_bad); 753 return (IPPROTO_NONE); 754 } 755 break; 756 757 default : 758 break; 759 } 760 761 return (hdr->ip6r_nxt); 762 } 763 764 765 /* ------------------------------------------------------------------------ */ 766 /* Function: ipf_pr_fragment6 */ 767 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 768 /* Parameters: fin(I) - pointer to packet information */ 769 /* */ 770 /* IPv6 Only */ 771 /* Examine the IPv6 fragment header and extract fragment offset information.*/ 772 /* */ 773 /* Fragments in IPv6 are extraordinarily difficult to deal with - much more */ 774 /* so than in IPv4. There are 5 cases of fragments with IPv6 that all */ 775 /* packets with a fragment header can fit into. They are as follows: */ 776 /* */ 777 /* 1. [IPv6][0-n EH][FH][0-n EH] (no L4HDR present) */ 778 /* 2. [IPV6][0-n EH][FH][0-n EH][L4HDR part] (short) */ 779 /* 3. [IPV6][0-n EH][FH][L4HDR part][0-n data] (short) */ 780 /* 4. [IPV6][0-n EH][FH][0-n EH][L4HDR][0-n data] */ 781 /* 5. [IPV6][0-n EH][FH][data] */ 782 /* */ 783 /* IPV6 = IPv6 header, FH = Fragment Header, */ 784 /* 0-n EH = 0 or more extension headers, 0-n data = 0 or more bytes of data */ 785 /* */ 786 /* Packets that match 1, 2, 3 will be dropped as the only reasonable */ 787 /* scenario in which they happen is in extreme circumstances that are most */ 788 /* likely to be an indication of an attack rather than normal traffic. */ 789 /* A type 3 packet may be sent by an attacked after a type 4 packet. There */ 790 /* are two rules that can be used to guard against type 3 packets: L4 */ 791 /* headers must always be in a packet that has the offset field set to 0 */ 792 /* and no packet is allowed to overlay that where offset = 0. */ 793 /* ------------------------------------------------------------------------ */ 794 static inline int 795 ipf_pr_fragment6(fr_info_t *fin) 796 { 797 ipf_main_softc_t *softc = fin->fin_main_soft; 798 struct ip6_frag *frag; 799 800 fin->fin_flx |= FI_FRAG; 801 802 frag = (struct ip6_frag *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT); 803 if (frag == NULL) { 804 LBUMPD(ipf_stats[fin->fin_out], fr_v6_frag_bad); 805 return (IPPROTO_NONE); 806 } 807 808 if ((frag->ip6f_offlg & IP6F_MORE_FRAG) != 0) { 809 /* 810 * Any fragment that isn't the last fragment must have its 811 * length as a multiple of 8. 812 */ 813 if ((fin->fin_plen & 7) != 0) { 814 fin->fin_flx |= FI_BAD; 815 DT2(ipf_fi_bad_frag_not_8, fr_info_t *, fin, u_int, (fin->fin_plen & 7)); 816 } 817 } 818 819 fin->fin_fraghdr = frag; 820 fin->fin_id = frag->ip6f_ident; 821 fin->fin_off = ntohs(frag->ip6f_offlg & IP6F_OFF_MASK); 822 if (fin->fin_off != 0) 823 fin->fin_flx |= FI_FRAGBODY; 824 825 /* 826 * Jumbograms aren't handled, so the max. length is 64k 827 */ 828 if ((fin->fin_off << 3) + fin->fin_dlen > 65535) { 829 fin->fin_flx |= FI_BAD; 830 DT2(ipf_fi_bad_jumbogram, fr_info_t *, fin, u_int, ((fin->fin_off << 3) + fin->fin_dlen)); 831 } 832 833 /* 834 * We don't know where the transport layer header (or whatever is next 835 * is), as it could be behind destination options (amongst others) so 836 * return the fragment header as the type of packet this is. Note that 837 * this effectively disables the fragment cache for > 1 protocol at a 838 * time. 839 */ 840 return (frag->ip6f_nxt); 841 } 842 843 844 /* ------------------------------------------------------------------------ */ 845 /* Function: ipf_pr_dstopts6 */ 846 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 847 /* Parameters: fin(I) - pointer to packet information */ 848 /* */ 849 /* IPv6 Only */ 850 /* This is function checks pending destination options extension header */ 851 /* ------------------------------------------------------------------------ */ 852 static inline int 853 ipf_pr_dstopts6(fr_info_t *fin) 854 { 855 ipf_main_softc_t *softc = fin->fin_main_soft; 856 struct ip6_ext *hdr; 857 858 hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_DSTOPTS); 859 if (hdr == NULL) { 860 LBUMPD(ipf_stats[fin->fin_out], fr_v6_dst_bad); 861 return (IPPROTO_NONE); 862 } 863 return (hdr->ip6e_nxt); 864 } 865 866 867 /* ------------------------------------------------------------------------ */ 868 /* Function: ipf_pr_icmp6 */ 869 /* Returns: void */ 870 /* Parameters: fin(I) - pointer to packet information */ 871 /* */ 872 /* IPv6 Only */ 873 /* This routine is mainly concerned with determining the minimum valid size */ 874 /* for an ICMPv6 packet. */ 875 /* ------------------------------------------------------------------------ */ 876 static inline void 877 ipf_pr_icmp6(fr_info_t *fin) 878 { 879 int minicmpsz = sizeof(struct icmp6_hdr); 880 struct icmp6_hdr *icmp6; 881 882 if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1) { 883 ipf_main_softc_t *softc = fin->fin_main_soft; 884 885 LBUMPD(ipf_stats[fin->fin_out], fr_v6_icmp6_pullup); 886 return; 887 } 888 889 if (fin->fin_dlen > 1) { 890 ip6_t *ip6; 891 892 icmp6 = fin->fin_dp; 893 if (icmp6 == NULL) 894 return; 895 896 fin->fin_data[0] = *(u_short *)icmp6; 897 898 if ((icmp6->icmp6_type & ICMP6_INFOMSG_MASK) != 0) 899 fin->fin_flx |= FI_ICMPQUERY; 900 901 switch (icmp6->icmp6_type) 902 { 903 case ICMP6_ECHO_REPLY : 904 case ICMP6_ECHO_REQUEST : 905 if (fin->fin_dlen >= 6) 906 fin->fin_data[1] = icmp6->icmp6_id; 907 minicmpsz = ICMP6ERR_MINPKTLEN - sizeof(ip6_t); 908 break; 909 910 case ICMP6_DST_UNREACH : 911 case ICMP6_PACKET_TOO_BIG : 912 case ICMP6_TIME_EXCEEDED : 913 case ICMP6_PARAM_PROB : 914 fin->fin_flx |= FI_ICMPERR; 915 minicmpsz = ICMP6ERR_IPICMPHLEN - sizeof(ip6_t); 916 if (fin->fin_plen < ICMP6ERR_IPICMPHLEN) 917 break; 918 919 if (fin->fin_m == NULL) 920 break; 921 922 if (M_LEN(fin->fin_m) < fin->fin_plen) { 923 if (ipf_coalesce(fin) != 1) 924 return; 925 } 926 927 if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN) == -1) 928 return; 929 930 /* 931 * If the destination of this packet doesn't match the 932 * source of the original packet then this packet is 933 * not correct. 934 */ 935 icmp6 = fin->fin_dp; 936 ip6 = (ip6_t *)((char *)icmp6 + ICMPERR_ICMPHLEN); 937 if (IP6_NEQ(&fin->fin_fi.fi_dst, 938 (i6addr_t *)&ip6->ip6_src)) { 939 fin->fin_flx |= FI_BAD; 940 DT1(ipf_fi_bad_icmp6, fr_info_t *, fin); 941 } 942 break; 943 default : 944 break; 945 } 946 } 947 948 ipf_pr_short6(fin, minicmpsz); 949 if ((fin->fin_flx & (FI_SHORT|FI_BAD)) == 0) { 950 u_char p = fin->fin_p; 951 952 fin->fin_p = IPPROTO_ICMPV6; 953 ipf_checkv6sum(fin); 954 fin->fin_p = p; 955 } 956 } 957 958 959 /* ------------------------------------------------------------------------ */ 960 /* Function: ipf_pr_udp6 */ 961 /* Returns: void */ 962 /* Parameters: fin(I) - pointer to packet information */ 963 /* */ 964 /* IPv6 Only */ 965 /* Analyse the packet for IPv6/UDP properties. */ 966 /* Is not expected to be called for fragmented packets. */ 967 /* ------------------------------------------------------------------------ */ 968 static inline void 969 ipf_pr_udp6(fr_info_t *fin) 970 { 971 972 if (ipf_pr_udpcommon(fin) == 0) { 973 u_char p = fin->fin_p; 974 975 fin->fin_p = IPPROTO_UDP; 976 ipf_checkv6sum(fin); 977 fin->fin_p = p; 978 } 979 } 980 981 982 /* ------------------------------------------------------------------------ */ 983 /* Function: ipf_pr_tcp6 */ 984 /* Returns: void */ 985 /* Parameters: fin(I) - pointer to packet information */ 986 /* */ 987 /* IPv6 Only */ 988 /* Analyse the packet for IPv6/TCP properties. */ 989 /* Is not expected to be called for fragmented packets. */ 990 /* ------------------------------------------------------------------------ */ 991 static inline void 992 ipf_pr_tcp6(fr_info_t *fin) 993 { 994 995 if (ipf_pr_tcpcommon(fin) == 0) { 996 u_char p = fin->fin_p; 997 998 fin->fin_p = IPPROTO_TCP; 999 ipf_checkv6sum(fin); 1000 fin->fin_p = p; 1001 } 1002 } 1003 1004 1005 /* ------------------------------------------------------------------------ */ 1006 /* Function: ipf_pr_esp6 */ 1007 /* Returns: void */ 1008 /* Parameters: fin(I) - pointer to packet information */ 1009 /* */ 1010 /* IPv6 Only */ 1011 /* Analyse the packet for ESP properties. */ 1012 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ 1013 /* even though the newer ESP packets must also have a sequence number that */ 1014 /* is 32bits as well, it is not possible(?) to determine the version from a */ 1015 /* simple packet header. */ 1016 /* ------------------------------------------------------------------------ */ 1017 static inline void 1018 ipf_pr_esp6(fr_info_t *fin) 1019 { 1020 1021 if ((fin->fin_off == 0) && (ipf_pr_pullup(fin, 8) == -1)) { 1022 ipf_main_softc_t *softc = fin->fin_main_soft; 1023 1024 LBUMPD(ipf_stats[fin->fin_out], fr_v6_esp_pullup); 1025 return; 1026 } 1027 } 1028 1029 1030 /* ------------------------------------------------------------------------ */ 1031 /* Function: ipf_pr_ah6 */ 1032 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 1033 /* Parameters: fin(I) - pointer to packet information */ 1034 /* */ 1035 /* IPv6 Only */ 1036 /* Analyse the packet for AH properties. */ 1037 /* The minimum length is taken to be the combination of all fields in the */ 1038 /* header being present and no authentication data (null algorithm used.) */ 1039 /* ------------------------------------------------------------------------ */ 1040 static inline int 1041 ipf_pr_ah6(fr_info_t *fin) 1042 { 1043 authhdr_t *ah; 1044 1045 fin->fin_flx |= FI_AH; 1046 1047 ah = (authhdr_t *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS); 1048 if (ah == NULL) { 1049 ipf_main_softc_t *softc = fin->fin_main_soft; 1050 1051 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ah_bad); 1052 return (IPPROTO_NONE); 1053 } 1054 1055 ipf_pr_short6(fin, sizeof(*ah)); 1056 1057 /* 1058 * No need for another pullup, ipf_pr_ipv6exthdr() will pullup 1059 * enough data to satisfy ah_next (the very first one.) 1060 */ 1061 return (ah->ah_next); 1062 } 1063 1064 1065 /* ------------------------------------------------------------------------ */ 1066 /* Function: ipf_pr_gre6 */ 1067 /* Returns: void */ 1068 /* Parameters: fin(I) - pointer to packet information */ 1069 /* */ 1070 /* Analyse the packet for GRE properties. */ 1071 /* ------------------------------------------------------------------------ */ 1072 static inline void 1073 ipf_pr_gre6(fr_info_t *fin) 1074 { 1075 grehdr_t *gre; 1076 1077 if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) { 1078 ipf_main_softc_t *softc = fin->fin_main_soft; 1079 1080 LBUMPD(ipf_stats[fin->fin_out], fr_v6_gre_pullup); 1081 return; 1082 } 1083 1084 gre = fin->fin_dp; 1085 if (GRE_REV(gre->gr_flags) == 1) 1086 fin->fin_data[0] = gre->gr_call; 1087 } 1088 #endif /* USE_INET6 */ 1089 1090 1091 /* ------------------------------------------------------------------------ */ 1092 /* Function: ipf_pr_pullup */ 1093 /* Returns: int - 0 == pullup succeeded, -1 == failure */ 1094 /* Parameters: fin(I) - pointer to packet information */ 1095 /* plen(I) - length (excluding L3 header) to pullup */ 1096 /* */ 1097 /* Short inline function to cut down on code duplication to perform a call */ 1098 /* to ipf_pullup to ensure there is the required amount of data, */ 1099 /* consecutively in the packet buffer. */ 1100 /* */ 1101 /* This function pulls up 'extra' data at the location of fin_dp. fin_dp */ 1102 /* points to the first byte after the complete layer 3 header, which will */ 1103 /* include all of the known extension headers for IPv6 or options for IPv4. */ 1104 /* */ 1105 /* Since fr_pullup() expects the total length of bytes to be pulled up, it */ 1106 /* is necessary to add those we can already assume to be pulled up (fin_dp */ 1107 /* - fin_ip) to what is passed through. */ 1108 /* ------------------------------------------------------------------------ */ 1109 int 1110 ipf_pr_pullup(fr_info_t *fin, int plen) 1111 { 1112 ipf_main_softc_t *softc = fin->fin_main_soft; 1113 1114 if (fin->fin_m != NULL) { 1115 if (fin->fin_dp != NULL) 1116 plen += (char *)fin->fin_dp - 1117 ((char *)fin->fin_ip + fin->fin_hlen); 1118 plen += fin->fin_hlen; 1119 if (M_LEN(fin->fin_m) < plen + fin->fin_ipoff) { 1120 #if defined(_KERNEL) 1121 if (ipf_pullup(fin->fin_m, fin, plen) == NULL) { 1122 DT1(ipf_pullup_fail, fr_info_t *, fin); 1123 LBUMP(ipf_stats[fin->fin_out].fr_pull[1]); 1124 fin->fin_reason = FRB_PULLUP; 1125 fin->fin_flx |= FI_BAD; 1126 return (-1); 1127 } 1128 LBUMP(ipf_stats[fin->fin_out].fr_pull[0]); 1129 #else 1130 LBUMP(ipf_stats[fin->fin_out].fr_pull[1]); 1131 /* 1132 * Fake ipf_pullup failing 1133 */ 1134 fin->fin_reason = FRB_PULLUP; 1135 *fin->fin_mp = NULL; 1136 fin->fin_m = NULL; 1137 fin->fin_ip = NULL; 1138 fin->fin_flx |= FI_BAD; 1139 return (-1); 1140 #endif 1141 } 1142 } 1143 return (0); 1144 } 1145 1146 1147 /* ------------------------------------------------------------------------ */ 1148 /* Function: ipf_pr_short */ 1149 /* Returns: void */ 1150 /* Parameters: fin(I) - pointer to packet information */ 1151 /* xmin(I) - minimum header size */ 1152 /* */ 1153 /* Check if a packet is "short" as defined by xmin. The rule we are */ 1154 /* applying here is that the packet must not be fragmented within the layer */ 1155 /* 4 header. That is, it must not be a fragment that has its offset set to */ 1156 /* start within the layer 4 header (hdrmin) or if it is at offset 0, the */ 1157 /* entire layer 4 header must be present (min). */ 1158 /* ------------------------------------------------------------------------ */ 1159 static inline void 1160 ipf_pr_short(fr_info_t *fin, int xmin) 1161 { 1162 1163 if (fin->fin_off == 0) { 1164 if (fin->fin_dlen < xmin) 1165 fin->fin_flx |= FI_SHORT; 1166 } else if (fin->fin_off < xmin) { 1167 fin->fin_flx |= FI_SHORT; 1168 } 1169 } 1170 1171 1172 /* ------------------------------------------------------------------------ */ 1173 /* Function: ipf_pr_icmp */ 1174 /* Returns: void */ 1175 /* Parameters: fin(I) - pointer to packet information */ 1176 /* */ 1177 /* IPv4 Only */ 1178 /* Do a sanity check on the packet for ICMP (v4). In nearly all cases, */ 1179 /* except extrememly bad packets, both type and code will be present. */ 1180 /* The expected minimum size of an ICMP packet is very much dependent on */ 1181 /* the type of it. */ 1182 /* */ 1183 /* XXX - other ICMP sanity checks? */ 1184 /* ------------------------------------------------------------------------ */ 1185 static inline void 1186 ipf_pr_icmp(fr_info_t *fin) 1187 { 1188 ipf_main_softc_t *softc = fin->fin_main_soft; 1189 int minicmpsz = sizeof(struct icmp); 1190 icmphdr_t *icmp; 1191 ip_t *oip; 1192 1193 ipf_pr_short(fin, ICMPERR_ICMPHLEN); 1194 1195 if (fin->fin_off != 0) { 1196 LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_frag); 1197 return; 1198 } 1199 1200 if (ipf_pr_pullup(fin, ICMPERR_ICMPHLEN) == -1) { 1201 LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_pullup); 1202 return; 1203 } 1204 1205 icmp = fin->fin_dp; 1206 if (icmp == NULL) 1207 return; 1208 1209 fin->fin_data[0] = *(u_short *)icmp; 1210 fin->fin_data[1] = icmp->icmp_id; 1211 1212 switch (icmp->icmp_type) 1213 { 1214 case ICMP_ECHOREPLY : 1215 case ICMP_ECHO : 1216 /* Router discovery messaes - RFC 1256 */ 1217 case ICMP_ROUTERADVERT : 1218 case ICMP_ROUTERSOLICIT : 1219 fin->fin_flx |= FI_ICMPQUERY; 1220 minicmpsz = ICMP_MINLEN; 1221 break; 1222 /* 1223 * type(1) + code(1) + cksum(2) + id(2) seq(2) + 1224 * 3 * timestamp(3 * 4) 1225 */ 1226 case ICMP_TSTAMP : 1227 case ICMP_TSTAMPREPLY : 1228 fin->fin_flx |= FI_ICMPQUERY; 1229 minicmpsz = 20; 1230 break; 1231 /* 1232 * type(1) + code(1) + cksum(2) + id(2) seq(2) + 1233 * mask(4) 1234 */ 1235 case ICMP_IREQ : 1236 case ICMP_IREQREPLY : 1237 case ICMP_MASKREQ : 1238 case ICMP_MASKREPLY : 1239 fin->fin_flx |= FI_ICMPQUERY; 1240 minicmpsz = 12; 1241 break; 1242 /* 1243 * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+) 1244 */ 1245 case ICMP_UNREACH : 1246 #ifdef icmp_nextmtu 1247 if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG) { 1248 if (icmp->icmp_nextmtu < softc->ipf_icmpminfragmtu) { 1249 fin->fin_flx |= FI_BAD; 1250 DT3(ipf_fi_bad_icmp_nextmtu, fr_info_t *, fin, u_int, icmp->icmp_nextmtu, u_int, softc->ipf_icmpminfragmtu); 1251 } 1252 } 1253 #endif 1254 /* FALLTHROUGH */ 1255 case ICMP_SOURCEQUENCH : 1256 case ICMP_REDIRECT : 1257 case ICMP_TIMXCEED : 1258 case ICMP_PARAMPROB : 1259 fin->fin_flx |= FI_ICMPERR; 1260 if (ipf_coalesce(fin) != 1) { 1261 LBUMPD(ipf_stats[fin->fin_out], fr_icmp_coalesce); 1262 return; 1263 } 1264 1265 /* 1266 * ICMP error packets should not be generated for IP 1267 * packets that are a fragment that isn't the first 1268 * fragment. 1269 */ 1270 oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN); 1271 if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0) { 1272 fin->fin_flx |= FI_BAD; 1273 DT2(ipf_fi_bad_icmp_err, fr_info_t, fin, u_int, (ntohs(oip->ip_off) & IP_OFFMASK)); 1274 } 1275 1276 /* 1277 * If the destination of this packet doesn't match the 1278 * source of the original packet then this packet is 1279 * not correct. 1280 */ 1281 if (oip->ip_src.s_addr != fin->fin_daddr) { 1282 fin->fin_flx |= FI_BAD; 1283 DT1(ipf_fi_bad_src_ne_dst, fr_info_t *, fin); 1284 } 1285 break; 1286 default : 1287 break; 1288 } 1289 1290 ipf_pr_short(fin, minicmpsz); 1291 1292 ipf_checkv4sum(fin); 1293 } 1294 1295 1296 /* ------------------------------------------------------------------------ */ 1297 /* Function: ipf_pr_tcpcommon */ 1298 /* Returns: int - 0 = header ok, 1 = bad packet, -1 = buffer error */ 1299 /* Parameters: fin(I) - pointer to packet information */ 1300 /* */ 1301 /* TCP header sanity checking. Look for bad combinations of TCP flags, */ 1302 /* and make some checks with how they interact with other fields. */ 1303 /* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is */ 1304 /* valid and mark the packet as bad if not. */ 1305 /* ------------------------------------------------------------------------ */ 1306 static inline int 1307 ipf_pr_tcpcommon(fr_info_t *fin) 1308 { 1309 ipf_main_softc_t *softc = fin->fin_main_soft; 1310 int flags, tlen; 1311 tcphdr_t *tcp; 1312 1313 fin->fin_flx |= FI_TCPUDP; 1314 if (fin->fin_off != 0) { 1315 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_frag); 1316 return (0); 1317 } 1318 1319 if (ipf_pr_pullup(fin, sizeof(*tcp)) == -1) { 1320 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup); 1321 return (-1); 1322 } 1323 1324 tcp = fin->fin_dp; 1325 if (fin->fin_dlen > 3) { 1326 fin->fin_sport = ntohs(tcp->th_sport); 1327 fin->fin_dport = ntohs(tcp->th_dport); 1328 } 1329 1330 if ((fin->fin_flx & FI_SHORT) != 0) { 1331 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_short); 1332 return (1); 1333 } 1334 1335 /* 1336 * Use of the TCP data offset *must* result in a value that is at 1337 * least the same size as the TCP header. 1338 */ 1339 tlen = TCP_OFF(tcp) << 2; 1340 if (tlen < sizeof(tcphdr_t)) { 1341 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_small); 1342 fin->fin_flx |= FI_BAD; 1343 DT3(ipf_fi_bad_tlen, fr_info_t, fin, u_int, tlen, u_int, sizeof(tcphdr_t)); 1344 return (1); 1345 } 1346 1347 flags = tcp_get_flags(tcp); 1348 fin->fin_tcpf = tcp_get_flags(tcp); 1349 1350 /* 1351 * If the urgent flag is set, then the urgent pointer must 1352 * also be set and vice versa. Good TCP packets do not have 1353 * just one of these set. 1354 */ 1355 if ((flags & TH_URG) != 0 && (tcp->th_urp == 0)) { 1356 fin->fin_flx |= FI_BAD; 1357 DT3(ipf_fi_bad_th_urg, fr_info_t*, fin, u_int, (flags & TH_URG), u_int, tcp->th_urp); 1358 #if 0 1359 } else if ((flags & TH_URG) == 0 && (tcp->th_urp != 0)) { 1360 /* 1361 * Ignore this case (#if 0) as it shows up in "real" 1362 * traffic with bogus values in the urgent pointer field. 1363 */ 1364 fin->fin_flx |= FI_BAD; 1365 DT3(ipf_fi_bad_th_urg0, fr_info_t *, fin, u_int, (flags & TH_URG), u_int, tcp->th_urp); 1366 #endif 1367 } else if (((flags & (TH_SYN|TH_FIN)) != 0) && 1368 ((flags & (TH_RST|TH_ACK)) == TH_RST)) { 1369 /* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */ 1370 fin->fin_flx |= FI_BAD; 1371 DT1(ipf_fi_bad_th_fin_rst_ack, fr_info_t, fin); 1372 #if 1 1373 } else if (((flags & TH_SYN) != 0) && 1374 ((flags & (TH_URG|TH_PUSH)) != 0)) { 1375 /* 1376 * SYN with URG and PUSH set is not for normal TCP but it is 1377 * possible(?) with T/TCP...but who uses T/TCP? 1378 */ 1379 fin->fin_flx |= FI_BAD; 1380 DT1(ipf_fi_bad_th_syn_urg_psh, fr_info_t *, fin); 1381 #endif 1382 } else if (!(flags & TH_ACK)) { 1383 /* 1384 * If the ack bit isn't set, then either the SYN or 1385 * RST bit must be set. If the SYN bit is set, then 1386 * we expect the ACK field to be 0. If the ACK is 1387 * not set and if URG, PSH or FIN are set, consdier 1388 * that to indicate a bad TCP packet. 1389 */ 1390 if ((flags == TH_SYN) && (tcp->th_ack != 0)) { 1391 /* 1392 * Cisco PIX sets the ACK field to a random value. 1393 * In light of this, do not set FI_BAD until a patch 1394 * is available from Cisco to ensure that 1395 * interoperability between existing systems is 1396 * achieved. 1397 */ 1398 /*fin->fin_flx |= FI_BAD*/; 1399 /*DT1(ipf_fi_bad_th_syn_ack, fr_info_t *, fin);*/ 1400 } else if (!(flags & (TH_RST|TH_SYN))) { 1401 fin->fin_flx |= FI_BAD; 1402 DT1(ipf_fi_bad_th_rst_syn, fr_info_t *, fin); 1403 } else if ((flags & (TH_URG|TH_PUSH|TH_FIN)) != 0) { 1404 fin->fin_flx |= FI_BAD; 1405 DT1(ipf_fi_bad_th_urg_push_fin, fr_info_t *, fin); 1406 } 1407 } 1408 if (fin->fin_flx & FI_BAD) { 1409 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_bad_flags); 1410 return (1); 1411 } 1412 1413 /* 1414 * At this point, it's not exactly clear what is to be gained by 1415 * marking up which TCP options are and are not present. The one we 1416 * are most interested in is the TCP window scale. This is only in 1417 * a SYN packet [RFC1323] so we don't need this here...? 1418 * Now if we were to analyse the header for passive fingerprinting, 1419 * then that might add some weight to adding this... 1420 */ 1421 if (tlen == sizeof(tcphdr_t)) { 1422 return (0); 1423 } 1424 1425 if (ipf_pr_pullup(fin, tlen) == -1) { 1426 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup); 1427 return (-1); 1428 } 1429 1430 #if 0 1431 tcp = fin->fin_dp; 1432 ip = fin->fin_ip; 1433 s = (u_char *)(tcp + 1); 1434 off = IP_HL(ip) << 2; 1435 # ifdef _KERNEL 1436 if (fin->fin_mp != NULL) { 1437 mb_t *m = *fin->fin_mp; 1438 1439 if (off + tlen > M_LEN(m)) 1440 return; 1441 } 1442 # endif 1443 for (tlen -= (int)sizeof(*tcp); tlen > 0; ) { 1444 opt = *s; 1445 if (opt == '\0') 1446 break; 1447 else if (opt == TCPOPT_NOP) 1448 ol = 1; 1449 else { 1450 if (tlen < 2) 1451 break; 1452 ol = (int)*(s + 1); 1453 if (ol < 2 || ol > tlen) 1454 break; 1455 } 1456 1457 for (i = 9, mv = 4; mv >= 0; ) { 1458 op = ipopts + i; 1459 if (opt == (u_char)op->ol_val) { 1460 optmsk |= op->ol_bit; 1461 break; 1462 } 1463 } 1464 tlen -= ol; 1465 s += ol; 1466 } 1467 #endif /* 0 */ 1468 1469 return (0); 1470 } 1471 1472 1473 1474 /* ------------------------------------------------------------------------ */ 1475 /* Function: ipf_pr_udpcommon */ 1476 /* Returns: int - 0 = header ok, 1 = bad packet */ 1477 /* Parameters: fin(I) - pointer to packet information */ 1478 /* */ 1479 /* Extract the UDP source and destination ports, if present. If compiled */ 1480 /* with IPFILTER_CKSUM, check to see if the UDP checksum is valid. */ 1481 /* ------------------------------------------------------------------------ */ 1482 static inline int 1483 ipf_pr_udpcommon(fr_info_t *fin) 1484 { 1485 udphdr_t *udp; 1486 1487 fin->fin_flx |= FI_TCPUDP; 1488 1489 if (!fin->fin_off && (fin->fin_dlen > 3)) { 1490 if (ipf_pr_pullup(fin, sizeof(*udp)) == -1) { 1491 ipf_main_softc_t *softc = fin->fin_main_soft; 1492 1493 fin->fin_flx |= FI_SHORT; 1494 LBUMPD(ipf_stats[fin->fin_out], fr_udp_pullup); 1495 return (1); 1496 } 1497 1498 udp = fin->fin_dp; 1499 1500 fin->fin_sport = ntohs(udp->uh_sport); 1501 fin->fin_dport = ntohs(udp->uh_dport); 1502 } 1503 1504 return (0); 1505 } 1506 1507 1508 /* ------------------------------------------------------------------------ */ 1509 /* Function: ipf_pr_tcp */ 1510 /* Returns: void */ 1511 /* Parameters: fin(I) - pointer to packet information */ 1512 /* */ 1513 /* IPv4 Only */ 1514 /* Analyse the packet for IPv4/TCP properties. */ 1515 /* ------------------------------------------------------------------------ */ 1516 static inline void 1517 ipf_pr_tcp(fr_info_t *fin) 1518 { 1519 1520 ipf_pr_short(fin, sizeof(tcphdr_t)); 1521 1522 if (ipf_pr_tcpcommon(fin) == 0) 1523 ipf_checkv4sum(fin); 1524 } 1525 1526 1527 /* ------------------------------------------------------------------------ */ 1528 /* Function: ipf_pr_udp */ 1529 /* Returns: void */ 1530 /* Parameters: fin(I) - pointer to packet information */ 1531 /* */ 1532 /* IPv4 Only */ 1533 /* Analyse the packet for IPv4/UDP properties. */ 1534 /* ------------------------------------------------------------------------ */ 1535 static inline void 1536 ipf_pr_udp(fr_info_t *fin) 1537 { 1538 1539 ipf_pr_short(fin, sizeof(udphdr_t)); 1540 1541 if (ipf_pr_udpcommon(fin) == 0) 1542 ipf_checkv4sum(fin); 1543 } 1544 1545 1546 /* ------------------------------------------------------------------------ */ 1547 /* Function: ipf_pr_esp */ 1548 /* Returns: void */ 1549 /* Parameters: fin(I) - pointer to packet information */ 1550 /* */ 1551 /* Analyse the packet for ESP properties. */ 1552 /* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ 1553 /* even though the newer ESP packets must also have a sequence number that */ 1554 /* is 32bits as well, it is not possible(?) to determine the version from a */ 1555 /* simple packet header. */ 1556 /* ------------------------------------------------------------------------ */ 1557 static inline void 1558 ipf_pr_esp(fr_info_t *fin) 1559 { 1560 1561 if (fin->fin_off == 0) { 1562 ipf_pr_short(fin, 8); 1563 if (ipf_pr_pullup(fin, 8) == -1) { 1564 ipf_main_softc_t *softc = fin->fin_main_soft; 1565 1566 LBUMPD(ipf_stats[fin->fin_out], fr_v4_esp_pullup); 1567 } 1568 } 1569 } 1570 1571 1572 /* ------------------------------------------------------------------------ */ 1573 /* Function: ipf_pr_ah */ 1574 /* Returns: int - value of the next header or IPPROTO_NONE if error */ 1575 /* Parameters: fin(I) - pointer to packet information */ 1576 /* */ 1577 /* Analyse the packet for AH properties. */ 1578 /* The minimum length is taken to be the combination of all fields in the */ 1579 /* header being present and no authentication data (null algorithm used.) */ 1580 /* ------------------------------------------------------------------------ */ 1581 static inline int 1582 ipf_pr_ah(fr_info_t *fin) 1583 { 1584 ipf_main_softc_t *softc = fin->fin_main_soft; 1585 authhdr_t *ah; 1586 int len; 1587 1588 fin->fin_flx |= FI_AH; 1589 ipf_pr_short(fin, sizeof(*ah)); 1590 1591 if (((fin->fin_flx & FI_SHORT) != 0) || (fin->fin_off != 0)) { 1592 LBUMPD(ipf_stats[fin->fin_out], fr_v4_ah_bad); 1593 return (IPPROTO_NONE); 1594 } 1595 1596 if (ipf_pr_pullup(fin, sizeof(*ah)) == -1) { 1597 DT(fr_v4_ah_pullup_1); 1598 LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup); 1599 return (IPPROTO_NONE); 1600 } 1601 1602 ah = (authhdr_t *)fin->fin_dp; 1603 1604 len = (ah->ah_plen + 2) << 2; 1605 ipf_pr_short(fin, len); 1606 if (ipf_pr_pullup(fin, len) == -1) { 1607 DT(fr_v4_ah_pullup_2); 1608 LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup); 1609 return (IPPROTO_NONE); 1610 } 1611 1612 /* 1613 * Adjust fin_dp and fin_dlen for skipping over the authentication 1614 * header. 1615 */ 1616 fin->fin_dp = (char *)fin->fin_dp + len; 1617 fin->fin_dlen -= len; 1618 return (ah->ah_next); 1619 } 1620 1621 1622 /* ------------------------------------------------------------------------ */ 1623 /* Function: ipf_pr_gre */ 1624 /* Returns: void */ 1625 /* Parameters: fin(I) - pointer to packet information */ 1626 /* */ 1627 /* Analyse the packet for GRE properties. */ 1628 /* ------------------------------------------------------------------------ */ 1629 static inline void 1630 ipf_pr_gre(fr_info_t *fin) 1631 { 1632 ipf_main_softc_t *softc = fin->fin_main_soft; 1633 grehdr_t *gre; 1634 1635 ipf_pr_short(fin, sizeof(grehdr_t)); 1636 1637 if (fin->fin_off != 0) { 1638 LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_frag); 1639 return; 1640 } 1641 1642 if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) { 1643 LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_pullup); 1644 return; 1645 } 1646 1647 gre = fin->fin_dp; 1648 if (GRE_REV(gre->gr_flags) == 1) 1649 fin->fin_data[0] = gre->gr_call; 1650 } 1651 1652 1653 /* ------------------------------------------------------------------------ */ 1654 /* Function: ipf_pr_ipv4hdr */ 1655 /* Returns: void */ 1656 /* Parameters: fin(I) - pointer to packet information */ 1657 /* */ 1658 /* IPv4 Only */ 1659 /* Analyze the IPv4 header and set fields in the fr_info_t structure. */ 1660 /* Check all options present and flag their presence if any exist. */ 1661 /* ------------------------------------------------------------------------ */ 1662 static inline void 1663 ipf_pr_ipv4hdr(fr_info_t *fin) 1664 { 1665 u_short optmsk = 0, secmsk = 0, auth = 0; 1666 int hlen, ol, mv, p, i; 1667 const struct optlist *op; 1668 u_char *s, opt; 1669 u_short off; 1670 fr_ip_t *fi; 1671 ip_t *ip; 1672 1673 fi = &fin->fin_fi; 1674 hlen = fin->fin_hlen; 1675 1676 ip = fin->fin_ip; 1677 p = ip->ip_p; 1678 fi->fi_p = p; 1679 fin->fin_crc = p; 1680 fi->fi_tos = ip->ip_tos; 1681 fin->fin_id = ntohs(ip->ip_id); 1682 off = ntohs(ip->ip_off); 1683 1684 /* Get both TTL and protocol */ 1685 fi->fi_p = ip->ip_p; 1686 fi->fi_ttl = ip->ip_ttl; 1687 1688 /* Zero out bits not used in IPv6 address */ 1689 fi->fi_src.i6[1] = 0; 1690 fi->fi_src.i6[2] = 0; 1691 fi->fi_src.i6[3] = 0; 1692 fi->fi_dst.i6[1] = 0; 1693 fi->fi_dst.i6[2] = 0; 1694 fi->fi_dst.i6[3] = 0; 1695 1696 fi->fi_saddr = ip->ip_src.s_addr; 1697 fin->fin_crc += fi->fi_saddr; 1698 fi->fi_daddr = ip->ip_dst.s_addr; 1699 fin->fin_crc += fi->fi_daddr; 1700 if (IN_MULTICAST(ntohl(fi->fi_daddr))) 1701 fin->fin_flx |= FI_MULTICAST|FI_MBCAST; 1702 1703 /* 1704 * set packet attribute flags based on the offset and 1705 * calculate the byte offset that it represents. 1706 */ 1707 off &= IP_MF|IP_OFFMASK; 1708 if (off != 0) { 1709 int morefrag = off & IP_MF; 1710 1711 fi->fi_flx |= FI_FRAG; 1712 off &= IP_OFFMASK; 1713 if (off == 1 && p == IPPROTO_TCP) { 1714 fin->fin_flx |= FI_SHORT; /* RFC 3128 */ 1715 DT1(ipf_fi_tcp_frag_off_1, fr_info_t *, fin); 1716 } 1717 if (off != 0) { 1718 fin->fin_flx |= FI_FRAGBODY; 1719 off <<= 3; 1720 if ((off + fin->fin_dlen > 65535) || 1721 (fin->fin_dlen == 0) || 1722 ((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) { 1723 /* 1724 * The length of the packet, starting at its 1725 * offset cannot exceed 65535 (0xffff) as the 1726 * length of an IP packet is only 16 bits. 1727 * 1728 * Any fragment that isn't the last fragment 1729 * must have a length greater than 0 and it 1730 * must be an even multiple of 8. 1731 */ 1732 fi->fi_flx |= FI_BAD; 1733 DT1(ipf_fi_bad_fragbody_gt_65535, fr_info_t *, fin); 1734 } 1735 } 1736 } 1737 fin->fin_off = off; 1738 1739 /* 1740 * Call per-protocol setup and checking 1741 */ 1742 if (p == IPPROTO_AH) { 1743 /* 1744 * Treat AH differently because we expect there to be another 1745 * layer 4 header after it. 1746 */ 1747 p = ipf_pr_ah(fin); 1748 } 1749 1750 switch (p) 1751 { 1752 case IPPROTO_UDP : 1753 ipf_pr_udp(fin); 1754 break; 1755 case IPPROTO_TCP : 1756 ipf_pr_tcp(fin); 1757 break; 1758 case IPPROTO_ICMP : 1759 ipf_pr_icmp(fin); 1760 break; 1761 case IPPROTO_ESP : 1762 ipf_pr_esp(fin); 1763 break; 1764 case IPPROTO_GRE : 1765 ipf_pr_gre(fin); 1766 break; 1767 } 1768 1769 ip = fin->fin_ip; 1770 if (ip == NULL) 1771 return; 1772 1773 /* 1774 * If it is a standard IP header (no options), set the flag fields 1775 * which relate to options to 0. 1776 */ 1777 if (hlen == sizeof(*ip)) { 1778 fi->fi_optmsk = 0; 1779 fi->fi_secmsk = 0; 1780 fi->fi_auth = 0; 1781 return; 1782 } 1783 1784 /* 1785 * So the IP header has some IP options attached. Walk the entire 1786 * list of options present with this packet and set flags to indicate 1787 * which ones are here and which ones are not. For the somewhat out 1788 * of date and obscure security classification options, set a flag to 1789 * represent which classification is present. 1790 */ 1791 fi->fi_flx |= FI_OPTIONS; 1792 1793 for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) { 1794 opt = *s; 1795 if (opt == '\0') 1796 break; 1797 else if (opt == IPOPT_NOP) 1798 ol = 1; 1799 else { 1800 if (hlen < 2) 1801 break; 1802 ol = (int)*(s + 1); 1803 if (ol < 2 || ol > hlen) 1804 break; 1805 } 1806 for (i = 9, mv = 4; mv >= 0; ) { 1807 op = ipopts + i; 1808 1809 if ((opt == (u_char)op->ol_val) && (ol > 4)) { 1810 u_32_t doi; 1811 1812 switch (opt) 1813 { 1814 case IPOPT_SECURITY : 1815 if (optmsk & op->ol_bit) { 1816 fin->fin_flx |= FI_BAD; 1817 DT2(ipf_fi_bad_ipopt_security, fr_info_t *, fin, u_short, (optmsk & op->ol_bit)); 1818 } else { 1819 doi = ipf_checkripso(s); 1820 secmsk = doi >> 16; 1821 auth = doi & 0xffff; 1822 } 1823 break; 1824 1825 case IPOPT_CIPSO : 1826 1827 if (optmsk & op->ol_bit) { 1828 fin->fin_flx |= FI_BAD; 1829 DT2(ipf_fi_bad_ipopt_cipso, fr_info_t *, fin, u_short, (optmsk & op->ol_bit)); 1830 } else { 1831 doi = ipf_checkcipso(fin, 1832 s, ol); 1833 secmsk = doi >> 16; 1834 auth = doi & 0xffff; 1835 } 1836 break; 1837 } 1838 optmsk |= op->ol_bit; 1839 } 1840 1841 if (opt < op->ol_val) 1842 i -= mv; 1843 else 1844 i += mv; 1845 mv--; 1846 } 1847 hlen -= ol; 1848 s += ol; 1849 } 1850 1851 /* 1852 * 1853 */ 1854 if (auth && !(auth & 0x0100)) 1855 auth &= 0xff00; 1856 fi->fi_optmsk = optmsk; 1857 fi->fi_secmsk = secmsk; 1858 fi->fi_auth = auth; 1859 } 1860 1861 1862 /* ------------------------------------------------------------------------ */ 1863 /* Function: ipf_checkripso */ 1864 /* Returns: void */ 1865 /* Parameters: s(I) - pointer to start of RIPSO option */ 1866 /* */ 1867 /* ------------------------------------------------------------------------ */ 1868 static u_32_t 1869 ipf_checkripso(u_char *s) 1870 { 1871 const struct optlist *sp; 1872 u_short secmsk = 0, auth = 0; 1873 u_char sec; 1874 int j, m; 1875 1876 sec = *(s + 2); /* classification */ 1877 for (j = 3, m = 2; m >= 0; ) { 1878 sp = secopt + j; 1879 if (sec == sp->ol_val) { 1880 secmsk |= sp->ol_bit; 1881 auth = *(s + 3); 1882 auth *= 256; 1883 auth += *(s + 4); 1884 break; 1885 } 1886 if (sec < sp->ol_val) 1887 j -= m; 1888 else 1889 j += m; 1890 m--; 1891 } 1892 1893 return (secmsk << 16) | auth; 1894 } 1895 1896 1897 /* ------------------------------------------------------------------------ */ 1898 /* Function: ipf_checkcipso */ 1899 /* Returns: u_32_t - 0 = failure, else the doi from the header */ 1900 /* Parameters: fin(IO) - pointer to packet information */ 1901 /* s(I) - pointer to start of CIPSO option */ 1902 /* ol(I) - length of CIPSO option field */ 1903 /* */ 1904 /* This function returns the domain of integrity (DOI) field from the CIPSO */ 1905 /* header and returns that whilst also storing the highest sensitivity */ 1906 /* value found in the fr_info_t structure. */ 1907 /* */ 1908 /* No attempt is made to extract the category bitmaps as these are defined */ 1909 /* by the user (rather than the protocol) and can be rather numerous on the */ 1910 /* end nodes. */ 1911 /* ------------------------------------------------------------------------ */ 1912 static u_32_t 1913 ipf_checkcipso(fr_info_t *fin, u_char *s, int ol) 1914 { 1915 ipf_main_softc_t *softc = fin->fin_main_soft; 1916 fr_ip_t *fi; 1917 u_32_t doi; 1918 u_char *t, tag, tlen, sensitivity; 1919 int len; 1920 1921 if (ol < 6 || ol > 40) { 1922 LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_bad); 1923 fin->fin_flx |= FI_BAD; 1924 DT2(ipf_fi_bad_checkcipso_ol, fr_info_t *, fin, u_int, ol); 1925 return (0); 1926 } 1927 1928 fi = &fin->fin_fi; 1929 fi->fi_sensitivity = 0; 1930 /* 1931 * The DOI field MUST be there. 1932 */ 1933 bcopy(s + 2, &doi, sizeof(doi)); 1934 1935 t = (u_char *)s + 6; 1936 for (len = ol - 6; len >= 2; len -= tlen, t+= tlen) { 1937 tag = *t; 1938 tlen = *(t + 1); 1939 if (tlen > len || tlen < 4 || tlen > 34) { 1940 LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_tlen); 1941 fin->fin_flx |= FI_BAD; 1942 DT2(ipf_fi_bad_checkcipso_tlen, fr_info_t *, fin, u_int, tlen); 1943 return (0); 1944 } 1945 1946 sensitivity = 0; 1947 /* 1948 * Tag numbers 0, 1, 2, 5 are laid out in the CIPSO Internet 1949 * draft (16 July 1992) that has expired. 1950 */ 1951 if (tag == 0) { 1952 fin->fin_flx |= FI_BAD; 1953 DT2(ipf_fi_bad_checkcipso_tag, fr_info_t *, fin, u_int, tag); 1954 continue; 1955 } else if (tag == 1) { 1956 if (*(t + 2) != 0) { 1957 fin->fin_flx |= FI_BAD; 1958 DT2(ipf_fi_bad_checkcipso_tag1_t2, fr_info_t *, fin, u_int, (*t + 2)); 1959 continue; 1960 } 1961 sensitivity = *(t + 3); 1962 /* Category bitmap for categories 0-239 */ 1963 1964 } else if (tag == 4) { 1965 if (*(t + 2) != 0) { 1966 fin->fin_flx |= FI_BAD; 1967 DT2(ipf_fi_bad_checkcipso_tag4_t2, fr_info_t *, fin, u_int, (*t + 2)); 1968 continue; 1969 } 1970 sensitivity = *(t + 3); 1971 /* Enumerated categories, 16bits each, upto 15 */ 1972 1973 } else if (tag == 5) { 1974 if (*(t + 2) != 0) { 1975 fin->fin_flx |= FI_BAD; 1976 DT2(ipf_fi_bad_checkcipso_tag5_t2, fr_info_t *, fin, u_int, (*t + 2)); 1977 continue; 1978 } 1979 sensitivity = *(t + 3); 1980 /* Range of categories (2*16bits), up to 7 pairs */ 1981 1982 } else if (tag > 127) { 1983 /* Custom defined DOI */ 1984 ; 1985 } else { 1986 fin->fin_flx |= FI_BAD; 1987 DT2(ipf_fi_bad_checkcipso_tag127, fr_info_t *, fin, u_int, tag); 1988 continue; 1989 } 1990 1991 if (sensitivity > fi->fi_sensitivity) 1992 fi->fi_sensitivity = sensitivity; 1993 } 1994 1995 return (doi); 1996 } 1997 1998 1999 /* ------------------------------------------------------------------------ */ 2000 /* Function: ipf_makefrip */ 2001 /* Returns: int - 0 == packet ok, -1 == packet freed or bad length */ 2002 /* Parameters: hlen(I) - length of IP packet header */ 2003 /* ip(I) - pointer to the IP header */ 2004 /* fin(IO) - pointer to packet information */ 2005 /* */ 2006 /* Compact the IP header into a structure which contains just the info. */ 2007 /* which is useful for comparing IP headers with and store this information */ 2008 /* in the fr_info_t structure pointer to by fin. At present, it is assumed */ 2009 /* this function will be called with either an IPv4 or IPv6 packet. */ 2010 /* ------------------------------------------------------------------------ */ 2011 int 2012 ipf_makefrip(int hlen, ip_t *ip, fr_info_t *fin) 2013 { 2014 ipf_main_softc_t *softc = fin->fin_main_soft; 2015 int v; 2016 2017 fin->fin_depth = 0; 2018 fin->fin_hlen = (u_short)hlen; 2019 fin->fin_ip = ip; 2020 fin->fin_rule = 0xffffffff; 2021 fin->fin_group[0] = -1; 2022 fin->fin_group[1] = '\0'; 2023 fin->fin_dp = (char *)ip + hlen; 2024 2025 v = fin->fin_v; 2026 if (v == 4) { 2027 fin->fin_plen = ntohs(ip->ip_len); 2028 fin->fin_dlen = fin->fin_plen - hlen; 2029 if (fin->fin_m != NULL && fin->fin_m->m_flags & M_PKTHDR && fin->fin_m->m_pkthdr.len < fin->fin_plen) { 2030 LBUMPD(ipf_stats[fin->fin_out], fr_bad); 2031 return (-1); 2032 } else { 2033 ipf_pr_ipv4hdr(fin); 2034 } 2035 #ifdef USE_INET6 2036 } else if (v == 6) { 2037 fin->fin_plen = ntohs(((ip6_t *)ip)->ip6_plen); 2038 fin->fin_dlen = fin->fin_plen; 2039 fin->fin_plen += hlen; 2040 if (fin->fin_m != NULL && fin->fin_m->m_flags & M_PKTHDR && fin->fin_m->m_pkthdr.len < fin->fin_plen) { 2041 LBUMPD(ipf_stats[fin->fin_out], fr_v6_bad); 2042 return (-1); 2043 } else { 2044 ipf_pr_ipv6hdr(fin); 2045 } 2046 #endif 2047 } 2048 if (fin->fin_ip == NULL) { 2049 LBUMP(ipf_stats[fin->fin_out].fr_ip_freed); 2050 return (-1); 2051 } 2052 return (0); 2053 } 2054 2055 2056 /* ------------------------------------------------------------------------ */ 2057 /* Function: ipf_portcheck */ 2058 /* Returns: int - 1 == port matched, 0 == port match failed */ 2059 /* Parameters: frp(I) - pointer to port check `expression' */ 2060 /* pop(I) - port number to evaluate */ 2061 /* */ 2062 /* Perform a comparison of a port number against some other(s), using a */ 2063 /* structure with compare information stored in it. */ 2064 /* ------------------------------------------------------------------------ */ 2065 static inline int 2066 ipf_portcheck(frpcmp_t *frp, u_32_t pop) 2067 { 2068 int err = 1; 2069 u_32_t po; 2070 2071 po = frp->frp_port; 2072 2073 /* 2074 * Do opposite test to that required and continue if that succeeds. 2075 */ 2076 switch (frp->frp_cmp) 2077 { 2078 case FR_EQUAL : 2079 if (pop != po) /* EQUAL */ 2080 err = 0; 2081 break; 2082 case FR_NEQUAL : 2083 if (pop == po) /* NOTEQUAL */ 2084 err = 0; 2085 break; 2086 case FR_LESST : 2087 if (pop >= po) /* LESSTHAN */ 2088 err = 0; 2089 break; 2090 case FR_GREATERT : 2091 if (pop <= po) /* GREATERTHAN */ 2092 err = 0; 2093 break; 2094 case FR_LESSTE : 2095 if (pop > po) /* LT or EQ */ 2096 err = 0; 2097 break; 2098 case FR_GREATERTE : 2099 if (pop < po) /* GT or EQ */ 2100 err = 0; 2101 break; 2102 case FR_OUTRANGE : 2103 if (pop >= po && pop <= frp->frp_top) /* Out of range */ 2104 err = 0; 2105 break; 2106 case FR_INRANGE : 2107 if (pop <= po || pop >= frp->frp_top) /* In range */ 2108 err = 0; 2109 break; 2110 case FR_INCRANGE : 2111 if (pop < po || pop > frp->frp_top) /* Inclusive range */ 2112 err = 0; 2113 break; 2114 default : 2115 break; 2116 } 2117 return (err); 2118 } 2119 2120 2121 /* ------------------------------------------------------------------------ */ 2122 /* Function: ipf_tcpudpchk */ 2123 /* Returns: int - 1 == protocol matched, 0 == check failed */ 2124 /* Parameters: fda(I) - pointer to packet information */ 2125 /* ft(I) - pointer to structure with comparison data */ 2126 /* */ 2127 /* Compares the current pcket (assuming it is TCP/UDP) information with a */ 2128 /* structure containing information that we want to match against. */ 2129 /* ------------------------------------------------------------------------ */ 2130 int 2131 ipf_tcpudpchk(fr_ip_t *fi, frtuc_t *ft) 2132 { 2133 int err = 1; 2134 2135 /* 2136 * Both ports should *always* be in the first fragment. 2137 * So far, I cannot find any cases where they can not be. 2138 * 2139 * compare destination ports 2140 */ 2141 if (ft->ftu_dcmp) 2142 err = ipf_portcheck(&ft->ftu_dst, fi->fi_ports[1]); 2143 2144 /* 2145 * compare source ports 2146 */ 2147 if (err && ft->ftu_scmp) 2148 err = ipf_portcheck(&ft->ftu_src, fi->fi_ports[0]); 2149 2150 /* 2151 * If we don't have all the TCP/UDP header, then how can we 2152 * expect to do any sort of match on it ? If we were looking for 2153 * TCP flags, then NO match. If not, then match (which should 2154 * satisfy the "short" class too). 2155 */ 2156 if (err && (fi->fi_p == IPPROTO_TCP)) { 2157 if (fi->fi_flx & FI_SHORT) 2158 return (!(ft->ftu_tcpf | ft->ftu_tcpfm)); 2159 /* 2160 * Match the flags ? If not, abort this match. 2161 */ 2162 if (ft->ftu_tcpfm && 2163 ft->ftu_tcpf != (fi->fi_tcpf & ft->ftu_tcpfm)) { 2164 FR_DEBUG(("f. %#x & %#x != %#x\n", fi->fi_tcpf, 2165 ft->ftu_tcpfm, ft->ftu_tcpf)); 2166 err = 0; 2167 } 2168 } 2169 return (err); 2170 } 2171 2172 2173 /* ------------------------------------------------------------------------ */ 2174 /* Function: ipf_check_ipf */ 2175 /* Returns: int - 0 == match, else no match */ 2176 /* Parameters: fin(I) - pointer to packet information */ 2177 /* fr(I) - pointer to filter rule */ 2178 /* portcmp(I) - flag indicating whether to attempt matching on */ 2179 /* TCP/UDP port data. */ 2180 /* */ 2181 /* Check to see if a packet matches an IPFilter rule. Checks of addresses, */ 2182 /* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */ 2183 /* this function. */ 2184 /* ------------------------------------------------------------------------ */ 2185 static inline int 2186 ipf_check_ipf(fr_info_t *fin, frentry_t *fr, int portcmp) 2187 { 2188 u_32_t *ld, *lm, *lip; 2189 fripf_t *fri; 2190 fr_ip_t *fi; 2191 int i; 2192 2193 fi = &fin->fin_fi; 2194 fri = fr->fr_ipf; 2195 lip = (u_32_t *)fi; 2196 lm = (u_32_t *)&fri->fri_mip; 2197 ld = (u_32_t *)&fri->fri_ip; 2198 2199 /* 2200 * first 32 bits to check coversion: 2201 * IP version, TOS, TTL, protocol 2202 */ 2203 i = ((*lip & *lm) != *ld); 2204 FR_DEBUG(("0. %#08x & %#08x != %#08x\n", 2205 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2206 if (i) 2207 return (1); 2208 2209 /* 2210 * Next 32 bits is a constructed bitmask indicating which IP options 2211 * are present (if any) in this packet. 2212 */ 2213 lip++, lm++, ld++; 2214 i = ((*lip & *lm) != *ld); 2215 FR_DEBUG(("1. %#08x & %#08x != %#08x\n", 2216 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2217 if (i != 0) 2218 return (1); 2219 2220 lip++, lm++, ld++; 2221 /* 2222 * Unrolled loops (4 each, for 32 bits) for address checks. 2223 */ 2224 /* 2225 * Check the source address. 2226 */ 2227 if (fr->fr_satype == FRI_LOOKUP) { 2228 i = (*fr->fr_srcfunc)(fin->fin_main_soft, fr->fr_srcptr, 2229 fi->fi_v, lip, fin->fin_plen); 2230 if (i == -1) 2231 return (1); 2232 lip += 3; 2233 lm += 3; 2234 ld += 3; 2235 } else { 2236 i = ((*lip & *lm) != *ld); 2237 FR_DEBUG(("2a. %#08x & %#08x != %#08x\n", 2238 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2239 if (fi->fi_v == 6) { 2240 lip++, lm++, ld++; 2241 i |= ((*lip & *lm) != *ld); 2242 FR_DEBUG(("2b. %#08x & %#08x != %#08x\n", 2243 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2244 lip++, lm++, ld++; 2245 i |= ((*lip & *lm) != *ld); 2246 FR_DEBUG(("2c. %#08x & %#08x != %#08x\n", 2247 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2248 lip++, lm++, ld++; 2249 i |= ((*lip & *lm) != *ld); 2250 FR_DEBUG(("2d. %#08x & %#08x != %#08x\n", 2251 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2252 } else { 2253 lip += 3; 2254 lm += 3; 2255 ld += 3; 2256 } 2257 } 2258 i ^= (fr->fr_flags & FR_NOTSRCIP) >> 6; 2259 if (i != 0) 2260 return (1); 2261 2262 /* 2263 * Check the destination address. 2264 */ 2265 lip++, lm++, ld++; 2266 if (fr->fr_datype == FRI_LOOKUP) { 2267 i = (*fr->fr_dstfunc)(fin->fin_main_soft, fr->fr_dstptr, 2268 fi->fi_v, lip, fin->fin_plen); 2269 if (i == -1) 2270 return (1); 2271 lip += 3; 2272 lm += 3; 2273 ld += 3; 2274 } else { 2275 i = ((*lip & *lm) != *ld); 2276 FR_DEBUG(("3a. %#08x & %#08x != %#08x\n", 2277 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2278 if (fi->fi_v == 6) { 2279 lip++, lm++, ld++; 2280 i |= ((*lip & *lm) != *ld); 2281 FR_DEBUG(("3b. %#08x & %#08x != %#08x\n", 2282 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2283 lip++, lm++, ld++; 2284 i |= ((*lip & *lm) != *ld); 2285 FR_DEBUG(("3c. %#08x & %#08x != %#08x\n", 2286 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2287 lip++, lm++, ld++; 2288 i |= ((*lip & *lm) != *ld); 2289 FR_DEBUG(("3d. %#08x & %#08x != %#08x\n", 2290 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2291 } else { 2292 lip += 3; 2293 lm += 3; 2294 ld += 3; 2295 } 2296 } 2297 i ^= (fr->fr_flags & FR_NOTDSTIP) >> 7; 2298 if (i != 0) 2299 return (1); 2300 /* 2301 * IP addresses matched. The next 32bits contains: 2302 * mast of old IP header security & authentication bits. 2303 */ 2304 lip++, lm++, ld++; 2305 i = (*ld - (*lip & *lm)); 2306 FR_DEBUG(("4. %#08x & %#08x != %#08x\n", *lip, *lm, *ld)); 2307 2308 /* 2309 * Next we have 32 bits of packet flags. 2310 */ 2311 lip++, lm++, ld++; 2312 i |= (*ld - (*lip & *lm)); 2313 FR_DEBUG(("5. %#08x & %#08x != %#08x\n", *lip, *lm, *ld)); 2314 2315 if (i == 0) { 2316 /* 2317 * If a fragment, then only the first has what we're 2318 * looking for here... 2319 */ 2320 if (portcmp) { 2321 if (!ipf_tcpudpchk(&fin->fin_fi, &fr->fr_tuc)) 2322 i = 1; 2323 } else { 2324 if (fr->fr_dcmp || fr->fr_scmp || 2325 fr->fr_tcpf || fr->fr_tcpfm) 2326 i = 1; 2327 if (fr->fr_icmpm || fr->fr_icmp) { 2328 if (((fi->fi_p != IPPROTO_ICMP) && 2329 (fi->fi_p != IPPROTO_ICMPV6)) || 2330 fin->fin_off || (fin->fin_dlen < 2)) 2331 i = 1; 2332 else if ((fin->fin_data[0] & fr->fr_icmpm) != 2333 fr->fr_icmp) { 2334 FR_DEBUG(("i. %#x & %#x != %#x\n", 2335 fin->fin_data[0], 2336 fr->fr_icmpm, fr->fr_icmp)); 2337 i = 1; 2338 } 2339 } 2340 } 2341 } 2342 return (i); 2343 } 2344 2345 2346 /* ------------------------------------------------------------------------ */ 2347 /* Function: ipf_scanlist */ 2348 /* Returns: int - result flags of scanning filter list */ 2349 /* Parameters: fin(I) - pointer to packet information */ 2350 /* pass(I) - default result to return for filtering */ 2351 /* */ 2352 /* Check the input/output list of rules for a match to the current packet. */ 2353 /* If a match is found, the value of fr_flags from the rule becomes the */ 2354 /* return value and fin->fin_fr points to the matched rule. */ 2355 /* */ 2356 /* This function may be called recursively upto 16 times (limit inbuilt.) */ 2357 /* When unwinding, it should finish up with fin_depth as 0. */ 2358 /* */ 2359 /* Could be per interface, but this gets real nasty when you don't have, */ 2360 /* or can't easily change, the kernel source code to . */ 2361 /* ------------------------------------------------------------------------ */ 2362 int 2363 ipf_scanlist(fr_info_t *fin, u_32_t pass) 2364 { 2365 ipf_main_softc_t *softc = fin->fin_main_soft; 2366 int rulen, portcmp, off, skip; 2367 struct frentry *fr, *fnext; 2368 u_32_t passt, passo; 2369 2370 /* 2371 * Do not allow nesting deeper than 16 levels. 2372 */ 2373 if (fin->fin_depth >= 16) 2374 return (pass); 2375 2376 fr = fin->fin_fr; 2377 2378 /* 2379 * If there are no rules in this list, return now. 2380 */ 2381 if (fr == NULL) 2382 return (pass); 2383 2384 skip = 0; 2385 portcmp = 0; 2386 fin->fin_depth++; 2387 fin->fin_fr = NULL; 2388 off = fin->fin_off; 2389 2390 if ((fin->fin_flx & FI_TCPUDP) && (fin->fin_dlen > 3) && !off) 2391 portcmp = 1; 2392 2393 for (rulen = 0; fr; fr = fnext, rulen++) { 2394 fnext = fr->fr_next; 2395 if (skip != 0) { 2396 FR_VERBOSE(("SKIP %d (%#x)\n", skip, fr->fr_flags)); 2397 skip--; 2398 continue; 2399 } 2400 2401 /* 2402 * In all checks below, a null (zero) value in the 2403 * filter struture is taken to mean a wildcard. 2404 * 2405 * check that we are working for the right interface 2406 */ 2407 #ifdef _KERNEL 2408 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) 2409 continue; 2410 #else 2411 if (opts & (OPT_VERBOSE|OPT_DEBUG)) 2412 printf("\n"); 2413 FR_VERBOSE(("%c", FR_ISSKIP(pass) ? 's' : 2414 FR_ISPASS(pass) ? 'p' : 2415 FR_ISACCOUNT(pass) ? 'A' : 2416 FR_ISAUTH(pass) ? 'a' : 2417 (pass & FR_NOMATCH) ? 'n' :'b')); 2418 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) 2419 continue; 2420 FR_VERBOSE((":i")); 2421 #endif 2422 2423 switch (fr->fr_type) 2424 { 2425 case FR_T_IPF : 2426 case FR_T_IPF_BUILTIN : 2427 if (ipf_check_ipf(fin, fr, portcmp)) 2428 continue; 2429 break; 2430 #if defined(IPFILTER_BPF) 2431 case FR_T_BPFOPC : 2432 case FR_T_BPFOPC_BUILTIN : 2433 { 2434 u_char *mc; 2435 int wlen; 2436 2437 if (*fin->fin_mp == NULL) 2438 continue; 2439 if (fin->fin_family != fr->fr_family) 2440 continue; 2441 mc = (u_char *)fin->fin_m; 2442 wlen = fin->fin_dlen + fin->fin_hlen; 2443 if (!bpf_filter(fr->fr_data, mc, wlen, 0)) 2444 continue; 2445 break; 2446 } 2447 #endif 2448 case FR_T_CALLFUNC_BUILTIN : 2449 { 2450 frentry_t *f; 2451 2452 f = (*fr->fr_func)(fin, &pass); 2453 if (f != NULL) 2454 fr = f; 2455 else 2456 continue; 2457 break; 2458 } 2459 2460 case FR_T_IPFEXPR : 2461 case FR_T_IPFEXPR_BUILTIN : 2462 if (fin->fin_family != fr->fr_family) 2463 continue; 2464 if (ipf_fr_matcharray(fin, fr->fr_data) == 0) 2465 continue; 2466 break; 2467 2468 default : 2469 break; 2470 } 2471 2472 if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) { 2473 if (fin->fin_nattag == NULL) 2474 continue; 2475 if (ipf_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0) 2476 continue; 2477 } 2478 FR_VERBOSE(("=%d/%d.%d *", fr->fr_grhead, fr->fr_group, rulen)); 2479 2480 passt = fr->fr_flags; 2481 2482 /* 2483 * If the rule is a "call now" rule, then call the function 2484 * in the rule, if it exists and use the results from that. 2485 * If the function pointer is bad, just make like we ignore 2486 * it, except for increasing the hit counter. 2487 */ 2488 if ((passt & FR_CALLNOW) != 0) { 2489 frentry_t *frs; 2490 2491 ATOMIC_INC64(fr->fr_hits); 2492 if ((fr->fr_func == NULL) || 2493 (fr->fr_func == (ipfunc_t)-1)) 2494 continue; 2495 2496 frs = fin->fin_fr; 2497 fin->fin_fr = fr; 2498 fr = (*fr->fr_func)(fin, &passt); 2499 if (fr == NULL) { 2500 fin->fin_fr = frs; 2501 continue; 2502 } 2503 passt = fr->fr_flags; 2504 } 2505 fin->fin_fr = fr; 2506 2507 #ifdef IPFILTER_LOG 2508 /* 2509 * Just log this packet... 2510 */ 2511 if ((passt & FR_LOGMASK) == FR_LOG) { 2512 if (ipf_log_pkt(fin, passt) == -1) { 2513 if (passt & FR_LOGORBLOCK) { 2514 DT(frb_logfail); 2515 passt &= ~FR_CMDMASK; 2516 passt |= FR_BLOCK|FR_QUICK; 2517 fin->fin_reason = FRB_LOGFAIL; 2518 } 2519 } 2520 } 2521 #endif /* IPFILTER_LOG */ 2522 2523 MUTEX_ENTER(&fr->fr_lock); 2524 fr->fr_bytes += (U_QUAD_T)fin->fin_plen; 2525 fr->fr_hits++; 2526 MUTEX_EXIT(&fr->fr_lock); 2527 fin->fin_rule = rulen; 2528 2529 passo = pass; 2530 if (FR_ISSKIP(passt)) { 2531 skip = fr->fr_arg; 2532 continue; 2533 } else if (((passt & FR_LOGMASK) != FR_LOG) && 2534 ((passt & FR_LOGMASK) != FR_DECAPSULATE)) { 2535 pass = passt; 2536 } 2537 2538 if (passt & (FR_RETICMP|FR_FAKEICMP)) 2539 fin->fin_icode = fr->fr_icode; 2540 2541 if (fr->fr_group != -1) { 2542 (void) strncpy(fin->fin_group, 2543 FR_NAME(fr, fr_group), 2544 strlen(FR_NAME(fr, fr_group))); 2545 } else { 2546 fin->fin_group[0] = '\0'; 2547 } 2548 2549 FR_DEBUG(("pass %#x/%#x/%x\n", passo, pass, passt)); 2550 2551 if (fr->fr_grphead != NULL) { 2552 fin->fin_fr = fr->fr_grphead->fg_start; 2553 FR_VERBOSE(("group %s\n", FR_NAME(fr, fr_grhead))); 2554 2555 if (FR_ISDECAPS(passt)) 2556 passt = ipf_decaps(fin, pass, fr->fr_icode); 2557 else 2558 passt = ipf_scanlist(fin, pass); 2559 2560 if (fin->fin_fr == NULL) { 2561 fin->fin_rule = rulen; 2562 if (fr->fr_group != -1) 2563 (void) strncpy(fin->fin_group, 2564 fr->fr_names + 2565 fr->fr_group, 2566 strlen(fr->fr_names + 2567 fr->fr_group)); 2568 fin->fin_fr = fr; 2569 passt = pass; 2570 } 2571 pass = passt; 2572 } 2573 2574 if (pass & FR_QUICK) { 2575 /* 2576 * Finally, if we've asked to track state for this 2577 * packet, set it up. Add state for "quick" rules 2578 * here so that if the action fails we can consider 2579 * the rule to "not match" and keep on processing 2580 * filter rules. 2581 */ 2582 if ((pass & FR_KEEPSTATE) && !FR_ISAUTH(pass) && 2583 !(fin->fin_flx & FI_STATE)) { 2584 int out = fin->fin_out; 2585 2586 fin->fin_fr = fr; 2587 if (ipf_state_add(softc, fin, NULL, 0) == 0) { 2588 LBUMPD(ipf_stats[out], fr_ads); 2589 } else { 2590 LBUMPD(ipf_stats[out], fr_bads); 2591 pass = passo; 2592 continue; 2593 } 2594 } 2595 break; 2596 } 2597 } 2598 fin->fin_depth--; 2599 return (pass); 2600 } 2601 2602 2603 /* ------------------------------------------------------------------------ */ 2604 /* Function: ipf_acctpkt */ 2605 /* Returns: frentry_t* - always returns NULL */ 2606 /* Parameters: fin(I) - pointer to packet information */ 2607 /* passp(IO) - pointer to current/new filter decision (unused) */ 2608 /* */ 2609 /* Checks a packet against accounting rules, if there are any for the given */ 2610 /* IP protocol version. */ 2611 /* */ 2612 /* N.B.: this function returns NULL to match the prototype used by other */ 2613 /* functions called from the IPFilter "mainline" in ipf_check(). */ 2614 /* ------------------------------------------------------------------------ */ 2615 frentry_t * 2616 ipf_acctpkt(fr_info_t *fin, u_32_t *passp __unused) 2617 { 2618 ipf_main_softc_t *softc = fin->fin_main_soft; 2619 char group[FR_GROUPLEN]; 2620 frentry_t *fr, *frsave; 2621 u_32_t pass, rulen; 2622 2623 fr = softc->ipf_acct[fin->fin_out][softc->ipf_active]; 2624 2625 if (fr != NULL) { 2626 frsave = fin->fin_fr; 2627 bcopy(fin->fin_group, group, FR_GROUPLEN); 2628 rulen = fin->fin_rule; 2629 fin->fin_fr = fr; 2630 pass = ipf_scanlist(fin, FR_NOMATCH); 2631 if (FR_ISACCOUNT(pass)) { 2632 LBUMPD(ipf_stats[0], fr_acct); 2633 } 2634 fin->fin_fr = frsave; 2635 bcopy(group, fin->fin_group, FR_GROUPLEN); 2636 fin->fin_rule = rulen; 2637 } 2638 return (NULL); 2639 } 2640 2641 2642 /* ------------------------------------------------------------------------ */ 2643 /* Function: ipf_firewall */ 2644 /* Returns: frentry_t* - returns pointer to matched rule, if no matches */ 2645 /* were found, returns NULL. */ 2646 /* Parameters: fin(I) - pointer to packet information */ 2647 /* passp(IO) - pointer to current/new filter decision (unused) */ 2648 /* */ 2649 /* Applies an appropriate set of firewall rules to the packet, to see if */ 2650 /* there are any matches. The first check is to see if a match can be seen */ 2651 /* in the cache. If not, then search an appropriate list of rules. Once a */ 2652 /* matching rule is found, take any appropriate actions as defined by the */ 2653 /* rule - except logging. */ 2654 /* ------------------------------------------------------------------------ */ 2655 static frentry_t * 2656 ipf_firewall(fr_info_t *fin, u_32_t *passp) 2657 { 2658 ipf_main_softc_t *softc = fin->fin_main_soft; 2659 frentry_t *fr; 2660 u_32_t pass; 2661 int out; 2662 2663 out = fin->fin_out; 2664 pass = *passp; 2665 2666 /* 2667 * This rule cache will only affect packets that are not being 2668 * statefully filtered. 2669 */ 2670 fin->fin_fr = softc->ipf_rules[out][softc->ipf_active]; 2671 if (fin->fin_fr != NULL) 2672 pass = ipf_scanlist(fin, softc->ipf_pass); 2673 2674 if ((pass & FR_NOMATCH)) { 2675 LBUMPD(ipf_stats[out], fr_nom); 2676 } 2677 fr = fin->fin_fr; 2678 2679 /* 2680 * Apply packets per second rate-limiting to a rule as required. 2681 */ 2682 if ((fr != NULL) && (fr->fr_pps != 0) && 2683 !ppsratecheck(&fr->fr_lastpkt, &fr->fr_curpps, fr->fr_pps)) { 2684 DT2(frb_ppsrate, fr_info_t *, fin, frentry_t *, fr); 2685 pass &= ~(FR_CMDMASK|FR_RETICMP|FR_RETRST); 2686 pass |= FR_BLOCK; 2687 LBUMPD(ipf_stats[out], fr_ppshit); 2688 fin->fin_reason = FRB_PPSRATE; 2689 } 2690 2691 /* 2692 * If we fail to add a packet to the authorization queue, then we 2693 * drop the packet later. However, if it was added then pretend 2694 * we've dropped it already. 2695 */ 2696 if (FR_ISAUTH(pass)) { 2697 if (ipf_auth_new(fin->fin_m, fin) != 0) { 2698 DT1(frb_authnew, fr_info_t *, fin); 2699 fin->fin_m = *fin->fin_mp = NULL; 2700 fin->fin_reason = FRB_AUTHNEW; 2701 fin->fin_error = 0; 2702 } else { 2703 IPFERROR(1); 2704 fin->fin_error = ENOSPC; 2705 } 2706 } 2707 2708 if ((fr != NULL) && (fr->fr_func != NULL) && 2709 (fr->fr_func != (ipfunc_t)-1) && !(pass & FR_CALLNOW)) 2710 (void) (*fr->fr_func)(fin, &pass); 2711 2712 /* 2713 * If a rule is a pre-auth rule, check again in the list of rules 2714 * loaded for authenticated use. It does not particulary matter 2715 * if this search fails because a "preauth" result, from a rule, 2716 * is treated as "not a pass", hence the packet is blocked. 2717 */ 2718 if (FR_ISPREAUTH(pass)) { 2719 pass = ipf_auth_pre_scanlist(softc, fin, pass); 2720 } 2721 2722 /* 2723 * If the rule has "keep frag" and the packet is actually a fragment, 2724 * then create a fragment state entry. 2725 */ 2726 if (pass & FR_KEEPFRAG) { 2727 if (fin->fin_flx & FI_FRAG) { 2728 if (ipf_frag_new(softc, fin, pass) == -1) { 2729 LBUMP(ipf_stats[out].fr_bnfr); 2730 } else { 2731 LBUMP(ipf_stats[out].fr_nfr); 2732 } 2733 } else { 2734 LBUMP(ipf_stats[out].fr_cfr); 2735 } 2736 } 2737 2738 fr = fin->fin_fr; 2739 *passp = pass; 2740 2741 return (fr); 2742 } 2743 2744 2745 /* ------------------------------------------------------------------------ */ 2746 /* Function: ipf_check */ 2747 /* Returns: int - 0 == packet allowed through, */ 2748 /* User space: */ 2749 /* -1 == packet blocked */ 2750 /* 1 == packet not matched */ 2751 /* -2 == requires authentication */ 2752 /* Kernel: */ 2753 /* > 0 == filter error # for packet */ 2754 /* Parameters: ctx(I) - pointer to the instance context */ 2755 /* ip(I) - pointer to start of IPv4/6 packet */ 2756 /* hlen(I) - length of header */ 2757 /* ifp(I) - pointer to interface this packet is on */ 2758 /* out(I) - 0 == packet going in, 1 == packet going out */ 2759 /* mp(IO) - pointer to caller's buffer pointer that holds this */ 2760 /* IP packet. */ 2761 /* Solaris: */ 2762 /* qpi(I) - pointer to STREAMS queue information for this */ 2763 /* interface & direction. */ 2764 /* */ 2765 /* ipf_check() is the master function for all IPFilter packet processing. */ 2766 /* It orchestrates: Network Address Translation (NAT), checking for packet */ 2767 /* authorisation (or pre-authorisation), presence of related state info., */ 2768 /* generating log entries, IP packet accounting, routing of packets as */ 2769 /* directed by firewall rules and of course whether or not to allow the */ 2770 /* packet to be further processed by the kernel. */ 2771 /* */ 2772 /* For packets blocked, the contents of "mp" will be NULL'd and the buffer */ 2773 /* freed. Packets passed may be returned with the pointer pointed to by */ 2774 /* by "mp" changed to a new buffer. */ 2775 /* ------------------------------------------------------------------------ */ 2776 int 2777 ipf_check(void *ctx, ip_t *ip, int hlen, struct ifnet *ifp, int out 2778 #if defined(_KERNEL) && SOLARIS 2779 , void* qif, mb_t **mp) 2780 #else 2781 , mb_t **mp) 2782 #endif 2783 { 2784 /* 2785 * The above really sucks, but short of writing a diff 2786 */ 2787 ipf_main_softc_t *softc = ctx; 2788 fr_info_t frinfo; 2789 fr_info_t *fin = &frinfo; 2790 u_32_t pass = softc->ipf_pass; 2791 frentry_t *fr = NULL; 2792 int v = IP_V(ip); 2793 mb_t *mc = NULL; 2794 mb_t *m; 2795 /* 2796 * The first part of ipf_check() deals with making sure that what goes 2797 * into the filtering engine makes some sense. Information about the 2798 * the packet is distilled, collected into a fr_info_t structure and 2799 * the an attempt to ensure the buffer the packet is in is big enough 2800 * to hold all the required packet headers. 2801 */ 2802 #ifdef _KERNEL 2803 # if SOLARIS 2804 qpktinfo_t *qpi = qif; 2805 2806 # ifdef __sparc 2807 if ((u_int)ip & 0x3) 2808 return (2); 2809 # endif 2810 # else 2811 SPL_INT(s); 2812 # endif 2813 2814 if (softc->ipf_running <= 0) { 2815 return (0); 2816 } 2817 2818 bzero((char *)fin, sizeof(*fin)); 2819 2820 # if SOLARIS 2821 if (qpi->qpi_flags & QF_BROADCAST) 2822 fin->fin_flx |= FI_MBCAST|FI_BROADCAST; 2823 if (qpi->qpi_flags & QF_MULTICAST) 2824 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2825 m = qpi->qpi_m; 2826 fin->fin_qfm = m; 2827 fin->fin_qpi = qpi; 2828 # else /* SOLARIS */ 2829 2830 m = *mp; 2831 2832 # if defined(M_MCAST) 2833 if ((m->m_flags & M_MCAST) != 0) 2834 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2835 # endif 2836 # if defined(M_MLOOP) 2837 if ((m->m_flags & M_MLOOP) != 0) 2838 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2839 # endif 2840 # if defined(M_BCAST) 2841 if ((m->m_flags & M_BCAST) != 0) 2842 fin->fin_flx |= FI_MBCAST|FI_BROADCAST; 2843 # endif 2844 # ifdef M_CANFASTFWD 2845 /* 2846 * XXX For now, IP Filter and fast-forwarding of cached flows 2847 * XXX are mutually exclusive. Eventually, IP Filter should 2848 * XXX get a "can-fast-forward" filter rule. 2849 */ 2850 m->m_flags &= ~M_CANFASTFWD; 2851 # endif /* M_CANFASTFWD */ 2852 # if defined(CSUM_DELAY_DATA) && !defined(__FreeBSD__) 2853 /* 2854 * disable delayed checksums. 2855 */ 2856 if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 2857 in_delayed_cksum(m); 2858 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 2859 } 2860 # endif /* CSUM_DELAY_DATA */ 2861 # endif /* SOLARIS */ 2862 #else 2863 bzero((char *)fin, sizeof(*fin)); 2864 m = *mp; 2865 # if defined(M_MCAST) 2866 if ((m->m_flags & M_MCAST) != 0) 2867 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2868 # endif 2869 # if defined(M_MLOOP) 2870 if ((m->m_flags & M_MLOOP) != 0) 2871 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2872 # endif 2873 # if defined(M_BCAST) 2874 if ((m->m_flags & M_BCAST) != 0) 2875 fin->fin_flx |= FI_MBCAST|FI_BROADCAST; 2876 # endif 2877 #endif /* _KERNEL */ 2878 2879 fin->fin_v = v; 2880 fin->fin_m = m; 2881 fin->fin_ip = ip; 2882 fin->fin_mp = mp; 2883 fin->fin_out = out; 2884 fin->fin_ifp = ifp; 2885 fin->fin_error = ENETUNREACH; 2886 fin->fin_hlen = (u_short)hlen; 2887 fin->fin_dp = (char *)ip + hlen; 2888 fin->fin_main_soft = softc; 2889 2890 fin->fin_ipoff = (char *)ip - MTOD(m, char *); 2891 2892 SPL_NET(s); 2893 2894 #ifdef USE_INET6 2895 if (v == 6) { 2896 LBUMP(ipf_stats[out].fr_ipv6); 2897 /* 2898 * Jumbo grams are quite likely too big for internal buffer 2899 * structures to handle comfortably, for now, so just drop 2900 * them. 2901 */ 2902 if (((ip6_t *)ip)->ip6_plen == 0) { 2903 DT1(frb_jumbo, ip6_t *, (ip6_t *)ip); 2904 pass = FR_BLOCK|FR_NOMATCH; 2905 fin->fin_reason = FRB_JUMBO; 2906 goto finished; 2907 } 2908 fin->fin_family = AF_INET6; 2909 } else 2910 #endif 2911 { 2912 fin->fin_family = AF_INET; 2913 } 2914 2915 if (ipf_makefrip(hlen, ip, fin) == -1) { 2916 DT1(frb_makefrip, fr_info_t *, fin); 2917 pass = FR_BLOCK|FR_NOMATCH; 2918 fin->fin_reason = FRB_MAKEFRIP; 2919 goto finished; 2920 } 2921 2922 /* 2923 * For at least IPv6 packets, if a m_pullup() fails then this pointer 2924 * becomes NULL and so we have no packet to free. 2925 */ 2926 if (*fin->fin_mp == NULL) 2927 goto finished; 2928 2929 if (!out) { 2930 if (v == 4) { 2931 if (softc->ipf_chksrc && !ipf_verifysrc(fin)) { 2932 LBUMPD(ipf_stats[0], fr_v4_badsrc); 2933 fin->fin_flx |= FI_BADSRC; 2934 } 2935 if (fin->fin_ip->ip_ttl < softc->ipf_minttl) { 2936 LBUMPD(ipf_stats[0], fr_v4_badttl); 2937 fin->fin_flx |= FI_LOWTTL; 2938 } 2939 } 2940 #ifdef USE_INET6 2941 else if (v == 6) { 2942 if (((ip6_t *)ip)->ip6_hlim < softc->ipf_minttl) { 2943 LBUMPD(ipf_stats[0], fr_v6_badttl); 2944 fin->fin_flx |= FI_LOWTTL; 2945 } 2946 } 2947 #endif 2948 } 2949 2950 if (fin->fin_flx & FI_SHORT) { 2951 LBUMPD(ipf_stats[out], fr_short); 2952 } 2953 2954 READ_ENTER(&softc->ipf_mutex); 2955 2956 if (!out) { 2957 switch (fin->fin_v) 2958 { 2959 case 4 : 2960 if (ipf_nat_checkin(fin, &pass) == -1) { 2961 goto filterdone; 2962 } 2963 break; 2964 #ifdef USE_INET6 2965 case 6 : 2966 if (ipf_nat6_checkin(fin, &pass) == -1) { 2967 goto filterdone; 2968 } 2969 break; 2970 #endif 2971 default : 2972 break; 2973 } 2974 } 2975 /* 2976 * Check auth now. 2977 * If a packet is found in the auth table, then skip checking 2978 * the access lists for permission but we do need to consider 2979 * the result as if it were from the ACL's. In addition, being 2980 * found in the auth table means it has been seen before, so do 2981 * not pass it through accounting (again), lest it be counted twice. 2982 */ 2983 fr = ipf_auth_check(fin, &pass); 2984 if (!out && (fr == NULL)) 2985 (void) ipf_acctpkt(fin, NULL); 2986 2987 if (fr == NULL) { 2988 if ((fin->fin_flx & FI_FRAG) != 0) 2989 fr = ipf_frag_known(fin, &pass); 2990 2991 if (fr == NULL) 2992 fr = ipf_state_check(fin, &pass); 2993 } 2994 2995 if ((pass & FR_NOMATCH) || (fr == NULL)) 2996 fr = ipf_firewall(fin, &pass); 2997 2998 /* 2999 * If we've asked to track state for this packet, set it up. 3000 * Here rather than ipf_firewall because ipf_checkauth may decide 3001 * to return a packet for "keep state" 3002 */ 3003 if ((pass & FR_KEEPSTATE) && (fin->fin_m != NULL) && 3004 !(fin->fin_flx & FI_STATE)) { 3005 if (ipf_state_add(softc, fin, NULL, 0) == 0) { 3006 LBUMP(ipf_stats[out].fr_ads); 3007 } else { 3008 LBUMP(ipf_stats[out].fr_bads); 3009 if (FR_ISPASS(pass)) { 3010 DT(frb_stateadd); 3011 pass &= ~FR_CMDMASK; 3012 pass |= FR_BLOCK; 3013 fin->fin_reason = FRB_STATEADD; 3014 } 3015 } 3016 } 3017 3018 fin->fin_fr = fr; 3019 if ((fr != NULL) && !(fin->fin_flx & FI_STATE)) { 3020 fin->fin_dif = &fr->fr_dif; 3021 fin->fin_tif = &fr->fr_tifs[fin->fin_rev]; 3022 } 3023 3024 /* 3025 * Only count/translate packets which will be passed on, out the 3026 * interface. 3027 */ 3028 if (out && FR_ISPASS(pass)) { 3029 (void) ipf_acctpkt(fin, NULL); 3030 3031 switch (fin->fin_v) 3032 { 3033 case 4 : 3034 if (ipf_nat_checkout(fin, &pass) == -1) { 3035 ; 3036 } else if ((softc->ipf_update_ipid != 0) && (v == 4)) { 3037 if (ipf_updateipid(fin) == -1) { 3038 DT(frb_updateipid); 3039 LBUMP(ipf_stats[1].fr_ipud); 3040 pass &= ~FR_CMDMASK; 3041 pass |= FR_BLOCK; 3042 fin->fin_reason = FRB_UPDATEIPID; 3043 } else { 3044 LBUMP(ipf_stats[0].fr_ipud); 3045 } 3046 } 3047 break; 3048 #ifdef USE_INET6 3049 case 6 : 3050 (void) ipf_nat6_checkout(fin, &pass); 3051 break; 3052 #endif 3053 default : 3054 break; 3055 } 3056 } 3057 3058 filterdone: 3059 #ifdef IPFILTER_LOG 3060 if ((softc->ipf_flags & FF_LOGGING) || (pass & FR_LOGMASK)) { 3061 (void) ipf_dolog(fin, &pass); 3062 } 3063 #endif 3064 3065 /* 3066 * The FI_STATE flag is cleared here so that calling ipf_state_check 3067 * will work when called from inside of fr_fastroute. Although 3068 * there is a similar flag, FI_NATED, for NAT, it does have the same 3069 * impact on code execution. 3070 */ 3071 fin->fin_flx &= ~FI_STATE; 3072 3073 #if defined(FASTROUTE_RECURSION) 3074 /* 3075 * Up the reference on fr_lock and exit ipf_mutex. The generation of 3076 * a packet below can sometimes cause a recursive call into IPFilter. 3077 * On those platforms where that does happen, we need to hang onto 3078 * the filter rule just in case someone decides to remove or flush it 3079 * in the meantime. 3080 */ 3081 if (fr != NULL) { 3082 MUTEX_ENTER(&fr->fr_lock); 3083 fr->fr_ref++; 3084 MUTEX_EXIT(&fr->fr_lock); 3085 } 3086 3087 RWLOCK_EXIT(&softc->ipf_mutex); 3088 #endif 3089 3090 if ((pass & FR_RETMASK) != 0) { 3091 /* 3092 * Should we return an ICMP packet to indicate error 3093 * status passing through the packet filter ? 3094 * WARNING: ICMP error packets AND TCP RST packets should 3095 * ONLY be sent in repsonse to incoming packets. Sending 3096 * them in response to outbound packets can result in a 3097 * panic on some operating systems. 3098 */ 3099 if (!out) { 3100 if (pass & FR_RETICMP) { 3101 int dst; 3102 3103 if ((pass & FR_RETMASK) == FR_FAKEICMP) 3104 dst = 1; 3105 else 3106 dst = 0; 3107 (void) ipf_send_icmp_err(ICMP_UNREACH, fin, 3108 dst); 3109 LBUMP(ipf_stats[0].fr_ret); 3110 } else if (((pass & FR_RETMASK) == FR_RETRST) && 3111 !(fin->fin_flx & FI_SHORT)) { 3112 if (((fin->fin_flx & FI_OOW) != 0) || 3113 (ipf_send_reset(fin) == 0)) { 3114 LBUMP(ipf_stats[1].fr_ret); 3115 } 3116 } 3117 3118 /* 3119 * When using return-* with auth rules, the auth code 3120 * takes over disposing of this packet. 3121 */ 3122 if (FR_ISAUTH(pass) && (fin->fin_m != NULL)) { 3123 DT1(frb_authcapture, fr_info_t *, fin); 3124 fin->fin_m = *fin->fin_mp = NULL; 3125 fin->fin_reason = FRB_AUTHCAPTURE; 3126 m = NULL; 3127 } 3128 } else { 3129 if (pass & FR_RETRST) { 3130 fin->fin_error = ECONNRESET; 3131 } 3132 } 3133 } 3134 3135 /* 3136 * After the above so that ICMP unreachables and TCP RSTs get 3137 * created properly. 3138 */ 3139 if (FR_ISBLOCK(pass) && (fin->fin_flx & FI_NEWNAT)) 3140 ipf_nat_uncreate(fin); 3141 3142 /* 3143 * If we didn't drop off the bottom of the list of rules (and thus 3144 * the 'current' rule fr is not NULL), then we may have some extra 3145 * instructions about what to do with a packet. 3146 * Once we're finished return to our caller, freeing the packet if 3147 * we are dropping it. 3148 */ 3149 if (fr != NULL) { 3150 frdest_t *fdp; 3151 3152 /* 3153 * Generate a duplicated packet first because ipf_fastroute 3154 * can lead to fin_m being free'd... not good. 3155 */ 3156 fdp = fin->fin_dif; 3157 if ((fdp != NULL) && (fdp->fd_ptr != NULL) && 3158 (fdp->fd_ptr != (void *)-1)) { 3159 mc = M_COPY(fin->fin_m); 3160 if (mc != NULL) 3161 ipf_fastroute(mc, &mc, fin, fdp); 3162 } 3163 3164 fdp = fin->fin_tif; 3165 if (!out && (pass & FR_FASTROUTE)) { 3166 /* 3167 * For fastroute rule, no destination interface defined 3168 * so pass NULL as the frdest_t parameter 3169 */ 3170 (void) ipf_fastroute(fin->fin_m, mp, fin, NULL); 3171 m = *mp = NULL; 3172 } else if ((fdp != NULL) && (fdp->fd_ptr != NULL) && 3173 (fdp->fd_ptr != (struct ifnet *)-1)) { 3174 /* this is for to rules: */ 3175 ipf_fastroute(fin->fin_m, mp, fin, fdp); 3176 m = *mp = NULL; 3177 } 3178 3179 #if defined(FASTROUTE_RECURSION) 3180 (void) ipf_derefrule(softc, &fr); 3181 #endif 3182 } 3183 #if !defined(FASTROUTE_RECURSION) 3184 RWLOCK_EXIT(&softc->ipf_mutex); 3185 #endif 3186 3187 finished: 3188 if (!FR_ISPASS(pass)) { 3189 LBUMP(ipf_stats[out].fr_block); 3190 if (*mp != NULL) { 3191 #ifdef _KERNEL 3192 FREE_MB_T(*mp); 3193 #endif 3194 m = *mp = NULL; 3195 } 3196 } else { 3197 LBUMP(ipf_stats[out].fr_pass); 3198 } 3199 3200 SPL_X(s); 3201 3202 if (fin->fin_m == NULL && fin->fin_flx & FI_BAD && 3203 fin->fin_reason == FRB_PULLUP) { 3204 /* m_pullup() has freed the mbuf */ 3205 LBUMP(ipf_stats[out].fr_blocked[fin->fin_reason]); 3206 return (-1); 3207 } 3208 3209 3210 #ifdef _KERNEL 3211 if (FR_ISPASS(pass)) 3212 return (0); 3213 LBUMP(ipf_stats[out].fr_blocked[fin->fin_reason]); 3214 return (fin->fin_error); 3215 #else /* _KERNEL */ 3216 if (*mp != NULL) 3217 (*mp)->mb_ifp = fin->fin_ifp; 3218 blockreason = fin->fin_reason; 3219 FR_VERBOSE(("fin_flx %#x pass %#x ", fin->fin_flx, pass)); 3220 /*if ((pass & FR_CMDMASK) == (softc->ipf_pass & FR_CMDMASK))*/ 3221 if ((pass & FR_NOMATCH) != 0) 3222 return (1); 3223 3224 if ((pass & FR_RETMASK) != 0) 3225 switch (pass & FR_RETMASK) 3226 { 3227 case FR_RETRST : 3228 return (3); 3229 case FR_RETICMP : 3230 return (4); 3231 case FR_FAKEICMP : 3232 return (5); 3233 } 3234 3235 switch (pass & FR_CMDMASK) 3236 { 3237 case FR_PASS : 3238 return (0); 3239 case FR_BLOCK : 3240 return (-1); 3241 case FR_AUTH : 3242 return (-2); 3243 case FR_ACCOUNT : 3244 return (-3); 3245 case FR_PREAUTH : 3246 return (-4); 3247 } 3248 return (2); 3249 #endif /* _KERNEL */ 3250 } 3251 3252 3253 #ifdef IPFILTER_LOG 3254 /* ------------------------------------------------------------------------ */ 3255 /* Function: ipf_dolog */ 3256 /* Returns: frentry_t* - returns contents of fin_fr (no change made) */ 3257 /* Parameters: fin(I) - pointer to packet information */ 3258 /* passp(IO) - pointer to current/new filter decision (unused) */ 3259 /* */ 3260 /* Checks flags set to see how a packet should be logged, if it is to be */ 3261 /* logged. Adjust statistics based on its success or not. */ 3262 /* ------------------------------------------------------------------------ */ 3263 frentry_t * 3264 ipf_dolog(fr_info_t *fin, u_32_t *passp) 3265 { 3266 ipf_main_softc_t *softc = fin->fin_main_soft; 3267 u_32_t pass; 3268 int out; 3269 3270 out = fin->fin_out; 3271 pass = *passp; 3272 3273 if ((softc->ipf_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) { 3274 pass |= FF_LOGNOMATCH; 3275 LBUMPD(ipf_stats[out], fr_npkl); 3276 goto logit; 3277 3278 } else if (((pass & FR_LOGMASK) == FR_LOGP) || 3279 (FR_ISPASS(pass) && (softc->ipf_flags & FF_LOGPASS))) { 3280 if ((pass & FR_LOGMASK) != FR_LOGP) 3281 pass |= FF_LOGPASS; 3282 LBUMPD(ipf_stats[out], fr_ppkl); 3283 goto logit; 3284 3285 } else if (((pass & FR_LOGMASK) == FR_LOGB) || 3286 (FR_ISBLOCK(pass) && (softc->ipf_flags & FF_LOGBLOCK))) { 3287 if ((pass & FR_LOGMASK) != FR_LOGB) 3288 pass |= FF_LOGBLOCK; 3289 LBUMPD(ipf_stats[out], fr_bpkl); 3290 3291 logit: 3292 if (ipf_log_pkt(fin, pass) == -1) { 3293 /* 3294 * If the "or-block" option has been used then 3295 * block the packet if we failed to log it. 3296 */ 3297 if ((pass & FR_LOGORBLOCK) && FR_ISPASS(pass)) { 3298 DT1(frb_logfail2, u_int, pass); 3299 pass &= ~FR_CMDMASK; 3300 pass |= FR_BLOCK; 3301 fin->fin_reason = FRB_LOGFAIL2; 3302 } 3303 } 3304 *passp = pass; 3305 } 3306 3307 return (fin->fin_fr); 3308 } 3309 #endif /* IPFILTER_LOG */ 3310 3311 3312 /* ------------------------------------------------------------------------ */ 3313 /* Function: ipf_cksum */ 3314 /* Returns: u_short - IP header checksum */ 3315 /* Parameters: addr(I) - pointer to start of buffer to checksum */ 3316 /* len(I) - length of buffer in bytes */ 3317 /* */ 3318 /* Calculate the two's complement 16 bit checksum of the buffer passed. */ 3319 /* */ 3320 /* N.B.: addr should be 16bit aligned. */ 3321 /* ------------------------------------------------------------------------ */ 3322 u_short 3323 ipf_cksum(u_short *addr, int len) 3324 { 3325 u_32_t sum = 0; 3326 3327 for (sum = 0; len > 1; len -= 2) 3328 sum += *addr++; 3329 3330 /* mop up an odd byte, if necessary */ 3331 if (len == 1) 3332 sum += *(u_char *)addr; 3333 3334 /* 3335 * add back carry outs from top 16 bits to low 16 bits 3336 */ 3337 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 3338 sum += (sum >> 16); /* add carry */ 3339 return (u_short)(~sum); 3340 } 3341 3342 3343 /* ------------------------------------------------------------------------ */ 3344 /* Function: fr_cksum */ 3345 /* Returns: u_short - layer 4 checksum */ 3346 /* Parameters: fin(I) - pointer to packet information */ 3347 /* ip(I) - pointer to IP header */ 3348 /* l4proto(I) - protocol to caclulate checksum for */ 3349 /* l4hdr(I) - pointer to layer 4 header */ 3350 /* */ 3351 /* Calculates the TCP checksum for the packet held in "m", using the data */ 3352 /* in the IP header "ip" to seed it. */ 3353 /* */ 3354 /* NB: This function assumes we've pullup'd enough for all of the IP header */ 3355 /* and the TCP header. We also assume that data blocks aren't allocated in */ 3356 /* odd sizes. */ 3357 /* */ 3358 /* Expects ip_len and ip_off to be in network byte order when called. */ 3359 /* ------------------------------------------------------------------------ */ 3360 u_short 3361 fr_cksum(fr_info_t *fin, ip_t *ip, int l4proto, void *l4hdr) 3362 { 3363 u_short *sp, slen, sumsave, *csump; 3364 u_int sum, sum2; 3365 int hlen; 3366 int off; 3367 #ifdef USE_INET6 3368 ip6_t *ip6; 3369 #endif 3370 3371 csump = NULL; 3372 sumsave = 0; 3373 sp = NULL; 3374 slen = 0; 3375 hlen = 0; 3376 sum = 0; 3377 3378 sum = htons((u_short)l4proto); 3379 /* 3380 * Add up IP Header portion 3381 */ 3382 #ifdef USE_INET6 3383 if (IP_V(ip) == 4) { 3384 #endif 3385 hlen = IP_HL(ip) << 2; 3386 off = hlen; 3387 sp = (u_short *)&ip->ip_src; 3388 sum += *sp++; /* ip_src */ 3389 sum += *sp++; 3390 sum += *sp++; /* ip_dst */ 3391 sum += *sp++; 3392 slen = fin->fin_plen - off; 3393 sum += htons(slen); 3394 #ifdef USE_INET6 3395 } else if (IP_V(ip) == 6) { 3396 mb_t *m; 3397 3398 m = fin->fin_m; 3399 ip6 = (ip6_t *)ip; 3400 off = ((caddr_t)ip6 - m->m_data) + sizeof(struct ip6_hdr); 3401 int len = ntohs(ip6->ip6_plen) - (off - sizeof(*ip6)); 3402 return (ipf_pcksum6(m, ip6, off, len)); 3403 } else { 3404 return (0xffff); 3405 } 3406 #endif 3407 3408 switch (l4proto) 3409 { 3410 case IPPROTO_UDP : 3411 csump = &((udphdr_t *)l4hdr)->uh_sum; 3412 break; 3413 3414 case IPPROTO_TCP : 3415 csump = &((tcphdr_t *)l4hdr)->th_sum; 3416 break; 3417 case IPPROTO_ICMP : 3418 csump = &((icmphdr_t *)l4hdr)->icmp_cksum; 3419 sum = 0; /* Pseudo-checksum is not included */ 3420 break; 3421 #ifdef USE_INET6 3422 case IPPROTO_ICMPV6 : 3423 csump = &((struct icmp6_hdr *)l4hdr)->icmp6_cksum; 3424 break; 3425 #endif 3426 default : 3427 break; 3428 } 3429 3430 if (csump != NULL) { 3431 sumsave = *csump; 3432 *csump = 0; 3433 } 3434 3435 sum2 = ipf_pcksum(fin, off, sum); 3436 if (csump != NULL) 3437 *csump = sumsave; 3438 return (sum2); 3439 } 3440 3441 3442 /* ------------------------------------------------------------------------ */ 3443 /* Function: ipf_findgroup */ 3444 /* Returns: frgroup_t * - NULL = group not found, else pointer to group */ 3445 /* Parameters: softc(I) - pointer to soft context main structure */ 3446 /* group(I) - group name to search for */ 3447 /* unit(I) - device to which this group belongs */ 3448 /* set(I) - which set of rules (inactive/inactive) this is */ 3449 /* fgpp(O) - pointer to place to store pointer to the pointer */ 3450 /* to where to add the next (last) group or where */ 3451 /* to delete group from. */ 3452 /* */ 3453 /* Search amongst the defined groups for a particular group number. */ 3454 /* ------------------------------------------------------------------------ */ 3455 frgroup_t * 3456 ipf_findgroup(ipf_main_softc_t *softc, char *group, minor_t unit, int set, 3457 frgroup_t ***fgpp) 3458 { 3459 frgroup_t *fg, **fgp; 3460 3461 /* 3462 * Which list of groups to search in is dependent on which list of 3463 * rules are being operated on. 3464 */ 3465 fgp = &softc->ipf_groups[unit][set]; 3466 3467 while ((fg = *fgp) != NULL) { 3468 if (strncmp(group, fg->fg_name, FR_GROUPLEN) == 0) 3469 break; 3470 else 3471 fgp = &fg->fg_next; 3472 } 3473 if (fgpp != NULL) 3474 *fgpp = fgp; 3475 return (fg); 3476 } 3477 3478 3479 /* ------------------------------------------------------------------------ */ 3480 /* Function: ipf_group_add */ 3481 /* Returns: frgroup_t * - NULL == did not create group, */ 3482 /* != NULL == pointer to the group */ 3483 /* Parameters: softc(I) - pointer to soft context main structure */ 3484 /* num(I) - group number to add */ 3485 /* head(I) - rule pointer that is using this as the head */ 3486 /* flags(I) - rule flags which describe the type of rule it is */ 3487 /* unit(I) - device to which this group will belong to */ 3488 /* set(I) - which set of rules (inactive/inactive) this is */ 3489 /* Write Locks: ipf_mutex */ 3490 /* */ 3491 /* Add a new group head, or if it already exists, increase the reference */ 3492 /* count to it. */ 3493 /* ------------------------------------------------------------------------ */ 3494 frgroup_t * 3495 ipf_group_add(ipf_main_softc_t *softc, char *group, void *head, u_32_t flags, 3496 minor_t unit, int set) 3497 { 3498 frgroup_t *fg, **fgp; 3499 u_32_t gflags; 3500 3501 if (group == NULL) 3502 return (NULL); 3503 3504 if (unit == IPL_LOGIPF && *group == '\0') 3505 return (NULL); 3506 3507 fgp = NULL; 3508 gflags = flags & FR_INOUT; 3509 3510 fg = ipf_findgroup(softc, group, unit, set, &fgp); 3511 if (fg != NULL) { 3512 if (fg->fg_head == NULL && head != NULL) 3513 fg->fg_head = head; 3514 if (fg->fg_flags == 0) 3515 fg->fg_flags = gflags; 3516 else if (gflags != fg->fg_flags) 3517 return (NULL); 3518 fg->fg_ref++; 3519 return (fg); 3520 } 3521 3522 KMALLOC(fg, frgroup_t *); 3523 if (fg != NULL) { 3524 fg->fg_head = head; 3525 fg->fg_start = NULL; 3526 fg->fg_next = *fgp; 3527 bcopy(group, fg->fg_name, strnlen(group, FR_GROUPLEN) + 1); 3528 fg->fg_flags = gflags; 3529 fg->fg_ref = 1; 3530 fg->fg_set = &softc->ipf_groups[unit][set]; 3531 *fgp = fg; 3532 } 3533 return (fg); 3534 } 3535 3536 3537 /* ------------------------------------------------------------------------ */ 3538 /* Function: ipf_group_del */ 3539 /* Returns: int - number of rules deleted */ 3540 /* Parameters: softc(I) - pointer to soft context main structure */ 3541 /* group(I) - group name to delete */ 3542 /* fr(I) - filter rule from which group is referenced */ 3543 /* Write Locks: ipf_mutex */ 3544 /* */ 3545 /* This function is called whenever a reference to a group is to be dropped */ 3546 /* and thus its reference count needs to be lowered and the group free'd if */ 3547 /* the reference count reaches zero. Passing in fr is really for the sole */ 3548 /* purpose of knowing when the head rule is being deleted. */ 3549 /* ------------------------------------------------------------------------ */ 3550 void 3551 ipf_group_del(ipf_main_softc_t *softc, frgroup_t *group, frentry_t *fr) 3552 { 3553 3554 if (group->fg_head == fr) 3555 group->fg_head = NULL; 3556 3557 group->fg_ref--; 3558 if ((group->fg_ref == 0) && (group->fg_start == NULL)) 3559 ipf_group_free(group); 3560 } 3561 3562 3563 /* ------------------------------------------------------------------------ */ 3564 /* Function: ipf_group_free */ 3565 /* Returns: Nil */ 3566 /* Parameters: group(I) - pointer to filter rule group */ 3567 /* */ 3568 /* Remove the group from the list of groups and free it. */ 3569 /* ------------------------------------------------------------------------ */ 3570 static void 3571 ipf_group_free(frgroup_t *group) 3572 { 3573 frgroup_t **gp; 3574 3575 for (gp = group->fg_set; *gp != NULL; gp = &(*gp)->fg_next) { 3576 if (*gp == group) { 3577 *gp = group->fg_next; 3578 break; 3579 } 3580 } 3581 KFREE(group); 3582 } 3583 3584 3585 /* ------------------------------------------------------------------------ */ 3586 /* Function: ipf_group_flush */ 3587 /* Returns: int - number of rules flush from group */ 3588 /* Parameters: softc(I) - pointer to soft context main structure */ 3589 /* Parameters: group(I) - pointer to filter rule group */ 3590 /* */ 3591 /* Remove all of the rules that currently are listed under the given group. */ 3592 /* ------------------------------------------------------------------------ */ 3593 static int 3594 ipf_group_flush(ipf_main_softc_t *softc, frgroup_t *group) 3595 { 3596 int gone = 0; 3597 3598 (void) ipf_flushlist(softc, &gone, &group->fg_start); 3599 3600 return (gone); 3601 } 3602 3603 3604 /* ------------------------------------------------------------------------ */ 3605 /* Function: ipf_getrulen */ 3606 /* Returns: frentry_t * - NULL == not found, else pointer to rule n */ 3607 /* Parameters: softc(I) - pointer to soft context main structure */ 3608 /* Parameters: unit(I) - device for which to count the rule's number */ 3609 /* flags(I) - which set of rules to find the rule in */ 3610 /* group(I) - group name */ 3611 /* n(I) - rule number to find */ 3612 /* */ 3613 /* Find rule # n in group # g and return a pointer to it. Return NULl if */ 3614 /* group # g doesn't exist or there are less than n rules in the group. */ 3615 /* ------------------------------------------------------------------------ */ 3616 frentry_t * 3617 ipf_getrulen(ipf_main_softc_t *softc, int unit, char *group, u_32_t n) 3618 { 3619 frentry_t *fr; 3620 frgroup_t *fg; 3621 3622 fg = ipf_findgroup(softc, group, unit, softc->ipf_active, NULL); 3623 if (fg == NULL) 3624 return (NULL); 3625 for (fr = fg->fg_start; fr && n; fr = fr->fr_next, n--) 3626 ; 3627 if (n != 0) 3628 return (NULL); 3629 return (fr); 3630 } 3631 3632 3633 /* ------------------------------------------------------------------------ */ 3634 /* Function: ipf_flushlist */ 3635 /* Returns: int - >= 0 - number of flushed rules */ 3636 /* Parameters: softc(I) - pointer to soft context main structure */ 3637 /* nfreedp(O) - pointer to int where flush count is stored */ 3638 /* listp(I) - pointer to list to flush pointer */ 3639 /* Write Locks: ipf_mutex */ 3640 /* */ 3641 /* Recursively flush rules from the list, descending groups as they are */ 3642 /* encountered. if a rule is the head of a group and it has lost all its */ 3643 /* group members, then also delete the group reference. nfreedp is needed */ 3644 /* to store the accumulating count of rules removed, whereas the returned */ 3645 /* value is just the number removed from the current list. The latter is */ 3646 /* needed to correctly adjust reference counts on rules that define groups. */ 3647 /* */ 3648 /* NOTE: Rules not loaded from user space cannot be flushed. */ 3649 /* ------------------------------------------------------------------------ */ 3650 static int 3651 ipf_flushlist(ipf_main_softc_t *softc, int *nfreedp, frentry_t **listp) 3652 { 3653 int freed = 0; 3654 frentry_t *fp; 3655 3656 while ((fp = *listp) != NULL) { 3657 if ((fp->fr_type & FR_T_BUILTIN) || 3658 !(fp->fr_flags & FR_COPIED)) { 3659 listp = &fp->fr_next; 3660 continue; 3661 } 3662 *listp = fp->fr_next; 3663 if (fp->fr_next != NULL) 3664 fp->fr_next->fr_pnext = fp->fr_pnext; 3665 fp->fr_pnext = NULL; 3666 3667 if (fp->fr_grphead != NULL) { 3668 freed += ipf_group_flush(softc, fp->fr_grphead); 3669 fp->fr_names[fp->fr_grhead] = '\0'; 3670 } 3671 3672 if (fp->fr_icmpgrp != NULL) { 3673 freed += ipf_group_flush(softc, fp->fr_icmpgrp); 3674 fp->fr_names[fp->fr_icmphead] = '\0'; 3675 } 3676 3677 if (fp->fr_srctrack.ht_max_nodes) 3678 ipf_rb_ht_flush(&fp->fr_srctrack); 3679 3680 fp->fr_next = NULL; 3681 3682 ASSERT(fp->fr_ref > 0); 3683 if (ipf_derefrule(softc, &fp) == 0) 3684 freed++; 3685 } 3686 *nfreedp += freed; 3687 return (freed); 3688 } 3689 3690 3691 /* ------------------------------------------------------------------------ */ 3692 /* Function: ipf_flush */ 3693 /* Returns: int - >= 0 - number of flushed rules */ 3694 /* Parameters: softc(I) - pointer to soft context main structure */ 3695 /* unit(I) - device for which to flush rules */ 3696 /* flags(I) - which set of rules to flush */ 3697 /* */ 3698 /* Calls flushlist() for all filter rules (accounting, firewall - both IPv4 */ 3699 /* and IPv6) as defined by the value of flags. */ 3700 /* ------------------------------------------------------------------------ */ 3701 int 3702 ipf_flush(ipf_main_softc_t *softc, minor_t unit, int flags) 3703 { 3704 int flushed = 0, set; 3705 3706 WRITE_ENTER(&softc->ipf_mutex); 3707 3708 set = softc->ipf_active; 3709 if ((flags & FR_INACTIVE) == FR_INACTIVE) 3710 set = 1 - set; 3711 3712 if (flags & FR_OUTQUE) { 3713 ipf_flushlist(softc, &flushed, &softc->ipf_rules[1][set]); 3714 ipf_flushlist(softc, &flushed, &softc->ipf_acct[1][set]); 3715 } 3716 if (flags & FR_INQUE) { 3717 ipf_flushlist(softc, &flushed, &softc->ipf_rules[0][set]); 3718 ipf_flushlist(softc, &flushed, &softc->ipf_acct[0][set]); 3719 } 3720 3721 flushed += ipf_flush_groups(softc, &softc->ipf_groups[unit][set], 3722 flags & (FR_INQUE|FR_OUTQUE)); 3723 3724 RWLOCK_EXIT(&softc->ipf_mutex); 3725 3726 if (unit == IPL_LOGIPF) { 3727 int tmp; 3728 3729 tmp = ipf_flush(softc, IPL_LOGCOUNT, flags); 3730 if (tmp >= 0) 3731 flushed += tmp; 3732 } 3733 return (flushed); 3734 } 3735 3736 3737 /* ------------------------------------------------------------------------ */ 3738 /* Function: ipf_flush_groups */ 3739 /* Returns: int - >= 0 - number of flushed rules */ 3740 /* Parameters: softc(I) - soft context pointerto work with */ 3741 /* grhead(I) - pointer to the start of the group list to flush */ 3742 /* flags(I) - which set of rules to flush */ 3743 /* */ 3744 /* Walk through all of the groups under the given group head and remove all */ 3745 /* of those that match the flags passed in. The for loop here is bit more */ 3746 /* complicated than usual because the removal of a rule with ipf_derefrule */ 3747 /* may end up removing not only the structure pointed to by "fg" but also */ 3748 /* what is fg_next and fg_next after that. So if a filter rule is actually */ 3749 /* removed from the group then it is necessary to start again. */ 3750 /* ------------------------------------------------------------------------ */ 3751 static int 3752 ipf_flush_groups(ipf_main_softc_t *softc, frgroup_t **grhead, int flags) 3753 { 3754 frentry_t *fr, **frp; 3755 frgroup_t *fg, **fgp; 3756 int flushed = 0; 3757 int removed = 0; 3758 3759 for (fgp = grhead; (fg = *fgp) != NULL; ) { 3760 while ((fg != NULL) && ((fg->fg_flags & flags) == 0)) 3761 fg = fg->fg_next; 3762 if (fg == NULL) 3763 break; 3764 removed = 0; 3765 frp = &fg->fg_start; 3766 while ((removed == 0) && ((fr = *frp) != NULL)) { 3767 if ((fr->fr_flags & flags) == 0) { 3768 frp = &fr->fr_next; 3769 } else { 3770 if (fr->fr_next != NULL) 3771 fr->fr_next->fr_pnext = fr->fr_pnext; 3772 *frp = fr->fr_next; 3773 fr->fr_pnext = NULL; 3774 fr->fr_next = NULL; 3775 (void) ipf_derefrule(softc, &fr); 3776 flushed++; 3777 removed++; 3778 } 3779 } 3780 if (removed == 0) 3781 fgp = &fg->fg_next; 3782 } 3783 return (flushed); 3784 } 3785 3786 3787 /* ------------------------------------------------------------------------ */ 3788 /* Function: memstr */ 3789 /* Returns: char * - NULL if failed, != NULL pointer to matching bytes */ 3790 /* Parameters: src(I) - pointer to byte sequence to match */ 3791 /* dst(I) - pointer to byte sequence to search */ 3792 /* slen(I) - match length */ 3793 /* dlen(I) - length available to search in */ 3794 /* */ 3795 /* Search dst for a sequence of bytes matching those at src and extend for */ 3796 /* slen bytes. */ 3797 /* ------------------------------------------------------------------------ */ 3798 char * 3799 memstr(const char *src, char *dst, size_t slen, size_t dlen) 3800 { 3801 char *s = NULL; 3802 3803 while (dlen >= slen) { 3804 if (bcmp(src, dst, slen) == 0) { 3805 s = dst; 3806 break; 3807 } 3808 dst++; 3809 dlen--; 3810 } 3811 return (s); 3812 } 3813 /* ------------------------------------------------------------------------ */ 3814 /* Function: ipf_fixskip */ 3815 /* Returns: Nil */ 3816 /* Parameters: listp(IO) - pointer to start of list with skip rule */ 3817 /* rp(I) - rule added/removed with skip in it. */ 3818 /* addremove(I) - adjustment (-1/+1) to make to skip count, */ 3819 /* depending on whether a rule was just added */ 3820 /* or removed. */ 3821 /* */ 3822 /* Adjust all the rules in a list which would have skip'd past the position */ 3823 /* where we are inserting to skip to the right place given the change. */ 3824 /* ------------------------------------------------------------------------ */ 3825 void 3826 ipf_fixskip(frentry_t **listp, frentry_t *rp, int addremove) 3827 { 3828 int rules, rn; 3829 frentry_t *fp; 3830 3831 rules = 0; 3832 for (fp = *listp; (fp != NULL) && (fp != rp); fp = fp->fr_next) 3833 rules++; 3834 3835 if (fp == NULL) 3836 return; 3837 3838 for (rn = 0, fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++) 3839 if (FR_ISSKIP(fp->fr_flags) && (rn + fp->fr_arg >= rules)) 3840 fp->fr_arg += addremove; 3841 } 3842 3843 3844 #ifdef _KERNEL 3845 /* ------------------------------------------------------------------------ */ 3846 /* Function: count4bits */ 3847 /* Returns: int - >= 0 - number of consecutive bits in input */ 3848 /* Parameters: ip(I) - 32bit IP address */ 3849 /* */ 3850 /* IPv4 ONLY */ 3851 /* count consecutive 1's in bit mask. If the mask generated by counting */ 3852 /* consecutive 1's is different to that passed, return -1, else return # */ 3853 /* of bits. */ 3854 /* ------------------------------------------------------------------------ */ 3855 int 3856 count4bits(u_32_t ip) 3857 { 3858 u_32_t ipn; 3859 int cnt = 0, i, j; 3860 3861 ip = ipn = ntohl(ip); 3862 for (i = 32; i; i--, ipn *= 2) 3863 if (ipn & 0x80000000) 3864 cnt++; 3865 else 3866 break; 3867 ipn = 0; 3868 for (i = 32, j = cnt; i; i--, j--) { 3869 ipn *= 2; 3870 if (j > 0) 3871 ipn++; 3872 } 3873 if (ipn == ip) 3874 return (cnt); 3875 return (-1); 3876 } 3877 3878 3879 /* ------------------------------------------------------------------------ */ 3880 /* Function: count6bits */ 3881 /* Returns: int - >= 0 - number of consecutive bits in input */ 3882 /* Parameters: msk(I) - pointer to start of IPv6 bitmask */ 3883 /* */ 3884 /* IPv6 ONLY */ 3885 /* count consecutive 1's in bit mask. */ 3886 /* ------------------------------------------------------------------------ */ 3887 # ifdef USE_INET6 3888 int 3889 count6bits(u_32_t *msk) 3890 { 3891 int i = 0, k; 3892 u_32_t j; 3893 3894 for (k = 3; k >= 0; k--) 3895 if (msk[k] == 0xffffffff) 3896 i += 32; 3897 else { 3898 for (j = msk[k]; j; j <<= 1) 3899 if (j & 0x80000000) 3900 i++; 3901 } 3902 return (i); 3903 } 3904 # endif 3905 #endif /* _KERNEL */ 3906 3907 3908 /* ------------------------------------------------------------------------ */ 3909 /* Function: ipf_synclist */ 3910 /* Returns: int - 0 = no failures, else indication of first failure */ 3911 /* Parameters: fr(I) - start of filter list to sync interface names for */ 3912 /* ifp(I) - interface pointer for limiting sync lookups */ 3913 /* Write Locks: ipf_mutex */ 3914 /* */ 3915 /* Walk through a list of filter rules and resolve any interface names into */ 3916 /* pointers. Where dynamic addresses are used, also update the IP address */ 3917 /* used in the rule. The interface pointer is used to limit the lookups to */ 3918 /* a specific set of matching names if it is non-NULL. */ 3919 /* Errors can occur when resolving the destination name of to/dup-to fields */ 3920 /* when the name points to a pool and that pool doest not exist. If this */ 3921 /* does happen then it is necessary to check if there are any lookup refs */ 3922 /* that need to be dropped before returning with an error. */ 3923 /* ------------------------------------------------------------------------ */ 3924 static int 3925 ipf_synclist(ipf_main_softc_t *softc, frentry_t *fr, void *ifp) 3926 { 3927 frentry_t *frt, *start = fr; 3928 frdest_t *fdp; 3929 char *name; 3930 int error, interr; 3931 void *ifa; 3932 int v, i; 3933 3934 error = 0; 3935 3936 for (; fr; fr = fr->fr_next) { 3937 if (fr->fr_family == AF_INET) 3938 v = 4; 3939 else if (fr->fr_family == AF_INET6) 3940 v = 6; 3941 else 3942 v = 0; 3943 3944 /* 3945 * Lookup all the interface names that are part of the rule. 3946 */ 3947 for (i = 0; i < FR_NUM(fr->fr_ifas); i++) { 3948 if ((ifp != NULL) && (fr->fr_ifas[i] != ifp)) 3949 continue; 3950 if (fr->fr_ifnames[i] == -1) 3951 continue; 3952 name = FR_NAME(fr, fr_ifnames[i]); 3953 fr->fr_ifas[i] = ipf_resolvenic(softc, name, v); 3954 } 3955 3956 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) { 3957 /* 3958 * We do the validation for fr_sifpidx here because 3959 * it is a union that contains an offset only when 3960 * fr_sifpidx points to an interface name, an offset 3961 * into fr_names. The union is an offset into 3962 * fr_names in this case only. 3963 * 3964 * Note that sifpidx is only used in ipf_sync() which 3965 * implments ipf -y. 3966 */ 3967 if ((interr = ipf_check_names_string(fr->fr_names, fr->fr_namelen, fr->fr_sifpidx)) != 0) { 3968 IPFERROR(interr_tbl[interr-1]); 3969 error = EINVAL; 3970 goto unwind; 3971 } 3972 if (fr->fr_satype != FRI_NORMAL && 3973 fr->fr_satype != FRI_LOOKUP) { 3974 ifa = ipf_resolvenic(softc, fr->fr_names + 3975 fr->fr_sifpidx, v); 3976 ipf_ifpaddr(softc, v, fr->fr_satype, ifa, 3977 &fr->fr_src6, &fr->fr_smsk6); 3978 } 3979 if (fr->fr_datype != FRI_NORMAL && 3980 fr->fr_datype != FRI_LOOKUP) { 3981 ifa = ipf_resolvenic(softc, fr->fr_names + 3982 fr->fr_sifpidx, v); 3983 ipf_ifpaddr(softc, v, fr->fr_datype, ifa, 3984 &fr->fr_dst6, &fr->fr_dmsk6); 3985 } 3986 } 3987 3988 fdp = &fr->fr_tifs[0]; 3989 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) { 3990 error = ipf_resolvedest(softc, fr->fr_names, fdp, v); 3991 if (error != 0) 3992 goto unwind; 3993 } 3994 3995 fdp = &fr->fr_tifs[1]; 3996 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) { 3997 error = ipf_resolvedest(softc, fr->fr_names, fdp, v); 3998 if (error != 0) 3999 goto unwind; 4000 } 4001 4002 fdp = &fr->fr_dif; 4003 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) { 4004 error = ipf_resolvedest(softc, fr->fr_names, fdp, v); 4005 if (error != 0) 4006 goto unwind; 4007 } 4008 4009 if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 4010 (fr->fr_satype == FRI_LOOKUP) && (fr->fr_srcptr == NULL)) { 4011 fr->fr_srcptr = ipf_lookup_res_num(softc, 4012 fr->fr_srctype, 4013 IPL_LOGIPF, 4014 fr->fr_srcnum, 4015 &fr->fr_srcfunc); 4016 } 4017 if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 4018 (fr->fr_datype == FRI_LOOKUP) && (fr->fr_dstptr == NULL)) { 4019 fr->fr_dstptr = ipf_lookup_res_num(softc, 4020 fr->fr_dsttype, 4021 IPL_LOGIPF, 4022 fr->fr_dstnum, 4023 &fr->fr_dstfunc); 4024 } 4025 } 4026 return (0); 4027 4028 unwind: 4029 for (frt = start; frt != fr; fr = fr->fr_next) { 4030 if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 4031 (frt->fr_satype == FRI_LOOKUP) && (frt->fr_srcptr != NULL)) 4032 ipf_lookup_deref(softc, frt->fr_srctype, 4033 frt->fr_srcptr); 4034 if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 4035 (frt->fr_datype == FRI_LOOKUP) && (frt->fr_dstptr != NULL)) 4036 ipf_lookup_deref(softc, frt->fr_dsttype, 4037 frt->fr_dstptr); 4038 } 4039 return (error); 4040 } 4041 4042 4043 /* ------------------------------------------------------------------------ */ 4044 /* Function: ipf_sync */ 4045 /* Returns: void */ 4046 /* Parameters: Nil */ 4047 /* */ 4048 /* ipf_sync() is called when we suspect that the interface list or */ 4049 /* information about interfaces (like IP#) has changed. Go through all */ 4050 /* filter rules, NAT entries and the state table and check if anything */ 4051 /* needs to be changed/updated. */ 4052 /* ------------------------------------------------------------------------ */ 4053 int 4054 ipf_sync(ipf_main_softc_t *softc, void *ifp) 4055 { 4056 int i; 4057 4058 #if !SOLARIS 4059 ipf_nat_sync(softc, ifp); 4060 ipf_state_sync(softc, ifp); 4061 ipf_lookup_sync(softc, ifp); 4062 #endif 4063 4064 WRITE_ENTER(&softc->ipf_mutex); 4065 (void) ipf_synclist(softc, softc->ipf_acct[0][softc->ipf_active], ifp); 4066 (void) ipf_synclist(softc, softc->ipf_acct[1][softc->ipf_active], ifp); 4067 (void) ipf_synclist(softc, softc->ipf_rules[0][softc->ipf_active], ifp); 4068 (void) ipf_synclist(softc, softc->ipf_rules[1][softc->ipf_active], ifp); 4069 4070 for (i = 0; i < IPL_LOGSIZE; i++) { 4071 frgroup_t *g; 4072 4073 for (g = softc->ipf_groups[i][0]; g != NULL; g = g->fg_next) 4074 (void) ipf_synclist(softc, g->fg_start, ifp); 4075 for (g = softc->ipf_groups[i][1]; g != NULL; g = g->fg_next) 4076 (void) ipf_synclist(softc, g->fg_start, ifp); 4077 } 4078 RWLOCK_EXIT(&softc->ipf_mutex); 4079 4080 return (0); 4081 } 4082 4083 4084 /* 4085 * In the functions below, bcopy() is called because the pointer being 4086 * copied _from_ in this instance is a pointer to a char buf (which could 4087 * end up being unaligned) and on the kernel's local stack. 4088 */ 4089 /* ------------------------------------------------------------------------ */ 4090 /* Function: ipf_copyin_indirect */ 4091 /* Returns: int - 0 = success, else failure */ 4092 /* Parameters: src(I) - pointer to the source address */ 4093 /* dst(I) - destination address */ 4094 /* size(I) - number of bytes to copy */ 4095 /* */ 4096 /* Copy a block of data in from user space, given a pointer to the pointer */ 4097 /* to start copying from (src) and a pointer to where to store it (dst). */ 4098 /* NB: src - pointer to user space pointer, dst - kernel space pointer */ 4099 /* ------------------------------------------------------------------------ */ 4100 int 4101 ipf_copyin_indirect(ipf_main_softc_t *softc, void *src, void *dst, size_t size) 4102 { 4103 caddr_t ca; 4104 int error; 4105 4106 #if SOLARIS 4107 error = COPYIN(src, &ca, sizeof(ca)); 4108 if (error != 0) 4109 return (error); 4110 #else 4111 bcopy(src, (caddr_t)&ca, sizeof(ca)); 4112 #endif 4113 error = COPYIN(ca, dst, size); 4114 if (error != 0) { 4115 IPFERROR(3); 4116 error = EFAULT; 4117 } 4118 return (error); 4119 } 4120 4121 4122 /* ------------------------------------------------------------------------ */ 4123 /* Function: ipf_copyout_indirect */ 4124 /* Returns: int - 0 = success, else failure */ 4125 /* Parameters: src(I) - pointer to the source address */ 4126 /* dst(I) - destination address */ 4127 /* size(I) - number of bytes to copy */ 4128 /* */ 4129 /* Copy a block of data out to user space, given a pointer to the pointer */ 4130 /* to start copying from (src) and a pointer to where to store it (dst). */ 4131 /* NB: src - kernel space pointer, dst - pointer to user space pointer. */ 4132 /* ------------------------------------------------------------------------ */ 4133 int 4134 ipf_copyout_indirect(ipf_main_softc_t *softc, void *src, void *dst, size_t size) 4135 { 4136 caddr_t ca; 4137 int error; 4138 4139 bcopy(dst, (caddr_t)&ca, sizeof(ca)); 4140 error = COPYOUT(src, ca, size); 4141 if (error != 0) { 4142 IPFERROR(4); 4143 error = EFAULT; 4144 } 4145 return (error); 4146 } 4147 4148 4149 /* ------------------------------------------------------------------------ */ 4150 /* Function: ipf_lock */ 4151 /* Returns: int - 0 = success, else error */ 4152 /* Parameters: data(I) - pointer to lock value to set */ 4153 /* lockp(O) - pointer to location to store old lock value */ 4154 /* */ 4155 /* Get the new value for the lock integer, set it and return the old value */ 4156 /* in *lockp. */ 4157 /* ------------------------------------------------------------------------ */ 4158 int 4159 ipf_lock(caddr_t data, int *lockp) 4160 { 4161 int arg, err; 4162 4163 err = BCOPYIN(data, &arg, sizeof(arg)); 4164 if (err != 0) 4165 return (EFAULT); 4166 err = BCOPYOUT(lockp, data, sizeof(*lockp)); 4167 if (err != 0) 4168 return (EFAULT); 4169 *lockp = arg; 4170 return (0); 4171 } 4172 4173 4174 /* ------------------------------------------------------------------------ */ 4175 /* Function: ipf_getstat */ 4176 /* Returns: Nil */ 4177 /* Parameters: softc(I) - pointer to soft context main structure */ 4178 /* fiop(I) - pointer to ipfilter stats structure */ 4179 /* rev(I) - version claim by program doing ioctl */ 4180 /* */ 4181 /* Stores a copy of current pointers, counters, etc, in the friostat */ 4182 /* structure. */ 4183 /* If IPFILTER_COMPAT is compiled, we pretend to be whatever version the */ 4184 /* program is looking for. This ensure that validation of the version it */ 4185 /* expects will always succeed. Thus kernels with IPFILTER_COMPAT will */ 4186 /* allow older binaries to work but kernels without it will not. */ 4187 /* ------------------------------------------------------------------------ */ 4188 /*ARGSUSED*/ 4189 static void 4190 ipf_getstat(ipf_main_softc_t *softc, friostat_t *fiop, int rev) 4191 { 4192 int i; 4193 4194 bcopy((char *)softc->ipf_stats, (char *)fiop->f_st, 4195 sizeof(ipf_statistics_t) * 2); 4196 fiop->f_locks[IPL_LOGSTATE] = -1; 4197 fiop->f_locks[IPL_LOGNAT] = -1; 4198 fiop->f_locks[IPL_LOGIPF] = -1; 4199 fiop->f_locks[IPL_LOGAUTH] = -1; 4200 4201 fiop->f_ipf[0][0] = softc->ipf_rules[0][0]; 4202 fiop->f_acct[0][0] = softc->ipf_acct[0][0]; 4203 fiop->f_ipf[0][1] = softc->ipf_rules[0][1]; 4204 fiop->f_acct[0][1] = softc->ipf_acct[0][1]; 4205 fiop->f_ipf[1][0] = softc->ipf_rules[1][0]; 4206 fiop->f_acct[1][0] = softc->ipf_acct[1][0]; 4207 fiop->f_ipf[1][1] = softc->ipf_rules[1][1]; 4208 fiop->f_acct[1][1] = softc->ipf_acct[1][1]; 4209 4210 fiop->f_ticks = softc->ipf_ticks; 4211 fiop->f_active = softc->ipf_active; 4212 fiop->f_froute[0] = softc->ipf_frouteok[0]; 4213 fiop->f_froute[1] = softc->ipf_frouteok[1]; 4214 fiop->f_rb_no_mem = softc->ipf_rb_no_mem; 4215 fiop->f_rb_node_max = softc->ipf_rb_node_max; 4216 4217 fiop->f_running = softc->ipf_running; 4218 for (i = 0; i < IPL_LOGSIZE; i++) { 4219 fiop->f_groups[i][0] = softc->ipf_groups[i][0]; 4220 fiop->f_groups[i][1] = softc->ipf_groups[i][1]; 4221 } 4222 #ifdef IPFILTER_LOG 4223 fiop->f_log_ok = ipf_log_logok(softc, IPL_LOGIPF); 4224 fiop->f_log_fail = ipf_log_failures(softc, IPL_LOGIPF); 4225 fiop->f_logging = 1; 4226 #else 4227 fiop->f_log_ok = 0; 4228 fiop->f_log_fail = 0; 4229 fiop->f_logging = 0; 4230 #endif 4231 fiop->f_defpass = softc->ipf_pass; 4232 fiop->f_features = ipf_features; 4233 4234 #ifdef IPFILTER_COMPAT 4235 snprintf(fiop->f_version, sizeof(friostat.f_version), "IP Filter: v%d.%d.%d", 4236 (rev / 1000000) % 100, 4237 (rev / 10000) % 100, 4238 (rev / 100) % 100); 4239 #else 4240 (void)rev; /* UNUSED */ 4241 (void) strncpy(fiop->f_version, ipfilter_version, 4242 sizeof(fiop->f_version)); 4243 #endif 4244 } 4245 4246 4247 #ifdef USE_INET6 4248 int icmptoicmp6types[ICMP_MAXTYPE+1] = { 4249 ICMP6_ECHO_REPLY, /* 0: ICMP_ECHOREPLY */ 4250 -1, /* 1: UNUSED */ 4251 -1, /* 2: UNUSED */ 4252 ICMP6_DST_UNREACH, /* 3: ICMP_UNREACH */ 4253 -1, /* 4: ICMP_SOURCEQUENCH */ 4254 ND_REDIRECT, /* 5: ICMP_REDIRECT */ 4255 -1, /* 6: UNUSED */ 4256 -1, /* 7: UNUSED */ 4257 ICMP6_ECHO_REQUEST, /* 8: ICMP_ECHO */ 4258 -1, /* 9: UNUSED */ 4259 -1, /* 10: UNUSED */ 4260 ICMP6_TIME_EXCEEDED, /* 11: ICMP_TIMXCEED */ 4261 ICMP6_PARAM_PROB, /* 12: ICMP_PARAMPROB */ 4262 -1, /* 13: ICMP_TSTAMP */ 4263 -1, /* 14: ICMP_TSTAMPREPLY */ 4264 -1, /* 15: ICMP_IREQ */ 4265 -1, /* 16: ICMP_IREQREPLY */ 4266 -1, /* 17: ICMP_MASKREQ */ 4267 -1, /* 18: ICMP_MASKREPLY */ 4268 }; 4269 4270 4271 int icmptoicmp6unreach[ICMP_MAX_UNREACH] = { 4272 ICMP6_DST_UNREACH_ADDR, /* 0: ICMP_UNREACH_NET */ 4273 ICMP6_DST_UNREACH_ADDR, /* 1: ICMP_UNREACH_HOST */ 4274 -1, /* 2: ICMP_UNREACH_PROTOCOL */ 4275 ICMP6_DST_UNREACH_NOPORT, /* 3: ICMP_UNREACH_PORT */ 4276 -1, /* 4: ICMP_UNREACH_NEEDFRAG */ 4277 ICMP6_DST_UNREACH_NOTNEIGHBOR, /* 5: ICMP_UNREACH_SRCFAIL */ 4278 ICMP6_DST_UNREACH_ADDR, /* 6: ICMP_UNREACH_NET_UNKNOWN */ 4279 ICMP6_DST_UNREACH_ADDR, /* 7: ICMP_UNREACH_HOST_UNKNOWN */ 4280 -1, /* 8: ICMP_UNREACH_ISOLATED */ 4281 ICMP6_DST_UNREACH_ADMIN, /* 9: ICMP_UNREACH_NET_PROHIB */ 4282 ICMP6_DST_UNREACH_ADMIN, /* 10: ICMP_UNREACH_HOST_PROHIB */ 4283 -1, /* 11: ICMP_UNREACH_TOSNET */ 4284 -1, /* 12: ICMP_UNREACH_TOSHOST */ 4285 ICMP6_DST_UNREACH_ADMIN, /* 13: ICMP_UNREACH_ADMIN_PROHIBIT */ 4286 }; 4287 int icmpreplytype6[ICMP6_MAXTYPE + 1]; 4288 #endif 4289 4290 int icmpreplytype4[ICMP_MAXTYPE + 1]; 4291 4292 4293 /* ------------------------------------------------------------------------ */ 4294 /* Function: ipf_matchicmpqueryreply */ 4295 /* Returns: int - 1 if "icmp" is a valid reply to "ic" else 0. */ 4296 /* Parameters: v(I) - IP protocol version (4 or 6) */ 4297 /* ic(I) - ICMP information */ 4298 /* icmp(I) - ICMP packet header */ 4299 /* rev(I) - direction (0 = forward/1 = reverse) of packet */ 4300 /* */ 4301 /* Check if the ICMP packet defined by the header pointed to by icmp is a */ 4302 /* reply to one as described by what's in ic. If it is a match, return 1, */ 4303 /* else return 0 for no match. */ 4304 /* ------------------------------------------------------------------------ */ 4305 int 4306 ipf_matchicmpqueryreply(int v, icmpinfo_t *ic, icmphdr_t *icmp, int rev) 4307 { 4308 int ictype; 4309 4310 ictype = ic->ici_type; 4311 4312 if (v == 4) { 4313 /* 4314 * If we matched its type on the way in, then when going out 4315 * it will still be the same type. 4316 */ 4317 if ((!rev && (icmp->icmp_type == ictype)) || 4318 (rev && (icmpreplytype4[ictype] == icmp->icmp_type))) { 4319 if (icmp->icmp_type != ICMP_ECHOREPLY) 4320 return (1); 4321 if (icmp->icmp_id == ic->ici_id) 4322 return (1); 4323 } 4324 } 4325 #ifdef USE_INET6 4326 else if (v == 6) { 4327 if ((!rev && (icmp->icmp_type == ictype)) || 4328 (rev && (icmpreplytype6[ictype] == icmp->icmp_type))) { 4329 if (icmp->icmp_type != ICMP6_ECHO_REPLY) 4330 return (1); 4331 if (icmp->icmp_id == ic->ici_id) 4332 return (1); 4333 } 4334 } 4335 #endif 4336 return (0); 4337 } 4338 4339 4340 /* 4341 * IFNAMES are located in the variable length field starting at 4342 * frentry.fr_names. As pointers within the struct cannot be passed 4343 * to the kernel from ipf(8), an offset is used. An offset of -1 means it 4344 * is unused (invalid). If it is used (valid) it is an offset to the 4345 * character string of an interface name or a comment. The following 4346 * macros will assist those who follow to understand the code. 4347 */ 4348 #define IPF_IFNAME_VALID(_a) (_a != -1) 4349 #define IPF_IFNAME_INVALID(_a) (_a == -1) 4350 #define IPF_IFNAMES_DIFFERENT(_a) \ 4351 !((IPF_IFNAME_INVALID(fr1->_a) && \ 4352 IPF_IFNAME_INVALID(fr2->_a)) || \ 4353 (IPF_IFNAME_VALID(fr1->_a) && \ 4354 IPF_IFNAME_VALID(fr2->_a) && \ 4355 !strcmp(FR_NAME(fr1, _a), FR_NAME(fr2, _a)))) 4356 #define IPF_FRDEST_DIFFERENT(_a) \ 4357 (memcmp(&fr1->_a.fd_addr, &fr2->_a.fd_addr, \ 4358 offsetof(frdest_t, fd_name) - offsetof(frdest_t, fd_addr)) || \ 4359 IPF_IFNAMES_DIFFERENT(_a.fd_name)) 4360 4361 4362 /* ------------------------------------------------------------------------ */ 4363 /* Function: ipf_rule_compare */ 4364 /* Parameters: fr1(I) - first rule structure to compare */ 4365 /* fr2(I) - second rule structure to compare */ 4366 /* Returns: int - 0 == rules are the same, else mismatch */ 4367 /* */ 4368 /* Compare two rules and return 0 if they match or a number indicating */ 4369 /* which of the individual checks failed. */ 4370 /* ------------------------------------------------------------------------ */ 4371 static int 4372 ipf_rule_compare(frentry_t *fr1, frentry_t *fr2) 4373 { 4374 int i; 4375 4376 if (fr1->fr_cksum != fr2->fr_cksum) 4377 return (1); 4378 if (fr1->fr_size != fr2->fr_size) 4379 return (2); 4380 if (fr1->fr_dsize != fr2->fr_dsize) 4381 return (3); 4382 if (bcmp((char *)&fr1->fr_func, (char *)&fr2->fr_func, FR_CMPSIZ) 4383 != 0) 4384 return (4); 4385 /* 4386 * XXX: There is still a bug here as different rules with the 4387 * the same interfaces but in a different order will compare 4388 * differently. But since multiple interfaces in a rule doesn't 4389 * work anyway a simple straightforward compare is performed 4390 * here. Ultimately frentry_t creation will need to be 4391 * revisited in ipf_y.y. While the other issue, recognition 4392 * of only the first interface in a list of interfaces will 4393 * need to be separately addressed along with why only four. 4394 */ 4395 for (i = 0; i < FR_NUM(fr1->fr_ifnames); i++) { 4396 /* 4397 * XXX: It's either the same index or uninitialized. 4398 * We assume this because multiple interfaces 4399 * referenced by the same rule doesn't work anyway. 4400 */ 4401 if (IPF_IFNAMES_DIFFERENT(fr_ifnames[i])) 4402 return (5); 4403 } 4404 4405 if (IPF_FRDEST_DIFFERENT(fr_tif)) 4406 return (6); 4407 if (IPF_FRDEST_DIFFERENT(fr_rif)) 4408 return (7); 4409 if (IPF_FRDEST_DIFFERENT(fr_dif)) 4410 return (8); 4411 if (!fr1->fr_data && !fr2->fr_data) 4412 return (0); /* move along, nothing to see here */ 4413 if (fr1->fr_data && fr2->fr_data) { 4414 if (bcmp(fr1->fr_caddr, fr2->fr_caddr, fr1->fr_dsize) == 0) 4415 return (0); /* same */ 4416 } 4417 return (9); 4418 } 4419 4420 4421 /* ------------------------------------------------------------------------ */ 4422 /* Function: frrequest */ 4423 /* Returns: int - 0 == success, > 0 == errno value */ 4424 /* Parameters: unit(I) - device for which this is for */ 4425 /* req(I) - ioctl command (SIOC*) */ 4426 /* data(I) - pointr to ioctl data */ 4427 /* set(I) - 1 or 0 (filter set) */ 4428 /* makecopy(I) - flag indicating whether data points to a rule */ 4429 /* in kernel space & hence doesn't need copying. */ 4430 /* */ 4431 /* This function handles all the requests which operate on the list of */ 4432 /* filter rules. This includes adding, deleting, insertion. It is also */ 4433 /* responsible for creating groups when a "head" rule is loaded. Interface */ 4434 /* names are resolved here and other sanity checks are made on the content */ 4435 /* of the rule structure being loaded. If a rule has user defined timeouts */ 4436 /* then make sure they are created and initialised before exiting. */ 4437 /* ------------------------------------------------------------------------ */ 4438 int 4439 frrequest(ipf_main_softc_t *softc, int unit, ioctlcmd_t req, caddr_t data, 4440 int set, int makecopy) 4441 { 4442 int error = 0, in, family, need_free = 0, interr, i; 4443 enum { OP_ADD, /* add rule */ 4444 OP_REM, /* remove rule */ 4445 OP_ZERO /* zero statistics and counters */ } 4446 addrem = OP_ADD; 4447 frentry_t frd, *fp, *f, **fprev, **ftail; 4448 void *ptr, *uptr; 4449 u_int *p, *pp; 4450 frgroup_t *fg; 4451 char *group; 4452 4453 ptr = NULL; 4454 fg = NULL; 4455 fp = &frd; 4456 if (makecopy != 0) { 4457 bzero(fp, sizeof(frd)); 4458 error = ipf_inobj(softc, data, NULL, fp, IPFOBJ_FRENTRY); 4459 if (error) { 4460 return (error); 4461 } 4462 if ((fp->fr_type & FR_T_BUILTIN) != 0) { 4463 IPFERROR(6); 4464 return (EINVAL); 4465 } 4466 if (fp->fr_size < sizeof(frd)) { 4467 return (EINVAL); 4468 } 4469 if (sizeof(frd) + fp->fr_namelen != fp->fr_size ) { 4470 IPFERROR(155); 4471 return (EINVAL); 4472 } 4473 if (fp->fr_namelen < 0 || fp->fr_namelen > softc->ipf_max_namelen) { 4474 IPFERROR(156); 4475 return (EINVAL); 4476 } 4477 KMALLOCS(f, frentry_t *, fp->fr_size); 4478 if (f == NULL) { 4479 IPFERROR(131); 4480 return (ENOMEM); 4481 } 4482 bzero(f, fp->fr_size); 4483 error = ipf_inobjsz(softc, data, f, IPFOBJ_FRENTRY, 4484 fp->fr_size); 4485 if (error) { 4486 KFREES(f, fp->fr_size); 4487 return (error); 4488 } 4489 4490 fp = f; 4491 f = NULL; 4492 fp->fr_next = NULL; 4493 fp->fr_dnext = NULL; 4494 fp->fr_pnext = NULL; 4495 fp->fr_pdnext = NULL; 4496 fp->fr_grp = NULL; 4497 fp->fr_grphead = NULL; 4498 fp->fr_icmpgrp = NULL; 4499 fp->fr_isc = (void *)-1; 4500 fp->fr_ptr = NULL; 4501 fp->fr_ref = 0; 4502 fp->fr_flags |= FR_COPIED; 4503 4504 for (i = 0; i <= 3; i++) { 4505 if ((interr = ipf_check_names_string(fp->fr_names, fp->fr_namelen, fp->fr_ifnames[i])) != 0) { 4506 IPFERROR(interr_tbl[interr-1]); 4507 error = EINVAL; 4508 goto donenolock; 4509 } 4510 } 4511 if ((interr = ipf_check_names_string(fp->fr_names, fp->fr_namelen, fp->fr_comment)) != 0) { 4512 IPFERROR(interr_tbl[interr-1]); 4513 error = EINVAL; 4514 goto donenolock; 4515 } 4516 if ((interr = ipf_check_names_string(fp->fr_names, fp->fr_namelen, fp->fr_group)) != 0) { 4517 IPFERROR(interr_tbl[interr-1]); 4518 error = EINVAL; 4519 goto donenolock; 4520 } 4521 if ((interr = ipf_check_names_string(fp->fr_names, fp->fr_namelen, fp->fr_grhead)) != 0) { 4522 IPFERROR(interr_tbl[interr-1]); 4523 error = EINVAL; 4524 goto donenolock; 4525 } 4526 if ((interr = ipf_check_names_string(fp->fr_names, fp->fr_namelen, fp->fr_tif.fd_name)) != 0) { 4527 IPFERROR(interr_tbl[interr-1]); 4528 error = EINVAL; 4529 goto donenolock; 4530 } 4531 if ((interr = ipf_check_names_string(fp->fr_names, fp->fr_namelen, fp->fr_rif.fd_name)) != 0) { 4532 IPFERROR(interr_tbl[interr-1]); 4533 error = EINVAL; 4534 goto donenolock; 4535 } 4536 if ((interr = ipf_check_names_string(fp->fr_names, fp->fr_namelen, fp->fr_dif.fd_name)) != 0) { 4537 IPFERROR(interr_tbl[interr-1]); 4538 error = EINVAL; 4539 goto donenolock; 4540 } 4541 } else { 4542 fp = (frentry_t *)data; 4543 if ((fp->fr_type & FR_T_BUILTIN) == 0) { 4544 IPFERROR(7); 4545 return (EINVAL); 4546 } 4547 fp->fr_flags &= ~FR_COPIED; 4548 } 4549 4550 if (((fp->fr_dsize == 0) && (fp->fr_data != NULL)) || 4551 ((fp->fr_dsize != 0) && (fp->fr_data == NULL))) { 4552 IPFERROR(8); 4553 error = EINVAL; 4554 goto donenolock; 4555 } 4556 4557 family = fp->fr_family; 4558 uptr = fp->fr_data; 4559 4560 if (req == (ioctlcmd_t)SIOCINAFR || req == (ioctlcmd_t)SIOCINIFR || 4561 req == (ioctlcmd_t)SIOCADAFR || req == (ioctlcmd_t)SIOCADIFR) 4562 addrem = OP_ADD; /* Add rule */ 4563 else if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR) 4564 addrem = OP_REM; /* Remove rule */ 4565 else if (req == (ioctlcmd_t)SIOCZRLST) 4566 addrem = OP_ZERO; /* Zero statistics and counters */ 4567 else { 4568 IPFERROR(9); 4569 error = EINVAL; 4570 goto donenolock; 4571 } 4572 4573 /* 4574 * Only filter rules for IPv4 or IPv6 are accepted. 4575 */ 4576 if (family == AF_INET) { 4577 /*EMPTY*/; 4578 #ifdef USE_INET6 4579 } else if (family == AF_INET6) { 4580 /*EMPTY*/; 4581 #endif 4582 } else if (family != 0) { 4583 IPFERROR(10); 4584 error = EINVAL; 4585 goto donenolock; 4586 } 4587 4588 /* 4589 * If the rule is being loaded from user space, i.e. we had to copy it 4590 * into kernel space, then do not trust the function pointer in the 4591 * rule. 4592 */ 4593 if ((makecopy == 1) && (fp->fr_func != NULL)) { 4594 if (ipf_findfunc(fp->fr_func) == NULL) { 4595 IPFERROR(11); 4596 error = ESRCH; 4597 goto donenolock; 4598 } 4599 4600 if (addrem == OP_ADD) { 4601 error = ipf_funcinit(softc, fp); 4602 if (error != 0) 4603 goto donenolock; 4604 } 4605 } 4606 if ((fp->fr_flags & FR_CALLNOW) && 4607 ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) { 4608 IPFERROR(142); 4609 error = ESRCH; 4610 goto donenolock; 4611 } 4612 if (((fp->fr_flags & FR_CMDMASK) == FR_CALL) && 4613 ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) { 4614 IPFERROR(143); 4615 error = ESRCH; 4616 goto donenolock; 4617 } 4618 4619 ptr = NULL; 4620 4621 if (FR_ISACCOUNT(fp->fr_flags)) 4622 unit = IPL_LOGCOUNT; 4623 4624 /* 4625 * Check that each group name in the rule has a start index that 4626 * is valid. 4627 */ 4628 if (fp->fr_icmphead != -1) { 4629 if ((fp->fr_icmphead < 0) || 4630 (fp->fr_icmphead >= fp->fr_namelen)) { 4631 IPFERROR(136); 4632 error = EINVAL; 4633 goto donenolock; 4634 } 4635 if (!strcmp(FR_NAME(fp, fr_icmphead), "0")) 4636 fp->fr_names[fp->fr_icmphead] = '\0'; 4637 } 4638 4639 if (fp->fr_grhead != -1) { 4640 if ((fp->fr_grhead < 0) || 4641 (fp->fr_grhead >= fp->fr_namelen)) { 4642 IPFERROR(137); 4643 error = EINVAL; 4644 goto donenolock; 4645 } 4646 if (!strcmp(FR_NAME(fp, fr_grhead), "0")) 4647 fp->fr_names[fp->fr_grhead] = '\0'; 4648 } 4649 4650 if (fp->fr_group != -1) { 4651 if ((fp->fr_group < 0) || 4652 (fp->fr_group >= fp->fr_namelen)) { 4653 IPFERROR(138); 4654 error = EINVAL; 4655 goto donenolock; 4656 } 4657 if ((req != (int)SIOCZRLST) && (fp->fr_group != -1)) { 4658 /* 4659 * Allow loading rules that are in groups to cause 4660 * them to be created if they don't already exit. 4661 */ 4662 group = FR_NAME(fp, fr_group); 4663 if (addrem == OP_ADD) { 4664 fg = ipf_group_add(softc, group, NULL, 4665 fp->fr_flags, unit, set); 4666 fp->fr_grp = fg; 4667 } else { 4668 fg = ipf_findgroup(softc, group, unit, 4669 set, NULL); 4670 if (fg == NULL) { 4671 IPFERROR(12); 4672 error = ESRCH; 4673 goto donenolock; 4674 } 4675 } 4676 4677 if (fg->fg_flags == 0) { 4678 fg->fg_flags = fp->fr_flags & FR_INOUT; 4679 } else if (fg->fg_flags != (fp->fr_flags & FR_INOUT)) { 4680 IPFERROR(13); 4681 error = ESRCH; 4682 goto donenolock; 4683 } 4684 } 4685 } else { 4686 /* 4687 * If a rule is going to be part of a group then it does 4688 * not matter whether it is an in or out rule, but if it 4689 * isn't in a group, then it does... 4690 */ 4691 if ((fp->fr_flags & (FR_INQUE|FR_OUTQUE)) == 0) { 4692 IPFERROR(14); 4693 error = EINVAL; 4694 goto donenolock; 4695 } 4696 } 4697 in = (fp->fr_flags & FR_INQUE) ? 0 : 1; 4698 4699 /* 4700 * Work out which rule list this change is being applied to. 4701 */ 4702 ftail = NULL; 4703 fprev = NULL; 4704 if (unit == IPL_LOGAUTH) { 4705 if ((fp->fr_tifs[0].fd_ptr != NULL) || 4706 (fp->fr_tifs[1].fd_ptr != NULL) || 4707 (fp->fr_dif.fd_ptr != NULL) || 4708 (fp->fr_flags & FR_FASTROUTE)) { 4709 softc->ipf_interror = 145; 4710 error = EINVAL; 4711 goto donenolock; 4712 } 4713 fprev = ipf_auth_rulehead(softc); 4714 } else { 4715 if (FR_ISACCOUNT(fp->fr_flags)) 4716 fprev = &softc->ipf_acct[in][set]; 4717 else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0) 4718 fprev = &softc->ipf_rules[in][set]; 4719 } 4720 if (fprev == NULL) { 4721 IPFERROR(15); 4722 error = ESRCH; 4723 goto donenolock; 4724 } 4725 4726 if (fg != NULL) 4727 fprev = &fg->fg_start; 4728 4729 /* 4730 * Copy in extra data for the rule. 4731 */ 4732 if (fp->fr_dsize != 0) { 4733 if (makecopy != 0) { 4734 KMALLOCS(ptr, void *, fp->fr_dsize); 4735 if (ptr == NULL) { 4736 IPFERROR(16); 4737 error = ENOMEM; 4738 goto donenolock; 4739 } 4740 4741 /* 4742 * The bcopy case is for when the data is appended 4743 * to the rule by ipf_in_compat(). 4744 */ 4745 if (uptr >= (void *)fp && 4746 uptr < (void *)((char *)fp + fp->fr_size)) { 4747 bcopy(uptr, ptr, fp->fr_dsize); 4748 error = 0; 4749 } else { 4750 error = COPYIN(uptr, ptr, fp->fr_dsize); 4751 if (error != 0) { 4752 IPFERROR(17); 4753 error = EFAULT; 4754 goto donenolock; 4755 } 4756 } 4757 } else { 4758 ptr = uptr; 4759 } 4760 fp->fr_data = ptr; 4761 } else { 4762 fp->fr_data = NULL; 4763 } 4764 4765 /* 4766 * Perform per-rule type sanity checks of their members. 4767 * All code after this needs to be aware that allocated memory 4768 * may need to be free'd before exiting. 4769 */ 4770 switch (fp->fr_type & ~FR_T_BUILTIN) 4771 { 4772 #if defined(IPFILTER_BPF) 4773 case FR_T_BPFOPC : 4774 if (fp->fr_dsize == 0) { 4775 IPFERROR(19); 4776 error = EINVAL; 4777 break; 4778 } 4779 if (!bpf_validate(ptr, fp->fr_dsize/sizeof(struct bpf_insn))) { 4780 IPFERROR(20); 4781 error = EINVAL; 4782 break; 4783 } 4784 break; 4785 #endif 4786 case FR_T_IPF : 4787 /* 4788 * Preparation for error case at the bottom of this function. 4789 */ 4790 if (fp->fr_datype == FRI_LOOKUP) 4791 fp->fr_dstptr = NULL; 4792 if (fp->fr_satype == FRI_LOOKUP) 4793 fp->fr_srcptr = NULL; 4794 4795 if (fp->fr_dsize != sizeof(fripf_t)) { 4796 IPFERROR(21); 4797 error = EINVAL; 4798 break; 4799 } 4800 4801 /* 4802 * Allowing a rule with both "keep state" and "with oow" is 4803 * pointless because adding a state entry to the table will 4804 * fail with the out of window (oow) flag set. 4805 */ 4806 if ((fp->fr_flags & FR_KEEPSTATE) && (fp->fr_flx & FI_OOW)) { 4807 IPFERROR(22); 4808 error = EINVAL; 4809 break; 4810 } 4811 4812 switch (fp->fr_satype) 4813 { 4814 case FRI_BROADCAST : 4815 case FRI_DYNAMIC : 4816 case FRI_NETWORK : 4817 case FRI_NETMASKED : 4818 case FRI_PEERADDR : 4819 if (fp->fr_sifpidx < 0) { 4820 IPFERROR(23); 4821 error = EINVAL; 4822 } 4823 break; 4824 case FRI_LOOKUP : 4825 fp->fr_srcptr = ipf_findlookup(softc, unit, fp, 4826 &fp->fr_src6, 4827 &fp->fr_smsk6); 4828 if (fp->fr_srcfunc == NULL) { 4829 IPFERROR(132); 4830 error = ESRCH; 4831 break; 4832 } 4833 break; 4834 case FRI_NORMAL : 4835 break; 4836 default : 4837 IPFERROR(133); 4838 error = EINVAL; 4839 break; 4840 } 4841 if (error != 0) 4842 break; 4843 4844 switch (fp->fr_datype) 4845 { 4846 case FRI_BROADCAST : 4847 case FRI_DYNAMIC : 4848 case FRI_NETWORK : 4849 case FRI_NETMASKED : 4850 case FRI_PEERADDR : 4851 if (fp->fr_difpidx < 0) { 4852 IPFERROR(24); 4853 error = EINVAL; 4854 } 4855 break; 4856 case FRI_LOOKUP : 4857 fp->fr_dstptr = ipf_findlookup(softc, unit, fp, 4858 &fp->fr_dst6, 4859 &fp->fr_dmsk6); 4860 if (fp->fr_dstfunc == NULL) { 4861 IPFERROR(134); 4862 error = ESRCH; 4863 } 4864 break; 4865 case FRI_NORMAL : 4866 break; 4867 default : 4868 IPFERROR(135); 4869 error = EINVAL; 4870 } 4871 break; 4872 4873 case FR_T_NONE : 4874 case FR_T_CALLFUNC : 4875 case FR_T_COMPIPF : 4876 break; 4877 4878 case FR_T_IPFEXPR : 4879 if (ipf_matcharray_verify(fp->fr_data, fp->fr_dsize) == -1) { 4880 IPFERROR(25); 4881 error = EINVAL; 4882 } 4883 break; 4884 4885 default : 4886 IPFERROR(26); 4887 error = EINVAL; 4888 break; 4889 } 4890 if (error != 0) 4891 goto donenolock; 4892 4893 if (fp->fr_tif.fd_name != -1) { 4894 if ((fp->fr_tif.fd_name < 0) || 4895 (fp->fr_tif.fd_name >= fp->fr_namelen)) { 4896 IPFERROR(139); 4897 error = EINVAL; 4898 goto donenolock; 4899 } 4900 } 4901 4902 if (fp->fr_dif.fd_name != -1) { 4903 if ((fp->fr_dif.fd_name < 0) || 4904 (fp->fr_dif.fd_name >= fp->fr_namelen)) { 4905 IPFERROR(140); 4906 error = EINVAL; 4907 goto donenolock; 4908 } 4909 } 4910 4911 if (fp->fr_rif.fd_name != -1) { 4912 if ((fp->fr_rif.fd_name < 0) || 4913 (fp->fr_rif.fd_name >= fp->fr_namelen)) { 4914 IPFERROR(141); 4915 error = EINVAL; 4916 goto donenolock; 4917 } 4918 } 4919 4920 /* 4921 * Lookup all the interface names that are part of the rule. 4922 */ 4923 error = ipf_synclist(softc, fp, NULL); 4924 if (error != 0) 4925 goto donenolock; 4926 fp->fr_statecnt = 0; 4927 if (fp->fr_srctrack.ht_max_nodes != 0) 4928 ipf_rb_ht_init(&fp->fr_srctrack); 4929 4930 /* 4931 * Look for an existing matching filter rule, but don't include the 4932 * next or interface pointer in the comparison (fr_next, fr_ifa). 4933 * This elminates rules which are indentical being loaded. Checksum 4934 * the constant part of the filter rule to make comparisons quicker 4935 * (this meaning no pointers are included). 4936 */ 4937 pp = (u_int *)(fp->fr_caddr + fp->fr_dsize); 4938 for (fp->fr_cksum = 0, p = (u_int *)fp->fr_data; p < pp; p++) 4939 fp->fr_cksum += *p; 4940 4941 WRITE_ENTER(&softc->ipf_mutex); 4942 4943 /* 4944 * Now that the filter rule lists are locked, we can walk the 4945 * chain of them without fear. 4946 */ 4947 ftail = fprev; 4948 for (f = *ftail; (f = *ftail) != NULL; ftail = &f->fr_next) { 4949 if (fp->fr_collect <= f->fr_collect) { 4950 ftail = fprev; 4951 f = NULL; 4952 break; 4953 } 4954 fprev = ftail; 4955 } 4956 4957 for (; (f = *ftail) != NULL; ftail = &f->fr_next) { 4958 if (ipf_rule_compare(fp, f) == 0) 4959 break; 4960 } 4961 4962 /* 4963 * If zero'ing statistics, copy current to caller and zero. 4964 */ 4965 if (addrem == OP_ZERO) { 4966 if (f == NULL) { 4967 IPFERROR(27); 4968 error = ESRCH; 4969 } else { 4970 /* 4971 * Copy and reduce lock because of impending copyout. 4972 * Well we should, but if we do then the atomicity of 4973 * this call and the correctness of fr_hits and 4974 * fr_bytes cannot be guaranteed. As it is, this code 4975 * only resets them to 0 if they are successfully 4976 * copied out into user space. 4977 */ 4978 bcopy((char *)f, (char *)fp, f->fr_size); 4979 /* MUTEX_DOWNGRADE(&softc->ipf_mutex); */ 4980 4981 /* 4982 * When we copy this rule back out, set the data 4983 * pointer to be what it was in user space. 4984 */ 4985 fp->fr_data = uptr; 4986 error = ipf_outobj(softc, data, fp, IPFOBJ_FRENTRY); 4987 4988 if (error == 0) { 4989 if ((f->fr_dsize != 0) && (uptr != NULL)) { 4990 error = COPYOUT(f->fr_data, uptr, 4991 f->fr_dsize); 4992 if (error == 0) { 4993 f->fr_hits = 0; 4994 f->fr_bytes = 0; 4995 } else { 4996 IPFERROR(28); 4997 error = EFAULT; 4998 } 4999 } 5000 } 5001 } 5002 5003 if (makecopy != 0) { 5004 if (ptr != NULL) { 5005 KFREES(ptr, fp->fr_dsize); 5006 } 5007 KFREES(fp, fp->fr_size); 5008 } 5009 RWLOCK_EXIT(&softc->ipf_mutex); 5010 return (error); 5011 } 5012 5013 if (f == NULL) { 5014 /* 5015 * At the end of this, ftail must point to the place where the 5016 * new rule is to be saved/inserted/added. 5017 * For SIOCAD*FR, this should be the last rule in the group of 5018 * rules that have equal fr_collect fields. 5019 * For SIOCIN*FR, ... 5020 */ 5021 if (req == (ioctlcmd_t)SIOCADAFR || 5022 req == (ioctlcmd_t)SIOCADIFR) { 5023 5024 for (ftail = fprev; (f = *ftail) != NULL; ) { 5025 if (f->fr_collect > fp->fr_collect) 5026 break; 5027 ftail = &f->fr_next; 5028 fprev = ftail; 5029 } 5030 ftail = fprev; 5031 f = NULL; 5032 ptr = NULL; 5033 } else if (req == (ioctlcmd_t)SIOCINAFR || 5034 req == (ioctlcmd_t)SIOCINIFR) { 5035 while ((f = *fprev) != NULL) { 5036 if (f->fr_collect >= fp->fr_collect) 5037 break; 5038 fprev = &f->fr_next; 5039 } 5040 ftail = fprev; 5041 if (fp->fr_hits != 0) { 5042 while (fp->fr_hits && (f = *ftail)) { 5043 if (f->fr_collect != fp->fr_collect) 5044 break; 5045 fprev = ftail; 5046 ftail = &f->fr_next; 5047 fp->fr_hits--; 5048 } 5049 } 5050 f = NULL; 5051 ptr = NULL; 5052 } 5053 } 5054 5055 /* 5056 * Request to remove a rule. 5057 */ 5058 if (addrem == OP_REM) { 5059 if (f == NULL) { 5060 IPFERROR(29); 5061 error = ESRCH; 5062 } else { 5063 /* 5064 * Do not allow activity from user space to interfere 5065 * with rules not loaded that way. 5066 */ 5067 if ((makecopy == 1) && !(f->fr_flags & FR_COPIED)) { 5068 IPFERROR(30); 5069 error = EPERM; 5070 goto done; 5071 } 5072 5073 /* 5074 * Return EBUSY if the rule is being reference by 5075 * something else (eg state information.) 5076 */ 5077 if (f->fr_ref > 1) { 5078 IPFERROR(31); 5079 error = EBUSY; 5080 goto done; 5081 } 5082 #ifdef IPFILTER_SCAN 5083 if (f->fr_isctag != -1 && 5084 (f->fr_isc != (struct ipscan *)-1)) 5085 ipf_scan_detachfr(f); 5086 #endif 5087 5088 if (unit == IPL_LOGAUTH) { 5089 error = ipf_auth_precmd(softc, req, f, ftail); 5090 goto done; 5091 } 5092 5093 ipf_rule_delete(softc, f, unit, set); 5094 5095 need_free = makecopy; 5096 } 5097 } else { 5098 /* 5099 * Not removing, so we must be adding/inserting a rule. 5100 */ 5101 if (f != NULL) { 5102 IPFERROR(32); 5103 error = EEXIST; 5104 goto done; 5105 } 5106 if (unit == IPL_LOGAUTH) { 5107 error = ipf_auth_precmd(softc, req, fp, ftail); 5108 goto done; 5109 } 5110 5111 MUTEX_NUKE(&fp->fr_lock); 5112 MUTEX_INIT(&fp->fr_lock, "filter rule lock"); 5113 if (fp->fr_die != 0) 5114 ipf_rule_expire_insert(softc, fp, set); 5115 5116 fp->fr_hits = 0; 5117 if (makecopy != 0) 5118 fp->fr_ref = 1; 5119 fp->fr_pnext = ftail; 5120 fp->fr_next = *ftail; 5121 if (fp->fr_next != NULL) 5122 fp->fr_next->fr_pnext = &fp->fr_next; 5123 *ftail = fp; 5124 ipf_fixskip(ftail, fp, 1); 5125 5126 fp->fr_icmpgrp = NULL; 5127 if (fp->fr_icmphead != -1) { 5128 group = FR_NAME(fp, fr_icmphead); 5129 fg = ipf_group_add(softc, group, fp, 0, unit, set); 5130 fp->fr_icmpgrp = fg; 5131 } 5132 5133 fp->fr_grphead = NULL; 5134 if (fp->fr_grhead != -1) { 5135 group = FR_NAME(fp, fr_grhead); 5136 fg = ipf_group_add(softc, group, fp, fp->fr_flags, 5137 unit, set); 5138 fp->fr_grphead = fg; 5139 } 5140 } 5141 done: 5142 RWLOCK_EXIT(&softc->ipf_mutex); 5143 donenolock: 5144 if (need_free || (error != 0)) { 5145 if ((fp->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) { 5146 if ((fp->fr_satype == FRI_LOOKUP) && 5147 (fp->fr_srcptr != NULL)) 5148 ipf_lookup_deref(softc, fp->fr_srctype, 5149 fp->fr_srcptr); 5150 if ((fp->fr_datype == FRI_LOOKUP) && 5151 (fp->fr_dstptr != NULL)) 5152 ipf_lookup_deref(softc, fp->fr_dsttype, 5153 fp->fr_dstptr); 5154 } 5155 if (fp->fr_grp != NULL) { 5156 WRITE_ENTER(&softc->ipf_mutex); 5157 ipf_group_del(softc, fp->fr_grp, fp); 5158 RWLOCK_EXIT(&softc->ipf_mutex); 5159 } 5160 if ((ptr != NULL) && (makecopy != 0)) { 5161 KFREES(ptr, fp->fr_dsize); 5162 } 5163 KFREES(fp, fp->fr_size); 5164 } 5165 return (error); 5166 } 5167 5168 5169 /* ------------------------------------------------------------------------ */ 5170 /* Function: ipf_rule_delete */ 5171 /* Returns: Nil */ 5172 /* Parameters: softc(I) - pointer to soft context main structure */ 5173 /* f(I) - pointer to the rule being deleted */ 5174 /* ftail(I) - pointer to the pointer to f */ 5175 /* unit(I) - device for which this is for */ 5176 /* set(I) - 1 or 0 (filter set) */ 5177 /* */ 5178 /* This function attempts to do what it can to delete a filter rule: remove */ 5179 /* it from any linked lists and remove any groups it is responsible for. */ 5180 /* But in the end, removing a rule can only drop the reference count - we */ 5181 /* must use that as the guide for whether or not it can be freed. */ 5182 /* ------------------------------------------------------------------------ */ 5183 static void 5184 ipf_rule_delete(ipf_main_softc_t *softc, frentry_t *f, int unit, int set) 5185 { 5186 5187 /* 5188 * If fr_pdnext is set, then the rule is on the expire list, so 5189 * remove it from there. 5190 */ 5191 if (f->fr_pdnext != NULL) { 5192 *f->fr_pdnext = f->fr_dnext; 5193 if (f->fr_dnext != NULL) 5194 f->fr_dnext->fr_pdnext = f->fr_pdnext; 5195 f->fr_pdnext = NULL; 5196 f->fr_dnext = NULL; 5197 } 5198 5199 ipf_fixskip(f->fr_pnext, f, -1); 5200 if (f->fr_pnext != NULL) 5201 *f->fr_pnext = f->fr_next; 5202 if (f->fr_next != NULL) 5203 f->fr_next->fr_pnext = f->fr_pnext; 5204 f->fr_pnext = NULL; 5205 f->fr_next = NULL; 5206 5207 (void) ipf_derefrule(softc, &f); 5208 } 5209 5210 /* ------------------------------------------------------------------------ */ 5211 /* Function: ipf_rule_expire_insert */ 5212 /* Returns: Nil */ 5213 /* Parameters: softc(I) - pointer to soft context main structure */ 5214 /* f(I) - pointer to rule to be added to expire list */ 5215 /* set(I) - 1 or 0 (filter set) */ 5216 /* */ 5217 /* If the new rule has a given expiration time, insert it into the list of */ 5218 /* expiring rules with the ones to be removed first added to the front of */ 5219 /* the list. The insertion is O(n) but it is kept sorted for quick scans at */ 5220 /* expiration interval checks. */ 5221 /* ------------------------------------------------------------------------ */ 5222 static void 5223 ipf_rule_expire_insert(ipf_main_softc_t *softc, frentry_t *f, int set) 5224 { 5225 frentry_t *fr; 5226 5227 /* 5228 */ 5229 5230 f->fr_die = softc->ipf_ticks + IPF_TTLVAL(f->fr_die); 5231 for (fr = softc->ipf_rule_explist[set]; fr != NULL; 5232 fr = fr->fr_dnext) { 5233 if (f->fr_die < fr->fr_die) 5234 break; 5235 if (fr->fr_dnext == NULL) { 5236 /* 5237 * We've got to the last rule and everything 5238 * wanted to be expired before this new node, 5239 * so we have to tack it on the end... 5240 */ 5241 fr->fr_dnext = f; 5242 f->fr_pdnext = &fr->fr_dnext; 5243 fr = NULL; 5244 break; 5245 } 5246 } 5247 5248 if (softc->ipf_rule_explist[set] == NULL) { 5249 softc->ipf_rule_explist[set] = f; 5250 f->fr_pdnext = &softc->ipf_rule_explist[set]; 5251 } else if (fr != NULL) { 5252 f->fr_dnext = fr; 5253 f->fr_pdnext = fr->fr_pdnext; 5254 fr->fr_pdnext = &f->fr_dnext; 5255 } 5256 } 5257 5258 5259 /* ------------------------------------------------------------------------ */ 5260 /* Function: ipf_findlookup */ 5261 /* Returns: NULL = failure, else success */ 5262 /* Parameters: softc(I) - pointer to soft context main structure */ 5263 /* unit(I) - ipf device we want to find match for */ 5264 /* fp(I) - rule for which lookup is for */ 5265 /* addrp(I) - pointer to lookup information in address struct */ 5266 /* maskp(O) - pointer to lookup information for storage */ 5267 /* */ 5268 /* When using pools and hash tables to store addresses for matching in */ 5269 /* rules, it is necessary to resolve both the object referred to by the */ 5270 /* name or address (and return that pointer) and also provide the means by */ 5271 /* which to determine if an address belongs to that object to make the */ 5272 /* packet matching quicker. */ 5273 /* ------------------------------------------------------------------------ */ 5274 static void * 5275 ipf_findlookup(ipf_main_softc_t *softc, int unit, frentry_t *fr, 5276 i6addr_t *addrp, i6addr_t *maskp) 5277 { 5278 void *ptr = NULL; 5279 5280 switch (addrp->iplookupsubtype) 5281 { 5282 case 0 : 5283 ptr = ipf_lookup_res_num(softc, unit, addrp->iplookuptype, 5284 addrp->iplookupnum, 5285 &maskp->iplookupfunc); 5286 break; 5287 case 1 : 5288 if (addrp->iplookupname < 0) 5289 break; 5290 if (addrp->iplookupname >= fr->fr_namelen) 5291 break; 5292 ptr = ipf_lookup_res_name(softc, unit, addrp->iplookuptype, 5293 fr->fr_names + addrp->iplookupname, 5294 &maskp->iplookupfunc); 5295 break; 5296 default : 5297 break; 5298 } 5299 5300 return (ptr); 5301 } 5302 5303 5304 /* ------------------------------------------------------------------------ */ 5305 /* Function: ipf_funcinit */ 5306 /* Returns: int - 0 == success, else ESRCH: cannot resolve rule details */ 5307 /* Parameters: softc(I) - pointer to soft context main structure */ 5308 /* fr(I) - pointer to filter rule */ 5309 /* */ 5310 /* If a rule is a call rule, then check if the function it points to needs */ 5311 /* an init function to be called now the rule has been loaded. */ 5312 /* ------------------------------------------------------------------------ */ 5313 static int 5314 ipf_funcinit(ipf_main_softc_t *softc, frentry_t *fr) 5315 { 5316 ipfunc_resolve_t *ft; 5317 int err; 5318 5319 IPFERROR(34); 5320 err = ESRCH; 5321 5322 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5323 if (ft->ipfu_addr == fr->fr_func) { 5324 err = 0; 5325 if (ft->ipfu_init != NULL) 5326 err = (*ft->ipfu_init)(softc, fr); 5327 break; 5328 } 5329 return (err); 5330 } 5331 5332 5333 /* ------------------------------------------------------------------------ */ 5334 /* Function: ipf_funcfini */ 5335 /* Returns: Nil */ 5336 /* Parameters: softc(I) - pointer to soft context main structure */ 5337 /* fr(I) - pointer to filter rule */ 5338 /* */ 5339 /* For a given filter rule, call the matching "fini" function if the rule */ 5340 /* is using a known function that would have resulted in the "init" being */ 5341 /* called for ealier. */ 5342 /* ------------------------------------------------------------------------ */ 5343 static void 5344 ipf_funcfini(ipf_main_softc_t *softc, frentry_t *fr) 5345 { 5346 ipfunc_resolve_t *ft; 5347 5348 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5349 if (ft->ipfu_addr == fr->fr_func) { 5350 if (ft->ipfu_fini != NULL) 5351 (void) (*ft->ipfu_fini)(softc, fr); 5352 break; 5353 } 5354 } 5355 5356 5357 /* ------------------------------------------------------------------------ */ 5358 /* Function: ipf_findfunc */ 5359 /* Returns: ipfunc_t - pointer to function if found, else NULL */ 5360 /* Parameters: funcptr(I) - function pointer to lookup */ 5361 /* */ 5362 /* Look for a function in the table of known functions. */ 5363 /* ------------------------------------------------------------------------ */ 5364 static ipfunc_t 5365 ipf_findfunc(ipfunc_t funcptr) 5366 { 5367 ipfunc_resolve_t *ft; 5368 5369 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5370 if (ft->ipfu_addr == funcptr) 5371 return (funcptr); 5372 return (NULL); 5373 } 5374 5375 5376 /* ------------------------------------------------------------------------ */ 5377 /* Function: ipf_resolvefunc */ 5378 /* Returns: int - 0 == success, else error */ 5379 /* Parameters: data(IO) - ioctl data pointer to ipfunc_resolve_t struct */ 5380 /* */ 5381 /* Copy in a ipfunc_resolve_t structure and then fill in the missing field. */ 5382 /* This will either be the function name (if the pointer is set) or the */ 5383 /* function pointer if the name is set. When found, fill in the other one */ 5384 /* so that the entire, complete, structure can be copied back to user space.*/ 5385 /* ------------------------------------------------------------------------ */ 5386 int 5387 ipf_resolvefunc(ipf_main_softc_t *softc, void *data) 5388 { 5389 ipfunc_resolve_t res, *ft; 5390 int error; 5391 5392 error = BCOPYIN(data, &res, sizeof(res)); 5393 if (error != 0) { 5394 IPFERROR(123); 5395 return (EFAULT); 5396 } 5397 5398 if (res.ipfu_addr == NULL && res.ipfu_name[0] != '\0') { 5399 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5400 if (strncmp(res.ipfu_name, ft->ipfu_name, 5401 sizeof(res.ipfu_name)) == 0) { 5402 res.ipfu_addr = ft->ipfu_addr; 5403 res.ipfu_init = ft->ipfu_init; 5404 if (COPYOUT(&res, data, sizeof(res)) != 0) { 5405 IPFERROR(35); 5406 return (EFAULT); 5407 } 5408 return (0); 5409 } 5410 } 5411 if (res.ipfu_addr != NULL && res.ipfu_name[0] == '\0') { 5412 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5413 if (ft->ipfu_addr == res.ipfu_addr) { 5414 (void) strncpy(res.ipfu_name, ft->ipfu_name, 5415 sizeof(res.ipfu_name)); 5416 res.ipfu_init = ft->ipfu_init; 5417 if (COPYOUT(&res, data, sizeof(res)) != 0) { 5418 IPFERROR(36); 5419 return (EFAULT); 5420 } 5421 return (0); 5422 } 5423 } 5424 IPFERROR(37); 5425 return (ESRCH); 5426 } 5427 5428 5429 #if !defined(_KERNEL) || SOLARIS 5430 /* 5431 * From: NetBSD 5432 * ppsratecheck(): packets (or events) per second limitation. 5433 */ 5434 int 5435 ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps) 5436 /* maxpps: maximum pps allowed */ 5437 { 5438 struct timeval tv, delta; 5439 int rv; 5440 5441 GETKTIME(&tv); 5442 5443 delta.tv_sec = tv.tv_sec - lasttime->tv_sec; 5444 delta.tv_usec = tv.tv_usec - lasttime->tv_usec; 5445 if (delta.tv_usec < 0) { 5446 delta.tv_sec--; 5447 delta.tv_usec += 1000000; 5448 } 5449 5450 /* 5451 * check for 0,0 is so that the message will be seen at least once. 5452 * if more than one second have passed since the last update of 5453 * lasttime, reset the counter. 5454 * 5455 * we do increment *curpps even in *curpps < maxpps case, as some may 5456 * try to use *curpps for stat purposes as well. 5457 */ 5458 if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) || 5459 delta.tv_sec >= 1) { 5460 *lasttime = tv; 5461 *curpps = 0; 5462 rv = 1; 5463 } else if (maxpps < 0) 5464 rv = 1; 5465 else if (*curpps < maxpps) 5466 rv = 1; 5467 else 5468 rv = 0; 5469 *curpps = *curpps + 1; 5470 5471 return (rv); 5472 } 5473 #endif 5474 5475 5476 /* ------------------------------------------------------------------------ */ 5477 /* Function: ipf_derefrule */ 5478 /* Returns: int - 0 == rule freed up, else rule not freed */ 5479 /* Parameters: fr(I) - pointer to filter rule */ 5480 /* */ 5481 /* Decrement the reference counter to a rule by one. If it reaches zero, */ 5482 /* free it and any associated storage space being used by it. */ 5483 /* ------------------------------------------------------------------------ */ 5484 int 5485 ipf_derefrule(ipf_main_softc_t *softc, frentry_t **frp) 5486 { 5487 frentry_t *fr; 5488 frdest_t *fdp; 5489 5490 fr = *frp; 5491 *frp = NULL; 5492 5493 MUTEX_ENTER(&fr->fr_lock); 5494 fr->fr_ref--; 5495 if (fr->fr_ref == 0) { 5496 MUTEX_EXIT(&fr->fr_lock); 5497 MUTEX_DESTROY(&fr->fr_lock); 5498 5499 ipf_funcfini(softc, fr); 5500 5501 fdp = &fr->fr_tif; 5502 if (fdp->fd_type == FRD_DSTLIST) 5503 ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr); 5504 5505 fdp = &fr->fr_rif; 5506 if (fdp->fd_type == FRD_DSTLIST) 5507 ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr); 5508 5509 fdp = &fr->fr_dif; 5510 if (fdp->fd_type == FRD_DSTLIST) 5511 ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr); 5512 5513 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF && 5514 fr->fr_satype == FRI_LOOKUP) 5515 ipf_lookup_deref(softc, fr->fr_srctype, fr->fr_srcptr); 5516 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF && 5517 fr->fr_datype == FRI_LOOKUP) 5518 ipf_lookup_deref(softc, fr->fr_dsttype, fr->fr_dstptr); 5519 5520 if (fr->fr_grp != NULL) 5521 ipf_group_del(softc, fr->fr_grp, fr); 5522 5523 if (fr->fr_grphead != NULL) 5524 ipf_group_del(softc, fr->fr_grphead, fr); 5525 5526 if (fr->fr_icmpgrp != NULL) 5527 ipf_group_del(softc, fr->fr_icmpgrp, fr); 5528 5529 if ((fr->fr_flags & FR_COPIED) != 0) { 5530 if (fr->fr_dsize) { 5531 KFREES(fr->fr_data, fr->fr_dsize); 5532 } 5533 KFREES(fr, fr->fr_size); 5534 return (0); 5535 } 5536 return (1); 5537 } else { 5538 MUTEX_EXIT(&fr->fr_lock); 5539 } 5540 return (-1); 5541 } 5542 5543 5544 /* ------------------------------------------------------------------------ */ 5545 /* Function: ipf_grpmapinit */ 5546 /* Returns: int - 0 == success, else ESRCH because table entry not found*/ 5547 /* Parameters: fr(I) - pointer to rule to find hash table for */ 5548 /* */ 5549 /* Looks for group hash table fr_arg and stores a pointer to it in fr_ptr. */ 5550 /* fr_ptr is later used by ipf_srcgrpmap and ipf_dstgrpmap. */ 5551 /* ------------------------------------------------------------------------ */ 5552 static int 5553 ipf_grpmapinit(ipf_main_softc_t *softc, frentry_t *fr) 5554 { 5555 char name[FR_GROUPLEN]; 5556 iphtable_t *iph; 5557 5558 (void) snprintf(name, sizeof(name), "%d", fr->fr_arg); 5559 iph = ipf_lookup_find_htable(softc, IPL_LOGIPF, name); 5560 if (iph == NULL) { 5561 IPFERROR(38); 5562 return (ESRCH); 5563 } 5564 if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT)) { 5565 IPFERROR(39); 5566 return (ESRCH); 5567 } 5568 iph->iph_ref++; 5569 fr->fr_ptr = iph; 5570 return (0); 5571 } 5572 5573 5574 /* ------------------------------------------------------------------------ */ 5575 /* Function: ipf_grpmapfini */ 5576 /* Returns: int - 0 == success, else ESRCH because table entry not found*/ 5577 /* Parameters: softc(I) - pointer to soft context main structure */ 5578 /* fr(I) - pointer to rule to release hash table for */ 5579 /* */ 5580 /* For rules that have had ipf_grpmapinit called, ipf_lookup_deref needs to */ 5581 /* be called to undo what ipf_grpmapinit caused to be done. */ 5582 /* ------------------------------------------------------------------------ */ 5583 static int 5584 ipf_grpmapfini(ipf_main_softc_t *softc, frentry_t *fr) 5585 { 5586 iphtable_t *iph; 5587 iph = fr->fr_ptr; 5588 if (iph != NULL) 5589 ipf_lookup_deref(softc, IPLT_HASH, iph); 5590 return (0); 5591 } 5592 5593 5594 /* ------------------------------------------------------------------------ */ 5595 /* Function: ipf_srcgrpmap */ 5596 /* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ 5597 /* Parameters: fin(I) - pointer to packet information */ 5598 /* passp(IO) - pointer to current/new filter decision (unused) */ 5599 /* */ 5600 /* Look for a rule group head in a hash table, using the source address as */ 5601 /* the key, and descend into that group and continue matching rules against */ 5602 /* the packet. */ 5603 /* ------------------------------------------------------------------------ */ 5604 frentry_t * 5605 ipf_srcgrpmap(fr_info_t *fin, u_32_t *passp) 5606 { 5607 frgroup_t *fg; 5608 void *rval; 5609 5610 rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr, 5611 &fin->fin_src); 5612 if (rval == NULL) 5613 return (NULL); 5614 5615 fg = rval; 5616 fin->fin_fr = fg->fg_start; 5617 (void) ipf_scanlist(fin, *passp); 5618 return (fin->fin_fr); 5619 } 5620 5621 5622 /* ------------------------------------------------------------------------ */ 5623 /* Function: ipf_dstgrpmap */ 5624 /* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ 5625 /* Parameters: fin(I) - pointer to packet information */ 5626 /* passp(IO) - pointer to current/new filter decision (unused) */ 5627 /* */ 5628 /* Look for a rule group head in a hash table, using the destination */ 5629 /* address as the key, and descend into that group and continue matching */ 5630 /* rules against the packet. */ 5631 /* ------------------------------------------------------------------------ */ 5632 frentry_t * 5633 ipf_dstgrpmap(fr_info_t *fin, u_32_t *passp) 5634 { 5635 frgroup_t *fg; 5636 void *rval; 5637 5638 rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr, 5639 &fin->fin_dst); 5640 if (rval == NULL) 5641 return (NULL); 5642 5643 fg = rval; 5644 fin->fin_fr = fg->fg_start; 5645 (void) ipf_scanlist(fin, *passp); 5646 return (fin->fin_fr); 5647 } 5648 5649 /* 5650 * Queue functions 5651 * =============== 5652 * These functions manage objects on queues for efficient timeouts. There 5653 * are a number of system defined queues as well as user defined timeouts. 5654 * It is expected that a lock is held in the domain in which the queue 5655 * belongs (i.e. either state or NAT) when calling any of these functions 5656 * that prevents ipf_freetimeoutqueue() from being called at the same time 5657 * as any other. 5658 */ 5659 5660 5661 /* ------------------------------------------------------------------------ */ 5662 /* Function: ipf_addtimeoutqueue */ 5663 /* Returns: struct ifqtq * - NULL if malloc fails, else pointer to */ 5664 /* timeout queue with given interval. */ 5665 /* Parameters: parent(I) - pointer to pointer to parent node of this list */ 5666 /* of interface queues. */ 5667 /* seconds(I) - timeout value in seconds for this queue. */ 5668 /* */ 5669 /* This routine first looks for a timeout queue that matches the interval */ 5670 /* being requested. If it finds one, increments the reference counter and */ 5671 /* returns a pointer to it. If none are found, it allocates a new one and */ 5672 /* inserts it at the top of the list. */ 5673 /* */ 5674 /* Locking. */ 5675 /* It is assumed that the caller of this function has an appropriate lock */ 5676 /* held (exclusively) in the domain that encompases 'parent'. */ 5677 /* ------------------------------------------------------------------------ */ 5678 ipftq_t * 5679 ipf_addtimeoutqueue(ipf_main_softc_t *softc, ipftq_t **parent, u_int seconds) 5680 { 5681 ipftq_t *ifq; 5682 u_int period; 5683 5684 period = seconds * IPF_HZ_DIVIDE; 5685 5686 MUTEX_ENTER(&softc->ipf_timeoutlock); 5687 for (ifq = *parent; ifq != NULL; ifq = ifq->ifq_next) { 5688 if (ifq->ifq_ttl == period) { 5689 /* 5690 * Reset the delete flag, if set, so the structure 5691 * gets reused rather than freed and reallocated. 5692 */ 5693 MUTEX_ENTER(&ifq->ifq_lock); 5694 ifq->ifq_flags &= ~IFQF_DELETE; 5695 ifq->ifq_ref++; 5696 MUTEX_EXIT(&ifq->ifq_lock); 5697 MUTEX_EXIT(&softc->ipf_timeoutlock); 5698 5699 return (ifq); 5700 } 5701 } 5702 5703 KMALLOC(ifq, ipftq_t *); 5704 if (ifq != NULL) { 5705 MUTEX_NUKE(&ifq->ifq_lock); 5706 IPFTQ_INIT(ifq, period, "ipftq mutex"); 5707 ifq->ifq_next = *parent; 5708 ifq->ifq_pnext = parent; 5709 ifq->ifq_flags = IFQF_USER; 5710 ifq->ifq_ref++; 5711 *parent = ifq; 5712 softc->ipf_userifqs++; 5713 } 5714 MUTEX_EXIT(&softc->ipf_timeoutlock); 5715 return (ifq); 5716 } 5717 5718 5719 /* ------------------------------------------------------------------------ */ 5720 /* Function: ipf_deletetimeoutqueue */ 5721 /* Returns: int - new reference count value of the timeout queue */ 5722 /* Parameters: ifq(I) - timeout queue which is losing a reference. */ 5723 /* Locks: ifq->ifq_lock */ 5724 /* */ 5725 /* This routine must be called when we're discarding a pointer to a timeout */ 5726 /* queue object, taking care of the reference counter. */ 5727 /* */ 5728 /* Now that this just sets a DELETE flag, it requires the expire code to */ 5729 /* check the list of user defined timeout queues and call the free function */ 5730 /* below (currently commented out) to stop memory leaking. It is done this */ 5731 /* way because the locking may not be sufficient to safely do a free when */ 5732 /* this function is called. */ 5733 /* ------------------------------------------------------------------------ */ 5734 int 5735 ipf_deletetimeoutqueue(ipftq_t *ifq) 5736 { 5737 5738 ifq->ifq_ref--; 5739 if ((ifq->ifq_ref == 0) && ((ifq->ifq_flags & IFQF_USER) != 0)) { 5740 ifq->ifq_flags |= IFQF_DELETE; 5741 } 5742 5743 return (ifq->ifq_ref); 5744 } 5745 5746 5747 /* ------------------------------------------------------------------------ */ 5748 /* Function: ipf_freetimeoutqueue */ 5749 /* Parameters: ifq(I) - timeout queue which is losing a reference. */ 5750 /* Returns: Nil */ 5751 /* */ 5752 /* Locking: */ 5753 /* It is assumed that the caller of this function has an appropriate lock */ 5754 /* held (exclusively) in the domain that encompases the callers "domain". */ 5755 /* The ifq_lock for this structure should not be held. */ 5756 /* */ 5757 /* Remove a user defined timeout queue from the list of queues it is in and */ 5758 /* tidy up after this is done. */ 5759 /* ------------------------------------------------------------------------ */ 5760 void 5761 ipf_freetimeoutqueue(ipf_main_softc_t *softc, ipftq_t *ifq) 5762 { 5763 5764 if (((ifq->ifq_flags & IFQF_DELETE) == 0) || (ifq->ifq_ref != 0) || 5765 ((ifq->ifq_flags & IFQF_USER) == 0)) { 5766 printf("ipf_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n", 5767 (u_long)ifq, ifq->ifq_flags, ifq->ifq_ttl, 5768 ifq->ifq_ref); 5769 return; 5770 } 5771 5772 /* 5773 * Remove from its position in the list. 5774 */ 5775 *ifq->ifq_pnext = ifq->ifq_next; 5776 if (ifq->ifq_next != NULL) 5777 ifq->ifq_next->ifq_pnext = ifq->ifq_pnext; 5778 ifq->ifq_next = NULL; 5779 ifq->ifq_pnext = NULL; 5780 5781 MUTEX_DESTROY(&ifq->ifq_lock); 5782 ATOMIC_DEC(softc->ipf_userifqs); 5783 KFREE(ifq); 5784 } 5785 5786 5787 /* ------------------------------------------------------------------------ */ 5788 /* Function: ipf_deletequeueentry */ 5789 /* Returns: Nil */ 5790 /* Parameters: tqe(I) - timeout queue entry to delete */ 5791 /* */ 5792 /* Remove a tail queue entry from its queue and make it an orphan. */ 5793 /* ipf_deletetimeoutqueue is called to make sure the reference count on the */ 5794 /* queue is correct. We can't, however, call ipf_freetimeoutqueue because */ 5795 /* the correct lock(s) may not be held that would make it safe to do so. */ 5796 /* ------------------------------------------------------------------------ */ 5797 void 5798 ipf_deletequeueentry(ipftqent_t *tqe) 5799 { 5800 ipftq_t *ifq; 5801 5802 ifq = tqe->tqe_ifq; 5803 5804 MUTEX_ENTER(&ifq->ifq_lock); 5805 5806 if (tqe->tqe_pnext != NULL) { 5807 *tqe->tqe_pnext = tqe->tqe_next; 5808 if (tqe->tqe_next != NULL) 5809 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5810 else /* we must be the tail anyway */ 5811 ifq->ifq_tail = tqe->tqe_pnext; 5812 5813 tqe->tqe_pnext = NULL; 5814 tqe->tqe_ifq = NULL; 5815 } 5816 5817 (void) ipf_deletetimeoutqueue(ifq); 5818 ASSERT(ifq->ifq_ref > 0); 5819 5820 MUTEX_EXIT(&ifq->ifq_lock); 5821 } 5822 5823 5824 /* ------------------------------------------------------------------------ */ 5825 /* Function: ipf_queuefront */ 5826 /* Returns: Nil */ 5827 /* Parameters: tqe(I) - pointer to timeout queue entry */ 5828 /* */ 5829 /* Move a queue entry to the front of the queue, if it isn't already there. */ 5830 /* ------------------------------------------------------------------------ */ 5831 void 5832 ipf_queuefront(ipftqent_t *tqe) 5833 { 5834 ipftq_t *ifq; 5835 5836 ifq = tqe->tqe_ifq; 5837 if (ifq == NULL) 5838 return; 5839 5840 MUTEX_ENTER(&ifq->ifq_lock); 5841 if (ifq->ifq_head != tqe) { 5842 *tqe->tqe_pnext = tqe->tqe_next; 5843 if (tqe->tqe_next) 5844 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5845 else 5846 ifq->ifq_tail = tqe->tqe_pnext; 5847 5848 tqe->tqe_next = ifq->ifq_head; 5849 ifq->ifq_head->tqe_pnext = &tqe->tqe_next; 5850 ifq->ifq_head = tqe; 5851 tqe->tqe_pnext = &ifq->ifq_head; 5852 } 5853 MUTEX_EXIT(&ifq->ifq_lock); 5854 } 5855 5856 5857 /* ------------------------------------------------------------------------ */ 5858 /* Function: ipf_queueback */ 5859 /* Returns: Nil */ 5860 /* Parameters: ticks(I) - ipf tick time to use with this call */ 5861 /* tqe(I) - pointer to timeout queue entry */ 5862 /* */ 5863 /* Move a queue entry to the back of the queue, if it isn't already there. */ 5864 /* We use use ticks to calculate the expiration and mark for when we last */ 5865 /* touched the structure. */ 5866 /* ------------------------------------------------------------------------ */ 5867 void 5868 ipf_queueback(u_long ticks, ipftqent_t *tqe) 5869 { 5870 ipftq_t *ifq; 5871 5872 ifq = tqe->tqe_ifq; 5873 if (ifq == NULL) 5874 return; 5875 tqe->tqe_die = ticks + ifq->ifq_ttl; 5876 tqe->tqe_touched = ticks; 5877 5878 MUTEX_ENTER(&ifq->ifq_lock); 5879 if (tqe->tqe_next != NULL) { /* at the end already ? */ 5880 /* 5881 * Remove from list 5882 */ 5883 *tqe->tqe_pnext = tqe->tqe_next; 5884 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5885 5886 /* 5887 * Make it the last entry. 5888 */ 5889 tqe->tqe_next = NULL; 5890 tqe->tqe_pnext = ifq->ifq_tail; 5891 *ifq->ifq_tail = tqe; 5892 ifq->ifq_tail = &tqe->tqe_next; 5893 } 5894 MUTEX_EXIT(&ifq->ifq_lock); 5895 } 5896 5897 5898 /* ------------------------------------------------------------------------ */ 5899 /* Function: ipf_queueappend */ 5900 /* Returns: Nil */ 5901 /* Parameters: ticks(I) - ipf tick time to use with this call */ 5902 /* tqe(I) - pointer to timeout queue entry */ 5903 /* ifq(I) - pointer to timeout queue */ 5904 /* parent(I) - owing object pointer */ 5905 /* */ 5906 /* Add a new item to this queue and put it on the very end. */ 5907 /* We use use ticks to calculate the expiration and mark for when we last */ 5908 /* touched the structure. */ 5909 /* ------------------------------------------------------------------------ */ 5910 void 5911 ipf_queueappend(u_long ticks, ipftqent_t *tqe, ipftq_t *ifq, void *parent) 5912 { 5913 5914 MUTEX_ENTER(&ifq->ifq_lock); 5915 tqe->tqe_parent = parent; 5916 tqe->tqe_pnext = ifq->ifq_tail; 5917 *ifq->ifq_tail = tqe; 5918 ifq->ifq_tail = &tqe->tqe_next; 5919 tqe->tqe_next = NULL; 5920 tqe->tqe_ifq = ifq; 5921 tqe->tqe_die = ticks + ifq->ifq_ttl; 5922 tqe->tqe_touched = ticks; 5923 ifq->ifq_ref++; 5924 MUTEX_EXIT(&ifq->ifq_lock); 5925 } 5926 5927 5928 /* ------------------------------------------------------------------------ */ 5929 /* Function: ipf_movequeue */ 5930 /* Returns: Nil */ 5931 /* Parameters: tq(I) - pointer to timeout queue information */ 5932 /* oifp(I) - old timeout queue entry was on */ 5933 /* nifp(I) - new timeout queue to put entry on */ 5934 /* */ 5935 /* Move a queue entry from one timeout queue to another timeout queue. */ 5936 /* If it notices that the current entry is already last and does not need */ 5937 /* to move queue, the return. */ 5938 /* ------------------------------------------------------------------------ */ 5939 void 5940 ipf_movequeue(u_long ticks, ipftqent_t *tqe, ipftq_t *oifq, ipftq_t *nifq) 5941 { 5942 5943 /* 5944 * If the queue hasn't changed and we last touched this entry at the 5945 * same ipf time, then we're not going to achieve anything by either 5946 * changing the ttl or moving it on the queue. 5947 */ 5948 if (oifq == nifq && tqe->tqe_touched == ticks) 5949 return; 5950 5951 /* 5952 * For any of this to be outside the lock, there is a risk that two 5953 * packets entering simultaneously, with one changing to a different 5954 * queue and one not, could end up with things in a bizarre state. 5955 */ 5956 MUTEX_ENTER(&oifq->ifq_lock); 5957 5958 tqe->tqe_touched = ticks; 5959 tqe->tqe_die = ticks + nifq->ifq_ttl; 5960 /* 5961 * Is the operation here going to be a no-op ? 5962 */ 5963 if (oifq == nifq) { 5964 if ((tqe->tqe_next == NULL) || 5965 (tqe->tqe_next->tqe_die == tqe->tqe_die)) { 5966 MUTEX_EXIT(&oifq->ifq_lock); 5967 return; 5968 } 5969 } 5970 5971 /* 5972 * Remove from the old queue 5973 */ 5974 *tqe->tqe_pnext = tqe->tqe_next; 5975 if (tqe->tqe_next) 5976 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5977 else 5978 oifq->ifq_tail = tqe->tqe_pnext; 5979 tqe->tqe_next = NULL; 5980 5981 /* 5982 * If we're moving from one queue to another, release the 5983 * lock on the old queue and get a lock on the new queue. 5984 * For user defined queues, if we're moving off it, call 5985 * delete in case it can now be freed. 5986 */ 5987 if (oifq != nifq) { 5988 tqe->tqe_ifq = NULL; 5989 5990 (void) ipf_deletetimeoutqueue(oifq); 5991 5992 MUTEX_EXIT(&oifq->ifq_lock); 5993 5994 MUTEX_ENTER(&nifq->ifq_lock); 5995 5996 tqe->tqe_ifq = nifq; 5997 nifq->ifq_ref++; 5998 } 5999 6000 /* 6001 * Add to the bottom of the new queue 6002 */ 6003 tqe->tqe_pnext = nifq->ifq_tail; 6004 *nifq->ifq_tail = tqe; 6005 nifq->ifq_tail = &tqe->tqe_next; 6006 MUTEX_EXIT(&nifq->ifq_lock); 6007 } 6008 6009 6010 /* ------------------------------------------------------------------------ */ 6011 /* Function: ipf_updateipid */ 6012 /* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 6013 /* Parameters: fin(I) - pointer to packet information */ 6014 /* */ 6015 /* When we are doing NAT, change the IP of every packet to represent a */ 6016 /* single sequence of packets coming from the host, hiding any host */ 6017 /* specific sequencing that might otherwise be revealed. If the packet is */ 6018 /* a fragment, then store the 'new' IPid in the fragment cache and look up */ 6019 /* the fragment cache for non-leading fragments. If a non-leading fragment */ 6020 /* has no match in the cache, return an error. */ 6021 /* ------------------------------------------------------------------------ */ 6022 static int 6023 ipf_updateipid(fr_info_t *fin) 6024 { 6025 u_short id, ido, sums; 6026 u_32_t sumd, sum; 6027 ip_t *ip; 6028 6029 ip = fin->fin_ip; 6030 ido = ntohs(ip->ip_id); 6031 if (fin->fin_off != 0) { 6032 sum = ipf_frag_ipidknown(fin); 6033 if (sum == 0xffffffff) 6034 return (-1); 6035 sum &= 0xffff; 6036 id = (u_short)sum; 6037 ip->ip_id = htons(id); 6038 } else { 6039 ip_fillid(ip, V_ip_random_id); 6040 id = ntohs(ip->ip_id); 6041 if ((fin->fin_flx & FI_FRAG) != 0) 6042 (void) ipf_frag_ipidnew(fin, (u_32_t)id); 6043 } 6044 6045 if (id == ido) 6046 return (0); 6047 CALC_SUMD(ido, id, sumd); /* DESTRUCTIVE MACRO! id,ido change */ 6048 sum = (~ntohs(ip->ip_sum)) & 0xffff; 6049 sum += sumd; 6050 sum = (sum >> 16) + (sum & 0xffff); 6051 sum = (sum >> 16) + (sum & 0xffff); 6052 sums = ~(u_short)sum; 6053 ip->ip_sum = htons(sums); 6054 return (0); 6055 } 6056 6057 6058 #ifdef NEED_FRGETIFNAME 6059 /* ------------------------------------------------------------------------ */ 6060 /* Function: ipf_getifname */ 6061 /* Returns: char * - pointer to interface name */ 6062 /* Parameters: ifp(I) - pointer to network interface */ 6063 /* buffer(O) - pointer to where to store interface name */ 6064 /* */ 6065 /* Constructs an interface name in the buffer passed. The buffer passed is */ 6066 /* expected to be at least LIFNAMSIZ in bytes big. If buffer is passed in */ 6067 /* as a NULL pointer then return a pointer to a static array. */ 6068 /* ------------------------------------------------------------------------ */ 6069 char * 6070 ipf_getifname(struct ifnet *ifp, char *buffer) 6071 { 6072 static char namebuf[LIFNAMSIZ]; 6073 # if SOLARIS || defined(__FreeBSD__) 6074 int unit, space; 6075 char temp[20]; 6076 char *s; 6077 # endif 6078 6079 if (buffer == NULL) 6080 buffer = namebuf; 6081 (void) strncpy(buffer, ifp->if_name, LIFNAMSIZ); 6082 buffer[LIFNAMSIZ - 1] = '\0'; 6083 # if SOLARIS || defined(__FreeBSD__) 6084 for (s = buffer; *s; s++) 6085 ; 6086 unit = ifp->if_unit; 6087 space = LIFNAMSIZ - (s - buffer); 6088 if ((space > 0) && (unit >= 0)) { 6089 (void) snprintf(temp, sizeof(name), "%d", unit); 6090 (void) strncpy(s, temp, space); 6091 } 6092 # endif 6093 return (buffer); 6094 } 6095 #endif 6096 6097 6098 /* ------------------------------------------------------------------------ */ 6099 /* Function: ipf_ioctlswitch */ 6100 /* Returns: int - -1 continue processing, else ioctl return value */ 6101 /* Parameters: unit(I) - device unit opened */ 6102 /* data(I) - pointer to ioctl data */ 6103 /* cmd(I) - ioctl command */ 6104 /* mode(I) - mode value */ 6105 /* uid(I) - uid making the ioctl call */ 6106 /* ctx(I) - pointer to context data */ 6107 /* */ 6108 /* Based on the value of unit, call the appropriate ioctl handler or return */ 6109 /* EIO if ipfilter is not running. Also checks if write perms are req'd */ 6110 /* for the device in order to execute the ioctl. A special case is made */ 6111 /* SIOCIPFINTERROR so that the same code isn't required in every handler. */ 6112 /* The context data pointer is passed through as this is used as the key */ 6113 /* for locating a matching token for continued access for walking lists, */ 6114 /* etc. */ 6115 /* ------------------------------------------------------------------------ */ 6116 int 6117 ipf_ioctlswitch(ipf_main_softc_t *softc, int unit, void *data, ioctlcmd_t cmd, 6118 int mode, int uid, void *ctx) 6119 { 6120 int error = 0; 6121 6122 switch (cmd) 6123 { 6124 case SIOCIPFINTERROR : 6125 error = BCOPYOUT(&softc->ipf_interror, data, 6126 sizeof(softc->ipf_interror)); 6127 if (error != 0) { 6128 IPFERROR(40); 6129 error = EFAULT; 6130 } 6131 return (error); 6132 default : 6133 break; 6134 } 6135 6136 switch (unit) 6137 { 6138 case IPL_LOGIPF : 6139 error = ipf_ipf_ioctl(softc, data, cmd, mode, uid, ctx); 6140 break; 6141 case IPL_LOGNAT : 6142 if (softc->ipf_running > 0) { 6143 error = ipf_nat_ioctl(softc, data, cmd, mode, 6144 uid, ctx); 6145 } else { 6146 IPFERROR(42); 6147 error = EIO; 6148 } 6149 break; 6150 case IPL_LOGSTATE : 6151 if (softc->ipf_running > 0) { 6152 error = ipf_state_ioctl(softc, data, cmd, mode, 6153 uid, ctx); 6154 } else { 6155 IPFERROR(43); 6156 error = EIO; 6157 } 6158 break; 6159 case IPL_LOGAUTH : 6160 if (softc->ipf_running > 0) { 6161 error = ipf_auth_ioctl(softc, data, cmd, mode, 6162 uid, ctx); 6163 } else { 6164 IPFERROR(44); 6165 error = EIO; 6166 } 6167 break; 6168 case IPL_LOGSYNC : 6169 if (softc->ipf_running > 0) { 6170 error = ipf_sync_ioctl(softc, data, cmd, mode, 6171 uid, ctx); 6172 } else { 6173 error = EIO; 6174 IPFERROR(45); 6175 } 6176 break; 6177 case IPL_LOGSCAN : 6178 #ifdef IPFILTER_SCAN 6179 if (softc->ipf_running > 0) 6180 error = ipf_scan_ioctl(softc, data, cmd, mode, 6181 uid, ctx); 6182 else 6183 #endif 6184 { 6185 error = EIO; 6186 IPFERROR(46); 6187 } 6188 break; 6189 case IPL_LOGLOOKUP : 6190 if (softc->ipf_running > 0) { 6191 error = ipf_lookup_ioctl(softc, data, cmd, mode, 6192 uid, ctx); 6193 } else { 6194 error = EIO; 6195 IPFERROR(47); 6196 } 6197 break; 6198 default : 6199 IPFERROR(48); 6200 error = EIO; 6201 break; 6202 } 6203 6204 return (error); 6205 } 6206 6207 6208 /* 6209 * This array defines the expected size of objects coming into the kernel 6210 * for the various recognised object types. The first column is flags (see 6211 * below), 2nd column is current size, 3rd column is the version number of 6212 * when the current size became current. 6213 * Flags: 6214 * 1 = minimum size, not absolute size 6215 */ 6216 static const int ipf_objbytes[IPFOBJ_COUNT][3] = { 6217 { 1, sizeof(struct frentry), 5010000 }, /* 0 */ 6218 { 1, sizeof(struct friostat), 5010000 }, 6219 { 0, sizeof(struct fr_info), 5010000 }, 6220 { 0, sizeof(struct ipf_authstat), 4010100 }, 6221 { 0, sizeof(struct ipfrstat), 5010000 }, 6222 { 1, sizeof(struct ipnat), 5010000 }, /* 5 */ 6223 { 0, sizeof(struct natstat), 5010000 }, 6224 { 0, sizeof(struct ipstate_save), 5010000 }, 6225 { 1, sizeof(struct nat_save), 5010000 }, 6226 { 0, sizeof(struct natlookup), 5010000 }, 6227 { 1, sizeof(struct ipstate), 5010000 }, /* 10 */ 6228 { 0, sizeof(struct ips_stat), 5010000 }, 6229 { 0, sizeof(struct frauth), 5010000 }, 6230 { 0, sizeof(struct ipftune), 4010100 }, 6231 { 0, sizeof(struct nat), 5010000 }, 6232 { 0, sizeof(struct ipfruleiter), 4011400 }, /* 15 */ 6233 { 0, sizeof(struct ipfgeniter), 4011400 }, 6234 { 0, sizeof(struct ipftable), 4011400 }, 6235 { 0, sizeof(struct ipflookupiter), 4011400 }, 6236 { 0, sizeof(struct ipftq) * IPF_TCP_NSTATES }, 6237 { 1, 0, 0 }, /* IPFEXPR */ 6238 { 0, 0, 0 }, /* PROXYCTL */ 6239 { 0, sizeof (struct fripf), 5010000 } 6240 }; 6241 6242 6243 /* ------------------------------------------------------------------------ */ 6244 /* Function: ipf_inobj */ 6245 /* Returns: int - 0 = success, else failure */ 6246 /* Parameters: softc(I) - soft context pointerto work with */ 6247 /* data(I) - pointer to ioctl data */ 6248 /* objp(O) - where to store ipfobj structure */ 6249 /* ptr(I) - pointer to data to copy out */ 6250 /* type(I) - type of structure being moved */ 6251 /* */ 6252 /* Copy in the contents of what the ipfobj_t points to. In future, we */ 6253 /* add things to check for version numbers, sizes, etc, to make it backward */ 6254 /* compatible at the ABI for user land. */ 6255 /* If objp is not NULL then we assume that the caller wants to see what is */ 6256 /* in the ipfobj_t structure being copied in. As an example, this can tell */ 6257 /* the caller what version of ipfilter the ioctl program was written to. */ 6258 /* ------------------------------------------------------------------------ */ 6259 int 6260 ipf_inobj(ipf_main_softc_t *softc, void *data, ipfobj_t *objp, void *ptr, 6261 int type) 6262 { 6263 ipfobj_t obj; 6264 int error; 6265 int size; 6266 6267 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6268 IPFERROR(49); 6269 return (EINVAL); 6270 } 6271 6272 if (objp == NULL) 6273 objp = &obj; 6274 error = BCOPYIN(data, objp, sizeof(*objp)); 6275 if (error != 0) { 6276 IPFERROR(124); 6277 return (EFAULT); 6278 } 6279 6280 if (objp->ipfo_type != type) { 6281 IPFERROR(50); 6282 return (EINVAL); 6283 } 6284 6285 if (objp->ipfo_rev >= ipf_objbytes[type][2]) { 6286 if ((ipf_objbytes[type][0] & 1) != 0) { 6287 if (objp->ipfo_size < ipf_objbytes[type][1]) { 6288 IPFERROR(51); 6289 return (EINVAL); 6290 } 6291 size = ipf_objbytes[type][1]; 6292 } else if (objp->ipfo_size == ipf_objbytes[type][1]) { 6293 size = objp->ipfo_size; 6294 } else { 6295 IPFERROR(52); 6296 return (EINVAL); 6297 } 6298 error = COPYIN(objp->ipfo_ptr, ptr, size); 6299 if (error != 0) { 6300 IPFERROR(55); 6301 error = EFAULT; 6302 } 6303 } else { 6304 #ifdef IPFILTER_COMPAT 6305 error = ipf_in_compat(softc, objp, ptr, 0); 6306 #else 6307 IPFERROR(54); 6308 error = EINVAL; 6309 #endif 6310 } 6311 return (error); 6312 } 6313 6314 6315 /* ------------------------------------------------------------------------ */ 6316 /* Function: ipf_inobjsz */ 6317 /* Returns: int - 0 = success, else failure */ 6318 /* Parameters: softc(I) - soft context pointerto work with */ 6319 /* data(I) - pointer to ioctl data */ 6320 /* ptr(I) - pointer to store real data in */ 6321 /* type(I) - type of structure being moved */ 6322 /* sz(I) - size of data to copy */ 6323 /* */ 6324 /* As per ipf_inobj, except the size of the object to copy in is passed in */ 6325 /* but it must not be smaller than the size defined for the type and the */ 6326 /* type must allow for varied sized objects. The extra requirement here is */ 6327 /* that sz must match the size of the object being passed in - this is not */ 6328 /* not possible nor required in ipf_inobj(). */ 6329 /* ------------------------------------------------------------------------ */ 6330 int 6331 ipf_inobjsz(ipf_main_softc_t *softc, void *data, void *ptr, int type, int sz) 6332 { 6333 ipfobj_t obj; 6334 int error; 6335 6336 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6337 IPFERROR(56); 6338 return (EINVAL); 6339 } 6340 6341 error = BCOPYIN(data, &obj, sizeof(obj)); 6342 if (error != 0) { 6343 IPFERROR(125); 6344 return (EFAULT); 6345 } 6346 6347 if (obj.ipfo_type != type) { 6348 IPFERROR(58); 6349 return (EINVAL); 6350 } 6351 6352 if (obj.ipfo_rev >= ipf_objbytes[type][2]) { 6353 if (((ipf_objbytes[type][0] & 1) == 0) || 6354 (sz < ipf_objbytes[type][1])) { 6355 IPFERROR(57); 6356 return (EINVAL); 6357 } 6358 error = COPYIN(obj.ipfo_ptr, ptr, sz); 6359 if (error != 0) { 6360 IPFERROR(61); 6361 error = EFAULT; 6362 } 6363 } else { 6364 #ifdef IPFILTER_COMPAT 6365 error = ipf_in_compat(softc, &obj, ptr, sz); 6366 #else 6367 IPFERROR(60); 6368 error = EINVAL; 6369 #endif 6370 } 6371 return (error); 6372 } 6373 6374 6375 /* ------------------------------------------------------------------------ */ 6376 /* Function: ipf_outobjsz */ 6377 /* Returns: int - 0 = success, else failure */ 6378 /* Parameters: data(I) - pointer to ioctl data */ 6379 /* ptr(I) - pointer to store real data in */ 6380 /* type(I) - type of structure being moved */ 6381 /* sz(I) - size of data to copy */ 6382 /* */ 6383 /* As per ipf_outobj, except the size of the object to copy out is passed in*/ 6384 /* but it must not be smaller than the size defined for the type and the */ 6385 /* type must allow for varied sized objects. The extra requirement here is */ 6386 /* that sz must match the size of the object being passed in - this is not */ 6387 /* not possible nor required in ipf_outobj(). */ 6388 /* ------------------------------------------------------------------------ */ 6389 int 6390 ipf_outobjsz(ipf_main_softc_t *softc, void *data, void *ptr, int type, int sz) 6391 { 6392 ipfobj_t obj; 6393 int error; 6394 6395 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6396 IPFERROR(62); 6397 return (EINVAL); 6398 } 6399 6400 error = BCOPYIN(data, &obj, sizeof(obj)); 6401 if (error != 0) { 6402 IPFERROR(127); 6403 return (EFAULT); 6404 } 6405 6406 if (obj.ipfo_type != type) { 6407 IPFERROR(63); 6408 return (EINVAL); 6409 } 6410 6411 if (obj.ipfo_rev >= ipf_objbytes[type][2]) { 6412 if (((ipf_objbytes[type][0] & 1) == 0) || 6413 (sz < ipf_objbytes[type][1])) { 6414 IPFERROR(146); 6415 return (EINVAL); 6416 } 6417 error = COPYOUT(ptr, obj.ipfo_ptr, sz); 6418 if (error != 0) { 6419 IPFERROR(66); 6420 error = EFAULT; 6421 } 6422 } else { 6423 #ifdef IPFILTER_COMPAT 6424 error = ipf_out_compat(softc, &obj, ptr); 6425 #else 6426 IPFERROR(65); 6427 error = EINVAL; 6428 #endif 6429 } 6430 return (error); 6431 } 6432 6433 6434 /* ------------------------------------------------------------------------ */ 6435 /* Function: ipf_outobj */ 6436 /* Returns: int - 0 = success, else failure */ 6437 /* Parameters: data(I) - pointer to ioctl data */ 6438 /* ptr(I) - pointer to store real data in */ 6439 /* type(I) - type of structure being moved */ 6440 /* */ 6441 /* Copy out the contents of what ptr is to where ipfobj points to. In */ 6442 /* future, we add things to check for version numbers, sizes, etc, to make */ 6443 /* it backward compatible at the ABI for user land. */ 6444 /* ------------------------------------------------------------------------ */ 6445 int 6446 ipf_outobj(ipf_main_softc_t *softc, void *data, void *ptr, int type) 6447 { 6448 ipfobj_t obj; 6449 int error; 6450 6451 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6452 IPFERROR(67); 6453 return (EINVAL); 6454 } 6455 6456 error = BCOPYIN(data, &obj, sizeof(obj)); 6457 if (error != 0) { 6458 IPFERROR(126); 6459 return (EFAULT); 6460 } 6461 6462 if (obj.ipfo_type != type) { 6463 IPFERROR(68); 6464 return (EINVAL); 6465 } 6466 6467 if (obj.ipfo_rev >= ipf_objbytes[type][2]) { 6468 if ((ipf_objbytes[type][0] & 1) != 0) { 6469 if (obj.ipfo_size < ipf_objbytes[type][1]) { 6470 IPFERROR(69); 6471 return (EINVAL); 6472 } 6473 } else if (obj.ipfo_size != ipf_objbytes[type][1]) { 6474 IPFERROR(70); 6475 return (EINVAL); 6476 } 6477 6478 error = COPYOUT(ptr, obj.ipfo_ptr, obj.ipfo_size); 6479 if (error != 0) { 6480 IPFERROR(73); 6481 error = EFAULT; 6482 } 6483 } else { 6484 #ifdef IPFILTER_COMPAT 6485 error = ipf_out_compat(softc, &obj, ptr); 6486 #else 6487 IPFERROR(72); 6488 error = EINVAL; 6489 #endif 6490 } 6491 return (error); 6492 } 6493 6494 6495 /* ------------------------------------------------------------------------ */ 6496 /* Function: ipf_outobjk */ 6497 /* Returns: int - 0 = success, else failure */ 6498 /* Parameters: obj(I) - pointer to data description structure */ 6499 /* ptr(I) - pointer to kernel data to copy out */ 6500 /* */ 6501 /* In the above functions, the ipfobj_t structure is copied into the kernel,*/ 6502 /* telling ipfilter how to copy out data. In this instance, the ipfobj_t is */ 6503 /* already populated with information and now we just need to use it. */ 6504 /* There is no need for this function to have a "type" parameter as there */ 6505 /* is no point in validating information that comes from the kernel with */ 6506 /* itself. */ 6507 /* ------------------------------------------------------------------------ */ 6508 int 6509 ipf_outobjk(ipf_main_softc_t *softc, ipfobj_t *obj, void *ptr) 6510 { 6511 int type = obj->ipfo_type; 6512 int error; 6513 6514 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6515 IPFERROR(147); 6516 return (EINVAL); 6517 } 6518 6519 if (obj->ipfo_rev >= ipf_objbytes[type][2]) { 6520 if ((ipf_objbytes[type][0] & 1) != 0) { 6521 if (obj->ipfo_size < ipf_objbytes[type][1]) { 6522 IPFERROR(148); 6523 return (EINVAL); 6524 } 6525 6526 } else if (obj->ipfo_size != ipf_objbytes[type][1]) { 6527 IPFERROR(149); 6528 return (EINVAL); 6529 } 6530 6531 error = COPYOUT(ptr, obj->ipfo_ptr, obj->ipfo_size); 6532 if (error != 0) { 6533 IPFERROR(150); 6534 error = EFAULT; 6535 } 6536 } else { 6537 #ifdef IPFILTER_COMPAT 6538 error = ipf_out_compat(softc, obj, ptr); 6539 #else 6540 IPFERROR(151); 6541 error = EINVAL; 6542 #endif 6543 } 6544 return (error); 6545 } 6546 6547 6548 /* ------------------------------------------------------------------------ */ 6549 /* Function: ipf_checkl4sum */ 6550 /* Returns: int - 0 = good, -1 = bad, 1 = cannot check */ 6551 /* Parameters: fin(I) - pointer to packet information */ 6552 /* */ 6553 /* If possible, calculate the layer 4 checksum for the packet. If this is */ 6554 /* not possible, return without indicating a failure or success but in a */ 6555 /* way that is ditinguishable. This function should only be called by the */ 6556 /* ipf_checkv6sum() for each platform. */ 6557 /* ------------------------------------------------------------------------ */ 6558 inline int 6559 ipf_checkl4sum(fr_info_t *fin) 6560 { 6561 u_short sum, hdrsum, *csump; 6562 udphdr_t *udp; 6563 int dosum; 6564 6565 /* 6566 * If the TCP packet isn't a fragment, isn't too short and otherwise 6567 * isn't already considered "bad", then validate the checksum. If 6568 * this check fails then considered the packet to be "bad". 6569 */ 6570 if ((fin->fin_flx & (FI_FRAG|FI_SHORT|FI_BAD)) != 0) 6571 return (1); 6572 6573 DT2(l4sumo, int, fin->fin_out, int, (int)fin->fin_p); 6574 if (fin->fin_out == 1) { 6575 fin->fin_cksum = FI_CK_SUMOK; 6576 return (0); 6577 } 6578 6579 csump = NULL; 6580 hdrsum = 0; 6581 dosum = 0; 6582 sum = 0; 6583 6584 switch (fin->fin_p) 6585 { 6586 case IPPROTO_TCP : 6587 csump = &((tcphdr_t *)fin->fin_dp)->th_sum; 6588 dosum = 1; 6589 break; 6590 6591 case IPPROTO_UDP : 6592 udp = fin->fin_dp; 6593 if (udp->uh_sum != 0) { 6594 csump = &udp->uh_sum; 6595 dosum = 1; 6596 } 6597 break; 6598 6599 #ifdef USE_INET6 6600 case IPPROTO_ICMPV6 : 6601 csump = &((struct icmp6_hdr *)fin->fin_dp)->icmp6_cksum; 6602 dosum = 1; 6603 break; 6604 #endif 6605 6606 case IPPROTO_ICMP : 6607 csump = &((struct icmp *)fin->fin_dp)->icmp_cksum; 6608 dosum = 1; 6609 break; 6610 6611 default : 6612 return (1); 6613 /*NOTREACHED*/ 6614 } 6615 6616 if (csump != NULL) { 6617 hdrsum = *csump; 6618 if (fin->fin_p == IPPROTO_UDP && hdrsum == 0xffff) 6619 hdrsum = 0x0000; 6620 } 6621 6622 if (dosum) { 6623 sum = fr_cksum(fin, fin->fin_ip, fin->fin_p, fin->fin_dp); 6624 } 6625 #if !defined(_KERNEL) 6626 if (sum == hdrsum) { 6627 FR_DEBUG(("checkl4sum: %hx == %hx\n", sum, hdrsum)); 6628 } else { 6629 FR_DEBUG(("checkl4sum: %hx != %hx\n", sum, hdrsum)); 6630 } 6631 #endif 6632 DT3(l4sums, u_short, hdrsum, u_short, sum, fr_info_t *, fin); 6633 #ifdef USE_INET6 6634 if (hdrsum == sum || (sum == 0 && IP_V(fin->fin_ip) == 6)) { 6635 #else 6636 if (hdrsum == sum) { 6637 #endif 6638 fin->fin_cksum = FI_CK_SUMOK; 6639 return (0); 6640 } 6641 fin->fin_cksum = FI_CK_BAD; 6642 return (-1); 6643 } 6644 6645 6646 /* ------------------------------------------------------------------------ */ 6647 /* Function: ipf_ifpfillv4addr */ 6648 /* Returns: int - 0 = address update, -1 = address not updated */ 6649 /* Parameters: atype(I) - type of network address update to perform */ 6650 /* sin(I) - pointer to source of address information */ 6651 /* mask(I) - pointer to source of netmask information */ 6652 /* inp(I) - pointer to destination address store */ 6653 /* inpmask(I) - pointer to destination netmask store */ 6654 /* */ 6655 /* Given a type of network address update (atype) to perform, copy */ 6656 /* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ 6657 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ 6658 /* which case the operation fails. For all values of atype other than */ 6659 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ 6660 /* value. */ 6661 /* ------------------------------------------------------------------------ */ 6662 int 6663 ipf_ifpfillv4addr(int atype, struct sockaddr_in *sin, struct sockaddr_in *mask, 6664 struct in_addr *inp, struct in_addr *inpmask) 6665 { 6666 if (inpmask != NULL && atype != FRI_NETMASKED) 6667 inpmask->s_addr = 0xffffffff; 6668 6669 if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { 6670 if (atype == FRI_NETMASKED) { 6671 if (inpmask == NULL) 6672 return (-1); 6673 inpmask->s_addr = mask->sin_addr.s_addr; 6674 } 6675 inp->s_addr = sin->sin_addr.s_addr & mask->sin_addr.s_addr; 6676 } else { 6677 inp->s_addr = sin->sin_addr.s_addr; 6678 } 6679 return (0); 6680 } 6681 6682 6683 #ifdef USE_INET6 6684 /* ------------------------------------------------------------------------ */ 6685 /* Function: ipf_ifpfillv6addr */ 6686 /* Returns: int - 0 = address update, -1 = address not updated */ 6687 /* Parameters: atype(I) - type of network address update to perform */ 6688 /* sin(I) - pointer to source of address information */ 6689 /* mask(I) - pointer to source of netmask information */ 6690 /* inp(I) - pointer to destination address store */ 6691 /* inpmask(I) - pointer to destination netmask store */ 6692 /* */ 6693 /* Given a type of network address update (atype) to perform, copy */ 6694 /* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ 6695 /* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ 6696 /* which case the operation fails. For all values of atype other than */ 6697 /* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ 6698 /* value. */ 6699 /* ------------------------------------------------------------------------ */ 6700 int 6701 ipf_ifpfillv6addr(int atype, struct sockaddr_in6 *sin, 6702 struct sockaddr_in6 *mask, i6addr_t *inp, i6addr_t *inpmask) 6703 { 6704 i6addr_t *src, *and; 6705 6706 src = (i6addr_t *)&sin->sin6_addr; 6707 and = (i6addr_t *)&mask->sin6_addr; 6708 6709 if (inpmask != NULL && atype != FRI_NETMASKED) { 6710 inpmask->i6[0] = 0xffffffff; 6711 inpmask->i6[1] = 0xffffffff; 6712 inpmask->i6[2] = 0xffffffff; 6713 inpmask->i6[3] = 0xffffffff; 6714 } 6715 6716 if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { 6717 if (atype == FRI_NETMASKED) { 6718 if (inpmask == NULL) 6719 return (-1); 6720 inpmask->i6[0] = and->i6[0]; 6721 inpmask->i6[1] = and->i6[1]; 6722 inpmask->i6[2] = and->i6[2]; 6723 inpmask->i6[3] = and->i6[3]; 6724 } 6725 6726 inp->i6[0] = src->i6[0] & and->i6[0]; 6727 inp->i6[1] = src->i6[1] & and->i6[1]; 6728 inp->i6[2] = src->i6[2] & and->i6[2]; 6729 inp->i6[3] = src->i6[3] & and->i6[3]; 6730 } else { 6731 inp->i6[0] = src->i6[0]; 6732 inp->i6[1] = src->i6[1]; 6733 inp->i6[2] = src->i6[2]; 6734 inp->i6[3] = src->i6[3]; 6735 } 6736 return (0); 6737 } 6738 #endif 6739 6740 6741 /* ------------------------------------------------------------------------ */ 6742 /* Function: ipf_matchtag */ 6743 /* Returns: 0 == mismatch, 1 == match. */ 6744 /* Parameters: tag1(I) - pointer to first tag to compare */ 6745 /* tag2(I) - pointer to second tag to compare */ 6746 /* */ 6747 /* Returns true (non-zero) or false(0) if the two tag structures can be */ 6748 /* considered to be a match or not match, respectively. The tag is 16 */ 6749 /* bytes long (16 characters) but that is overlayed with 4 32bit ints so */ 6750 /* compare the ints instead, for speed. tag1 is the master of the */ 6751 /* comparison. This function should only be called with both tag1 and tag2 */ 6752 /* as non-NULL pointers. */ 6753 /* ------------------------------------------------------------------------ */ 6754 int 6755 ipf_matchtag(ipftag_t *tag1, ipftag_t *tag2) 6756 { 6757 if (tag1 == tag2) 6758 return (1); 6759 6760 if ((tag1->ipt_num[0] == 0) && (tag2->ipt_num[0] == 0)) 6761 return (1); 6762 6763 if ((tag1->ipt_num[0] == tag2->ipt_num[0]) && 6764 (tag1->ipt_num[1] == tag2->ipt_num[1]) && 6765 (tag1->ipt_num[2] == tag2->ipt_num[2]) && 6766 (tag1->ipt_num[3] == tag2->ipt_num[3])) 6767 return (1); 6768 return (0); 6769 } 6770 6771 6772 /* ------------------------------------------------------------------------ */ 6773 /* Function: ipf_coalesce */ 6774 /* Returns: 1 == success, -1 == failure, 0 == no change */ 6775 /* Parameters: fin(I) - pointer to packet information */ 6776 /* */ 6777 /* Attempt to get all of the packet data into a single, contiguous buffer. */ 6778 /* If this call returns a failure then the buffers have also been freed. */ 6779 /* ------------------------------------------------------------------------ */ 6780 int 6781 ipf_coalesce(fr_info_t *fin) 6782 { 6783 6784 if ((fin->fin_flx & FI_COALESCE) != 0) 6785 return (1); 6786 6787 /* 6788 * If the mbuf pointers indicate that there is no mbuf to work with, 6789 * return but do not indicate success or failure. 6790 */ 6791 if (fin->fin_m == NULL || fin->fin_mp == NULL) 6792 return (0); 6793 6794 #if defined(_KERNEL) 6795 if (ipf_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) { 6796 ipf_main_softc_t *softc = fin->fin_main_soft; 6797 6798 DT1(frb_coalesce, fr_info_t *, fin); 6799 LBUMP(ipf_stats[fin->fin_out].fr_badcoalesces); 6800 # if SOLARIS 6801 FREE_MB_T(*fin->fin_mp); 6802 # endif 6803 fin->fin_reason = FRB_COALESCE; 6804 *fin->fin_mp = NULL; 6805 fin->fin_m = NULL; 6806 return (-1); 6807 } 6808 #else 6809 fin = fin; /* LINT */ 6810 #endif 6811 return (1); 6812 } 6813 6814 6815 /* 6816 * The following table lists all of the tunable variables that can be 6817 * accessed via SIOCIPFGET/SIOCIPFSET/SIOCIPFGETNEXt. The format of each row 6818 * in the table below is as follows: 6819 * 6820 * pointer to value, name of value, minimum, maximum, size of the value's 6821 * container, value attribute flags 6822 * 6823 * For convienience, IPFT_RDONLY means the value is read-only, IPFT_WRDISABLED 6824 * means the value can only be written to when IPFilter is loaded but disabled. 6825 * The obvious implication is if neither of these are set then the value can be 6826 * changed at any time without harm. 6827 */ 6828 6829 6830 /* ------------------------------------------------------------------------ */ 6831 /* Function: ipf_tune_findbycookie */ 6832 /* Returns: NULL = search failed, else pointer to tune struct */ 6833 /* Parameters: cookie(I) - cookie value to search for amongst tuneables */ 6834 /* next(O) - pointer to place to store the cookie for the */ 6835 /* "next" tuneable, if it is desired. */ 6836 /* */ 6837 /* This function is used to walk through all of the existing tunables with */ 6838 /* successive calls. It searches the known tunables for the one which has */ 6839 /* a matching value for "cookie" - ie its address. When returning a match, */ 6840 /* the next one to be found may be returned inside next. */ 6841 /* ------------------------------------------------------------------------ */ 6842 static ipftuneable_t * 6843 ipf_tune_findbycookie(ipftuneable_t **ptop, void *cookie, void **next) 6844 { 6845 ipftuneable_t *ta, **tap; 6846 6847 for (ta = *ptop; ta->ipft_name != NULL; ta++) 6848 if (ta == cookie) { 6849 if (next != NULL) { 6850 /* 6851 * If the next entry in the array has a name 6852 * present, then return a pointer to it for 6853 * where to go next, else return a pointer to 6854 * the dynaminc list as a key to search there 6855 * next. This facilitates a weak linking of 6856 * the two "lists" together. 6857 */ 6858 if ((ta + 1)->ipft_name != NULL) 6859 *next = ta + 1; 6860 else 6861 *next = ptop; 6862 } 6863 return (ta); 6864 } 6865 6866 for (tap = ptop; (ta = *tap) != NULL; tap = &ta->ipft_next) 6867 if (tap == cookie) { 6868 if (next != NULL) 6869 *next = &ta->ipft_next; 6870 return (ta); 6871 } 6872 6873 if (next != NULL) 6874 *next = NULL; 6875 return (NULL); 6876 } 6877 6878 6879 /* ------------------------------------------------------------------------ */ 6880 /* Function: ipf_tune_findbyname */ 6881 /* Returns: NULL = search failed, else pointer to tune struct */ 6882 /* Parameters: name(I) - name of the tuneable entry to find. */ 6883 /* */ 6884 /* Search the static array of tuneables and the list of dynamic tuneables */ 6885 /* for an entry with a matching name. If we can find one, return a pointer */ 6886 /* to the matching structure. */ 6887 /* ------------------------------------------------------------------------ */ 6888 static ipftuneable_t * 6889 ipf_tune_findbyname(ipftuneable_t *top, const char *name) 6890 { 6891 ipftuneable_t *ta; 6892 6893 for (ta = top; ta != NULL; ta = ta->ipft_next) 6894 if (!strcmp(ta->ipft_name, name)) { 6895 return (ta); 6896 } 6897 6898 return (NULL); 6899 } 6900 6901 6902 /* ------------------------------------------------------------------------ */ 6903 /* Function: ipf_tune_add_array */ 6904 /* Returns: int - 0 == success, else failure */ 6905 /* Parameters: newtune - pointer to new tune array to add to tuneables */ 6906 /* */ 6907 /* Appends tune structures from the array passed in (newtune) to the end of */ 6908 /* the current list of "dynamic" tuneable parameters. */ 6909 /* If any entry to be added is already present (by name) then the operation */ 6910 /* is aborted - entries that have been added are removed before returning. */ 6911 /* An entry with no name (NULL) is used as the indication that the end of */ 6912 /* the array has been reached. */ 6913 /* ------------------------------------------------------------------------ */ 6914 int 6915 ipf_tune_add_array(ipf_main_softc_t *softc, ipftuneable_t *newtune) 6916 { 6917 ipftuneable_t *nt, *dt; 6918 int error = 0; 6919 6920 for (nt = newtune; nt->ipft_name != NULL; nt++) { 6921 error = ipf_tune_add(softc, nt); 6922 if (error != 0) { 6923 for (dt = newtune; dt != nt; dt++) { 6924 (void) ipf_tune_del(softc, dt); 6925 } 6926 } 6927 } 6928 6929 return (error); 6930 } 6931 6932 6933 /* ------------------------------------------------------------------------ */ 6934 /* Function: ipf_tune_array_link */ 6935 /* Returns: 0 == success, -1 == failure */ 6936 /* Parameters: softc(I) - soft context pointerto work with */ 6937 /* array(I) - pointer to an array of tuneables */ 6938 /* */ 6939 /* Given an array of tunables (array), append them to the current list of */ 6940 /* tuneables for this context (softc->ipf_tuners.) To properly prepare the */ 6941 /* the array for being appended to the list, initialise all of the next */ 6942 /* pointers so we don't need to walk parts of it with ++ and others with */ 6943 /* next. The array is expected to have an entry with a NULL name as the */ 6944 /* terminator. Trying to add an array with no non-NULL names will return as */ 6945 /* a failure. */ 6946 /* ------------------------------------------------------------------------ */ 6947 int 6948 ipf_tune_array_link(ipf_main_softc_t *softc, ipftuneable_t *array) 6949 { 6950 ipftuneable_t *t, **p; 6951 6952 t = array; 6953 if (t->ipft_name == NULL) 6954 return (-1); 6955 6956 for (; t[1].ipft_name != NULL; t++) 6957 t[0].ipft_next = &t[1]; 6958 t->ipft_next = NULL; 6959 6960 /* 6961 * Since a pointer to the last entry isn't kept, we need to find it 6962 * each time we want to add new variables to the list. 6963 */ 6964 for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next) 6965 if (t->ipft_name == NULL) 6966 break; 6967 *p = array; 6968 6969 return (0); 6970 } 6971 6972 6973 /* ------------------------------------------------------------------------ */ 6974 /* Function: ipf_tune_array_unlink */ 6975 /* Returns: 0 == success, -1 == failure */ 6976 /* Parameters: softc(I) - soft context pointerto work with */ 6977 /* array(I) - pointer to an array of tuneables */ 6978 /* */ 6979 /* ------------------------------------------------------------------------ */ 6980 int 6981 ipf_tune_array_unlink(ipf_main_softc_t *softc, ipftuneable_t *array) 6982 { 6983 ipftuneable_t *t, **p; 6984 6985 for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next) 6986 if (t == array) 6987 break; 6988 if (t == NULL) 6989 return (-1); 6990 6991 for (; t[1].ipft_name != NULL; t++) 6992 ; 6993 6994 *p = t->ipft_next; 6995 6996 return (0); 6997 } 6998 6999 7000 /* ------------------------------------------------------------------------ */ 7001 /* Function: ipf_tune_array_copy */ 7002 /* Returns: NULL = failure, else pointer to new array */ 7003 /* Parameters: base(I) - pointer to structure base */ 7004 /* size(I) - size of the array at template */ 7005 /* template(I) - original array to copy */ 7006 /* */ 7007 /* Allocate memory for a new set of tuneable values and copy everything */ 7008 /* from template into the new region of memory. The new region is full of */ 7009 /* uninitialised pointers (ipft_next) so set them up. Now, ipftp_offset... */ 7010 /* */ 7011 /* NOTE: the following assumes that sizeof(long) == sizeof(void *) */ 7012 /* In the array template, ipftp_offset is the offset (in bytes) of the */ 7013 /* location of the tuneable value inside the structure pointed to by base. */ 7014 /* As ipftp_offset is a union over the pointers to the tuneable values, if */ 7015 /* we add base to the copy's ipftp_offset, copy ends up with a pointer in */ 7016 /* ipftp_void that points to the stored value. */ 7017 /* ------------------------------------------------------------------------ */ 7018 ipftuneable_t * 7019 ipf_tune_array_copy(void *base, size_t size, ipftuneable_t *template) 7020 { 7021 ipftuneable_t *copy; 7022 int i; 7023 7024 7025 KMALLOCS(copy, ipftuneable_t *, size); 7026 if (copy == NULL) { 7027 return (NULL); 7028 } 7029 bcopy(template, copy, size); 7030 7031 for (i = 0; copy[i].ipft_name; i++) { 7032 copy[i].ipft_una.ipftp_offset += (u_long)base; 7033 copy[i].ipft_next = copy + i + 1; 7034 } 7035 7036 return (copy); 7037 } 7038 7039 7040 /* ------------------------------------------------------------------------ */ 7041 /* Function: ipf_tune_add */ 7042 /* Returns: int - 0 == success, else failure */ 7043 /* Parameters: newtune - pointer to new tune entry to add to tuneables */ 7044 /* */ 7045 /* Appends tune structures from the array passed in (newtune) to the end of */ 7046 /* the current list of "dynamic" tuneable parameters. Once added, the */ 7047 /* owner of the object is not expected to ever change "ipft_next". */ 7048 /* ------------------------------------------------------------------------ */ 7049 int 7050 ipf_tune_add(ipf_main_softc_t *softc, ipftuneable_t *newtune) 7051 { 7052 ipftuneable_t *ta, **tap; 7053 7054 ta = ipf_tune_findbyname(softc->ipf_tuners, newtune->ipft_name); 7055 if (ta != NULL) { 7056 IPFERROR(74); 7057 return (EEXIST); 7058 } 7059 7060 for (tap = &softc->ipf_tuners; *tap != NULL; tap = &(*tap)->ipft_next) 7061 ; 7062 7063 newtune->ipft_next = NULL; 7064 *tap = newtune; 7065 return (0); 7066 } 7067 7068 7069 /* ------------------------------------------------------------------------ */ 7070 /* Function: ipf_tune_del */ 7071 /* Returns: int - 0 == success, else failure */ 7072 /* Parameters: oldtune - pointer to tune entry to remove from the list of */ 7073 /* current dynamic tuneables */ 7074 /* */ 7075 /* Search for the tune structure, by pointer, in the list of those that are */ 7076 /* dynamically added at run time. If found, adjust the list so that this */ 7077 /* structure is no longer part of it. */ 7078 /* ------------------------------------------------------------------------ */ 7079 int 7080 ipf_tune_del(ipf_main_softc_t *softc, ipftuneable_t *oldtune) 7081 { 7082 ipftuneable_t *ta, **tap; 7083 int error = 0; 7084 7085 for (tap = &softc->ipf_tuners; (ta = *tap) != NULL; 7086 tap = &ta->ipft_next) { 7087 if (ta == oldtune) { 7088 *tap = oldtune->ipft_next; 7089 oldtune->ipft_next = NULL; 7090 break; 7091 } 7092 } 7093 7094 if (ta == NULL) { 7095 error = ESRCH; 7096 IPFERROR(75); 7097 } 7098 return (error); 7099 } 7100 7101 7102 /* ------------------------------------------------------------------------ */ 7103 /* Function: ipf_tune_del_array */ 7104 /* Returns: int - 0 == success, else failure */ 7105 /* Parameters: oldtune - pointer to tuneables array */ 7106 /* */ 7107 /* Remove each tuneable entry in the array from the list of "dynamic" */ 7108 /* tunables. If one entry should fail to be found, an error will be */ 7109 /* returned and no further ones removed. */ 7110 /* An entry with a NULL name is used as the indicator of the last entry in */ 7111 /* the array. */ 7112 /* ------------------------------------------------------------------------ */ 7113 int 7114 ipf_tune_del_array(ipf_main_softc_t *softc, ipftuneable_t *oldtune) 7115 { 7116 ipftuneable_t *ot; 7117 int error = 0; 7118 7119 for (ot = oldtune; ot->ipft_name != NULL; ot++) { 7120 error = ipf_tune_del(softc, ot); 7121 if (error != 0) 7122 break; 7123 } 7124 7125 return (error); 7126 7127 } 7128 7129 7130 /* ------------------------------------------------------------------------ */ 7131 /* Function: ipf_tune */ 7132 /* Returns: int - 0 == success, else failure */ 7133 /* Parameters: cmd(I) - ioctl command number */ 7134 /* data(I) - pointer to ioctl data structure */ 7135 /* */ 7136 /* Implement handling of SIOCIPFGETNEXT, SIOCIPFGET and SIOCIPFSET. These */ 7137 /* three ioctls provide the means to access and control global variables */ 7138 /* within IPFilter, allowing (for example) timeouts and table sizes to be */ 7139 /* changed without rebooting, reloading or recompiling. The initialisation */ 7140 /* and 'destruction' routines of the various components of ipfilter are all */ 7141 /* each responsible for handling their own values being too big. */ 7142 /* ------------------------------------------------------------------------ */ 7143 int 7144 ipf_ipftune(ipf_main_softc_t *softc, ioctlcmd_t cmd, void *data) 7145 { 7146 ipftuneable_t *ta; 7147 ipftune_t tu; 7148 void *cookie; 7149 int error; 7150 7151 error = ipf_inobj(softc, data, NULL, &tu, IPFOBJ_TUNEABLE); 7152 if (error != 0) 7153 return (error); 7154 7155 tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0'; 7156 cookie = tu.ipft_cookie; 7157 ta = NULL; 7158 7159 switch (cmd) 7160 { 7161 case SIOCIPFGETNEXT : 7162 /* 7163 * If cookie is non-NULL, assume it to be a pointer to the last 7164 * entry we looked at, so find it (if possible) and return a 7165 * pointer to the next one after it. The last entry in the 7166 * the table is a NULL entry, so when we get to it, set cookie 7167 * to NULL and return that, indicating end of list, erstwhile 7168 * if we come in with cookie set to NULL, we are starting anew 7169 * at the front of the list. 7170 */ 7171 if (cookie != NULL) { 7172 ta = ipf_tune_findbycookie(&softc->ipf_tuners, 7173 cookie, &tu.ipft_cookie); 7174 } else { 7175 ta = softc->ipf_tuners; 7176 tu.ipft_cookie = ta + 1; 7177 } 7178 if (ta != NULL) { 7179 /* 7180 * Entry found, but does the data pointed to by that 7181 * row fit in what we can return? 7182 */ 7183 if (ta->ipft_sz > sizeof(tu.ipft_un)) { 7184 IPFERROR(76); 7185 return (EINVAL); 7186 } 7187 7188 tu.ipft_vlong = 0; 7189 if (ta->ipft_sz == sizeof(u_long)) 7190 tu.ipft_vlong = *ta->ipft_plong; 7191 else if (ta->ipft_sz == sizeof(u_int)) 7192 tu.ipft_vint = *ta->ipft_pint; 7193 else if (ta->ipft_sz == sizeof(u_short)) 7194 tu.ipft_vshort = *ta->ipft_pshort; 7195 else if (ta->ipft_sz == sizeof(u_char)) 7196 tu.ipft_vchar = *ta->ipft_pchar; 7197 7198 tu.ipft_sz = ta->ipft_sz; 7199 tu.ipft_min = ta->ipft_min; 7200 tu.ipft_max = ta->ipft_max; 7201 tu.ipft_flags = ta->ipft_flags; 7202 bcopy(ta->ipft_name, tu.ipft_name, 7203 MIN(sizeof(tu.ipft_name), 7204 strlen(ta->ipft_name) + 1)); 7205 } 7206 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE); 7207 break; 7208 7209 case SIOCIPFGET : 7210 case SIOCIPFSET : 7211 /* 7212 * Search by name or by cookie value for a particular entry 7213 * in the tuning parameter table. 7214 */ 7215 IPFERROR(77); 7216 error = ESRCH; 7217 if (cookie != NULL) { 7218 ta = ipf_tune_findbycookie(&softc->ipf_tuners, 7219 cookie, NULL); 7220 if (ta != NULL) 7221 error = 0; 7222 } else if (tu.ipft_name[0] != '\0') { 7223 ta = ipf_tune_findbyname(softc->ipf_tuners, 7224 tu.ipft_name); 7225 if (ta != NULL) 7226 error = 0; 7227 } 7228 if (error != 0) 7229 break; 7230 7231 if (cmd == (ioctlcmd_t)SIOCIPFGET) { 7232 /* 7233 * Fetch the tuning parameters for a particular value 7234 */ 7235 tu.ipft_vlong = 0; 7236 if (ta->ipft_sz == sizeof(u_long)) 7237 tu.ipft_vlong = *ta->ipft_plong; 7238 else if (ta->ipft_sz == sizeof(u_int)) 7239 tu.ipft_vint = *ta->ipft_pint; 7240 else if (ta->ipft_sz == sizeof(u_short)) 7241 tu.ipft_vshort = *ta->ipft_pshort; 7242 else if (ta->ipft_sz == sizeof(u_char)) 7243 tu.ipft_vchar = *ta->ipft_pchar; 7244 tu.ipft_cookie = ta; 7245 tu.ipft_sz = ta->ipft_sz; 7246 tu.ipft_min = ta->ipft_min; 7247 tu.ipft_max = ta->ipft_max; 7248 tu.ipft_flags = ta->ipft_flags; 7249 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE); 7250 7251 } else if (cmd == (ioctlcmd_t)SIOCIPFSET) { 7252 /* 7253 * Set an internal parameter. The hard part here is 7254 * getting the new value safely and correctly out of 7255 * the kernel (given we only know its size, not type.) 7256 */ 7257 u_long in; 7258 7259 if (((ta->ipft_flags & IPFT_WRDISABLED) != 0) && 7260 (softc->ipf_running > 0)) { 7261 IPFERROR(78); 7262 error = EBUSY; 7263 break; 7264 } 7265 7266 in = tu.ipft_vlong; 7267 if (in < ta->ipft_min || in > ta->ipft_max) { 7268 IPFERROR(79); 7269 error = EINVAL; 7270 break; 7271 } 7272 7273 if (ta->ipft_func != NULL) { 7274 SPL_INT(s); 7275 7276 SPL_NET(s); 7277 error = (*ta->ipft_func)(softc, ta, 7278 &tu.ipft_un); 7279 SPL_X(s); 7280 7281 } else if (ta->ipft_sz == sizeof(u_long)) { 7282 tu.ipft_vlong = *ta->ipft_plong; 7283 *ta->ipft_plong = in; 7284 7285 } else if (ta->ipft_sz == sizeof(u_int)) { 7286 tu.ipft_vint = *ta->ipft_pint; 7287 *ta->ipft_pint = (u_int)(in & 0xffffffff); 7288 7289 } else if (ta->ipft_sz == sizeof(u_short)) { 7290 tu.ipft_vshort = *ta->ipft_pshort; 7291 *ta->ipft_pshort = (u_short)(in & 0xffff); 7292 7293 } else if (ta->ipft_sz == sizeof(u_char)) { 7294 tu.ipft_vchar = *ta->ipft_pchar; 7295 *ta->ipft_pchar = (u_char)(in & 0xff); 7296 } 7297 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE); 7298 } 7299 break; 7300 7301 default : 7302 IPFERROR(80); 7303 error = EINVAL; 7304 break; 7305 } 7306 7307 return (error); 7308 } 7309 7310 7311 /* ------------------------------------------------------------------------ */ 7312 /* Function: ipf_zerostats */ 7313 /* Returns: int - 0 = success, else failure */ 7314 /* Parameters: data(O) - pointer to pointer for copying data back to */ 7315 /* */ 7316 /* Copies the current statistics out to userspace and then zero's the */ 7317 /* current ones in the kernel. The lock is only held across the bzero() as */ 7318 /* the copyout may result in paging (ie network activity.) */ 7319 /* ------------------------------------------------------------------------ */ 7320 int 7321 ipf_zerostats(ipf_main_softc_t *softc, caddr_t data) 7322 { 7323 friostat_t fio; 7324 ipfobj_t obj; 7325 int error; 7326 7327 error = ipf_inobj(softc, data, &obj, &fio, IPFOBJ_IPFSTAT); 7328 if (error != 0) 7329 return (error); 7330 ipf_getstat(softc, &fio, obj.ipfo_rev); 7331 error = ipf_outobj(softc, data, &fio, IPFOBJ_IPFSTAT); 7332 if (error != 0) 7333 return (error); 7334 7335 WRITE_ENTER(&softc->ipf_mutex); 7336 bzero(&softc->ipf_stats, sizeof(softc->ipf_stats)); 7337 RWLOCK_EXIT(&softc->ipf_mutex); 7338 7339 return (0); 7340 } 7341 7342 7343 /* ------------------------------------------------------------------------ */ 7344 /* Function: ipf_resolvedest */ 7345 /* Returns: Nil */ 7346 /* Parameters: softc(I) - pointer to soft context main structure */ 7347 /* base(I) - where strings are stored */ 7348 /* fdp(IO) - pointer to destination information to resolve */ 7349 /* v(I) - IP protocol version to match */ 7350 /* */ 7351 /* Looks up an interface name in the frdest structure pointed to by fdp and */ 7352 /* if a matching name can be found for the particular IP protocol version */ 7353 /* then store the interface pointer in the frdest struct. If no match is */ 7354 /* found, then set the interface pointer to be -1 as NULL is considered to */ 7355 /* indicate there is no information at all in the structure. */ 7356 /* ------------------------------------------------------------------------ */ 7357 int 7358 ipf_resolvedest(ipf_main_softc_t *softc, char *base, frdest_t *fdp, int v) 7359 { 7360 int errval = 0; 7361 void *ifp; 7362 7363 ifp = NULL; 7364 7365 if (fdp->fd_name != -1) { 7366 if (fdp->fd_type == FRD_DSTLIST) { 7367 ifp = ipf_lookup_res_name(softc, IPL_LOGIPF, 7368 IPLT_DSTLIST, 7369 base + fdp->fd_name, 7370 NULL); 7371 if (ifp == NULL) { 7372 IPFERROR(144); 7373 errval = ESRCH; 7374 } 7375 } else { 7376 ifp = GETIFP(base + fdp->fd_name, v); 7377 if (ifp == NULL) 7378 ifp = (void *)-1; 7379 } 7380 } 7381 fdp->fd_ptr = ifp; 7382 7383 return (errval); 7384 } 7385 7386 7387 /* ------------------------------------------------------------------------ */ 7388 /* Function: ipf_resolvenic */ 7389 /* Returns: void* - NULL = wildcard name, -1 = failed to find NIC, else */ 7390 /* pointer to interface structure for NIC */ 7391 /* Parameters: softc(I)- pointer to soft context main structure */ 7392 /* name(I) - complete interface name */ 7393 /* v(I) - IP protocol version */ 7394 /* */ 7395 /* Look for a network interface structure that firstly has a matching name */ 7396 /* to that passed in and that is also being used for that IP protocol */ 7397 /* version (necessary on some platforms where there are separate listings */ 7398 /* for both IPv4 and IPv6 on the same physical NIC. */ 7399 /* ------------------------------------------------------------------------ */ 7400 void * 7401 ipf_resolvenic(ipf_main_softc_t *softc __unused, char *name, int v) 7402 { 7403 void *nic; 7404 7405 if (name[0] == '\0') 7406 return (NULL); 7407 7408 if ((name[1] == '\0') && ((name[0] == '-') || (name[0] == '*'))) { 7409 return (NULL); 7410 } 7411 7412 nic = GETIFP(name, v); 7413 if (nic == NULL) 7414 nic = (void *)-1; 7415 return (nic); 7416 } 7417 7418 7419 /* ------------------------------------------------------------------------ */ 7420 /* Function: ipf_token_expire */ 7421 /* Returns: None. */ 7422 /* Parameters: softc(I) - pointer to soft context main structure */ 7423 /* */ 7424 /* This function is run every ipf tick to see if there are any tokens that */ 7425 /* have been held for too long and need to be freed up. */ 7426 /* ------------------------------------------------------------------------ */ 7427 void 7428 ipf_token_expire(ipf_main_softc_t *softc) 7429 { 7430 ipftoken_t *it; 7431 7432 WRITE_ENTER(&softc->ipf_tokens); 7433 while ((it = softc->ipf_token_head) != NULL) { 7434 if (it->ipt_die > softc->ipf_ticks) 7435 break; 7436 7437 ipf_token_deref(softc, it); 7438 } 7439 RWLOCK_EXIT(&softc->ipf_tokens); 7440 } 7441 7442 7443 /* ------------------------------------------------------------------------ */ 7444 /* Function: ipf_token_flush */ 7445 /* Returns: None. */ 7446 /* Parameters: softc(I) - pointer to soft context main structure */ 7447 /* */ 7448 /* Loop through all of the existing tokens and call deref to see if they */ 7449 /* can be freed. Normally a function like this might just loop on */ 7450 /* ipf_token_head but there is a chance that a token might have a ref count */ 7451 /* of greater than one and in that case the reference would drop twice */ 7452 /* by code that is only entitled to drop it once. */ 7453 /* ------------------------------------------------------------------------ */ 7454 static void 7455 ipf_token_flush(ipf_main_softc_t *softc) 7456 { 7457 ipftoken_t *it, *next; 7458 7459 WRITE_ENTER(&softc->ipf_tokens); 7460 for (it = softc->ipf_token_head; it != NULL; it = next) { 7461 next = it->ipt_next; 7462 (void) ipf_token_deref(softc, it); 7463 } 7464 RWLOCK_EXIT(&softc->ipf_tokens); 7465 } 7466 7467 7468 /* ------------------------------------------------------------------------ */ 7469 /* Function: ipf_token_del */ 7470 /* Returns: int - 0 = success, else error */ 7471 /* Parameters: softc(I)- pointer to soft context main structure */ 7472 /* type(I) - the token type to match */ 7473 /* uid(I) - uid owning the token */ 7474 /* ptr(I) - context pointer for the token */ 7475 /* */ 7476 /* This function looks for a token in the current list that matches up */ 7477 /* the fields (type, uid, ptr). If none is found, ESRCH is returned, else */ 7478 /* call ipf_token_dewref() to remove it from the list. In the event that */ 7479 /* the token has a reference held elsewhere, setting ipt_complete to 2 */ 7480 /* enables debugging to distinguish between the two paths that ultimately */ 7481 /* lead to a token to be deleted. */ 7482 /* ------------------------------------------------------------------------ */ 7483 int 7484 ipf_token_del(ipf_main_softc_t *softc, int type, int uid, void *ptr) 7485 { 7486 ipftoken_t *it; 7487 int error; 7488 7489 IPFERROR(82); 7490 error = ESRCH; 7491 7492 WRITE_ENTER(&softc->ipf_tokens); 7493 for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) { 7494 if (ptr == it->ipt_ctx && type == it->ipt_type && 7495 uid == it->ipt_uid) { 7496 it->ipt_complete = 2; 7497 ipf_token_deref(softc, it); 7498 error = 0; 7499 break; 7500 } 7501 } 7502 RWLOCK_EXIT(&softc->ipf_tokens); 7503 7504 return (error); 7505 } 7506 7507 7508 /* ------------------------------------------------------------------------ */ 7509 /* Function: ipf_token_mark_complete */ 7510 /* Returns: None. */ 7511 /* Parameters: token(I) - pointer to token structure */ 7512 /* */ 7513 /* Mark a token as being ineligable for being found with ipf_token_find. */ 7514 /* ------------------------------------------------------------------------ */ 7515 void 7516 ipf_token_mark_complete(ipftoken_t *token) 7517 { 7518 if (token->ipt_complete == 0) 7519 token->ipt_complete = 1; 7520 } 7521 7522 7523 /* ------------------------------------------------------------------------ */ 7524 /* Function: ipf_token_find */ 7525 /* Returns: ipftoken_t * - NULL if no memory, else pointer to token */ 7526 /* Parameters: softc(I)- pointer to soft context main structure */ 7527 /* type(I) - the token type to match */ 7528 /* uid(I) - uid owning the token */ 7529 /* ptr(I) - context pointer for the token */ 7530 /* */ 7531 /* This function looks for a live token in the list of current tokens that */ 7532 /* matches the tuple (type, uid, ptr). If one cannot be found then one is */ 7533 /* allocated. If one is found then it is moved to the top of the list of */ 7534 /* currently active tokens. */ 7535 /* ------------------------------------------------------------------------ */ 7536 ipftoken_t * 7537 ipf_token_find(ipf_main_softc_t *softc, int type, int uid, void *ptr) 7538 { 7539 ipftoken_t *it, *new; 7540 7541 KMALLOC(new, ipftoken_t *); 7542 if (new != NULL) 7543 bzero((char *)new, sizeof(*new)); 7544 7545 WRITE_ENTER(&softc->ipf_tokens); 7546 for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) { 7547 if ((ptr == it->ipt_ctx) && (type == it->ipt_type) && 7548 (uid == it->ipt_uid) && (it->ipt_complete < 2)) 7549 break; 7550 } 7551 7552 if (it == NULL) { 7553 it = new; 7554 new = NULL; 7555 if (it == NULL) { 7556 RWLOCK_EXIT(&softc->ipf_tokens); 7557 return (NULL); 7558 } 7559 it->ipt_ctx = ptr; 7560 it->ipt_uid = uid; 7561 it->ipt_type = type; 7562 it->ipt_ref = 1; 7563 } else { 7564 if (new != NULL) { 7565 KFREE(new); 7566 new = NULL; 7567 } 7568 7569 if (it->ipt_complete > 0) 7570 it = NULL; 7571 else 7572 ipf_token_unlink(softc, it); 7573 } 7574 7575 if (it != NULL) { 7576 it->ipt_pnext = softc->ipf_token_tail; 7577 *softc->ipf_token_tail = it; 7578 softc->ipf_token_tail = &it->ipt_next; 7579 it->ipt_next = NULL; 7580 it->ipt_ref++; 7581 7582 it->ipt_die = softc->ipf_ticks + 20; 7583 } 7584 7585 RWLOCK_EXIT(&softc->ipf_tokens); 7586 7587 return (it); 7588 } 7589 7590 7591 /* ------------------------------------------------------------------------ */ 7592 /* Function: ipf_token_unlink */ 7593 /* Returns: None. */ 7594 /* Parameters: softc(I) - pointer to soft context main structure */ 7595 /* token(I) - pointer to token structure */ 7596 /* Write Locks: ipf_tokens */ 7597 /* */ 7598 /* This function unlinks a token structure from the linked list of tokens */ 7599 /* that "own" it. The head pointer never needs to be explicitly adjusted */ 7600 /* but the tail does due to the linked list implementation. */ 7601 /* ------------------------------------------------------------------------ */ 7602 static void 7603 ipf_token_unlink(ipf_main_softc_t *softc, ipftoken_t *token) 7604 { 7605 7606 if (softc->ipf_token_tail == &token->ipt_next) 7607 softc->ipf_token_tail = token->ipt_pnext; 7608 7609 *token->ipt_pnext = token->ipt_next; 7610 if (token->ipt_next != NULL) 7611 token->ipt_next->ipt_pnext = token->ipt_pnext; 7612 token->ipt_next = NULL; 7613 token->ipt_pnext = NULL; 7614 } 7615 7616 7617 /* ------------------------------------------------------------------------ */ 7618 /* Function: ipf_token_deref */ 7619 /* Returns: int - 0 == token freed, else reference count */ 7620 /* Parameters: softc(I) - pointer to soft context main structure */ 7621 /* token(I) - pointer to token structure */ 7622 /* Write Locks: ipf_tokens */ 7623 /* */ 7624 /* Drop the reference count on the token structure and if it drops to zero, */ 7625 /* call the dereference function for the token type because it is then */ 7626 /* possible to free the token data structure. */ 7627 /* ------------------------------------------------------------------------ */ 7628 int 7629 ipf_token_deref(ipf_main_softc_t *softc, ipftoken_t *token) 7630 { 7631 void *data, **datap; 7632 7633 ASSERT(token->ipt_ref > 0); 7634 token->ipt_ref--; 7635 if (token->ipt_ref > 0) 7636 return (token->ipt_ref); 7637 7638 data = token->ipt_data; 7639 datap = &data; 7640 7641 if ((data != NULL) && (data != (void *)-1)) { 7642 switch (token->ipt_type) 7643 { 7644 case IPFGENITER_IPF : 7645 (void) ipf_derefrule(softc, (frentry_t **)datap); 7646 break; 7647 case IPFGENITER_IPNAT : 7648 WRITE_ENTER(&softc->ipf_nat); 7649 ipf_nat_rule_deref(softc, (ipnat_t **)datap); 7650 RWLOCK_EXIT(&softc->ipf_nat); 7651 break; 7652 case IPFGENITER_NAT : 7653 ipf_nat_deref(softc, (nat_t **)datap); 7654 break; 7655 case IPFGENITER_STATE : 7656 ipf_state_deref(softc, (ipstate_t **)datap); 7657 break; 7658 case IPFGENITER_FRAG : 7659 ipf_frag_pkt_deref(softc, (ipfr_t **)datap); 7660 break; 7661 case IPFGENITER_NATFRAG : 7662 ipf_frag_nat_deref(softc, (ipfr_t **)datap); 7663 break; 7664 case IPFGENITER_HOSTMAP : 7665 WRITE_ENTER(&softc->ipf_nat); 7666 ipf_nat_hostmapdel(softc, (hostmap_t **)datap); 7667 RWLOCK_EXIT(&softc->ipf_nat); 7668 break; 7669 default : 7670 ipf_lookup_iterderef(softc, token->ipt_type, data); 7671 break; 7672 } 7673 } 7674 7675 ipf_token_unlink(softc, token); 7676 KFREE(token); 7677 return (0); 7678 } 7679 7680 7681 /* ------------------------------------------------------------------------ */ 7682 /* Function: ipf_nextrule */ 7683 /* Returns: frentry_t * - NULL == no more rules, else pointer to next */ 7684 /* Parameters: softc(I) - pointer to soft context main structure */ 7685 /* fr(I) - pointer to filter rule */ 7686 /* out(I) - 1 == out rules, 0 == input rules */ 7687 /* */ 7688 /* Starting with "fr", find the next rule to visit. This includes visiting */ 7689 /* the list of rule groups if either fr is NULL (empty list) or it is the */ 7690 /* last rule in the list. When walking rule lists, it is either input or */ 7691 /* output rules that are returned, never both. */ 7692 /* ------------------------------------------------------------------------ */ 7693 static frentry_t * 7694 ipf_nextrule(ipf_main_softc_t *softc, int active, int unit, frentry_t *fr, 7695 int out) 7696 { 7697 frentry_t *next; 7698 frgroup_t *fg; 7699 7700 if (fr != NULL && fr->fr_group != -1) { 7701 fg = ipf_findgroup(softc, fr->fr_names + fr->fr_group, 7702 unit, active, NULL); 7703 if (fg != NULL) 7704 fg = fg->fg_next; 7705 } else { 7706 fg = softc->ipf_groups[unit][active]; 7707 } 7708 7709 while (fg != NULL) { 7710 next = fg->fg_start; 7711 while (next != NULL) { 7712 if (out) { 7713 if (next->fr_flags & FR_OUTQUE) 7714 return (next); 7715 } else if (next->fr_flags & FR_INQUE) { 7716 return (next); 7717 } 7718 next = next->fr_next; 7719 } 7720 if (next == NULL) 7721 fg = fg->fg_next; 7722 } 7723 7724 return (NULL); 7725 } 7726 7727 /* ------------------------------------------------------------------------ */ 7728 /* Function: ipf_getnextrule */ 7729 /* Returns: int - 0 = success, else error */ 7730 /* Parameters: softc(I)- pointer to soft context main structure */ 7731 /* t(I) - pointer to destination information to resolve */ 7732 /* ptr(I) - pointer to ipfobj_t to copyin from user space */ 7733 /* */ 7734 /* This function's first job is to bring in the ipfruleiter_t structure via */ 7735 /* the ipfobj_t structure to determine what should be the next rule to */ 7736 /* return. Once the ipfruleiter_t has been brought in, it then tries to */ 7737 /* find the 'next rule'. This may include searching rule group lists or */ 7738 /* just be as simple as looking at the 'next' field in the rule structure. */ 7739 /* When we have found the rule to return, increase its reference count and */ 7740 /* if we used an existing rule to get here, decrease its reference count. */ 7741 /* ------------------------------------------------------------------------ */ 7742 int 7743 ipf_getnextrule(ipf_main_softc_t *softc, ipftoken_t *t, void *ptr) 7744 { 7745 frentry_t *fr, *next, zero; 7746 ipfruleiter_t it; 7747 int error, out; 7748 frgroup_t *fg; 7749 ipfobj_t obj; 7750 int predict; 7751 char *dst; 7752 int unit; 7753 7754 if (t == NULL || ptr == NULL) { 7755 IPFERROR(84); 7756 return (EFAULT); 7757 } 7758 7759 error = ipf_inobj(softc, ptr, &obj, &it, IPFOBJ_IPFITER); 7760 if (error != 0) 7761 return (error); 7762 7763 if ((it.iri_inout < 0) || (it.iri_inout > 3)) { 7764 IPFERROR(85); 7765 return (EINVAL); 7766 } 7767 if ((it.iri_active != 0) && (it.iri_active != 1)) { 7768 IPFERROR(86); 7769 return (EINVAL); 7770 } 7771 if (it.iri_nrules == 0) { 7772 IPFERROR(87); 7773 return (ENOSPC); 7774 } 7775 if (it.iri_rule == NULL) { 7776 IPFERROR(88); 7777 return (EFAULT); 7778 } 7779 7780 fg = NULL; 7781 fr = t->ipt_data; 7782 if ((it.iri_inout & F_OUT) != 0) 7783 out = 1; 7784 else 7785 out = 0; 7786 if ((it.iri_inout & F_ACIN) != 0) 7787 unit = IPL_LOGCOUNT; 7788 else 7789 unit = IPL_LOGIPF; 7790 7791 READ_ENTER(&softc->ipf_mutex); 7792 if (fr == NULL) { 7793 if (*it.iri_group == '\0') { 7794 if (unit == IPL_LOGCOUNT) { 7795 next = softc->ipf_acct[out][it.iri_active]; 7796 } else { 7797 next = softc->ipf_rules[out][it.iri_active]; 7798 } 7799 if (next == NULL) 7800 next = ipf_nextrule(softc, it.iri_active, 7801 unit, NULL, out); 7802 } else { 7803 fg = ipf_findgroup(softc, it.iri_group, unit, 7804 it.iri_active, NULL); 7805 if (fg != NULL) 7806 next = fg->fg_start; 7807 else 7808 next = NULL; 7809 } 7810 } else { 7811 next = fr->fr_next; 7812 if (next == NULL) 7813 next = ipf_nextrule(softc, it.iri_active, unit, 7814 fr, out); 7815 } 7816 7817 if (next != NULL && next->fr_next != NULL) 7818 predict = 1; 7819 else if (ipf_nextrule(softc, it.iri_active, unit, next, out) != NULL) 7820 predict = 1; 7821 else 7822 predict = 0; 7823 7824 if (fr != NULL) 7825 (void) ipf_derefrule(softc, &fr); 7826 7827 obj.ipfo_type = IPFOBJ_FRENTRY; 7828 dst = (char *)it.iri_rule; 7829 7830 if (next != NULL) { 7831 obj.ipfo_size = next->fr_size; 7832 MUTEX_ENTER(&next->fr_lock); 7833 next->fr_ref++; 7834 MUTEX_EXIT(&next->fr_lock); 7835 t->ipt_data = next; 7836 } else { 7837 obj.ipfo_size = sizeof(frentry_t); 7838 bzero(&zero, sizeof(zero)); 7839 next = &zero; 7840 t->ipt_data = NULL; 7841 } 7842 it.iri_rule = predict ? next : NULL; 7843 if (predict == 0) 7844 ipf_token_mark_complete(t); 7845 7846 RWLOCK_EXIT(&softc->ipf_mutex); 7847 7848 obj.ipfo_ptr = dst; 7849 error = ipf_outobjk(softc, &obj, next); 7850 if (error == 0 && t->ipt_data != NULL) { 7851 dst += obj.ipfo_size; 7852 if (next->fr_data != NULL) { 7853 ipfobj_t dobj; 7854 7855 if (next->fr_type == FR_T_IPFEXPR) 7856 dobj.ipfo_type = IPFOBJ_IPFEXPR; 7857 else 7858 dobj.ipfo_type = IPFOBJ_FRIPF; 7859 dobj.ipfo_size = next->fr_dsize; 7860 dobj.ipfo_rev = obj.ipfo_rev; 7861 dobj.ipfo_ptr = dst; 7862 error = ipf_outobjk(softc, &dobj, next->fr_data); 7863 } 7864 } 7865 7866 if ((fr != NULL) && (next == &zero)) 7867 (void) ipf_derefrule(softc, &fr); 7868 7869 return (error); 7870 } 7871 7872 7873 /* ------------------------------------------------------------------------ */ 7874 /* Function: ipf_frruleiter */ 7875 /* Returns: int - 0 = success, else error */ 7876 /* Parameters: softc(I)- pointer to soft context main structure */ 7877 /* data(I) - the token type to match */ 7878 /* uid(I) - uid owning the token */ 7879 /* ptr(I) - context pointer for the token */ 7880 /* */ 7881 /* This function serves as a stepping stone between ipf_ipf_ioctl and */ 7882 /* ipf_getnextrule. It's role is to find the right token in the kernel for */ 7883 /* the process doing the ioctl and use that to ask for the next rule. */ 7884 /* ------------------------------------------------------------------------ */ 7885 static int 7886 ipf_frruleiter(ipf_main_softc_t *softc, void *data, int uid, void *ctx) 7887 { 7888 ipftoken_t *token; 7889 ipfruleiter_t it; 7890 ipfobj_t obj; 7891 int error; 7892 7893 token = ipf_token_find(softc, IPFGENITER_IPF, uid, ctx); 7894 if (token != NULL) { 7895 error = ipf_getnextrule(softc, token, data); 7896 WRITE_ENTER(&softc->ipf_tokens); 7897 ipf_token_deref(softc, token); 7898 RWLOCK_EXIT(&softc->ipf_tokens); 7899 } else { 7900 error = ipf_inobj(softc, data, &obj, &it, IPFOBJ_IPFITER); 7901 if (error != 0) 7902 return (error); 7903 it.iri_rule = NULL; 7904 error = ipf_outobj(softc, data, &it, IPFOBJ_IPFITER); 7905 } 7906 7907 return (error); 7908 } 7909 7910 7911 /* ------------------------------------------------------------------------ */ 7912 /* Function: ipf_geniter */ 7913 /* Returns: int - 0 = success, else error */ 7914 /* Parameters: softc(I) - pointer to soft context main structure */ 7915 /* token(I) - pointer to ipftoken_t structure */ 7916 /* itp(I) - pointer to iterator data */ 7917 /* */ 7918 /* Decide which iterator function to call using information passed through */ 7919 /* the ipfgeniter_t structure at itp. */ 7920 /* ------------------------------------------------------------------------ */ 7921 static int 7922 ipf_geniter(ipf_main_softc_t *softc, ipftoken_t *token, ipfgeniter_t *itp) 7923 { 7924 int error; 7925 7926 switch (itp->igi_type) 7927 { 7928 case IPFGENITER_FRAG : 7929 error = ipf_frag_pkt_next(softc, token, itp); 7930 break; 7931 default : 7932 IPFERROR(92); 7933 error = EINVAL; 7934 break; 7935 } 7936 7937 return (error); 7938 } 7939 7940 7941 /* ------------------------------------------------------------------------ */ 7942 /* Function: ipf_genericiter */ 7943 /* Returns: int - 0 = success, else error */ 7944 /* Parameters: softc(I)- pointer to soft context main structure */ 7945 /* data(I) - the token type to match */ 7946 /* uid(I) - uid owning the token */ 7947 /* ptr(I) - context pointer for the token */ 7948 /* */ 7949 /* Handle the SIOCGENITER ioctl for the ipfilter device. The primary role */ 7950 /* ------------------------------------------------------------------------ */ 7951 int 7952 ipf_genericiter(ipf_main_softc_t *softc, void *data, int uid, void *ctx) 7953 { 7954 ipftoken_t *token; 7955 ipfgeniter_t iter; 7956 int error; 7957 7958 error = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_GENITER); 7959 if (error != 0) 7960 return (error); 7961 7962 token = ipf_token_find(softc, iter.igi_type, uid, ctx); 7963 if (token != NULL) { 7964 token->ipt_subtype = iter.igi_type; 7965 error = ipf_geniter(softc, token, &iter); 7966 WRITE_ENTER(&softc->ipf_tokens); 7967 ipf_token_deref(softc, token); 7968 RWLOCK_EXIT(&softc->ipf_tokens); 7969 } else { 7970 IPFERROR(93); 7971 error = 0; 7972 } 7973 7974 return (error); 7975 } 7976 7977 7978 /* ------------------------------------------------------------------------ */ 7979 /* Function: ipf_ipf_ioctl */ 7980 /* Returns: int - 0 = success, else error */ 7981 /* Parameters: softc(I)- pointer to soft context main structure */ 7982 /* data(I) - the token type to match */ 7983 /* cmd(I) - the ioctl command number */ 7984 /* mode(I) - mode flags for the ioctl */ 7985 /* uid(I) - uid owning the token */ 7986 /* ptr(I) - context pointer for the token */ 7987 /* */ 7988 /* This function handles all of the ioctl command that are actually issued */ 7989 /* to the /dev/ipl device. */ 7990 /* ------------------------------------------------------------------------ */ 7991 int 7992 ipf_ipf_ioctl(ipf_main_softc_t *softc, caddr_t data, ioctlcmd_t cmd, int mode, 7993 int uid, void *ctx) 7994 { 7995 friostat_t fio; 7996 int error, tmp; 7997 ipfobj_t obj; 7998 SPL_INT(s); 7999 8000 switch (cmd) 8001 { 8002 case SIOCFRENB : 8003 if (!(mode & FWRITE)) { 8004 IPFERROR(94); 8005 error = EPERM; 8006 } else { 8007 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8008 if (error != 0) { 8009 IPFERROR(95); 8010 error = EFAULT; 8011 break; 8012 } 8013 8014 WRITE_ENTER(&softc->ipf_global); 8015 if (tmp) { 8016 if (softc->ipf_running > 0) 8017 error = 0; 8018 else 8019 error = ipfattach(softc); 8020 if (error == 0) 8021 softc->ipf_running = 1; 8022 else 8023 (void) ipfdetach(softc); 8024 } else { 8025 if (softc->ipf_running == 1) 8026 error = ipfdetach(softc); 8027 else 8028 error = 0; 8029 if (error == 0) 8030 softc->ipf_running = -1; 8031 } 8032 RWLOCK_EXIT(&softc->ipf_global); 8033 } 8034 break; 8035 8036 case SIOCIPFSET : 8037 if (!(mode & FWRITE)) { 8038 IPFERROR(96); 8039 error = EPERM; 8040 break; 8041 } 8042 /* FALLTHRU */ 8043 case SIOCIPFGETNEXT : 8044 case SIOCIPFGET : 8045 error = ipf_ipftune(softc, cmd, (void *)data); 8046 break; 8047 8048 case SIOCSETFF : 8049 if (!(mode & FWRITE)) { 8050 IPFERROR(97); 8051 error = EPERM; 8052 } else { 8053 error = BCOPYIN(data, &softc->ipf_flags, 8054 sizeof(softc->ipf_flags)); 8055 if (error != 0) { 8056 IPFERROR(98); 8057 error = EFAULT; 8058 } 8059 } 8060 break; 8061 8062 case SIOCGETFF : 8063 error = BCOPYOUT(&softc->ipf_flags, data, 8064 sizeof(softc->ipf_flags)); 8065 if (error != 0) { 8066 IPFERROR(99); 8067 error = EFAULT; 8068 } 8069 break; 8070 8071 case SIOCFUNCL : 8072 error = ipf_resolvefunc(softc, (void *)data); 8073 break; 8074 8075 case SIOCINAFR : 8076 case SIOCRMAFR : 8077 case SIOCADAFR : 8078 case SIOCZRLST : 8079 if (!(mode & FWRITE)) { 8080 IPFERROR(100); 8081 error = EPERM; 8082 } else { 8083 error = frrequest(softc, IPL_LOGIPF, cmd, (caddr_t)data, 8084 softc->ipf_active, 1); 8085 } 8086 break; 8087 8088 case SIOCINIFR : 8089 case SIOCRMIFR : 8090 case SIOCADIFR : 8091 if (!(mode & FWRITE)) { 8092 IPFERROR(101); 8093 error = EPERM; 8094 } else { 8095 error = frrequest(softc, IPL_LOGIPF, cmd, (caddr_t)data, 8096 1 - softc->ipf_active, 1); 8097 } 8098 break; 8099 8100 case SIOCSWAPA : 8101 if (!(mode & FWRITE)) { 8102 IPFERROR(102); 8103 error = EPERM; 8104 } else { 8105 WRITE_ENTER(&softc->ipf_mutex); 8106 error = BCOPYOUT(&softc->ipf_active, data, 8107 sizeof(softc->ipf_active)); 8108 if (error != 0) { 8109 IPFERROR(103); 8110 error = EFAULT; 8111 } else { 8112 softc->ipf_active = 1 - softc->ipf_active; 8113 } 8114 RWLOCK_EXIT(&softc->ipf_mutex); 8115 } 8116 break; 8117 8118 case SIOCGETFS : 8119 error = ipf_inobj(softc, (void *)data, &obj, &fio, 8120 IPFOBJ_IPFSTAT); 8121 if (error != 0) 8122 break; 8123 ipf_getstat(softc, &fio, obj.ipfo_rev); 8124 error = ipf_outobj(softc, (void *)data, &fio, IPFOBJ_IPFSTAT); 8125 break; 8126 8127 case SIOCFRZST : 8128 if (!(mode & FWRITE)) { 8129 IPFERROR(104); 8130 error = EPERM; 8131 } else 8132 error = ipf_zerostats(softc, (caddr_t)data); 8133 break; 8134 8135 case SIOCIPFFL : 8136 if (!(mode & FWRITE)) { 8137 IPFERROR(105); 8138 error = EPERM; 8139 } else { 8140 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8141 if (!error) { 8142 tmp = ipf_flush(softc, IPL_LOGIPF, tmp); 8143 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8144 if (error != 0) { 8145 IPFERROR(106); 8146 error = EFAULT; 8147 } 8148 } else { 8149 IPFERROR(107); 8150 error = EFAULT; 8151 } 8152 } 8153 break; 8154 8155 #ifdef USE_INET6 8156 case SIOCIPFL6 : 8157 if (!(mode & FWRITE)) { 8158 IPFERROR(108); 8159 error = EPERM; 8160 } else { 8161 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8162 if (!error) { 8163 tmp = ipf_flush(softc, IPL_LOGIPF, tmp); 8164 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8165 if (error != 0) { 8166 IPFERROR(109); 8167 error = EFAULT; 8168 } 8169 } else { 8170 IPFERROR(110); 8171 error = EFAULT; 8172 } 8173 } 8174 break; 8175 #endif 8176 8177 case SIOCSTLCK : 8178 if (!(mode & FWRITE)) { 8179 IPFERROR(122); 8180 error = EPERM; 8181 } else { 8182 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8183 if (error == 0) { 8184 ipf_state_setlock(softc->ipf_state_soft, tmp); 8185 ipf_nat_setlock(softc->ipf_nat_soft, tmp); 8186 ipf_frag_setlock(softc->ipf_frag_soft, tmp); 8187 ipf_auth_setlock(softc->ipf_auth_soft, tmp); 8188 } else { 8189 IPFERROR(111); 8190 error = EFAULT; 8191 } 8192 } 8193 break; 8194 8195 #ifdef IPFILTER_LOG 8196 case SIOCIPFFB : 8197 if (!(mode & FWRITE)) { 8198 IPFERROR(112); 8199 error = EPERM; 8200 } else { 8201 tmp = ipf_log_clear(softc, IPL_LOGIPF); 8202 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8203 if (error) { 8204 IPFERROR(113); 8205 error = EFAULT; 8206 } 8207 } 8208 break; 8209 #endif /* IPFILTER_LOG */ 8210 8211 case SIOCFRSYN : 8212 if (!(mode & FWRITE)) { 8213 IPFERROR(114); 8214 error = EPERM; 8215 } else { 8216 WRITE_ENTER(&softc->ipf_global); 8217 #if (SOLARIS && defined(_KERNEL)) && !defined(INSTANCES) 8218 error = ipfsync(); 8219 #else 8220 ipf_sync(softc, NULL); 8221 error = 0; 8222 #endif 8223 RWLOCK_EXIT(&softc->ipf_global); 8224 8225 } 8226 break; 8227 8228 case SIOCGFRST : 8229 error = ipf_outobj(softc, (void *)data, 8230 ipf_frag_stats(softc->ipf_frag_soft), 8231 IPFOBJ_FRAGSTAT); 8232 break; 8233 8234 #ifdef IPFILTER_LOG 8235 case FIONREAD : 8236 tmp = ipf_log_bytesused(softc, IPL_LOGIPF); 8237 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8238 break; 8239 #endif 8240 8241 case SIOCIPFITER : 8242 SPL_SCHED(s); 8243 error = ipf_frruleiter(softc, data, uid, ctx); 8244 SPL_X(s); 8245 break; 8246 8247 case SIOCGENITER : 8248 SPL_SCHED(s); 8249 error = ipf_genericiter(softc, data, uid, ctx); 8250 SPL_X(s); 8251 break; 8252 8253 case SIOCIPFDELTOK : 8254 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8255 if (error == 0) { 8256 SPL_SCHED(s); 8257 error = ipf_token_del(softc, tmp, uid, ctx); 8258 SPL_X(s); 8259 } 8260 break; 8261 8262 default : 8263 IPFERROR(115); 8264 error = EINVAL; 8265 break; 8266 } 8267 8268 return (error); 8269 } 8270 8271 8272 /* ------------------------------------------------------------------------ */ 8273 /* Function: ipf_decaps */ 8274 /* Returns: int - -1 == decapsulation failed, else bit mask of */ 8275 /* flags indicating packet filtering decision. */ 8276 /* Parameters: fin(I) - pointer to packet information */ 8277 /* pass(I) - IP protocol version to match */ 8278 /* l5proto(I) - layer 5 protocol to decode UDP data as. */ 8279 /* */ 8280 /* This function is called for packets that are wrapt up in other packets, */ 8281 /* for example, an IP packet that is the entire data segment for another IP */ 8282 /* packet. If the basic constraints for this are satisfied, change the */ 8283 /* buffer to point to the start of the inner packet and start processing */ 8284 /* rules belonging to the head group this rule specifies. */ 8285 /* ------------------------------------------------------------------------ */ 8286 u_32_t 8287 ipf_decaps(fr_info_t *fin, u_32_t pass, int l5proto) 8288 { 8289 fr_info_t fin2, *fino = NULL; 8290 int elen, hlen, nh; 8291 grehdr_t gre; 8292 ip_t *ip; 8293 mb_t *m; 8294 8295 if ((fin->fin_flx & FI_COALESCE) == 0) 8296 if (ipf_coalesce(fin) == -1) 8297 goto cantdecaps; 8298 8299 m = fin->fin_m; 8300 hlen = fin->fin_hlen; 8301 8302 switch (fin->fin_p) 8303 { 8304 case IPPROTO_UDP : 8305 /* 8306 * In this case, the specific protocol being decapsulated 8307 * inside UDP frames comes from the rule. 8308 */ 8309 nh = fin->fin_fr->fr_icode; 8310 break; 8311 8312 case IPPROTO_GRE : /* 47 */ 8313 bcopy(fin->fin_dp, (char *)&gre, sizeof(gre)); 8314 hlen += sizeof(grehdr_t); 8315 if (gre.gr_R|gre.gr_s) 8316 goto cantdecaps; 8317 if (gre.gr_C) 8318 hlen += 4; 8319 if (gre.gr_K) 8320 hlen += 4; 8321 if (gre.gr_S) 8322 hlen += 4; 8323 8324 nh = IPPROTO_IP; 8325 8326 /* 8327 * If the routing options flag is set, validate that it is 8328 * there and bounce over it. 8329 */ 8330 #if 0 8331 /* This is really heavy weight and lots of room for error, */ 8332 /* so for now, put it off and get the simple stuff right. */ 8333 if (gre.gr_R) { 8334 u_char off, len, *s; 8335 u_short af; 8336 int end; 8337 8338 end = 0; 8339 s = fin->fin_dp; 8340 s += hlen; 8341 aplen = fin->fin_plen - hlen; 8342 while (aplen > 3) { 8343 af = (s[0] << 8) | s[1]; 8344 off = s[2]; 8345 len = s[3]; 8346 aplen -= 4; 8347 s += 4; 8348 if (af == 0 && len == 0) { 8349 end = 1; 8350 break; 8351 } 8352 if (aplen < len) 8353 break; 8354 s += len; 8355 aplen -= len; 8356 } 8357 if (end != 1) 8358 goto cantdecaps; 8359 hlen = s - (u_char *)fin->fin_dp; 8360 } 8361 #endif 8362 break; 8363 8364 #ifdef IPPROTO_IPIP 8365 case IPPROTO_IPIP : /* 4 */ 8366 #endif 8367 nh = IPPROTO_IP; 8368 break; 8369 8370 default : /* Includes ESP, AH is special for IPv4 */ 8371 goto cantdecaps; 8372 } 8373 8374 switch (nh) 8375 { 8376 case IPPROTO_IP : 8377 case IPPROTO_IPV6 : 8378 break; 8379 default : 8380 goto cantdecaps; 8381 } 8382 8383 bcopy((char *)fin, (char *)&fin2, sizeof(fin2)); 8384 fino = fin; 8385 fin = &fin2; 8386 elen = hlen; 8387 #if SOLARIS && defined(_KERNEL) 8388 m->b_rptr += elen; 8389 #else 8390 m->m_data += elen; 8391 m->m_len -= elen; 8392 #endif 8393 fin->fin_plen -= elen; 8394 8395 ip = (ip_t *)((char *)fin->fin_ip + elen); 8396 8397 /* 8398 * Make sure we have at least enough data for the network layer 8399 * header. 8400 */ 8401 if (IP_V(ip) == 4) 8402 hlen = IP_HL(ip) << 2; 8403 #ifdef USE_INET6 8404 else if (IP_V(ip) == 6) 8405 hlen = sizeof(ip6_t); 8406 #endif 8407 else 8408 goto cantdecaps2; 8409 8410 if (fin->fin_plen < hlen) 8411 goto cantdecaps2; 8412 8413 fin->fin_dp = (char *)ip + hlen; 8414 8415 if (IP_V(ip) == 4) { 8416 /* 8417 * Perform IPv4 header checksum validation. 8418 */ 8419 if (ipf_cksum((u_short *)ip, hlen)) 8420 goto cantdecaps2; 8421 } 8422 8423 if (ipf_makefrip(hlen, ip, fin) == -1) { 8424 cantdecaps2: 8425 if (m != NULL) { 8426 #if SOLARIS && defined(_KERNEL) 8427 m->b_rptr -= elen; 8428 #else 8429 m->m_data -= elen; 8430 m->m_len += elen; 8431 #endif 8432 } 8433 cantdecaps: 8434 DT1(frb_decapfrip, fr_info_t *, fin); 8435 pass &= ~FR_CMDMASK; 8436 pass |= FR_BLOCK|FR_QUICK; 8437 fin->fin_reason = FRB_DECAPFRIP; 8438 return (-1); 8439 } 8440 8441 pass = ipf_scanlist(fin, pass); 8442 8443 /* 8444 * Copy the packet filter "result" fields out of the fr_info_t struct 8445 * that is local to the decapsulation processing and back into the 8446 * one we were called with. 8447 */ 8448 fino->fin_flx = fin->fin_flx; 8449 fino->fin_rev = fin->fin_rev; 8450 fino->fin_icode = fin->fin_icode; 8451 fino->fin_rule = fin->fin_rule; 8452 (void) strncpy(fino->fin_group, fin->fin_group, FR_GROUPLEN); 8453 fino->fin_fr = fin->fin_fr; 8454 fino->fin_error = fin->fin_error; 8455 fino->fin_mp = fin->fin_mp; 8456 fino->fin_m = fin->fin_m; 8457 m = fin->fin_m; 8458 if (m != NULL) { 8459 #if SOLARIS && defined(_KERNEL) 8460 m->b_rptr -= elen; 8461 #else 8462 m->m_data -= elen; 8463 m->m_len += elen; 8464 #endif 8465 } 8466 return (pass); 8467 } 8468 8469 8470 /* ------------------------------------------------------------------------ */ 8471 /* Function: ipf_matcharray_load */ 8472 /* Returns: int - 0 = success, else error */ 8473 /* Parameters: softc(I) - pointer to soft context main structure */ 8474 /* data(I) - pointer to ioctl data */ 8475 /* objp(I) - ipfobj_t structure to load data into */ 8476 /* arrayptr(I) - pointer to location to store array pointer */ 8477 /* */ 8478 /* This function loads in a mathing array through the ipfobj_t struct that */ 8479 /* describes it. Sanity checking and array size limitations are enforced */ 8480 /* in this function to prevent userspace from trying to load in something */ 8481 /* that is insanely big. Once the size of the array is known, the memory */ 8482 /* required is malloc'd and returned through changing *arrayptr. The */ 8483 /* contents of the array are verified before returning. Only in the event */ 8484 /* of a successful call is the caller required to free up the malloc area. */ 8485 /* ------------------------------------------------------------------------ */ 8486 int 8487 ipf_matcharray_load(ipf_main_softc_t *softc, caddr_t data, ipfobj_t *objp, 8488 int **arrayptr) 8489 { 8490 int arraysize, *array, error; 8491 8492 *arrayptr = NULL; 8493 8494 error = BCOPYIN(data, objp, sizeof(*objp)); 8495 if (error != 0) { 8496 IPFERROR(116); 8497 return (EFAULT); 8498 } 8499 8500 if (objp->ipfo_type != IPFOBJ_IPFEXPR) { 8501 IPFERROR(117); 8502 return (EINVAL); 8503 } 8504 8505 if (((objp->ipfo_size & 3) != 0) || (objp->ipfo_size == 0) || 8506 (objp->ipfo_size > 1024)) { 8507 IPFERROR(118); 8508 return (EINVAL); 8509 } 8510 8511 arraysize = objp->ipfo_size * sizeof(*array); 8512 KMALLOCS(array, int *, arraysize); 8513 if (array == NULL) { 8514 IPFERROR(119); 8515 return (ENOMEM); 8516 } 8517 8518 error = COPYIN(objp->ipfo_ptr, array, arraysize); 8519 if (error != 0) { 8520 KFREES(array, arraysize); 8521 IPFERROR(120); 8522 return (EFAULT); 8523 } 8524 8525 if (ipf_matcharray_verify(array, arraysize) != 0) { 8526 KFREES(array, arraysize); 8527 IPFERROR(121); 8528 return (EINVAL); 8529 } 8530 8531 *arrayptr = array; 8532 return (0); 8533 } 8534 8535 8536 /* ------------------------------------------------------------------------ */ 8537 /* Function: ipf_matcharray_verify */ 8538 /* Returns: Nil */ 8539 /* Parameters: array(I) - pointer to matching array */ 8540 /* arraysize(I) - number of elements in the array */ 8541 /* */ 8542 /* Verify the contents of a matching array by stepping through each element */ 8543 /* in it. The actual commands in the array are not verified for */ 8544 /* correctness, only that all of the sizes are correctly within limits. */ 8545 /* ------------------------------------------------------------------------ */ 8546 int 8547 ipf_matcharray_verify(int *array, int arraysize) 8548 { 8549 u_int i, nelem, maxidx; 8550 ipfexp_t *e; 8551 8552 nelem = arraysize / sizeof(*array); 8553 8554 /* 8555 * Currently, it makes no sense to have an array less than 6 8556 * elements long - the initial size at the from, a single operation 8557 * (minimum 4 in length) and a trailer, for a total of 6. 8558 */ 8559 if ((array[0] < 6) || (arraysize < 24) || (arraysize > 4096)) { 8560 return (-1); 8561 } 8562 8563 /* 8564 * Verify the size of data pointed to by array with how long 8565 * the array claims to be itself. 8566 */ 8567 if (array[0] * sizeof(*array) != arraysize) { 8568 return (-1); 8569 } 8570 8571 maxidx = nelem - 1; 8572 /* 8573 * The last opcode in this array should be an IPF_EXP_END. 8574 */ 8575 if (array[maxidx] != IPF_EXP_END) { 8576 return (-1); 8577 } 8578 8579 for (i = 1; i < maxidx; ) { 8580 e = (ipfexp_t *)(array + i); 8581 8582 /* 8583 * The length of the bits to check must be at least 1 8584 * (or else there is nothing to comapre with!) and it 8585 * cannot exceed the length of the data present. 8586 */ 8587 if ((e->ipfe_size < 1 ) || 8588 (e->ipfe_size + i > maxidx)) { 8589 return (-1); 8590 } 8591 i += e->ipfe_size; 8592 } 8593 return (0); 8594 } 8595 8596 8597 /* ------------------------------------------------------------------------ */ 8598 /* Function: ipf_fr_matcharray */ 8599 /* Returns: int - 0 = match failed, else positive match */ 8600 /* Parameters: fin(I) - pointer to packet information */ 8601 /* array(I) - pointer to matching array */ 8602 /* */ 8603 /* This function is used to apply a matching array against a packet and */ 8604 /* return an indication of whether or not the packet successfully matches */ 8605 /* all of the commands in it. */ 8606 /* ------------------------------------------------------------------------ */ 8607 static int 8608 ipf_fr_matcharray(fr_info_t *fin, int *array) 8609 { 8610 u_int i, n, *x, rv, p; 8611 ipfexp_t *e; 8612 8613 rv = 0; 8614 n = array[0]; 8615 x = array + 1; 8616 8617 for (; n > 0; x += 3 + x[3], rv = 0) { 8618 e = (ipfexp_t *)x; 8619 if (e->ipfe_cmd == IPF_EXP_END) 8620 break; 8621 n -= e->ipfe_size; 8622 8623 /* 8624 * The upper 16 bits currently store the protocol value. 8625 * This is currently used with TCP and UDP port compares and 8626 * allows "tcp.port = 80" without requiring an explicit 8627 " "ip.pr = tcp" first. 8628 */ 8629 p = e->ipfe_cmd >> 16; 8630 if ((p != 0) && (p != fin->fin_p)) 8631 break; 8632 8633 switch (e->ipfe_cmd) 8634 { 8635 case IPF_EXP_IP_PR : 8636 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8637 rv |= (fin->fin_p == e->ipfe_arg0[i]); 8638 } 8639 break; 8640 8641 case IPF_EXP_IP_SRCADDR : 8642 if (fin->fin_v != 4) 8643 break; 8644 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8645 rv |= ((fin->fin_saddr & 8646 e->ipfe_arg0[i * 2 + 1]) == 8647 e->ipfe_arg0[i * 2]); 8648 } 8649 break; 8650 8651 case IPF_EXP_IP_DSTADDR : 8652 if (fin->fin_v != 4) 8653 break; 8654 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8655 rv |= ((fin->fin_daddr & 8656 e->ipfe_arg0[i * 2 + 1]) == 8657 e->ipfe_arg0[i * 2]); 8658 } 8659 break; 8660 8661 case IPF_EXP_IP_ADDR : 8662 if (fin->fin_v != 4) 8663 break; 8664 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8665 rv |= ((fin->fin_saddr & 8666 e->ipfe_arg0[i * 2 + 1]) == 8667 e->ipfe_arg0[i * 2]) || 8668 ((fin->fin_daddr & 8669 e->ipfe_arg0[i * 2 + 1]) == 8670 e->ipfe_arg0[i * 2]); 8671 } 8672 break; 8673 8674 #ifdef USE_INET6 8675 case IPF_EXP_IP6_SRCADDR : 8676 if (fin->fin_v != 6) 8677 break; 8678 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8679 rv |= IP6_MASKEQ(&fin->fin_src6, 8680 &e->ipfe_arg0[i * 8 + 4], 8681 &e->ipfe_arg0[i * 8]); 8682 } 8683 break; 8684 8685 case IPF_EXP_IP6_DSTADDR : 8686 if (fin->fin_v != 6) 8687 break; 8688 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8689 rv |= IP6_MASKEQ(&fin->fin_dst6, 8690 &e->ipfe_arg0[i * 8 + 4], 8691 &e->ipfe_arg0[i * 8]); 8692 } 8693 break; 8694 8695 case IPF_EXP_IP6_ADDR : 8696 if (fin->fin_v != 6) 8697 break; 8698 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8699 rv |= IP6_MASKEQ(&fin->fin_src6, 8700 &e->ipfe_arg0[i * 8 + 4], 8701 &e->ipfe_arg0[i * 8]) || 8702 IP6_MASKEQ(&fin->fin_dst6, 8703 &e->ipfe_arg0[i * 8 + 4], 8704 &e->ipfe_arg0[i * 8]); 8705 } 8706 break; 8707 #endif 8708 8709 case IPF_EXP_UDP_PORT : 8710 case IPF_EXP_TCP_PORT : 8711 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8712 rv |= (fin->fin_sport == e->ipfe_arg0[i]) || 8713 (fin->fin_dport == e->ipfe_arg0[i]); 8714 } 8715 break; 8716 8717 case IPF_EXP_UDP_SPORT : 8718 case IPF_EXP_TCP_SPORT : 8719 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8720 rv |= (fin->fin_sport == e->ipfe_arg0[i]); 8721 } 8722 break; 8723 8724 case IPF_EXP_UDP_DPORT : 8725 case IPF_EXP_TCP_DPORT : 8726 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8727 rv |= (fin->fin_dport == e->ipfe_arg0[i]); 8728 } 8729 break; 8730 8731 case IPF_EXP_TCP_FLAGS : 8732 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8733 rv |= ((fin->fin_tcpf & 8734 e->ipfe_arg0[i * 2 + 1]) == 8735 e->ipfe_arg0[i * 2]); 8736 } 8737 break; 8738 } 8739 rv ^= e->ipfe_not; 8740 8741 if (rv == 0) 8742 break; 8743 } 8744 8745 return (rv); 8746 } 8747 8748 8749 /* ------------------------------------------------------------------------ */ 8750 /* Function: ipf_queueflush */ 8751 /* Returns: int - number of entries flushed (0 = none) */ 8752 /* Parameters: softc(I) - pointer to soft context main structure */ 8753 /* deletefn(I) - function to call to delete entry */ 8754 /* ipfqs(I) - top of the list of ipf internal queues */ 8755 /* userqs(I) - top of the list of user defined timeouts */ 8756 /* */ 8757 /* This fucntion gets called when the state/NAT hash tables fill up and we */ 8758 /* need to try a bit harder to free up some space. The algorithm used here */ 8759 /* split into two parts but both halves have the same goal: to reduce the */ 8760 /* number of connections considered to be "active" to the low watermark. */ 8761 /* There are two steps in doing this: */ 8762 /* 1) Remove any TCP connections that are already considered to be "closed" */ 8763 /* but have not yet been removed from the state table. The two states */ 8764 /* TCPS_TIME_WAIT and TCPS_CLOSED are considered to be the perfect */ 8765 /* candidates for this style of removal. If freeing up entries in */ 8766 /* CLOSED or both CLOSED and TIME_WAIT brings us to the low watermark, */ 8767 /* we do not go on to step 2. */ 8768 /* */ 8769 /* 2) Look for the oldest entries on each timeout queue and free them if */ 8770 /* they are within the given window we are considering. Where the */ 8771 /* window starts and the steps taken to increase its size depend upon */ 8772 /* how long ipf has been running (ipf_ticks.) Anything modified in the */ 8773 /* last 30 seconds is not touched. */ 8774 /* touched */ 8775 /* die ipf_ticks 30*1.5 1800*1.5 | 43200*1.5 */ 8776 /* | | | | | | */ 8777 /* future <--+----------+--------+-----------+-----+-----+-----------> past */ 8778 /* now \_int=30s_/ \_int=1hr_/ \_int=12hr */ 8779 /* */ 8780 /* Points to note: */ 8781 /* - tqe_die is the time, in the future, when entries die. */ 8782 /* - tqe_die - ipf_ticks is how long left the connection has to live in ipf */ 8783 /* ticks. */ 8784 /* - tqe_touched is when the entry was last used by NAT/state */ 8785 /* - the closer tqe_touched is to ipf_ticks, the further tqe_die will be */ 8786 /* ipf_ticks any given timeout queue and vice versa. */ 8787 /* - both tqe_die and tqe_touched increase over time */ 8788 /* - timeout queues are sorted with the highest value of tqe_die at the */ 8789 /* bottom and therefore the smallest values of each are at the top */ 8790 /* - the pointer passed in as ipfqs should point to an array of timeout */ 8791 /* queues representing each of the TCP states */ 8792 /* */ 8793 /* We start by setting up a maximum range to scan for things to move of */ 8794 /* iend (newest) to istart (oldest) in chunks of "interval". If nothing is */ 8795 /* found in that range, "interval" is adjusted (so long as it isn't 30) and */ 8796 /* we start again with a new value for "iend" and "istart". This is */ 8797 /* continued until we either finish the scan of 30 second intervals or the */ 8798 /* low water mark is reached. */ 8799 /* ------------------------------------------------------------------------ */ 8800 int 8801 ipf_queueflush(ipf_main_softc_t *softc, ipftq_delete_fn_t deletefn, 8802 ipftq_t *ipfqs, ipftq_t *userqs, u_int *activep, int size, int low) 8803 { 8804 u_long interval, istart, iend; 8805 ipftq_t *ifq, *ifqnext; 8806 ipftqent_t *tqe, *tqn; 8807 int removed = 0; 8808 8809 for (tqn = ipfqs[IPF_TCPS_CLOSED].ifq_head; ((tqe = tqn) != NULL); ) { 8810 tqn = tqe->tqe_next; 8811 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8812 removed++; 8813 } 8814 if ((*activep * 100 / size) > low) { 8815 for (tqn = ipfqs[IPF_TCPS_TIME_WAIT].ifq_head; 8816 ((tqe = tqn) != NULL); ) { 8817 tqn = tqe->tqe_next; 8818 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8819 removed++; 8820 } 8821 } 8822 8823 if ((*activep * 100 / size) <= low) { 8824 return (removed); 8825 } 8826 8827 /* 8828 * NOTE: Use of "* 15 / 10" is required here because if "* 1.5" is 8829 * used then the operations are upgraded to floating point 8830 * and kernels don't like floating point... 8831 */ 8832 if (softc->ipf_ticks > IPF_TTLVAL(43200 * 15 / 10)) { 8833 istart = IPF_TTLVAL(86400 * 4); 8834 interval = IPF_TTLVAL(43200); 8835 } else if (softc->ipf_ticks > IPF_TTLVAL(1800 * 15 / 10)) { 8836 istart = IPF_TTLVAL(43200); 8837 interval = IPF_TTLVAL(1800); 8838 } else if (softc->ipf_ticks > IPF_TTLVAL(30 * 15 / 10)) { 8839 istart = IPF_TTLVAL(1800); 8840 interval = IPF_TTLVAL(30); 8841 } else { 8842 return (0); 8843 } 8844 if (istart > softc->ipf_ticks) { 8845 if (softc->ipf_ticks - interval < interval) 8846 istart = interval; 8847 else 8848 istart = (softc->ipf_ticks / interval) * interval; 8849 } 8850 8851 iend = softc->ipf_ticks - interval; 8852 8853 while ((*activep * 100 / size) > low) { 8854 u_long try; 8855 8856 try = softc->ipf_ticks - istart; 8857 8858 for (ifq = ipfqs; ifq != NULL; ifq = ifq->ifq_next) { 8859 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { 8860 if (try < tqe->tqe_touched) 8861 break; 8862 tqn = tqe->tqe_next; 8863 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8864 removed++; 8865 } 8866 } 8867 8868 for (ifq = userqs; ifq != NULL; ifq = ifqnext) { 8869 ifqnext = ifq->ifq_next; 8870 8871 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { 8872 if (try < tqe->tqe_touched) 8873 break; 8874 tqn = tqe->tqe_next; 8875 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8876 removed++; 8877 } 8878 } 8879 8880 if (try >= iend) { 8881 if (interval == IPF_TTLVAL(43200)) { 8882 interval = IPF_TTLVAL(1800); 8883 } else if (interval == IPF_TTLVAL(1800)) { 8884 interval = IPF_TTLVAL(30); 8885 } else { 8886 break; 8887 } 8888 if (interval >= softc->ipf_ticks) 8889 break; 8890 8891 iend = softc->ipf_ticks - interval; 8892 } 8893 istart -= interval; 8894 } 8895 8896 return (removed); 8897 } 8898 8899 8900 /* ------------------------------------------------------------------------ */ 8901 /* Function: ipf_deliverlocal */ 8902 /* Returns: int - 1 = local address, 0 = non-local address */ 8903 /* Parameters: softc(I) - pointer to soft context main structure */ 8904 /* ipversion(I) - IP protocol version (4 or 6) */ 8905 /* ifp(I) - network interface pointer */ 8906 /* ipaddr(I) - IPv4/6 destination address */ 8907 /* */ 8908 /* This fucntion is used to determine in the address "ipaddr" belongs to */ 8909 /* the network interface represented by ifp. */ 8910 /* ------------------------------------------------------------------------ */ 8911 int 8912 ipf_deliverlocal(ipf_main_softc_t *softc, int ipversion, void *ifp, 8913 i6addr_t *ipaddr) 8914 { 8915 i6addr_t addr; 8916 int islocal = 0; 8917 8918 if (ipversion == 4) { 8919 if (ipf_ifpaddr(softc, 4, FRI_NORMAL, ifp, &addr, NULL) == 0) { 8920 if (addr.in4.s_addr == ipaddr->in4.s_addr) 8921 islocal = 1; 8922 } 8923 8924 #ifdef USE_INET6 8925 } else if (ipversion == 6) { 8926 if (ipf_ifpaddr(softc, 6, FRI_NORMAL, ifp, &addr, NULL) == 0) { 8927 if (IP6_EQ(&addr, ipaddr)) 8928 islocal = 1; 8929 } 8930 #endif 8931 } 8932 8933 return (islocal); 8934 } 8935 8936 8937 /* ------------------------------------------------------------------------ */ 8938 /* Function: ipf_settimeout */ 8939 /* Returns: int - 0 = success, -1 = failure */ 8940 /* Parameters: softc(I) - pointer to soft context main structure */ 8941 /* t(I) - pointer to tuneable array entry */ 8942 /* p(I) - pointer to values passed in to apply */ 8943 /* */ 8944 /* This function is called to set the timeout values for each distinct */ 8945 /* queue timeout that is available. When called, it calls into both the */ 8946 /* state and NAT code, telling them to update their timeout queues. */ 8947 /* ------------------------------------------------------------------------ */ 8948 static int 8949 ipf_settimeout(struct ipf_main_softc_s *softc, ipftuneable_t *t, 8950 ipftuneval_t *p) 8951 { 8952 8953 /* 8954 * ipf_interror should be set by the functions called here, not 8955 * by this function - it's just a middle man. 8956 */ 8957 if (ipf_state_settimeout(softc, t, p) == -1) 8958 return (-1); 8959 if (ipf_nat_settimeout(softc, t, p) == -1) 8960 return (-1); 8961 return (0); 8962 } 8963 8964 8965 /* ------------------------------------------------------------------------ */ 8966 /* Function: ipf_apply_timeout */ 8967 /* Returns: int - 0 = success, -1 = failure */ 8968 /* Parameters: head(I) - pointer to tuneable array entry */ 8969 /* seconds(I) - pointer to values passed in to apply */ 8970 /* */ 8971 /* This function applies a timeout of "seconds" to the timeout queue that */ 8972 /* is pointed to by "head". All entries on this list have an expiration */ 8973 /* set to be the current tick value of ipf plus the ttl. Given that this */ 8974 /* function should only be called when the delta is non-zero, the task is */ 8975 /* to walk the entire list and apply the change. The sort order will not */ 8976 /* change. The only catch is that this is O(n) across the list, so if the */ 8977 /* queue has lots of entries (10s of thousands or 100s of thousands), it */ 8978 /* could take a relatively long time to work through them all. */ 8979 /* ------------------------------------------------------------------------ */ 8980 void 8981 ipf_apply_timeout(ipftq_t *head, u_int seconds) 8982 { 8983 u_int oldtimeout, newtimeout; 8984 ipftqent_t *tqe; 8985 int delta; 8986 8987 MUTEX_ENTER(&head->ifq_lock); 8988 oldtimeout = head->ifq_ttl; 8989 newtimeout = IPF_TTLVAL(seconds); 8990 delta = oldtimeout - newtimeout; 8991 8992 head->ifq_ttl = newtimeout; 8993 8994 for (tqe = head->ifq_head; tqe != NULL; tqe = tqe->tqe_next) { 8995 tqe->tqe_die += delta; 8996 } 8997 MUTEX_EXIT(&head->ifq_lock); 8998 } 8999 9000 9001 /* ------------------------------------------------------------------------ */ 9002 /* Function: ipf_settimeout_tcp */ 9003 /* Returns: int - 0 = successfully applied, -1 = failed */ 9004 /* Parameters: t(I) - pointer to tuneable to change */ 9005 /* p(I) - pointer to new timeout information */ 9006 /* tab(I) - pointer to table of TCP queues */ 9007 /* */ 9008 /* This function applies the new timeout (p) to the TCP tunable (t) and */ 9009 /* updates all of the entries on the relevant timeout queue by calling */ 9010 /* ipf_apply_timeout(). */ 9011 /* ------------------------------------------------------------------------ */ 9012 int 9013 ipf_settimeout_tcp(ipftuneable_t *t, ipftuneval_t *p, ipftq_t *tab) 9014 { 9015 if (!strcmp(t->ipft_name, "tcp_idle_timeout") || 9016 !strcmp(t->ipft_name, "tcp_established")) { 9017 ipf_apply_timeout(&tab[IPF_TCPS_ESTABLISHED], p->ipftu_int); 9018 } else if (!strcmp(t->ipft_name, "tcp_close_wait")) { 9019 ipf_apply_timeout(&tab[IPF_TCPS_CLOSE_WAIT], p->ipftu_int); 9020 } else if (!strcmp(t->ipft_name, "tcp_last_ack")) { 9021 ipf_apply_timeout(&tab[IPF_TCPS_LAST_ACK], p->ipftu_int); 9022 } else if (!strcmp(t->ipft_name, "tcp_timeout")) { 9023 ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int); 9024 ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int); 9025 ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int); 9026 } else if (!strcmp(t->ipft_name, "tcp_listen")) { 9027 ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int); 9028 } else if (!strcmp(t->ipft_name, "tcp_half_established")) { 9029 ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int); 9030 } else if (!strcmp(t->ipft_name, "tcp_closing")) { 9031 ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int); 9032 } else if (!strcmp(t->ipft_name, "tcp_syn_received")) { 9033 ipf_apply_timeout(&tab[IPF_TCPS_SYN_RECEIVED], p->ipftu_int); 9034 } else if (!strcmp(t->ipft_name, "tcp_syn_sent")) { 9035 ipf_apply_timeout(&tab[IPF_TCPS_SYN_SENT], p->ipftu_int); 9036 } else if (!strcmp(t->ipft_name, "tcp_closed")) { 9037 ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int); 9038 } else if (!strcmp(t->ipft_name, "tcp_half_closed")) { 9039 ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int); 9040 } else if (!strcmp(t->ipft_name, "tcp_time_wait")) { 9041 ipf_apply_timeout(&tab[IPF_TCPS_TIME_WAIT], p->ipftu_int); 9042 } else { 9043 /* 9044 * ipf_interror isn't set here because it should be set 9045 * by whatever called this function. 9046 */ 9047 return (-1); 9048 } 9049 return (0); 9050 } 9051 9052 9053 /* ------------------------------------------------------------------------ */ 9054 /* Function: ipf_main_soft_create */ 9055 /* Returns: NULL = failure, else success */ 9056 /* Parameters: arg(I) - pointer to soft context structure if already allocd */ 9057 /* */ 9058 /* Create the foundation soft context structure. In circumstances where it */ 9059 /* is not required to dynamically allocate the context, a pointer can be */ 9060 /* passed in (rather than NULL) to a structure to be initialised. */ 9061 /* The main thing of interest is that a number of locks are initialised */ 9062 /* here instead of in the where might be expected - in the relevant create */ 9063 /* function elsewhere. This is done because the current locking design has */ 9064 /* some areas where these locks are used outside of their module. */ 9065 /* Possibly the most important exercise that is done here is setting of all */ 9066 /* the timeout values, allowing them to be changed before init(). */ 9067 /* ------------------------------------------------------------------------ */ 9068 void * 9069 ipf_main_soft_create(void *arg) 9070 { 9071 ipf_main_softc_t *softc; 9072 9073 if (arg == NULL) { 9074 KMALLOC(softc, ipf_main_softc_t *); 9075 if (softc == NULL) 9076 return (NULL); 9077 } else { 9078 softc = arg; 9079 } 9080 9081 bzero((char *)softc, sizeof(*softc)); 9082 9083 /* 9084 * This serves as a flag as to whether or not the softc should be 9085 * free'd when _destroy is called. 9086 */ 9087 softc->ipf_dynamic_softc = (arg == NULL) ? 1 : 0; 9088 9089 softc->ipf_tuners = ipf_tune_array_copy(softc, 9090 sizeof(ipf_main_tuneables), 9091 ipf_main_tuneables); 9092 if (softc->ipf_tuners == NULL) { 9093 ipf_main_soft_destroy(softc); 9094 return (NULL); 9095 } 9096 9097 MUTEX_INIT(&softc->ipf_rw, "ipf rw mutex"); 9098 MUTEX_INIT(&softc->ipf_timeoutlock, "ipf timeout lock"); 9099 RWLOCK_INIT(&softc->ipf_global, "ipf filter load/unload mutex"); 9100 RWLOCK_INIT(&softc->ipf_mutex, "ipf filter rwlock"); 9101 RWLOCK_INIT(&softc->ipf_tokens, "ipf token rwlock"); 9102 RWLOCK_INIT(&softc->ipf_state, "ipf state rwlock"); 9103 RWLOCK_INIT(&softc->ipf_nat, "ipf IP NAT rwlock"); 9104 RWLOCK_INIT(&softc->ipf_poolrw, "ipf pool rwlock"); 9105 RWLOCK_INIT(&softc->ipf_frag, "ipf frag rwlock"); 9106 9107 softc->ipf_token_head = NULL; 9108 softc->ipf_token_tail = &softc->ipf_token_head; 9109 9110 softc->ipf_tcpidletimeout = FIVE_DAYS; 9111 softc->ipf_tcpclosewait = IPF_TTLVAL(2 * TCP_MSL); 9112 softc->ipf_tcplastack = IPF_TTLVAL(30); 9113 softc->ipf_tcptimewait = IPF_TTLVAL(2 * TCP_MSL); 9114 softc->ipf_tcptimeout = IPF_TTLVAL(2 * TCP_MSL); 9115 softc->ipf_tcpsynsent = IPF_TTLVAL(2 * TCP_MSL); 9116 softc->ipf_tcpsynrecv = IPF_TTLVAL(2 * TCP_MSL); 9117 softc->ipf_tcpclosed = IPF_TTLVAL(30); 9118 softc->ipf_tcphalfclosed = IPF_TTLVAL(2 * 3600); 9119 softc->ipf_udptimeout = IPF_TTLVAL(120); 9120 softc->ipf_udpacktimeout = IPF_TTLVAL(12); 9121 softc->ipf_icmptimeout = IPF_TTLVAL(60); 9122 softc->ipf_icmpacktimeout = IPF_TTLVAL(6); 9123 softc->ipf_iptimeout = IPF_TTLVAL(60); 9124 9125 #if defined(IPFILTER_DEFAULT_BLOCK) 9126 softc->ipf_pass = FR_BLOCK|FR_NOMATCH; 9127 #else 9128 softc->ipf_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH; 9129 #endif 9130 softc->ipf_minttl = 4; 9131 softc->ipf_icmpminfragmtu = 68; 9132 softc->ipf_max_namelen = 128; 9133 softc->ipf_flags = IPF_LOGGING; 9134 softc->ipf_jail_allowed = 0; 9135 9136 #ifdef LARGE_NAT 9137 softc->ipf_large_nat = 1; 9138 #endif 9139 ipf_fbsd_kenv_get(softc); 9140 9141 return (softc); 9142 } 9143 9144 /* ------------------------------------------------------------------------ */ 9145 /* Function: ipf_main_soft_init */ 9146 /* Returns: 0 = success, -1 = failure */ 9147 /* Parameters: softc(I) - pointer to soft context main structure */ 9148 /* */ 9149 /* A null-op function that exists as a placeholder so that the flow in */ 9150 /* other functions is obvious. */ 9151 /* ------------------------------------------------------------------------ */ 9152 /*ARGSUSED*/ 9153 int 9154 ipf_main_soft_init(ipf_main_softc_t *softc) 9155 { 9156 return (0); 9157 } 9158 9159 9160 /* ------------------------------------------------------------------------ */ 9161 /* Function: ipf_main_soft_destroy */ 9162 /* Returns: void */ 9163 /* Parameters: softc(I) - pointer to soft context main structure */ 9164 /* */ 9165 /* Undo everything that we did in ipf_main_soft_create. */ 9166 /* */ 9167 /* The most important check that needs to be made here is whether or not */ 9168 /* the structure was allocated by ipf_main_soft_create() by checking what */ 9169 /* value is stored in ipf_dynamic_main. */ 9170 /* ------------------------------------------------------------------------ */ 9171 /*ARGSUSED*/ 9172 void 9173 ipf_main_soft_destroy(ipf_main_softc_t *softc) 9174 { 9175 9176 RW_DESTROY(&softc->ipf_frag); 9177 RW_DESTROY(&softc->ipf_poolrw); 9178 RW_DESTROY(&softc->ipf_nat); 9179 RW_DESTROY(&softc->ipf_state); 9180 RW_DESTROY(&softc->ipf_tokens); 9181 RW_DESTROY(&softc->ipf_mutex); 9182 RW_DESTROY(&softc->ipf_global); 9183 MUTEX_DESTROY(&softc->ipf_timeoutlock); 9184 MUTEX_DESTROY(&softc->ipf_rw); 9185 9186 if (softc->ipf_tuners != NULL) { 9187 KFREES(softc->ipf_tuners, sizeof(ipf_main_tuneables)); 9188 } 9189 if (softc->ipf_dynamic_softc == 1) { 9190 KFREE(softc); 9191 } 9192 } 9193 9194 9195 /* ------------------------------------------------------------------------ */ 9196 /* Function: ipf_main_soft_fini */ 9197 /* Returns: 0 = success, -1 = failure */ 9198 /* Parameters: softc(I) - pointer to soft context main structure */ 9199 /* */ 9200 /* Clean out the rules which have been added since _init was last called, */ 9201 /* the only dynamic part of the mainline. */ 9202 /* ------------------------------------------------------------------------ */ 9203 int 9204 ipf_main_soft_fini(ipf_main_softc_t *softc) 9205 { 9206 (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE|FR_INACTIVE); 9207 (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE); 9208 (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE|FR_INACTIVE); 9209 (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE); 9210 9211 return (0); 9212 } 9213 9214 9215 /* ------------------------------------------------------------------------ */ 9216 /* Function: ipf_main_load */ 9217 /* Returns: 0 = success, -1 = failure */ 9218 /* Parameters: none */ 9219 /* */ 9220 /* Handle global initialisation that needs to be done for the base part of */ 9221 /* IPFilter. At present this just amounts to initialising some ICMP lookup */ 9222 /* arrays that get used by the state/NAT code. */ 9223 /* ------------------------------------------------------------------------ */ 9224 int 9225 ipf_main_load(void) 9226 { 9227 int i; 9228 9229 /* fill icmp reply type table */ 9230 for (i = 0; i <= ICMP_MAXTYPE; i++) 9231 icmpreplytype4[i] = -1; 9232 icmpreplytype4[ICMP_ECHO] = ICMP_ECHOREPLY; 9233 icmpreplytype4[ICMP_TSTAMP] = ICMP_TSTAMPREPLY; 9234 icmpreplytype4[ICMP_IREQ] = ICMP_IREQREPLY; 9235 icmpreplytype4[ICMP_MASKREQ] = ICMP_MASKREPLY; 9236 9237 #ifdef USE_INET6 9238 /* fill icmp reply type table */ 9239 for (i = 0; i <= ICMP6_MAXTYPE; i++) 9240 icmpreplytype6[i] = -1; 9241 icmpreplytype6[ICMP6_ECHO_REQUEST] = ICMP6_ECHO_REPLY; 9242 icmpreplytype6[ICMP6_MEMBERSHIP_QUERY] = ICMP6_MEMBERSHIP_REPORT; 9243 icmpreplytype6[ICMP6_NI_QUERY] = ICMP6_NI_REPLY; 9244 icmpreplytype6[ND_ROUTER_SOLICIT] = ND_ROUTER_ADVERT; 9245 icmpreplytype6[ND_NEIGHBOR_SOLICIT] = ND_NEIGHBOR_ADVERT; 9246 #endif 9247 9248 return (0); 9249 } 9250 9251 9252 /* ------------------------------------------------------------------------ */ 9253 /* Function: ipf_main_unload */ 9254 /* Returns: 0 = success, -1 = failure */ 9255 /* Parameters: none */ 9256 /* */ 9257 /* A null-op function that exists as a placeholder so that the flow in */ 9258 /* other functions is obvious. */ 9259 /* ------------------------------------------------------------------------ */ 9260 int 9261 ipf_main_unload(void) 9262 { 9263 return (0); 9264 } 9265 9266 9267 /* ------------------------------------------------------------------------ */ 9268 /* Function: ipf_load_all */ 9269 /* Returns: 0 = success, -1 = failure */ 9270 /* Parameters: none */ 9271 /* */ 9272 /* Work through all of the subsystems inside IPFilter and call the load */ 9273 /* function for each in an order that won't lead to a crash :) */ 9274 /* ------------------------------------------------------------------------ */ 9275 int 9276 ipf_load_all(void) 9277 { 9278 if (ipf_main_load() == -1) 9279 return (-1); 9280 9281 if (ipf_state_main_load() == -1) 9282 return (-1); 9283 9284 if (ipf_nat_main_load() == -1) 9285 return (-1); 9286 9287 if (ipf_frag_main_load() == -1) 9288 return (-1); 9289 9290 if (ipf_auth_main_load() == -1) 9291 return (-1); 9292 9293 if (ipf_proxy_main_load() == -1) 9294 return (-1); 9295 9296 return (0); 9297 } 9298 9299 9300 /* ------------------------------------------------------------------------ */ 9301 /* Function: ipf_unload_all */ 9302 /* Returns: 0 = success, -1 = failure */ 9303 /* Parameters: none */ 9304 /* */ 9305 /* Work through all of the subsystems inside IPFilter and call the unload */ 9306 /* function for each in an order that won't lead to a crash :) */ 9307 /* ------------------------------------------------------------------------ */ 9308 int 9309 ipf_unload_all(void) 9310 { 9311 if (ipf_proxy_main_unload() == -1) 9312 return (-1); 9313 9314 if (ipf_auth_main_unload() == -1) 9315 return (-1); 9316 9317 if (ipf_frag_main_unload() == -1) 9318 return (-1); 9319 9320 if (ipf_nat_main_unload() == -1) 9321 return (-1); 9322 9323 if (ipf_state_main_unload() == -1) 9324 return (-1); 9325 9326 if (ipf_main_unload() == -1) 9327 return (-1); 9328 9329 return (0); 9330 } 9331 9332 9333 /* ------------------------------------------------------------------------ */ 9334 /* Function: ipf_create_all */ 9335 /* Returns: NULL = failure, else success */ 9336 /* Parameters: arg(I) - pointer to soft context main structure */ 9337 /* */ 9338 /* Work through all of the subsystems inside IPFilter and call the create */ 9339 /* function for each in an order that won't lead to a crash :) */ 9340 /* ------------------------------------------------------------------------ */ 9341 ipf_main_softc_t * 9342 ipf_create_all(void *arg) 9343 { 9344 ipf_main_softc_t *softc; 9345 9346 softc = ipf_main_soft_create(arg); 9347 if (softc == NULL) 9348 return (NULL); 9349 9350 #ifdef IPFILTER_LOG 9351 softc->ipf_log_soft = ipf_log_soft_create(softc); 9352 if (softc->ipf_log_soft == NULL) { 9353 ipf_destroy_all(softc); 9354 return (NULL); 9355 } 9356 #endif 9357 9358 softc->ipf_lookup_soft = ipf_lookup_soft_create(softc); 9359 if (softc->ipf_lookup_soft == NULL) { 9360 ipf_destroy_all(softc); 9361 return (NULL); 9362 } 9363 9364 softc->ipf_sync_soft = ipf_sync_soft_create(softc); 9365 if (softc->ipf_sync_soft == NULL) { 9366 ipf_destroy_all(softc); 9367 return (NULL); 9368 } 9369 9370 softc->ipf_state_soft = ipf_state_soft_create(softc); 9371 if (softc->ipf_state_soft == NULL) { 9372 ipf_destroy_all(softc); 9373 return (NULL); 9374 } 9375 9376 softc->ipf_nat_soft = ipf_nat_soft_create(softc); 9377 if (softc->ipf_nat_soft == NULL) { 9378 ipf_destroy_all(softc); 9379 return (NULL); 9380 } 9381 9382 softc->ipf_frag_soft = ipf_frag_soft_create(softc); 9383 if (softc->ipf_frag_soft == NULL) { 9384 ipf_destroy_all(softc); 9385 return (NULL); 9386 } 9387 9388 softc->ipf_auth_soft = ipf_auth_soft_create(softc); 9389 if (softc->ipf_auth_soft == NULL) { 9390 ipf_destroy_all(softc); 9391 return (NULL); 9392 } 9393 9394 softc->ipf_proxy_soft = ipf_proxy_soft_create(softc); 9395 if (softc->ipf_proxy_soft == NULL) { 9396 ipf_destroy_all(softc); 9397 return (NULL); 9398 } 9399 9400 return (softc); 9401 } 9402 9403 9404 /* ------------------------------------------------------------------------ */ 9405 /* Function: ipf_destroy_all */ 9406 /* Returns: void */ 9407 /* Parameters: softc(I) - pointer to soft context main structure */ 9408 /* */ 9409 /* Work through all of the subsystems inside IPFilter and call the destroy */ 9410 /* function for each in an order that won't lead to a crash :) */ 9411 /* */ 9412 /* Every one of these functions is expected to succeed, so there is no */ 9413 /* checking of return values. */ 9414 /* ------------------------------------------------------------------------ */ 9415 void 9416 ipf_destroy_all(ipf_main_softc_t *softc) 9417 { 9418 9419 if (softc->ipf_state_soft != NULL) { 9420 ipf_state_soft_destroy(softc, softc->ipf_state_soft); 9421 softc->ipf_state_soft = NULL; 9422 } 9423 9424 if (softc->ipf_nat_soft != NULL) { 9425 ipf_nat_soft_destroy(softc, softc->ipf_nat_soft); 9426 softc->ipf_nat_soft = NULL; 9427 } 9428 9429 if (softc->ipf_frag_soft != NULL) { 9430 ipf_frag_soft_destroy(softc, softc->ipf_frag_soft); 9431 softc->ipf_frag_soft = NULL; 9432 } 9433 9434 if (softc->ipf_auth_soft != NULL) { 9435 ipf_auth_soft_destroy(softc, softc->ipf_auth_soft); 9436 softc->ipf_auth_soft = NULL; 9437 } 9438 9439 if (softc->ipf_proxy_soft != NULL) { 9440 ipf_proxy_soft_destroy(softc, softc->ipf_proxy_soft); 9441 softc->ipf_proxy_soft = NULL; 9442 } 9443 9444 if (softc->ipf_sync_soft != NULL) { 9445 ipf_sync_soft_destroy(softc, softc->ipf_sync_soft); 9446 softc->ipf_sync_soft = NULL; 9447 } 9448 9449 if (softc->ipf_lookup_soft != NULL) { 9450 ipf_lookup_soft_destroy(softc, softc->ipf_lookup_soft); 9451 softc->ipf_lookup_soft = NULL; 9452 } 9453 9454 #ifdef IPFILTER_LOG 9455 if (softc->ipf_log_soft != NULL) { 9456 ipf_log_soft_destroy(softc, softc->ipf_log_soft); 9457 softc->ipf_log_soft = NULL; 9458 } 9459 #endif 9460 9461 ipf_main_soft_destroy(softc); 9462 } 9463 9464 9465 /* ------------------------------------------------------------------------ */ 9466 /* Function: ipf_init_all */ 9467 /* Returns: 0 = success, -1 = failure */ 9468 /* Parameters: softc(I) - pointer to soft context main structure */ 9469 /* */ 9470 /* Work through all of the subsystems inside IPFilter and call the init */ 9471 /* function for each in an order that won't lead to a crash :) */ 9472 /* ------------------------------------------------------------------------ */ 9473 int 9474 ipf_init_all(ipf_main_softc_t *softc) 9475 { 9476 9477 if (ipf_main_soft_init(softc) == -1) 9478 return (-1); 9479 9480 #ifdef IPFILTER_LOG 9481 if (ipf_log_soft_init(softc, softc->ipf_log_soft) == -1) 9482 return (-1); 9483 #endif 9484 9485 if (ipf_lookup_soft_init(softc, softc->ipf_lookup_soft) == -1) 9486 return (-1); 9487 9488 if (ipf_sync_soft_init(softc, softc->ipf_sync_soft) == -1) 9489 return (-1); 9490 9491 if (ipf_state_soft_init(softc, softc->ipf_state_soft) == -1) 9492 return (-1); 9493 9494 if (ipf_nat_soft_init(softc, softc->ipf_nat_soft) == -1) 9495 return (-1); 9496 9497 if (ipf_frag_soft_init(softc, softc->ipf_frag_soft) == -1) 9498 return (-1); 9499 9500 if (ipf_auth_soft_init(softc, softc->ipf_auth_soft) == -1) 9501 return (-1); 9502 9503 if (ipf_proxy_soft_init(softc, softc->ipf_proxy_soft) == -1) 9504 return (-1); 9505 9506 return (0); 9507 } 9508 9509 9510 /* ------------------------------------------------------------------------ */ 9511 /* Function: ipf_fini_all */ 9512 /* Returns: 0 = success, -1 = failure */ 9513 /* Parameters: softc(I) - pointer to soft context main structure */ 9514 /* */ 9515 /* Work through all of the subsystems inside IPFilter and call the fini */ 9516 /* function for each in an order that won't lead to a crash :) */ 9517 /* ------------------------------------------------------------------------ */ 9518 int 9519 ipf_fini_all(ipf_main_softc_t *softc) 9520 { 9521 9522 ipf_token_flush(softc); 9523 9524 if (ipf_proxy_soft_fini(softc, softc->ipf_proxy_soft) == -1) 9525 return (-1); 9526 9527 if (ipf_auth_soft_fini(softc, softc->ipf_auth_soft) == -1) 9528 return (-1); 9529 9530 if (ipf_frag_soft_fini(softc, softc->ipf_frag_soft) == -1) 9531 return (-1); 9532 9533 if (ipf_nat_soft_fini(softc, softc->ipf_nat_soft) == -1) 9534 return (-1); 9535 9536 if (ipf_state_soft_fini(softc, softc->ipf_state_soft) == -1) 9537 return (-1); 9538 9539 if (ipf_sync_soft_fini(softc, softc->ipf_sync_soft) == -1) 9540 return (-1); 9541 9542 if (ipf_lookup_soft_fini(softc, softc->ipf_lookup_soft) == -1) 9543 return (-1); 9544 9545 #ifdef IPFILTER_LOG 9546 if (ipf_log_soft_fini(softc, softc->ipf_log_soft) == -1) 9547 return (-1); 9548 #endif 9549 9550 if (ipf_main_soft_fini(softc) == -1) 9551 return (-1); 9552 9553 return (0); 9554 } 9555 9556 9557 /* ------------------------------------------------------------------------ */ 9558 /* Function: ipf_rule_expire */ 9559 /* Returns: Nil */ 9560 /* Parameters: softc(I) - pointer to soft context main structure */ 9561 /* */ 9562 /* At present this function exists just to support temporary addition of */ 9563 /* firewall rules. Both inactive and active lists are scanned for items to */ 9564 /* purge, as by rights, the expiration is computed as soon as the rule is */ 9565 /* loaded in. */ 9566 /* ------------------------------------------------------------------------ */ 9567 void 9568 ipf_rule_expire(ipf_main_softc_t *softc) 9569 { 9570 frentry_t *fr; 9571 9572 if ((softc->ipf_rule_explist[0] == NULL) && 9573 (softc->ipf_rule_explist[1] == NULL)) 9574 return; 9575 9576 WRITE_ENTER(&softc->ipf_mutex); 9577 9578 while ((fr = softc->ipf_rule_explist[0]) != NULL) { 9579 /* 9580 * Because the list is kept sorted on insertion, the fist 9581 * one that dies in the future means no more work to do. 9582 */ 9583 if (fr->fr_die > softc->ipf_ticks) 9584 break; 9585 ipf_rule_delete(softc, fr, IPL_LOGIPF, 0); 9586 } 9587 9588 while ((fr = softc->ipf_rule_explist[1]) != NULL) { 9589 /* 9590 * Because the list is kept sorted on insertion, the fist 9591 * one that dies in the future means no more work to do. 9592 */ 9593 if (fr->fr_die > softc->ipf_ticks) 9594 break; 9595 ipf_rule_delete(softc, fr, IPL_LOGIPF, 1); 9596 } 9597 9598 RWLOCK_EXIT(&softc->ipf_mutex); 9599 } 9600 9601 9602 static int ipf_ht_node_cmp(struct host_node_s *, struct host_node_s *); 9603 static void ipf_ht_node_make_key(host_track_t *, host_node_t *, int, 9604 i6addr_t *); 9605 9606 host_node_t RBI_ZERO(ipf_rb); 9607 RBI_CODE(ipf_rb, host_node_t, hn_entry, ipf_ht_node_cmp) 9608 9609 9610 /* ------------------------------------------------------------------------ */ 9611 /* Function: ipf_ht_node_cmp */ 9612 /* Returns: int - 0 == nodes are the same, .. */ 9613 /* Parameters: k1(I) - pointer to first key to compare */ 9614 /* k2(I) - pointer to second key to compare */ 9615 /* */ 9616 /* The "key" for the node is a combination of two fields: the address */ 9617 /* family and the address itself. */ 9618 /* */ 9619 /* Because we're not actually interpreting the address data, it isn't */ 9620 /* necessary to convert them to/from network/host byte order. The mask is */ 9621 /* just used to remove bits that aren't significant - it doesn't matter */ 9622 /* where they are, as long as they're always in the same place. */ 9623 /* */ 9624 /* As with IP6_EQ, comparing IPv6 addresses starts at the bottom because */ 9625 /* this is where individual ones will differ the most - but not true for */ 9626 /* for /48's, etc. */ 9627 /* ------------------------------------------------------------------------ */ 9628 static int 9629 ipf_ht_node_cmp(struct host_node_s *k1, struct host_node_s *k2) 9630 { 9631 int i; 9632 9633 i = (k2->hn_addr.adf_family - k1->hn_addr.adf_family); 9634 if (i != 0) 9635 return (i); 9636 9637 if (k1->hn_addr.adf_family == AF_INET) 9638 return (k2->hn_addr.adf_addr.in4.s_addr - 9639 k1->hn_addr.adf_addr.in4.s_addr); 9640 9641 i = k2->hn_addr.adf_addr.i6[3] - k1->hn_addr.adf_addr.i6[3]; 9642 if (i != 0) 9643 return (i); 9644 i = k2->hn_addr.adf_addr.i6[2] - k1->hn_addr.adf_addr.i6[2]; 9645 if (i != 0) 9646 return (i); 9647 i = k2->hn_addr.adf_addr.i6[1] - k1->hn_addr.adf_addr.i6[1]; 9648 if (i != 0) 9649 return (i); 9650 i = k2->hn_addr.adf_addr.i6[0] - k1->hn_addr.adf_addr.i6[0]; 9651 return (i); 9652 } 9653 9654 9655 /* ------------------------------------------------------------------------ */ 9656 /* Function: ipf_ht_node_make_key */ 9657 /* Returns: Nil */ 9658 /* parameters: htp(I) - pointer to address tracking structure */ 9659 /* key(I) - where to store masked address for lookup */ 9660 /* family(I) - protocol family of address */ 9661 /* addr(I) - pointer to network address */ 9662 /* */ 9663 /* Using the "netmask" (number of bits) stored parent host tracking struct, */ 9664 /* copy the address passed in into the key structure whilst masking out the */ 9665 /* bits that we don't want. */ 9666 /* */ 9667 /* Because the parser will set ht_netmask to 128 if there is no protocol */ 9668 /* specified (the parser doesn't know if it should be a v4 or v6 rule), we */ 9669 /* have to be wary of that and not allow 32-128 to happen. */ 9670 /* ------------------------------------------------------------------------ */ 9671 static void 9672 ipf_ht_node_make_key(host_track_t *htp, host_node_t *key, int family, 9673 i6addr_t *addr) 9674 { 9675 key->hn_addr.adf_family = family; 9676 if (family == AF_INET) { 9677 u_32_t mask; 9678 int bits; 9679 9680 key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in4); 9681 bits = htp->ht_netmask; 9682 if (bits >= 32) { 9683 mask = 0xffffffff; 9684 } else { 9685 mask = htonl(0xffffffff << (32 - bits)); 9686 } 9687 key->hn_addr.adf_addr.in4.s_addr = addr->in4.s_addr & mask; 9688 #ifdef USE_INET6 9689 } else { 9690 int bits = htp->ht_netmask; 9691 9692 key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in6); 9693 if (bits > 96) { 9694 key->hn_addr.adf_addr.i6[3] = addr->i6[3] & 9695 htonl(0xffffffff << (128 - bits)); 9696 key->hn_addr.adf_addr.i6[2] = addr->i6[2]; 9697 key->hn_addr.adf_addr.i6[1] = addr->i6[2]; 9698 key->hn_addr.adf_addr.i6[0] = addr->i6[2]; 9699 } else if (bits > 64) { 9700 key->hn_addr.adf_addr.i6[3] = 0; 9701 key->hn_addr.adf_addr.i6[2] = addr->i6[2] & 9702 htonl(0xffffffff << (96 - bits)); 9703 key->hn_addr.adf_addr.i6[1] = addr->i6[1]; 9704 key->hn_addr.adf_addr.i6[0] = addr->i6[0]; 9705 } else if (bits > 32) { 9706 key->hn_addr.adf_addr.i6[3] = 0; 9707 key->hn_addr.adf_addr.i6[2] = 0; 9708 key->hn_addr.adf_addr.i6[1] = addr->i6[1] & 9709 htonl(0xffffffff << (64 - bits)); 9710 key->hn_addr.adf_addr.i6[0] = addr->i6[0]; 9711 } else { 9712 key->hn_addr.adf_addr.i6[3] = 0; 9713 key->hn_addr.adf_addr.i6[2] = 0; 9714 key->hn_addr.adf_addr.i6[1] = 0; 9715 key->hn_addr.adf_addr.i6[0] = addr->i6[0] & 9716 htonl(0xffffffff << (32 - bits)); 9717 } 9718 #endif 9719 } 9720 } 9721 9722 9723 /* ------------------------------------------------------------------------ */ 9724 /* Function: ipf_ht_node_add */ 9725 /* Returns: int - 0 == success, -1 == failure */ 9726 /* Parameters: softc(I) - pointer to soft context main structure */ 9727 /* htp(I) - pointer to address tracking structure */ 9728 /* family(I) - protocol family of address */ 9729 /* addr(I) - pointer to network address */ 9730 /* */ 9731 /* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS */ 9732 /* ipf_ht_node_del FROM RUNNING CONCURRENTLY ON THE SAME htp. */ 9733 /* */ 9734 /* After preparing the key with the address information to find, look in */ 9735 /* the red-black tree to see if the address is known. A successful call to */ 9736 /* this function can mean one of two things: a new node was added to the */ 9737 /* tree or a matching node exists and we're able to bump up its activity. */ 9738 /* ------------------------------------------------------------------------ */ 9739 int 9740 ipf_ht_node_add(ipf_main_softc_t *softc, host_track_t *htp, int family, 9741 i6addr_t *addr) 9742 { 9743 host_node_t *h; 9744 host_node_t k; 9745 9746 ipf_ht_node_make_key(htp, &k, family, addr); 9747 9748 h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k); 9749 if (h == NULL) { 9750 if (htp->ht_cur_nodes >= htp->ht_max_nodes) 9751 return (-1); 9752 KMALLOC(h, host_node_t *); 9753 if (h == NULL) { 9754 DT(ipf_rb_no_mem); 9755 LBUMP(ipf_rb_no_mem); 9756 return (-1); 9757 } 9758 9759 /* 9760 * If there was a macro to initialise the RB node then that 9761 * would get used here, but there isn't... 9762 */ 9763 bzero((char *)h, sizeof(*h)); 9764 h->hn_addr = k.hn_addr; 9765 h->hn_addr.adf_family = k.hn_addr.adf_family; 9766 RBI_INSERT(ipf_rb, &htp->ht_root, h); 9767 htp->ht_cur_nodes++; 9768 } else { 9769 if ((htp->ht_max_per_node != 0) && 9770 (h->hn_active >= htp->ht_max_per_node)) { 9771 DT(ipf_rb_node_max); 9772 LBUMP(ipf_rb_node_max); 9773 return (-1); 9774 } 9775 } 9776 9777 h->hn_active++; 9778 9779 return (0); 9780 } 9781 9782 9783 /* ------------------------------------------------------------------------ */ 9784 /* Function: ipf_ht_node_del */ 9785 /* Returns: int - 0 == success, -1 == failure */ 9786 /* parameters: htp(I) - pointer to address tracking structure */ 9787 /* family(I) - protocol family of address */ 9788 /* addr(I) - pointer to network address */ 9789 /* */ 9790 /* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS */ 9791 /* ipf_ht_node_add FROM RUNNING CONCURRENTLY ON THE SAME htp. */ 9792 /* */ 9793 /* Try and find the address passed in amongst the leavese on this tree to */ 9794 /* be friend. If found then drop the active account for that node drops by */ 9795 /* one. If that count reaches 0, it is time to free it all up. */ 9796 /* ------------------------------------------------------------------------ */ 9797 int 9798 ipf_ht_node_del(host_track_t *htp, int family, i6addr_t *addr) 9799 { 9800 host_node_t *h; 9801 host_node_t k; 9802 9803 ipf_ht_node_make_key(htp, &k, family, addr); 9804 9805 h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k); 9806 if (h == NULL) { 9807 return (-1); 9808 } else { 9809 h->hn_active--; 9810 if (h->hn_active == 0) { 9811 (void) RBI_DELETE(ipf_rb, &htp->ht_root, h); 9812 htp->ht_cur_nodes--; 9813 KFREE(h); 9814 } 9815 } 9816 9817 return (0); 9818 } 9819 9820 9821 /* ------------------------------------------------------------------------ */ 9822 /* Function: ipf_rb_ht_init */ 9823 /* Returns: Nil */ 9824 /* Parameters: head(I) - pointer to host tracking structure */ 9825 /* */ 9826 /* Initialise the host tracking structure to be ready for use above. */ 9827 /* ------------------------------------------------------------------------ */ 9828 void 9829 ipf_rb_ht_init(host_track_t *head) 9830 { 9831 RBI_INIT(ipf_rb, &head->ht_root); 9832 } 9833 9834 9835 /* ------------------------------------------------------------------------ */ 9836 /* Function: ipf_rb_ht_freenode */ 9837 /* Returns: Nil */ 9838 /* Parameters: head(I) - pointer to host tracking structure */ 9839 /* arg(I) - additional argument from walk caller */ 9840 /* */ 9841 /* Free an actual host_node_t structure. */ 9842 /* ------------------------------------------------------------------------ */ 9843 void 9844 ipf_rb_ht_freenode(host_node_t *node, void *arg) 9845 { 9846 KFREE(node); 9847 } 9848 9849 9850 /* ------------------------------------------------------------------------ */ 9851 /* Function: ipf_rb_ht_flush */ 9852 /* Returns: Nil */ 9853 /* Parameters: head(I) - pointer to host tracking structure */ 9854 /* */ 9855 /* Remove all of the nodes in the tree tracking hosts by calling a walker */ 9856 /* and free'ing each one. */ 9857 /* ------------------------------------------------------------------------ */ 9858 void 9859 ipf_rb_ht_flush(host_track_t *head) 9860 { 9861 RBI_WALK(ipf_rb, &head->ht_root, ipf_rb_ht_freenode, NULL); 9862 } 9863 9864 9865 /* ------------------------------------------------------------------------ */ 9866 /* Function: ipf_slowtimer */ 9867 /* Returns: Nil */ 9868 /* Parameters: ptr(I) - pointer to main ipf soft context structure */ 9869 /* */ 9870 /* Slowly expire held state for fragments. Timeouts are set * in */ 9871 /* expectation of this being called twice per second. */ 9872 /* ------------------------------------------------------------------------ */ 9873 void 9874 ipf_slowtimer(ipf_main_softc_t *softc) 9875 { 9876 9877 ipf_token_expire(softc); 9878 ipf_frag_expire(softc); 9879 ipf_state_expire(softc); 9880 ipf_nat_expire(softc); 9881 ipf_auth_expire(softc); 9882 ipf_lookup_expire(softc); 9883 ipf_rule_expire(softc); 9884 ipf_sync_expire(softc); 9885 softc->ipf_ticks++; 9886 } 9887 9888 9889 /* ------------------------------------------------------------------------ */ 9890 /* Function: ipf_inet_mask_add */ 9891 /* Returns: Nil */ 9892 /* Parameters: bits(I) - pointer to nat context information */ 9893 /* mtab(I) - pointer to mask hash table structure */ 9894 /* */ 9895 /* When called, bits represents the mask of a new NAT rule that has just */ 9896 /* been added. This function inserts a bitmask into the array of masks to */ 9897 /* search when searching for a matching NAT rule for a packet. */ 9898 /* Prevention of duplicate masks is achieved by checking the use count for */ 9899 /* a given netmask. */ 9900 /* ------------------------------------------------------------------------ */ 9901 void 9902 ipf_inet_mask_add(int bits, ipf_v4_masktab_t *mtab) 9903 { 9904 u_32_t mask; 9905 int i, j; 9906 9907 mtab->imt4_masks[bits]++; 9908 if (mtab->imt4_masks[bits] > 1) 9909 return; 9910 9911 if (bits == 0) 9912 mask = 0; 9913 else 9914 mask = 0xffffffff << (32 - bits); 9915 9916 for (i = 0; i < 33; i++) { 9917 if (ntohl(mtab->imt4_active[i]) < mask) { 9918 for (j = 32; j > i; j--) 9919 mtab->imt4_active[j] = mtab->imt4_active[j - 1]; 9920 mtab->imt4_active[i] = htonl(mask); 9921 break; 9922 } 9923 } 9924 mtab->imt4_max++; 9925 } 9926 9927 9928 /* ------------------------------------------------------------------------ */ 9929 /* Function: ipf_inet_mask_del */ 9930 /* Returns: Nil */ 9931 /* Parameters: bits(I) - number of bits set in the netmask */ 9932 /* mtab(I) - pointer to mask hash table structure */ 9933 /* */ 9934 /* Remove the 32bit bitmask represented by "bits" from the collection of */ 9935 /* netmasks stored inside of mtab. */ 9936 /* ------------------------------------------------------------------------ */ 9937 void 9938 ipf_inet_mask_del(int bits, ipf_v4_masktab_t *mtab) 9939 { 9940 u_32_t mask; 9941 int i, j; 9942 9943 mtab->imt4_masks[bits]--; 9944 if (mtab->imt4_masks[bits] > 0) 9945 return; 9946 9947 mask = htonl(0xffffffff << (32 - bits)); 9948 for (i = 0; i < 33; i++) { 9949 if (mtab->imt4_active[i] == mask) { 9950 for (j = i + 1; j < 33; j++) 9951 mtab->imt4_active[j - 1] = mtab->imt4_active[j]; 9952 break; 9953 } 9954 } 9955 mtab->imt4_max--; 9956 ASSERT(mtab->imt4_max >= 0); 9957 } 9958 9959 9960 #ifdef USE_INET6 9961 /* ------------------------------------------------------------------------ */ 9962 /* Function: ipf_inet6_mask_add */ 9963 /* Returns: Nil */ 9964 /* Parameters: bits(I) - number of bits set in mask */ 9965 /* mask(I) - pointer to mask to add */ 9966 /* mtab(I) - pointer to mask hash table structure */ 9967 /* */ 9968 /* When called, bitcount represents the mask of a IPv6 NAT map rule that */ 9969 /* has just been added. This function inserts a bitmask into the array of */ 9970 /* masks to search when searching for a matching NAT rule for a packet. */ 9971 /* Prevention of duplicate masks is achieved by checking the use count for */ 9972 /* a given netmask. */ 9973 /* ------------------------------------------------------------------------ */ 9974 void 9975 ipf_inet6_mask_add(int bits, i6addr_t *mask, ipf_v6_masktab_t *mtab) 9976 { 9977 i6addr_t zero; 9978 int i, j; 9979 9980 mtab->imt6_masks[bits]++; 9981 if (mtab->imt6_masks[bits] > 1) 9982 return; 9983 9984 if (bits == 0) { 9985 mask = &zero; 9986 zero.i6[0] = 0; 9987 zero.i6[1] = 0; 9988 zero.i6[2] = 0; 9989 zero.i6[3] = 0; 9990 } 9991 9992 for (i = 0; i < 129; i++) { 9993 if (IP6_LT(&mtab->imt6_active[i], mask)) { 9994 for (j = 128; j > i; j--) 9995 mtab->imt6_active[j] = mtab->imt6_active[j - 1]; 9996 mtab->imt6_active[i] = *mask; 9997 break; 9998 } 9999 } 10000 mtab->imt6_max++; 10001 } 10002 10003 10004 /* ------------------------------------------------------------------------ */ 10005 /* Function: ipf_inet6_mask_del */ 10006 /* Returns: Nil */ 10007 /* Parameters: bits(I) - number of bits set in mask */ 10008 /* mask(I) - pointer to mask to remove */ 10009 /* mtab(I) - pointer to mask hash table structure */ 10010 /* */ 10011 /* Remove the 128bit bitmask represented by "bits" from the collection of */ 10012 /* netmasks stored inside of mtab. */ 10013 /* ------------------------------------------------------------------------ */ 10014 void 10015 ipf_inet6_mask_del(int bits, i6addr_t *mask, ipf_v6_masktab_t *mtab) 10016 { 10017 i6addr_t zero; 10018 int i, j; 10019 10020 mtab->imt6_masks[bits]--; 10021 if (mtab->imt6_masks[bits] > 0) 10022 return; 10023 10024 if (bits == 0) 10025 mask = &zero; 10026 zero.i6[0] = 0; 10027 zero.i6[1] = 0; 10028 zero.i6[2] = 0; 10029 zero.i6[3] = 0; 10030 10031 for (i = 0; i < 129; i++) { 10032 if (IP6_EQ(&mtab->imt6_active[i], mask)) { 10033 for (j = i + 1; j < 129; j++) { 10034 mtab->imt6_active[j - 1] = mtab->imt6_active[j]; 10035 if (IP6_EQ(&mtab->imt6_active[j - 1], &zero)) 10036 break; 10037 } 10038 break; 10039 } 10040 } 10041 mtab->imt6_max--; 10042 ASSERT(mtab->imt6_max >= 0); 10043 } 10044 #endif 10045 10046 /* ------------------------------------------------------------------------ */ 10047 /* Function: ipf_check_names_string */ 10048 /* Returns: int - 0 == success */ 10049 /* - 1 == negative offset */ 10050 /* - 2 == offset exceds namelen */ 10051 /* - 3 == string exceeds the names string */ 10052 /* Parameters: names - pointer to names string */ 10053 /* namelen - total length of names string */ 10054 /* offset - offset into names string */ 10055 /* */ 10056 /* Validate the names string (fr_names for ipfilter, in_names for ipnat). */ 10057 /* ------------------------------------------------------------------------ */ 10058 int 10059 ipf_check_names_string(char *names, int namelen, int offset) 10060 { 10061 const char *name; 10062 size_t len; 10063 10064 if (offset == -1) 10065 return (0); 10066 if (offset < 0) 10067 return (1); 10068 if (offset > namelen) 10069 return (2); 10070 name = &names[offset]; 10071 len = strnlen(name, namelen - offset); 10072 if (len == namelen - offset) 10073 return (3); 10074 return (0); 10075 } 10076