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> 100extern struct callout ipf_slowtimer_ch; 101#endif 102/* END OF INCLUDES */ 103 104 105#ifndef _KERNEL 106# include "ipf.h" 107# include "ipt.h" 108extern int opts; 109extern 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 117static inline int ipf_check_ipf(fr_info_t *, frentry_t *, int); 118static u_32_t ipf_checkcipso(fr_info_t *, u_char *, int); 119static u_32_t ipf_checkripso(u_char *); 120static u_32_t ipf_decaps(fr_info_t *, u_32_t, int); 121#ifdef IPFILTER_LOG 122static frentry_t *ipf_dolog(fr_info_t *, u_32_t *); 123#endif 124static int ipf_flushlist(ipf_main_softc_t *, int *, frentry_t **); 125static int ipf_flush_groups(ipf_main_softc_t *, frgroup_t **, 126 int); 127static ipfunc_t ipf_findfunc(ipfunc_t); 128static void *ipf_findlookup(ipf_main_softc_t *, int, frentry_t *, 129 i6addr_t *, i6addr_t *); 130static frentry_t *ipf_firewall(fr_info_t *, u_32_t *); 131static int ipf_fr_matcharray(fr_info_t *, int *); 132static int ipf_frruleiter(ipf_main_softc_t *, void *, int, 133 void *); 134static void ipf_funcfini(ipf_main_softc_t *, frentry_t *); 135static int ipf_funcinit(ipf_main_softc_t *, frentry_t *); 136static int ipf_geniter(ipf_main_softc_t *, ipftoken_t *, 137 ipfgeniter_t *); 138static void ipf_getstat(ipf_main_softc_t *, 139 struct friostat *, int); 140static int ipf_group_flush(ipf_main_softc_t *, frgroup_t *); 141static void ipf_group_free(frgroup_t *); 142static int ipf_grpmapfini(struct ipf_main_softc_s *, 143 frentry_t *); 144static int ipf_grpmapinit(struct ipf_main_softc_s *, 145 frentry_t *); 146static frentry_t *ipf_nextrule(ipf_main_softc_t *, int, int, 147 frentry_t *, int); 148static int ipf_portcheck(frpcmp_t *, u_32_t); 149static inline int ipf_pr_ah(fr_info_t *); 150static inline void ipf_pr_esp(fr_info_t *); 151static inline void ipf_pr_gre(fr_info_t *); 152static inline void ipf_pr_udp(fr_info_t *); 153static inline void ipf_pr_tcp(fr_info_t *); 154static inline void ipf_pr_icmp(fr_info_t *); 155static inline void ipf_pr_ipv4hdr(fr_info_t *); 156static inline void ipf_pr_short(fr_info_t *, int); 157static inline int ipf_pr_tcpcommon(fr_info_t *); 158static inline int ipf_pr_udpcommon(fr_info_t *); 159static void ipf_rule_delete(ipf_main_softc_t *, frentry_t *f, 160 int, int); 161static void ipf_rule_expire_insert(ipf_main_softc_t *, 162 frentry_t *, int); 163static int ipf_synclist(ipf_main_softc_t *, frentry_t *, 164 void *); 165static void ipf_token_flush(ipf_main_softc_t *); 166static void ipf_token_unlink(ipf_main_softc_t *, 167 ipftoken_t *); 168static ipftuneable_t *ipf_tune_findbyname(ipftuneable_t *, 169 const char *); 170static ipftuneable_t *ipf_tune_findbycookie(ipftuneable_t **, void *, 171 void **); 172static int ipf_updateipid(fr_info_t *); 173static int ipf_settimeout(struct ipf_main_softc_s *, 174 struct ipftuneable *, 175 ipftuneval_t *); 176#if !defined(_KERNEL) || SOLARIS 177static 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 */ 187static 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 211static 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 */ 228static 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 239char ipfilter_version[] = IPL_VERSION; 240 241int ipf_features = 0 242#ifdef IPFILTER_LKM 243 | IPF_FEAT_LKM 244#endif 245#ifdef IPFILTER_LOG 246 | IPF_FEAT_LOG 247#endif 248 | IPF_FEAT_LOOKUP 249#ifdef IPFILTER_BPF 250 | IPF_FEAT_BPF 251#endif 252#ifdef IPFILTER_COMPILED 253 | IPF_FEAT_COMPILED 254#endif 255#ifdef IPFILTER_CKSUM 256 | IPF_FEAT_CKSUM 257#endif 258 | IPF_FEAT_SYNC 259#ifdef IPFILTER_SCAN 260 | IPF_FEAT_SCAN 261#endif 262#ifdef USE_INET6 263 | IPF_FEAT_IPV6 264#endif 265 ; 266 267 268/* 269 * Table of functions available for use with call rules. 270 */ 271static ipfunc_resolve_t ipf_availfuncs[] = { 272 { "srcgrpmap", ipf_srcgrpmap, ipf_grpmapinit, ipf_grpmapfini }, 273 { "dstgrpmap", ipf_dstgrpmap, ipf_grpmapinit, ipf_grpmapfini }, 274 { "", NULL, NULL, NULL } 275}; 276 277static ipftuneable_t ipf_main_tuneables[] = { 278 { { (void *)offsetof(struct ipf_main_softc_s, ipf_flags) }, 279 "ipf_flags", 0, 0xffffffff, 280 stsizeof(ipf_main_softc_t, ipf_flags), 281 0, NULL, NULL }, 282 { { (void *)offsetof(struct ipf_main_softc_s, ipf_active) }, 283 "active", 0, 0, 284 stsizeof(ipf_main_softc_t, ipf_active), 285 IPFT_RDONLY, NULL, NULL }, 286 { { (void *)offsetof(ipf_main_softc_t, ipf_control_forwarding) }, 287 "control_forwarding", 0, 1, 288 stsizeof(ipf_main_softc_t, ipf_control_forwarding), 289 0, NULL, NULL }, 290 { { (void *)offsetof(ipf_main_softc_t, ipf_update_ipid) }, 291 "update_ipid", 0, 1, 292 stsizeof(ipf_main_softc_t, ipf_update_ipid), 293 0, NULL, NULL }, 294 { { (void *)offsetof(ipf_main_softc_t, ipf_chksrc) }, 295 "chksrc", 0, 1, 296 stsizeof(ipf_main_softc_t, ipf_chksrc), 297 0, NULL, NULL }, 298 { { (void *)offsetof(ipf_main_softc_t, ipf_minttl) }, 299 "min_ttl", 0, 1, 300 stsizeof(ipf_main_softc_t, ipf_minttl), 301 0, NULL, NULL }, 302 { { (void *)offsetof(ipf_main_softc_t, ipf_icmpminfragmtu) }, 303 "icmp_minfragmtu", 0, 1, 304 stsizeof(ipf_main_softc_t, ipf_icmpminfragmtu), 305 0, NULL, NULL }, 306 { { (void *)offsetof(ipf_main_softc_t, ipf_pass) }, 307 "default_pass", 0, 0xffffffff, 308 stsizeof(ipf_main_softc_t, ipf_pass), 309 0, NULL, NULL }, 310 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpidletimeout) }, 311 "tcp_idle_timeout", 1, 0x7fffffff, 312 stsizeof(ipf_main_softc_t, ipf_tcpidletimeout), 313 0, NULL, ipf_settimeout }, 314 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosewait) }, 315 "tcp_close_wait", 1, 0x7fffffff, 316 stsizeof(ipf_main_softc_t, ipf_tcpclosewait), 317 0, NULL, ipf_settimeout }, 318 { { (void *)offsetof(ipf_main_softc_t, ipf_tcplastack) }, 319 "tcp_last_ack", 1, 0x7fffffff, 320 stsizeof(ipf_main_softc_t, ipf_tcplastack), 321 0, NULL, ipf_settimeout }, 322 { { (void *)offsetof(ipf_main_softc_t, ipf_tcptimeout) }, 323 "tcp_timeout", 1, 0x7fffffff, 324 stsizeof(ipf_main_softc_t, ipf_tcptimeout), 325 0, NULL, ipf_settimeout }, 326 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynsent) }, 327 "tcp_syn_sent", 1, 0x7fffffff, 328 stsizeof(ipf_main_softc_t, ipf_tcpsynsent), 329 0, NULL, ipf_settimeout }, 330 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpsynrecv) }, 331 "tcp_syn_received", 1, 0x7fffffff, 332 stsizeof(ipf_main_softc_t, ipf_tcpsynrecv), 333 0, NULL, ipf_settimeout }, 334 { { (void *)offsetof(ipf_main_softc_t, ipf_tcpclosed) }, 335 "tcp_closed", 1, 0x7fffffff, 336 stsizeof(ipf_main_softc_t, ipf_tcpclosed), 337 0, NULL, ipf_settimeout }, 338 { { (void *)offsetof(ipf_main_softc_t, ipf_tcphalfclosed) }, 339 "tcp_half_closed", 1, 0x7fffffff, 340 stsizeof(ipf_main_softc_t, ipf_tcphalfclosed), 341 0, NULL, ipf_settimeout }, 342 { { (void *)offsetof(ipf_main_softc_t, ipf_tcptimewait) }, 343 "tcp_time_wait", 1, 0x7fffffff, 344 stsizeof(ipf_main_softc_t, ipf_tcptimewait), 345 0, NULL, ipf_settimeout }, 346 { { (void *)offsetof(ipf_main_softc_t, ipf_udptimeout) }, 347 "udp_timeout", 1, 0x7fffffff, 348 stsizeof(ipf_main_softc_t, ipf_udptimeout), 349 0, NULL, ipf_settimeout }, 350 { { (void *)offsetof(ipf_main_softc_t, ipf_udpacktimeout) }, 351 "udp_ack_timeout", 1, 0x7fffffff, 352 stsizeof(ipf_main_softc_t, ipf_udpacktimeout), 353 0, NULL, ipf_settimeout }, 354 { { (void *)offsetof(ipf_main_softc_t, ipf_icmptimeout) }, 355 "icmp_timeout", 1, 0x7fffffff, 356 stsizeof(ipf_main_softc_t, ipf_icmptimeout), 357 0, NULL, ipf_settimeout }, 358 { { (void *)offsetof(ipf_main_softc_t, ipf_icmpacktimeout) }, 359 "icmp_ack_timeout", 1, 0x7fffffff, 360 stsizeof(ipf_main_softc_t, ipf_icmpacktimeout), 361 0, NULL, ipf_settimeout }, 362 { { (void *)offsetof(ipf_main_softc_t, ipf_iptimeout) }, 363 "ip_timeout", 1, 0x7fffffff, 364 stsizeof(ipf_main_softc_t, ipf_iptimeout), 365 0, NULL, ipf_settimeout }, 366#if defined(INSTANCES) && defined(_KERNEL) 367 { { (void *)offsetof(ipf_main_softc_t, ipf_get_loopback) }, 368 "intercept_loopback", 0, 1, 369 stsizeof(ipf_main_softc_t, ipf_get_loopback), 370 0, NULL, ipf_set_loopback }, 371#endif 372 { { 0 }, 373 NULL, 0, 0, 374 0, 375 0, NULL, NULL } 376}; 377 378 379/* 380 * The next section of code is a collection of small routines that set 381 * fields in the fr_info_t structure passed based on properties of the 382 * current packet. There are different routines for the same protocol 383 * for each of IPv4 and IPv6. Adding a new protocol, for which there 384 * will "special" inspection for setup, is now more easily done by adding 385 * a new routine and expanding the ipf_pr_ipinit*() function rather than by 386 * adding more code to a growing switch statement. 387 */ 388#ifdef USE_INET6 389static inline int ipf_pr_ah6(fr_info_t *); 390static inline void ipf_pr_esp6(fr_info_t *); 391static inline void ipf_pr_gre6(fr_info_t *); 392static inline void ipf_pr_udp6(fr_info_t *); 393static inline void ipf_pr_tcp6(fr_info_t *); 394static inline void ipf_pr_icmp6(fr_info_t *); 395static inline void ipf_pr_ipv6hdr(fr_info_t *); 396static inline void ipf_pr_short6(fr_info_t *, int); 397static inline int ipf_pr_hopopts6(fr_info_t *); 398static inline int ipf_pr_mobility6(fr_info_t *); 399static inline int ipf_pr_routing6(fr_info_t *); 400static inline int ipf_pr_dstopts6(fr_info_t *); 401static inline int ipf_pr_fragment6(fr_info_t *); 402static inline struct ip6_ext *ipf_pr_ipv6exthdr(fr_info_t *, int, int); 403 404 405/* ------------------------------------------------------------------------ */ 406/* Function: ipf_pr_short6 */ 407/* Returns: void */ 408/* Parameters: fin(I) - pointer to packet information */ 409/* xmin(I) - minimum header size */ 410/* */ 411/* IPv6 Only */ 412/* This is function enforces the 'is a packet too short to be legit' rule */ 413/* for IPv6 and marks the packet with FI_SHORT if so. See function comment */ 414/* for ipf_pr_short() for more details. */ 415/* ------------------------------------------------------------------------ */ 416static inline void 417ipf_pr_short6(fr_info_t *fin, int xmin) 418{ 419 420 if (fin->fin_dlen < xmin) 421 fin->fin_flx |= FI_SHORT; 422} 423 424 425/* ------------------------------------------------------------------------ */ 426/* Function: ipf_pr_ipv6hdr */ 427/* Returns: void */ 428/* Parameters: fin(I) - pointer to packet information */ 429/* */ 430/* IPv6 Only */ 431/* Copy values from the IPv6 header into the fr_info_t struct and call the */ 432/* per-protocol analyzer if it exists. In validating the packet, a protocol*/ 433/* analyzer may pullup or free the packet itself so we need to be vigiliant */ 434/* of that possibility arising. */ 435/* ------------------------------------------------------------------------ */ 436static inline void 437ipf_pr_ipv6hdr(fr_info_t *fin) 438{ 439 ip6_t *ip6 = (ip6_t *)fin->fin_ip; 440 int p, go = 1, i, hdrcount; 441 fr_ip_t *fi = &fin->fin_fi; 442 443 fin->fin_off = 0; 444 445 fi->fi_tos = 0; 446 fi->fi_optmsk = 0; 447 fi->fi_secmsk = 0; 448 fi->fi_auth = 0; 449 450 p = ip6->ip6_nxt; 451 fin->fin_crc = p; 452 fi->fi_ttl = ip6->ip6_hlim; 453 fi->fi_src.in6 = ip6->ip6_src; 454 fin->fin_crc += fi->fi_src.i6[0]; 455 fin->fin_crc += fi->fi_src.i6[1]; 456 fin->fin_crc += fi->fi_src.i6[2]; 457 fin->fin_crc += fi->fi_src.i6[3]; 458 fi->fi_dst.in6 = ip6->ip6_dst; 459 fin->fin_crc += fi->fi_dst.i6[0]; 460 fin->fin_crc += fi->fi_dst.i6[1]; 461 fin->fin_crc += fi->fi_dst.i6[2]; 462 fin->fin_crc += fi->fi_dst.i6[3]; 463 fin->fin_id = 0; 464 if (IN6_IS_ADDR_MULTICAST(&fi->fi_dst.in6)) 465 fin->fin_flx |= FI_MULTICAST|FI_MBCAST; 466 467 hdrcount = 0; 468 while (go && !(fin->fin_flx & FI_SHORT)) { 469 switch (p) 470 { 471 case IPPROTO_UDP : 472 ipf_pr_udp6(fin); 473 go = 0; 474 break; 475 476 case IPPROTO_TCP : 477 ipf_pr_tcp6(fin); 478 go = 0; 479 break; 480 481 case IPPROTO_ICMPV6 : 482 ipf_pr_icmp6(fin); 483 go = 0; 484 break; 485 486 case IPPROTO_GRE : 487 ipf_pr_gre6(fin); 488 go = 0; 489 break; 490 491 case IPPROTO_HOPOPTS : 492 p = ipf_pr_hopopts6(fin); 493 break; 494 495 case IPPROTO_MOBILITY : 496 p = ipf_pr_mobility6(fin); 497 break; 498 499 case IPPROTO_DSTOPTS : 500 p = ipf_pr_dstopts6(fin); 501 break; 502 503 case IPPROTO_ROUTING : 504 p = ipf_pr_routing6(fin); 505 break; 506 507 case IPPROTO_AH : 508 p = ipf_pr_ah6(fin); 509 break; 510 511 case IPPROTO_ESP : 512 ipf_pr_esp6(fin); 513 go = 0; 514 break; 515 516 case IPPROTO_IPV6 : 517 for (i = 0; ip6exthdr[i].ol_bit != 0; i++) 518 if (ip6exthdr[i].ol_val == p) { 519 fin->fin_flx |= ip6exthdr[i].ol_bit; 520 break; 521 } 522 go = 0; 523 break; 524 525 case IPPROTO_NONE : 526 go = 0; 527 break; 528 529 case IPPROTO_FRAGMENT : 530 p = ipf_pr_fragment6(fin); 531 /* 532 * Given that the only fragments we want to let through 533 * (where fin_off != 0) are those where the non-first 534 * fragments only have data, we can safely stop looking 535 * at headers if this is a non-leading fragment. 536 */ 537 if (fin->fin_off != 0) 538 go = 0; 539 break; 540 541 default : 542 go = 0; 543 break; 544 } 545 hdrcount++; 546 547 /* 548 * It is important to note that at this point, for the 549 * extension headers (go != 0), the entire header may not have 550 * been pulled up when the code gets to this point. This is 551 * only done for "go != 0" because the other header handlers 552 * will all pullup their complete header. The other indicator 553 * of an incomplete packet is that this was just an extension 554 * header. 555 */ 556 if ((go != 0) && (p != IPPROTO_NONE) && 557 (ipf_pr_pullup(fin, 0) == -1)) { 558 p = IPPROTO_NONE; 559 break; 560 } 561 } 562 563 /* 564 * Some of the above functions, like ipf_pr_esp6(), can call ipf_pullup 565 * and destroy whatever packet was here. The caller of this function 566 * expects us to return if there is a problem with ipf_pullup. 567 */ 568 if (fin->fin_m == NULL) { 569 ipf_main_softc_t *softc = fin->fin_main_soft; 570 571 LBUMPD(ipf_stats[fin->fin_out], fr_v6_bad); 572 return; 573 } 574 575 fi->fi_p = p; 576 577 /* 578 * IPv6 fragment case 1 - see comment for ipf_pr_fragment6(). 579 * "go != 0" implies the above loop hasn't arrived at a layer 4 header. 580 */ 581 if ((go != 0) && (fin->fin_flx & FI_FRAG) && (fin->fin_off == 0)) { 582 ipf_main_softc_t *softc = fin->fin_main_soft; 583 584 fin->fin_flx |= FI_BAD; 585 DT2(ipf_fi_bad_ipv6_frag_1, fr_info_t *, fin, int, go); 586 LBUMPD(ipf_stats[fin->fin_out], fr_v6_badfrag); 587 LBUMP(ipf_stats[fin->fin_out].fr_v6_bad); 588 } 589} 590 591 592/* ------------------------------------------------------------------------ */ 593/* Function: ipf_pr_ipv6exthdr */ 594/* Returns: struct ip6_ext * - pointer to the start of the next header */ 595/* or NULL if there is a prolblem. */ 596/* Parameters: fin(I) - pointer to packet information */ 597/* multiple(I) - flag indicating yes/no if multiple occurances */ 598/* of this extension header are allowed. */ 599/* proto(I) - protocol number for this extension header */ 600/* */ 601/* IPv6 Only */ 602/* This function embodies a number of common checks that all IPv6 extension */ 603/* headers must be subjected to. For example, making sure the packet is */ 604/* big enough for it to be in, checking if it is repeated and setting a */ 605/* flag to indicate its presence. */ 606/* ------------------------------------------------------------------------ */ 607static inline struct ip6_ext * 608ipf_pr_ipv6exthdr(fr_info_t *fin, int multiple, int proto) 609{ 610 ipf_main_softc_t *softc = fin->fin_main_soft; 611 struct ip6_ext *hdr; 612 u_short shift; 613 int i; 614 615 fin->fin_flx |= FI_V6EXTHDR; 616 617 /* 8 is default length of extension hdr */ 618 if ((fin->fin_dlen - 8) < 0) { 619 fin->fin_flx |= FI_SHORT; 620 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_short); 621 return (NULL); 622 } 623 624 if (ipf_pr_pullup(fin, 8) == -1) { 625 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_pullup); 626 return (NULL); 627 } 628 629 hdr = fin->fin_dp; 630 switch (proto) 631 { 632 case IPPROTO_FRAGMENT : 633 shift = 8; 634 break; 635 default : 636 shift = 8 + (hdr->ip6e_len << 3); 637 break; 638 } 639 640 if (shift > fin->fin_dlen) { /* Nasty extension header length? */ 641 fin->fin_flx |= FI_BAD; 642 DT3(ipf_fi_bad_pr_ipv6exthdr_len, fr_info_t *, fin, u_short, shift, u_short, fin->fin_dlen); 643 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ext_hlen); 644 return (NULL); 645 } 646 647 fin->fin_dp = (char *)fin->fin_dp + shift; 648 fin->fin_dlen -= shift; 649 650 /* 651 * If we have seen a fragment header, do not set any flags to indicate 652 * the presence of this extension header as it has no impact on the 653 * end result until after it has been defragmented. 654 */ 655 if (fin->fin_flx & FI_FRAG) 656 return (hdr); 657 658 for (i = 0; ip6exthdr[i].ol_bit != 0; i++) 659 if (ip6exthdr[i].ol_val == proto) { 660 /* 661 * Most IPv6 extension headers are only allowed once. 662 */ 663 if ((multiple == 0) && 664 ((fin->fin_optmsk & ip6exthdr[i].ol_bit) != 0)) { 665 fin->fin_flx |= FI_BAD; 666 DT2(ipf_fi_bad_ipv6exthdr_once, fr_info_t *, fin, u_int, (fin->fin_optmsk & ip6exthdr[i].ol_bit)); 667 } else 668 fin->fin_optmsk |= ip6exthdr[i].ol_bit; 669 break; 670 } 671 672 return (hdr); 673} 674 675 676/* ------------------------------------------------------------------------ */ 677/* Function: ipf_pr_hopopts6 */ 678/* Returns: int - value of the next header or IPPROTO_NONE if error */ 679/* Parameters: fin(I) - pointer to packet information */ 680/* */ 681/* IPv6 Only */ 682/* This is function checks pending hop by hop options extension header */ 683/* ------------------------------------------------------------------------ */ 684static inline int 685ipf_pr_hopopts6(fr_info_t *fin) 686{ 687 struct ip6_ext *hdr; 688 689 hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS); 690 if (hdr == NULL) 691 return (IPPROTO_NONE); 692 return (hdr->ip6e_nxt); 693} 694 695 696/* ------------------------------------------------------------------------ */ 697/* Function: ipf_pr_mobility6 */ 698/* Returns: int - value of the next header or IPPROTO_NONE if error */ 699/* Parameters: fin(I) - pointer to packet information */ 700/* */ 701/* IPv6 Only */ 702/* This is function checks the IPv6 mobility extension header */ 703/* ------------------------------------------------------------------------ */ 704static inline int 705ipf_pr_mobility6(fr_info_t *fin) 706{ 707 struct ip6_ext *hdr; 708 709 hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_MOBILITY); 710 if (hdr == NULL) 711 return (IPPROTO_NONE); 712 return (hdr->ip6e_nxt); 713} 714 715 716/* ------------------------------------------------------------------------ */ 717/* Function: ipf_pr_routing6 */ 718/* Returns: int - value of the next header or IPPROTO_NONE if error */ 719/* Parameters: fin(I) - pointer to packet information */ 720/* */ 721/* IPv6 Only */ 722/* This is function checks pending routing extension header */ 723/* ------------------------------------------------------------------------ */ 724static inline int 725ipf_pr_routing6(fr_info_t *fin) 726{ 727 struct ip6_routing *hdr; 728 729 hdr = (struct ip6_routing *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_ROUTING); 730 if (hdr == NULL) 731 return (IPPROTO_NONE); 732 733 switch (hdr->ip6r_type) 734 { 735 case 0 : 736 /* 737 * Nasty extension header length? 738 */ 739 if (((hdr->ip6r_len >> 1) < hdr->ip6r_segleft) || 740 (hdr->ip6r_segleft && (hdr->ip6r_len & 1))) { 741 ipf_main_softc_t *softc = fin->fin_main_soft; 742 743 fin->fin_flx |= FI_BAD; 744 DT1(ipf_fi_bad_routing6, fr_info_t *, fin); 745 LBUMPD(ipf_stats[fin->fin_out], fr_v6_rh_bad); 746 return (IPPROTO_NONE); 747 } 748 break; 749 750 default : 751 break; 752 } 753 754 return (hdr->ip6r_nxt); 755} 756 757 758/* ------------------------------------------------------------------------ */ 759/* Function: ipf_pr_fragment6 */ 760/* Returns: int - value of the next header or IPPROTO_NONE if error */ 761/* Parameters: fin(I) - pointer to packet information */ 762/* */ 763/* IPv6 Only */ 764/* Examine the IPv6 fragment header and extract fragment offset information.*/ 765/* */ 766/* Fragments in IPv6 are extraordinarily difficult to deal with - much more */ 767/* so than in IPv4. There are 5 cases of fragments with IPv6 that all */ 768/* packets with a fragment header can fit into. They are as follows: */ 769/* */ 770/* 1. [IPv6][0-n EH][FH][0-n EH] (no L4HDR present) */ 771/* 2. [IPV6][0-n EH][FH][0-n EH][L4HDR part] (short) */ 772/* 3. [IPV6][0-n EH][FH][L4HDR part][0-n data] (short) */ 773/* 4. [IPV6][0-n EH][FH][0-n EH][L4HDR][0-n data] */ 774/* 5. [IPV6][0-n EH][FH][data] */ 775/* */ 776/* IPV6 = IPv6 header, FH = Fragment Header, */ 777/* 0-n EH = 0 or more extension headers, 0-n data = 0 or more bytes of data */ 778/* */ 779/* Packets that match 1, 2, 3 will be dropped as the only reasonable */ 780/* scenario in which they happen is in extreme circumstances that are most */ 781/* likely to be an indication of an attack rather than normal traffic. */ 782/* A type 3 packet may be sent by an attacked after a type 4 packet. There */ 783/* are two rules that can be used to guard against type 3 packets: L4 */ 784/* headers must always be in a packet that has the offset field set to 0 */ 785/* and no packet is allowed to overlay that where offset = 0. */ 786/* ------------------------------------------------------------------------ */ 787static inline int 788ipf_pr_fragment6(fr_info_t *fin) 789{ 790 ipf_main_softc_t *softc = fin->fin_main_soft; 791 struct ip6_frag *frag; 792 793 fin->fin_flx |= FI_FRAG; 794 795 frag = (struct ip6_frag *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_FRAGMENT); 796 if (frag == NULL) { 797 LBUMPD(ipf_stats[fin->fin_out], fr_v6_frag_bad); 798 return (IPPROTO_NONE); 799 } 800 801 if ((frag->ip6f_offlg & IP6F_MORE_FRAG) != 0) { 802 /* 803 * Any fragment that isn't the last fragment must have its 804 * length as a multiple of 8. 805 */ 806 if ((fin->fin_plen & 7) != 0) { 807 fin->fin_flx |= FI_BAD; 808 DT2(ipf_fi_bad_frag_not_8, fr_info_t *, fin, u_int, (fin->fin_plen & 7)); 809 } 810 } 811 812 fin->fin_fraghdr = frag; 813 fin->fin_id = frag->ip6f_ident; 814 fin->fin_off = ntohs(frag->ip6f_offlg & IP6F_OFF_MASK); 815 if (fin->fin_off != 0) 816 fin->fin_flx |= FI_FRAGBODY; 817 818 /* 819 * Jumbograms aren't handled, so the max. length is 64k 820 */ 821 if ((fin->fin_off << 3) + fin->fin_dlen > 65535) { 822 fin->fin_flx |= FI_BAD; 823 DT2(ipf_fi_bad_jumbogram, fr_info_t *, fin, u_int, ((fin->fin_off << 3) + fin->fin_dlen)); 824 } 825 826 /* 827 * We don't know where the transport layer header (or whatever is next 828 * is), as it could be behind destination options (amongst others) so 829 * return the fragment header as the type of packet this is. Note that 830 * this effectively disables the fragment cache for > 1 protocol at a 831 * time. 832 */ 833 return (frag->ip6f_nxt); 834} 835 836 837/* ------------------------------------------------------------------------ */ 838/* Function: ipf_pr_dstopts6 */ 839/* Returns: int - value of the next header or IPPROTO_NONE if error */ 840/* Parameters: fin(I) - pointer to packet information */ 841/* */ 842/* IPv6 Only */ 843/* This is function checks pending destination options extension header */ 844/* ------------------------------------------------------------------------ */ 845static inline int 846ipf_pr_dstopts6(fr_info_t *fin) 847{ 848 ipf_main_softc_t *softc = fin->fin_main_soft; 849 struct ip6_ext *hdr; 850 851 hdr = ipf_pr_ipv6exthdr(fin, 0, IPPROTO_DSTOPTS); 852 if (hdr == NULL) { 853 LBUMPD(ipf_stats[fin->fin_out], fr_v6_dst_bad); 854 return (IPPROTO_NONE); 855 } 856 return (hdr->ip6e_nxt); 857} 858 859 860/* ------------------------------------------------------------------------ */ 861/* Function: ipf_pr_icmp6 */ 862/* Returns: void */ 863/* Parameters: fin(I) - pointer to packet information */ 864/* */ 865/* IPv6 Only */ 866/* This routine is mainly concerned with determining the minimum valid size */ 867/* for an ICMPv6 packet. */ 868/* ------------------------------------------------------------------------ */ 869static inline void 870ipf_pr_icmp6(fr_info_t *fin) 871{ 872 int minicmpsz = sizeof(struct icmp6_hdr); 873 struct icmp6_hdr *icmp6; 874 875 if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN - sizeof(ip6_t)) == -1) { 876 ipf_main_softc_t *softc = fin->fin_main_soft; 877 878 LBUMPD(ipf_stats[fin->fin_out], fr_v6_icmp6_pullup); 879 return; 880 } 881 882 if (fin->fin_dlen > 1) { 883 ip6_t *ip6; 884 885 icmp6 = fin->fin_dp; 886 887 fin->fin_data[0] = *(u_short *)icmp6; 888 889 if ((icmp6->icmp6_type & ICMP6_INFOMSG_MASK) != 0) 890 fin->fin_flx |= FI_ICMPQUERY; 891 892 switch (icmp6->icmp6_type) 893 { 894 case ICMP6_ECHO_REPLY : 895 case ICMP6_ECHO_REQUEST : 896 if (fin->fin_dlen >= 6) 897 fin->fin_data[1] = icmp6->icmp6_id; 898 minicmpsz = ICMP6ERR_MINPKTLEN - sizeof(ip6_t); 899 break; 900 901 case ICMP6_DST_UNREACH : 902 case ICMP6_PACKET_TOO_BIG : 903 case ICMP6_TIME_EXCEEDED : 904 case ICMP6_PARAM_PROB : 905 fin->fin_flx |= FI_ICMPERR; 906 minicmpsz = ICMP6ERR_IPICMPHLEN - sizeof(ip6_t); 907 if (fin->fin_plen < ICMP6ERR_IPICMPHLEN) 908 break; 909 910 if (M_LEN(fin->fin_m) < fin->fin_plen) { 911 if (ipf_coalesce(fin) != 1) 912 return; 913 } 914 915 if (ipf_pr_pullup(fin, ICMP6ERR_MINPKTLEN) == -1) 916 return; 917 918 /* 919 * If the destination of this packet doesn't match the 920 * source of the original packet then this packet is 921 * not correct. 922 */ 923 icmp6 = fin->fin_dp; 924 ip6 = (ip6_t *)((char *)icmp6 + ICMPERR_ICMPHLEN); 925 if (IP6_NEQ(&fin->fin_fi.fi_dst, 926 (i6addr_t *)&ip6->ip6_src)) { 927 fin->fin_flx |= FI_BAD; 928 DT1(ipf_fi_bad_icmp6, fr_info_t *, fin); 929 } 930 break; 931 default : 932 break; 933 } 934 } 935 936 ipf_pr_short6(fin, minicmpsz); 937 if ((fin->fin_flx & (FI_SHORT|FI_BAD)) == 0) { 938 u_char p = fin->fin_p; 939 940 fin->fin_p = IPPROTO_ICMPV6; 941 ipf_checkv6sum(fin); 942 fin->fin_p = p; 943 } 944} 945 946 947/* ------------------------------------------------------------------------ */ 948/* Function: ipf_pr_udp6 */ 949/* Returns: void */ 950/* Parameters: fin(I) - pointer to packet information */ 951/* */ 952/* IPv6 Only */ 953/* Analyse the packet for IPv6/UDP properties. */ 954/* Is not expected to be called for fragmented packets. */ 955/* ------------------------------------------------------------------------ */ 956static inline void 957ipf_pr_udp6(fr_info_t *fin) 958{ 959 960 if (ipf_pr_udpcommon(fin) == 0) { 961 u_char p = fin->fin_p; 962 963 fin->fin_p = IPPROTO_UDP; 964 ipf_checkv6sum(fin); 965 fin->fin_p = p; 966 } 967} 968 969 970/* ------------------------------------------------------------------------ */ 971/* Function: ipf_pr_tcp6 */ 972/* Returns: void */ 973/* Parameters: fin(I) - pointer to packet information */ 974/* */ 975/* IPv6 Only */ 976/* Analyse the packet for IPv6/TCP properties. */ 977/* Is not expected to be called for fragmented packets. */ 978/* ------------------------------------------------------------------------ */ 979static inline void 980ipf_pr_tcp6(fr_info_t *fin) 981{ 982 983 if (ipf_pr_tcpcommon(fin) == 0) { 984 u_char p = fin->fin_p; 985 986 fin->fin_p = IPPROTO_TCP; 987 ipf_checkv6sum(fin); 988 fin->fin_p = p; 989 } 990} 991 992 993/* ------------------------------------------------------------------------ */ 994/* Function: ipf_pr_esp6 */ 995/* Returns: void */ 996/* Parameters: fin(I) - pointer to packet information */ 997/* */ 998/* IPv6 Only */ 999/* Analyse the packet for ESP properties. */ 1000/* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ 1001/* even though the newer ESP packets must also have a sequence number that */ 1002/* is 32bits as well, it is not possible(?) to determine the version from a */ 1003/* simple packet header. */ 1004/* ------------------------------------------------------------------------ */ 1005static inline void 1006ipf_pr_esp6(fr_info_t *fin) 1007{ 1008 1009 if ((fin->fin_off == 0) && (ipf_pr_pullup(fin, 8) == -1)) { 1010 ipf_main_softc_t *softc = fin->fin_main_soft; 1011 1012 LBUMPD(ipf_stats[fin->fin_out], fr_v6_esp_pullup); 1013 return; 1014 } 1015} 1016 1017 1018/* ------------------------------------------------------------------------ */ 1019/* Function: ipf_pr_ah6 */ 1020/* Returns: int - value of the next header or IPPROTO_NONE if error */ 1021/* Parameters: fin(I) - pointer to packet information */ 1022/* */ 1023/* IPv6 Only */ 1024/* Analyse the packet for AH properties. */ 1025/* The minimum length is taken to be the combination of all fields in the */ 1026/* header being present and no authentication data (null algorithm used.) */ 1027/* ------------------------------------------------------------------------ */ 1028static inline int 1029ipf_pr_ah6(fr_info_t *fin) 1030{ 1031 authhdr_t *ah; 1032 1033 fin->fin_flx |= FI_AH; 1034 1035 ah = (authhdr_t *)ipf_pr_ipv6exthdr(fin, 0, IPPROTO_HOPOPTS); 1036 if (ah == NULL) { 1037 ipf_main_softc_t *softc = fin->fin_main_soft; 1038 1039 LBUMPD(ipf_stats[fin->fin_out], fr_v6_ah_bad); 1040 return (IPPROTO_NONE); 1041 } 1042 1043 ipf_pr_short6(fin, sizeof(*ah)); 1044 1045 /* 1046 * No need for another pullup, ipf_pr_ipv6exthdr() will pullup 1047 * enough data to satisfy ah_next (the very first one.) 1048 */ 1049 return (ah->ah_next); 1050} 1051 1052 1053/* ------------------------------------------------------------------------ */ 1054/* Function: ipf_pr_gre6 */ 1055/* Returns: void */ 1056/* Parameters: fin(I) - pointer to packet information */ 1057/* */ 1058/* Analyse the packet for GRE properties. */ 1059/* ------------------------------------------------------------------------ */ 1060static inline void 1061ipf_pr_gre6(fr_info_t *fin) 1062{ 1063 grehdr_t *gre; 1064 1065 if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) { 1066 ipf_main_softc_t *softc = fin->fin_main_soft; 1067 1068 LBUMPD(ipf_stats[fin->fin_out], fr_v6_gre_pullup); 1069 return; 1070 } 1071 1072 gre = fin->fin_dp; 1073 if (GRE_REV(gre->gr_flags) == 1) 1074 fin->fin_data[0] = gre->gr_call; 1075} 1076#endif /* USE_INET6 */ 1077 1078 1079/* ------------------------------------------------------------------------ */ 1080/* Function: ipf_pr_pullup */ 1081/* Returns: int - 0 == pullup succeeded, -1 == failure */ 1082/* Parameters: fin(I) - pointer to packet information */ 1083/* plen(I) - length (excluding L3 header) to pullup */ 1084/* */ 1085/* Short inline function to cut down on code duplication to perform a call */ 1086/* to ipf_pullup to ensure there is the required amount of data, */ 1087/* consecutively in the packet buffer. */ 1088/* */ 1089/* This function pulls up 'extra' data at the location of fin_dp. fin_dp */ 1090/* points to the first byte after the complete layer 3 header, which will */ 1091/* include all of the known extension headers for IPv6 or options for IPv4. */ 1092/* */ 1093/* Since fr_pullup() expects the total length of bytes to be pulled up, it */ 1094/* is necessary to add those we can already assume to be pulled up (fin_dp */ 1095/* - fin_ip) to what is passed through. */ 1096/* ------------------------------------------------------------------------ */ 1097int 1098ipf_pr_pullup(fr_info_t *fin, int plen) 1099{ 1100 ipf_main_softc_t *softc = fin->fin_main_soft; 1101 1102 if (fin->fin_m != NULL) { 1103 if (fin->fin_dp != NULL) 1104 plen += (char *)fin->fin_dp - 1105 ((char *)fin->fin_ip + fin->fin_hlen); 1106 plen += fin->fin_hlen; 1107 if (M_LEN(fin->fin_m) < plen + fin->fin_ipoff) { 1108#if defined(_KERNEL) 1109 if (ipf_pullup(fin->fin_m, fin, plen) == NULL) { 1110 DT1(ipf_pullup_fail, fr_info_t *, fin); 1111 LBUMP(ipf_stats[fin->fin_out].fr_pull[1]); 1112 fin->fin_reason = FRB_PULLUP; 1113 fin->fin_flx |= FI_BAD; 1114 return (-1); 1115 } 1116 LBUMP(ipf_stats[fin->fin_out].fr_pull[0]); 1117#else 1118 LBUMP(ipf_stats[fin->fin_out].fr_pull[1]); 1119 /* 1120 * Fake ipf_pullup failing 1121 */ 1122 fin->fin_reason = FRB_PULLUP; 1123 *fin->fin_mp = NULL; 1124 fin->fin_m = NULL; 1125 fin->fin_ip = NULL; 1126 fin->fin_flx |= FI_BAD; 1127 return (-1); 1128#endif 1129 } 1130 } 1131 return (0); 1132} 1133 1134 1135/* ------------------------------------------------------------------------ */ 1136/* Function: ipf_pr_short */ 1137/* Returns: void */ 1138/* Parameters: fin(I) - pointer to packet information */ 1139/* xmin(I) - minimum header size */ 1140/* */ 1141/* Check if a packet is "short" as defined by xmin. The rule we are */ 1142/* applying here is that the packet must not be fragmented within the layer */ 1143/* 4 header. That is, it must not be a fragment that has its offset set to */ 1144/* start within the layer 4 header (hdrmin) or if it is at offset 0, the */ 1145/* entire layer 4 header must be present (min). */ 1146/* ------------------------------------------------------------------------ */ 1147static inline void 1148ipf_pr_short(fr_info_t *fin, int xmin) 1149{ 1150 1151 if (fin->fin_off == 0) { 1152 if (fin->fin_dlen < xmin) 1153 fin->fin_flx |= FI_SHORT; 1154 } else if (fin->fin_off < xmin) { 1155 fin->fin_flx |= FI_SHORT; 1156 } 1157} 1158 1159 1160/* ------------------------------------------------------------------------ */ 1161/* Function: ipf_pr_icmp */ 1162/* Returns: void */ 1163/* Parameters: fin(I) - pointer to packet information */ 1164/* */ 1165/* IPv4 Only */ 1166/* Do a sanity check on the packet for ICMP (v4). In nearly all cases, */ 1167/* except extrememly bad packets, both type and code will be present. */ 1168/* The expected minimum size of an ICMP packet is very much dependent on */ 1169/* the type of it. */ 1170/* */ 1171/* XXX - other ICMP sanity checks? */ 1172/* ------------------------------------------------------------------------ */ 1173static inline void 1174ipf_pr_icmp(fr_info_t *fin) 1175{ 1176 ipf_main_softc_t *softc = fin->fin_main_soft; 1177 int minicmpsz = sizeof(struct icmp); 1178 icmphdr_t *icmp; 1179 ip_t *oip; 1180 1181 ipf_pr_short(fin, ICMPERR_ICMPHLEN); 1182 1183 if (fin->fin_off != 0) { 1184 LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_frag); 1185 return; 1186 } 1187 1188 if (ipf_pr_pullup(fin, ICMPERR_ICMPHLEN) == -1) { 1189 LBUMPD(ipf_stats[fin->fin_out], fr_v4_icmp_pullup); 1190 return; 1191 } 1192 1193 icmp = fin->fin_dp; 1194 1195 fin->fin_data[0] = *(u_short *)icmp; 1196 fin->fin_data[1] = icmp->icmp_id; 1197 1198 switch (icmp->icmp_type) 1199 { 1200 case ICMP_ECHOREPLY : 1201 case ICMP_ECHO : 1202 /* Router discovery messaes - RFC 1256 */ 1203 case ICMP_ROUTERADVERT : 1204 case ICMP_ROUTERSOLICIT : 1205 fin->fin_flx |= FI_ICMPQUERY; 1206 minicmpsz = ICMP_MINLEN; 1207 break; 1208 /* 1209 * type(1) + code(1) + cksum(2) + id(2) seq(2) + 1210 * 3 * timestamp(3 * 4) 1211 */ 1212 case ICMP_TSTAMP : 1213 case ICMP_TSTAMPREPLY : 1214 fin->fin_flx |= FI_ICMPQUERY; 1215 minicmpsz = 20; 1216 break; 1217 /* 1218 * type(1) + code(1) + cksum(2) + id(2) seq(2) + 1219 * mask(4) 1220 */ 1221 case ICMP_IREQ : 1222 case ICMP_IREQREPLY : 1223 case ICMP_MASKREQ : 1224 case ICMP_MASKREPLY : 1225 fin->fin_flx |= FI_ICMPQUERY; 1226 minicmpsz = 12; 1227 break; 1228 /* 1229 * type(1) + code(1) + cksum(2) + id(2) seq(2) + ip(20+) 1230 */ 1231 case ICMP_UNREACH : 1232#ifdef icmp_nextmtu 1233 if (icmp->icmp_code == ICMP_UNREACH_NEEDFRAG) { 1234 if (icmp->icmp_nextmtu < softc->ipf_icmpminfragmtu) { 1235 fin->fin_flx |= FI_BAD; 1236 DT3(ipf_fi_bad_icmp_nextmtu, fr_info_t *, fin, u_int, icmp->icmp_nextmtu, u_int, softc->ipf_icmpminfragmtu); 1237 } 1238 } 1239#endif 1240 /* FALLTHROUGH */ 1241 case ICMP_SOURCEQUENCH : 1242 case ICMP_REDIRECT : 1243 case ICMP_TIMXCEED : 1244 case ICMP_PARAMPROB : 1245 fin->fin_flx |= FI_ICMPERR; 1246 if (ipf_coalesce(fin) != 1) { 1247 LBUMPD(ipf_stats[fin->fin_out], fr_icmp_coalesce); 1248 return; 1249 } 1250 1251 /* 1252 * ICMP error packets should not be generated for IP 1253 * packets that are a fragment that isn't the first 1254 * fragment. 1255 */ 1256 oip = (ip_t *)((char *)fin->fin_dp + ICMPERR_ICMPHLEN); 1257 if ((ntohs(oip->ip_off) & IP_OFFMASK) != 0) { 1258 fin->fin_flx |= FI_BAD; 1259 DT2(ipf_fi_bad_icmp_err, fr_info_t, fin, u_int, (ntohs(oip->ip_off) & IP_OFFMASK)); 1260 } 1261 1262 /* 1263 * If the destination of this packet doesn't match the 1264 * source of the original packet then this packet is 1265 * not correct. 1266 */ 1267 if (oip->ip_src.s_addr != fin->fin_daddr) { 1268 fin->fin_flx |= FI_BAD; 1269 DT1(ipf_fi_bad_src_ne_dst, fr_info_t *, fin); 1270 } 1271 break; 1272 default : 1273 break; 1274 } 1275 1276 ipf_pr_short(fin, minicmpsz); 1277 1278 ipf_checkv4sum(fin); 1279} 1280 1281 1282/* ------------------------------------------------------------------------ */ 1283/* Function: ipf_pr_tcpcommon */ 1284/* Returns: int - 0 = header ok, 1 = bad packet, -1 = buffer error */ 1285/* Parameters: fin(I) - pointer to packet information */ 1286/* */ 1287/* TCP header sanity checking. Look for bad combinations of TCP flags, */ 1288/* and make some checks with how they interact with other fields. */ 1289/* If compiled with IPFILTER_CKSUM, check to see if the TCP checksum is */ 1290/* valid and mark the packet as bad if not. */ 1291/* ------------------------------------------------------------------------ */ 1292static inline int 1293ipf_pr_tcpcommon(fr_info_t *fin) 1294{ 1295 ipf_main_softc_t *softc = fin->fin_main_soft; 1296 int flags, tlen; 1297 tcphdr_t *tcp; 1298 1299 fin->fin_flx |= FI_TCPUDP; 1300 if (fin->fin_off != 0) { 1301 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_frag); 1302 return (0); 1303 } 1304 1305 if (ipf_pr_pullup(fin, sizeof(*tcp)) == -1) { 1306 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup); 1307 return (-1); 1308 } 1309 1310 tcp = fin->fin_dp; 1311 if (fin->fin_dlen > 3) { 1312 fin->fin_sport = ntohs(tcp->th_sport); 1313 fin->fin_dport = ntohs(tcp->th_dport); 1314 } 1315 1316 if ((fin->fin_flx & FI_SHORT) != 0) { 1317 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_short); 1318 return (1); 1319 } 1320 1321 /* 1322 * Use of the TCP data offset *must* result in a value that is at 1323 * least the same size as the TCP header. 1324 */ 1325 tlen = TCP_OFF(tcp) << 2; 1326 if (tlen < sizeof(tcphdr_t)) { 1327 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_small); 1328 fin->fin_flx |= FI_BAD; 1329 DT3(ipf_fi_bad_tlen, fr_info_t, fin, u_int, tlen, u_int, sizeof(tcphdr_t)); 1330 return (1); 1331 } 1332 1333 flags = tcp->th_flags; 1334 fin->fin_tcpf = tcp->th_flags; 1335 1336 /* 1337 * If the urgent flag is set, then the urgent pointer must 1338 * also be set and vice versa. Good TCP packets do not have 1339 * just one of these set. 1340 */ 1341 if ((flags & TH_URG) != 0 && (tcp->th_urp == 0)) { 1342 fin->fin_flx |= FI_BAD; 1343 DT3(ipf_fi_bad_th_urg, fr_info_t*, fin, u_int, (flags & TH_URG), u_int, tcp->th_urp); 1344#if 0 1345 } else if ((flags & TH_URG) == 0 && (tcp->th_urp != 0)) { 1346 /* 1347 * Ignore this case (#if 0) as it shows up in "real" 1348 * traffic with bogus values in the urgent pointer field. 1349 */ 1350 fin->fin_flx |= FI_BAD; 1351 DT3(ipf_fi_bad_th_urg0, fr_info_t *, fin, u_int, (flags & TH_URG), u_int, tcp->th_urp); 1352#endif 1353 } else if (((flags & (TH_SYN|TH_FIN)) != 0) && 1354 ((flags & (TH_RST|TH_ACK)) == TH_RST)) { 1355 /* TH_FIN|TH_RST|TH_ACK seems to appear "naturally" */ 1356 fin->fin_flx |= FI_BAD; 1357 DT1(ipf_fi_bad_th_fin_rst_ack, fr_info_t, fin); 1358#if 1 1359 } else if (((flags & TH_SYN) != 0) && 1360 ((flags & (TH_URG|TH_PUSH)) != 0)) { 1361 /* 1362 * SYN with URG and PUSH set is not for normal TCP but it is 1363 * possible(?) with T/TCP...but who uses T/TCP? 1364 */ 1365 fin->fin_flx |= FI_BAD; 1366 DT1(ipf_fi_bad_th_syn_urg_psh, fr_info_t *, fin); 1367#endif 1368 } else if (!(flags & TH_ACK)) { 1369 /* 1370 * If the ack bit isn't set, then either the SYN or 1371 * RST bit must be set. If the SYN bit is set, then 1372 * we expect the ACK field to be 0. If the ACK is 1373 * not set and if URG, PSH or FIN are set, consdier 1374 * that to indicate a bad TCP packet. 1375 */ 1376 if ((flags == TH_SYN) && (tcp->th_ack != 0)) { 1377 /* 1378 * Cisco PIX sets the ACK field to a random value. 1379 * In light of this, do not set FI_BAD until a patch 1380 * is available from Cisco to ensure that 1381 * interoperability between existing systems is 1382 * achieved. 1383 */ 1384 /*fin->fin_flx |= FI_BAD*/; 1385 /*DT1(ipf_fi_bad_th_syn_ack, fr_info_t *, fin);*/ 1386 } else if (!(flags & (TH_RST|TH_SYN))) { 1387 fin->fin_flx |= FI_BAD; 1388 DT1(ipf_fi_bad_th_rst_syn, fr_info_t *, fin); 1389 } else if ((flags & (TH_URG|TH_PUSH|TH_FIN)) != 0) { 1390 fin->fin_flx |= FI_BAD; 1391 DT1(ipf_fi_bad_th_urg_push_fin, fr_info_t *, fin); 1392 } 1393 } 1394 if (fin->fin_flx & FI_BAD) { 1395 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_bad_flags); 1396 return (1); 1397 } 1398 1399 /* 1400 * At this point, it's not exactly clear what is to be gained by 1401 * marking up which TCP options are and are not present. The one we 1402 * are most interested in is the TCP window scale. This is only in 1403 * a SYN packet [RFC1323] so we don't need this here...? 1404 * Now if we were to analyse the header for passive fingerprinting, 1405 * then that might add some weight to adding this... 1406 */ 1407 if (tlen == sizeof(tcphdr_t)) { 1408 return (0); 1409 } 1410 1411 if (ipf_pr_pullup(fin, tlen) == -1) { 1412 LBUMPD(ipf_stats[fin->fin_out], fr_tcp_pullup); 1413 return (-1); 1414 } 1415 1416#if 0 1417 tcp = fin->fin_dp; 1418 ip = fin->fin_ip; 1419 s = (u_char *)(tcp + 1); 1420 off = IP_HL(ip) << 2; 1421# ifdef _KERNEL 1422 if (fin->fin_mp != NULL) { 1423 mb_t *m = *fin->fin_mp; 1424 1425 if (off + tlen > M_LEN(m)) 1426 return; 1427 } 1428# endif 1429 for (tlen -= (int)sizeof(*tcp); tlen > 0; ) { 1430 opt = *s; 1431 if (opt == '\0') 1432 break; 1433 else if (opt == TCPOPT_NOP) 1434 ol = 1; 1435 else { 1436 if (tlen < 2) 1437 break; 1438 ol = (int)*(s + 1); 1439 if (ol < 2 || ol > tlen) 1440 break; 1441 } 1442 1443 for (i = 9, mv = 4; mv >= 0; ) { 1444 op = ipopts + i; 1445 if (opt == (u_char)op->ol_val) { 1446 optmsk |= op->ol_bit; 1447 break; 1448 } 1449 } 1450 tlen -= ol; 1451 s += ol; 1452 } 1453#endif /* 0 */ 1454 1455 return (0); 1456} 1457 1458 1459 1460/* ------------------------------------------------------------------------ */ 1461/* Function: ipf_pr_udpcommon */ 1462/* Returns: int - 0 = header ok, 1 = bad packet */ 1463/* Parameters: fin(I) - pointer to packet information */ 1464/* */ 1465/* Extract the UDP source and destination ports, if present. If compiled */ 1466/* with IPFILTER_CKSUM, check to see if the UDP checksum is valid. */ 1467/* ------------------------------------------------------------------------ */ 1468static inline int 1469ipf_pr_udpcommon(fr_info_t *fin) 1470{ 1471 udphdr_t *udp; 1472 1473 fin->fin_flx |= FI_TCPUDP; 1474 1475 if (!fin->fin_off && (fin->fin_dlen > 3)) { 1476 if (ipf_pr_pullup(fin, sizeof(*udp)) == -1) { 1477 ipf_main_softc_t *softc = fin->fin_main_soft; 1478 1479 fin->fin_flx |= FI_SHORT; 1480 LBUMPD(ipf_stats[fin->fin_out], fr_udp_pullup); 1481 return (1); 1482 } 1483 1484 udp = fin->fin_dp; 1485 1486 fin->fin_sport = ntohs(udp->uh_sport); 1487 fin->fin_dport = ntohs(udp->uh_dport); 1488 } 1489 1490 return (0); 1491} 1492 1493 1494/* ------------------------------------------------------------------------ */ 1495/* Function: ipf_pr_tcp */ 1496/* Returns: void */ 1497/* Parameters: fin(I) - pointer to packet information */ 1498/* */ 1499/* IPv4 Only */ 1500/* Analyse the packet for IPv4/TCP properties. */ 1501/* ------------------------------------------------------------------------ */ 1502static inline void 1503ipf_pr_tcp(fr_info_t *fin) 1504{ 1505 1506 ipf_pr_short(fin, sizeof(tcphdr_t)); 1507 1508 if (ipf_pr_tcpcommon(fin) == 0) 1509 ipf_checkv4sum(fin); 1510} 1511 1512 1513/* ------------------------------------------------------------------------ */ 1514/* Function: ipf_pr_udp */ 1515/* Returns: void */ 1516/* Parameters: fin(I) - pointer to packet information */ 1517/* */ 1518/* IPv4 Only */ 1519/* Analyse the packet for IPv4/UDP properties. */ 1520/* ------------------------------------------------------------------------ */ 1521static inline void 1522ipf_pr_udp(fr_info_t *fin) 1523{ 1524 1525 ipf_pr_short(fin, sizeof(udphdr_t)); 1526 1527 if (ipf_pr_udpcommon(fin) == 0) 1528 ipf_checkv4sum(fin); 1529} 1530 1531 1532/* ------------------------------------------------------------------------ */ 1533/* Function: ipf_pr_esp */ 1534/* Returns: void */ 1535/* Parameters: fin(I) - pointer to packet information */ 1536/* */ 1537/* Analyse the packet for ESP properties. */ 1538/* The minimum length is taken to be the SPI (32bits) plus a tail (32bits) */ 1539/* even though the newer ESP packets must also have a sequence number that */ 1540/* is 32bits as well, it is not possible(?) to determine the version from a */ 1541/* simple packet header. */ 1542/* ------------------------------------------------------------------------ */ 1543static inline void 1544ipf_pr_esp(fr_info_t *fin) 1545{ 1546 1547 if (fin->fin_off == 0) { 1548 ipf_pr_short(fin, 8); 1549 if (ipf_pr_pullup(fin, 8) == -1) { 1550 ipf_main_softc_t *softc = fin->fin_main_soft; 1551 1552 LBUMPD(ipf_stats[fin->fin_out], fr_v4_esp_pullup); 1553 } 1554 } 1555} 1556 1557 1558/* ------------------------------------------------------------------------ */ 1559/* Function: ipf_pr_ah */ 1560/* Returns: int - value of the next header or IPPROTO_NONE if error */ 1561/* Parameters: fin(I) - pointer to packet information */ 1562/* */ 1563/* Analyse the packet for AH properties. */ 1564/* The minimum length is taken to be the combination of all fields in the */ 1565/* header being present and no authentication data (null algorithm used.) */ 1566/* ------------------------------------------------------------------------ */ 1567static inline int 1568ipf_pr_ah(fr_info_t *fin) 1569{ 1570 ipf_main_softc_t *softc = fin->fin_main_soft; 1571 authhdr_t *ah; 1572 int len; 1573 1574 fin->fin_flx |= FI_AH; 1575 ipf_pr_short(fin, sizeof(*ah)); 1576 1577 if (((fin->fin_flx & FI_SHORT) != 0) || (fin->fin_off != 0)) { 1578 LBUMPD(ipf_stats[fin->fin_out], fr_v4_ah_bad); 1579 return (IPPROTO_NONE); 1580 } 1581 1582 if (ipf_pr_pullup(fin, sizeof(*ah)) == -1) { 1583 DT(fr_v4_ah_pullup_1); 1584 LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup); 1585 return (IPPROTO_NONE); 1586 } 1587 1588 ah = (authhdr_t *)fin->fin_dp; 1589 1590 len = (ah->ah_plen + 2) << 2; 1591 ipf_pr_short(fin, len); 1592 if (ipf_pr_pullup(fin, len) == -1) { 1593 DT(fr_v4_ah_pullup_2); 1594 LBUMP(ipf_stats[fin->fin_out].fr_v4_ah_pullup); 1595 return (IPPROTO_NONE); 1596 } 1597 1598 /* 1599 * Adjust fin_dp and fin_dlen for skipping over the authentication 1600 * header. 1601 */ 1602 fin->fin_dp = (char *)fin->fin_dp + len; 1603 fin->fin_dlen -= len; 1604 return (ah->ah_next); 1605} 1606 1607 1608/* ------------------------------------------------------------------------ */ 1609/* Function: ipf_pr_gre */ 1610/* Returns: void */ 1611/* Parameters: fin(I) - pointer to packet information */ 1612/* */ 1613/* Analyse the packet for GRE properties. */ 1614/* ------------------------------------------------------------------------ */ 1615static inline void 1616ipf_pr_gre(fr_info_t *fin) 1617{ 1618 ipf_main_softc_t *softc = fin->fin_main_soft; 1619 grehdr_t *gre; 1620 1621 ipf_pr_short(fin, sizeof(grehdr_t)); 1622 1623 if (fin->fin_off != 0) { 1624 LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_frag); 1625 return; 1626 } 1627 1628 if (ipf_pr_pullup(fin, sizeof(grehdr_t)) == -1) { 1629 LBUMPD(ipf_stats[fin->fin_out], fr_v4_gre_pullup); 1630 return; 1631 } 1632 1633 gre = fin->fin_dp; 1634 if (GRE_REV(gre->gr_flags) == 1) 1635 fin->fin_data[0] = gre->gr_call; 1636} 1637 1638 1639/* ------------------------------------------------------------------------ */ 1640/* Function: ipf_pr_ipv4hdr */ 1641/* Returns: void */ 1642/* Parameters: fin(I) - pointer to packet information */ 1643/* */ 1644/* IPv4 Only */ 1645/* Analyze the IPv4 header and set fields in the fr_info_t structure. */ 1646/* Check all options present and flag their presence if any exist. */ 1647/* ------------------------------------------------------------------------ */ 1648static inline void 1649ipf_pr_ipv4hdr(fr_info_t *fin) 1650{ 1651 u_short optmsk = 0, secmsk = 0, auth = 0; 1652 int hlen, ol, mv, p, i; 1653 const struct optlist *op; 1654 u_char *s, opt; 1655 u_short off; 1656 fr_ip_t *fi; 1657 ip_t *ip; 1658 1659 fi = &fin->fin_fi; 1660 hlen = fin->fin_hlen; 1661 1662 ip = fin->fin_ip; 1663 p = ip->ip_p; 1664 fi->fi_p = p; 1665 fin->fin_crc = p; 1666 fi->fi_tos = ip->ip_tos; 1667 fin->fin_id = ntohs(ip->ip_id); 1668 off = ntohs(ip->ip_off); 1669 1670 /* Get both TTL and protocol */ 1671 fi->fi_p = ip->ip_p; 1672 fi->fi_ttl = ip->ip_ttl; 1673 1674 /* Zero out bits not used in IPv6 address */ 1675 fi->fi_src.i6[1] = 0; 1676 fi->fi_src.i6[2] = 0; 1677 fi->fi_src.i6[3] = 0; 1678 fi->fi_dst.i6[1] = 0; 1679 fi->fi_dst.i6[2] = 0; 1680 fi->fi_dst.i6[3] = 0; 1681 1682 fi->fi_saddr = ip->ip_src.s_addr; 1683 fin->fin_crc += fi->fi_saddr; 1684 fi->fi_daddr = ip->ip_dst.s_addr; 1685 fin->fin_crc += fi->fi_daddr; 1686 if (IN_MULTICAST(ntohl(fi->fi_daddr))) 1687 fin->fin_flx |= FI_MULTICAST|FI_MBCAST; 1688 1689 /* 1690 * set packet attribute flags based on the offset and 1691 * calculate the byte offset that it represents. 1692 */ 1693 off &= IP_MF|IP_OFFMASK; 1694 if (off != 0) { 1695 int morefrag = off & IP_MF; 1696 1697 fi->fi_flx |= FI_FRAG; 1698 off &= IP_OFFMASK; 1699 if (off == 1 && p == IPPROTO_TCP) { 1700 fin->fin_flx |= FI_SHORT; /* RFC 3128 */ 1701 DT1(ipf_fi_tcp_frag_off_1, fr_info_t *, fin); 1702 } 1703 if (off != 0) { 1704 fin->fin_flx |= FI_FRAGBODY; 1705 off <<= 3; 1706 if ((off + fin->fin_dlen > 65535) || 1707 (fin->fin_dlen == 0) || 1708 ((morefrag != 0) && ((fin->fin_dlen & 7) != 0))) { 1709 /* 1710 * The length of the packet, starting at its 1711 * offset cannot exceed 65535 (0xffff) as the 1712 * length of an IP packet is only 16 bits. 1713 * 1714 * Any fragment that isn't the last fragment 1715 * must have a length greater than 0 and it 1716 * must be an even multiple of 8. 1717 */ 1718 fi->fi_flx |= FI_BAD; 1719 DT1(ipf_fi_bad_fragbody_gt_65535, fr_info_t *, fin); 1720 } 1721 } 1722 } 1723 fin->fin_off = off; 1724 1725 /* 1726 * Call per-protocol setup and checking 1727 */ 1728 if (p == IPPROTO_AH) { 1729 /* 1730 * Treat AH differently because we expect there to be another 1731 * layer 4 header after it. 1732 */ 1733 p = ipf_pr_ah(fin); 1734 } 1735 1736 switch (p) 1737 { 1738 case IPPROTO_UDP : 1739 ipf_pr_udp(fin); 1740 break; 1741 case IPPROTO_TCP : 1742 ipf_pr_tcp(fin); 1743 break; 1744 case IPPROTO_ICMP : 1745 ipf_pr_icmp(fin); 1746 break; 1747 case IPPROTO_ESP : 1748 ipf_pr_esp(fin); 1749 break; 1750 case IPPROTO_GRE : 1751 ipf_pr_gre(fin); 1752 break; 1753 } 1754 1755 ip = fin->fin_ip; 1756 if (ip == NULL) 1757 return; 1758 1759 /* 1760 * If it is a standard IP header (no options), set the flag fields 1761 * which relate to options to 0. 1762 */ 1763 if (hlen == sizeof(*ip)) { 1764 fi->fi_optmsk = 0; 1765 fi->fi_secmsk = 0; 1766 fi->fi_auth = 0; 1767 return; 1768 } 1769 1770 /* 1771 * So the IP header has some IP options attached. Walk the entire 1772 * list of options present with this packet and set flags to indicate 1773 * which ones are here and which ones are not. For the somewhat out 1774 * of date and obscure security classification options, set a flag to 1775 * represent which classification is present. 1776 */ 1777 fi->fi_flx |= FI_OPTIONS; 1778 1779 for (s = (u_char *)(ip + 1), hlen -= (int)sizeof(*ip); hlen > 0; ) { 1780 opt = *s; 1781 if (opt == '\0') 1782 break; 1783 else if (opt == IPOPT_NOP) 1784 ol = 1; 1785 else { 1786 if (hlen < 2) 1787 break; 1788 ol = (int)*(s + 1); 1789 if (ol < 2 || ol > hlen) 1790 break; 1791 } 1792 for (i = 9, mv = 4; mv >= 0; ) { 1793 op = ipopts + i; 1794 1795 if ((opt == (u_char)op->ol_val) && (ol > 4)) { 1796 u_32_t doi; 1797 1798 switch (opt) 1799 { 1800 case IPOPT_SECURITY : 1801 if (optmsk & op->ol_bit) { 1802 fin->fin_flx |= FI_BAD; 1803 DT2(ipf_fi_bad_ipopt_security, fr_info_t *, fin, u_short, (optmsk & op->ol_bit)); 1804 } else { 1805 doi = ipf_checkripso(s); 1806 secmsk = doi >> 16; 1807 auth = doi & 0xffff; 1808 } 1809 break; 1810 1811 case IPOPT_CIPSO : 1812 1813 if (optmsk & op->ol_bit) { 1814 fin->fin_flx |= FI_BAD; 1815 DT2(ipf_fi_bad_ipopt_cipso, fr_info_t *, fin, u_short, (optmsk & op->ol_bit)); 1816 } else { 1817 doi = ipf_checkcipso(fin, 1818 s, ol); 1819 secmsk = doi >> 16; 1820 auth = doi & 0xffff; 1821 } 1822 break; 1823 } 1824 optmsk |= op->ol_bit; 1825 } 1826 1827 if (opt < op->ol_val) 1828 i -= mv; 1829 else 1830 i += mv; 1831 mv--; 1832 } 1833 hlen -= ol; 1834 s += ol; 1835 } 1836 1837 /* 1838 * 1839 */ 1840 if (auth && !(auth & 0x0100)) 1841 auth &= 0xff00; 1842 fi->fi_optmsk = optmsk; 1843 fi->fi_secmsk = secmsk; 1844 fi->fi_auth = auth; 1845} 1846 1847 1848/* ------------------------------------------------------------------------ */ 1849/* Function: ipf_checkripso */ 1850/* Returns: void */ 1851/* Parameters: s(I) - pointer to start of RIPSO option */ 1852/* */ 1853/* ------------------------------------------------------------------------ */ 1854static u_32_t 1855ipf_checkripso(u_char *s) 1856{ 1857 const struct optlist *sp; 1858 u_short secmsk = 0, auth = 0; 1859 u_char sec; 1860 int j, m; 1861 1862 sec = *(s + 2); /* classification */ 1863 for (j = 3, m = 2; m >= 0; ) { 1864 sp = secopt + j; 1865 if (sec == sp->ol_val) { 1866 secmsk |= sp->ol_bit; 1867 auth = *(s + 3); 1868 auth *= 256; 1869 auth += *(s + 4); 1870 break; 1871 } 1872 if (sec < sp->ol_val) 1873 j -= m; 1874 else 1875 j += m; 1876 m--; 1877 } 1878 1879 return (secmsk << 16) | auth; 1880} 1881 1882 1883/* ------------------------------------------------------------------------ */ 1884/* Function: ipf_checkcipso */ 1885/* Returns: u_32_t - 0 = failure, else the doi from the header */ 1886/* Parameters: fin(IO) - pointer to packet information */ 1887/* s(I) - pointer to start of CIPSO option */ 1888/* ol(I) - length of CIPSO option field */ 1889/* */ 1890/* This function returns the domain of integrity (DOI) field from the CIPSO */ 1891/* header and returns that whilst also storing the highest sensitivity */ 1892/* value found in the fr_info_t structure. */ 1893/* */ 1894/* No attempt is made to extract the category bitmaps as these are defined */ 1895/* by the user (rather than the protocol) and can be rather numerous on the */ 1896/* end nodes. */ 1897/* ------------------------------------------------------------------------ */ 1898static u_32_t 1899ipf_checkcipso(fr_info_t *fin, u_char *s, int ol) 1900{ 1901 ipf_main_softc_t *softc = fin->fin_main_soft; 1902 fr_ip_t *fi; 1903 u_32_t doi; 1904 u_char *t, tag, tlen, sensitivity; 1905 int len; 1906 1907 if (ol < 6 || ol > 40) { 1908 LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_bad); 1909 fin->fin_flx |= FI_BAD; 1910 DT2(ipf_fi_bad_checkcipso_ol, fr_info_t *, fin, u_int, ol); 1911 return (0); 1912 } 1913 1914 fi = &fin->fin_fi; 1915 fi->fi_sensitivity = 0; 1916 /* 1917 * The DOI field MUST be there. 1918 */ 1919 bcopy(s + 2, &doi, sizeof(doi)); 1920 1921 t = (u_char *)s + 6; 1922 for (len = ol - 6; len >= 2; len -= tlen, t+= tlen) { 1923 tag = *t; 1924 tlen = *(t + 1); 1925 if (tlen > len || tlen < 4 || tlen > 34) { 1926 LBUMPD(ipf_stats[fin->fin_out], fr_v4_cipso_tlen); 1927 fin->fin_flx |= FI_BAD; 1928 DT2(ipf_fi_bad_checkcipso_tlen, fr_info_t *, fin, u_int, tlen); 1929 return (0); 1930 } 1931 1932 sensitivity = 0; 1933 /* 1934 * Tag numbers 0, 1, 2, 5 are laid out in the CIPSO Internet 1935 * draft (16 July 1992) that has expired. 1936 */ 1937 if (tag == 0) { 1938 fin->fin_flx |= FI_BAD; 1939 DT2(ipf_fi_bad_checkcipso_tag, fr_info_t *, fin, u_int, tag); 1940 continue; 1941 } else if (tag == 1) { 1942 if (*(t + 2) != 0) { 1943 fin->fin_flx |= FI_BAD; 1944 DT2(ipf_fi_bad_checkcipso_tag1_t2, fr_info_t *, fin, u_int, (*t + 2)); 1945 continue; 1946 } 1947 sensitivity = *(t + 3); 1948 /* Category bitmap for categories 0-239 */ 1949 1950 } else if (tag == 4) { 1951 if (*(t + 2) != 0) { 1952 fin->fin_flx |= FI_BAD; 1953 DT2(ipf_fi_bad_checkcipso_tag4_t2, fr_info_t *, fin, u_int, (*t + 2)); 1954 continue; 1955 } 1956 sensitivity = *(t + 3); 1957 /* Enumerated categories, 16bits each, upto 15 */ 1958 1959 } else if (tag == 5) { 1960 if (*(t + 2) != 0) { 1961 fin->fin_flx |= FI_BAD; 1962 DT2(ipf_fi_bad_checkcipso_tag5_t2, fr_info_t *, fin, u_int, (*t + 2)); 1963 continue; 1964 } 1965 sensitivity = *(t + 3); 1966 /* Range of categories (2*16bits), up to 7 pairs */ 1967 1968 } else if (tag > 127) { 1969 /* Custom defined DOI */ 1970 ; 1971 } else { 1972 fin->fin_flx |= FI_BAD; 1973 DT2(ipf_fi_bad_checkcipso_tag127, fr_info_t *, fin, u_int, tag); 1974 continue; 1975 } 1976 1977 if (sensitivity > fi->fi_sensitivity) 1978 fi->fi_sensitivity = sensitivity; 1979 } 1980 1981 return (doi); 1982} 1983 1984 1985/* ------------------------------------------------------------------------ */ 1986/* Function: ipf_makefrip */ 1987/* Returns: int - 0 == packet ok, -1 == packet freed */ 1988/* Parameters: hlen(I) - length of IP packet header */ 1989/* ip(I) - pointer to the IP header */ 1990/* fin(IO) - pointer to packet information */ 1991/* */ 1992/* Compact the IP header into a structure which contains just the info. */ 1993/* which is useful for comparing IP headers with and store this information */ 1994/* in the fr_info_t structure pointer to by fin. At present, it is assumed */ 1995/* this function will be called with either an IPv4 or IPv6 packet. */ 1996/* ------------------------------------------------------------------------ */ 1997int 1998ipf_makefrip(int hlen, ip_t *ip, fr_info_t *fin) 1999{ 2000 ipf_main_softc_t *softc = fin->fin_main_soft; 2001 int v; 2002 2003 fin->fin_depth = 0; 2004 fin->fin_hlen = (u_short)hlen; 2005 fin->fin_ip = ip; 2006 fin->fin_rule = 0xffffffff; 2007 fin->fin_group[0] = -1; 2008 fin->fin_group[1] = '\0'; 2009 fin->fin_dp = (char *)ip + hlen; 2010 2011 v = fin->fin_v; 2012 if (v == 4) { 2013 fin->fin_plen = ntohs(ip->ip_len); 2014 fin->fin_dlen = fin->fin_plen - hlen; 2015 ipf_pr_ipv4hdr(fin); 2016#ifdef USE_INET6 2017 } else if (v == 6) { 2018 fin->fin_plen = ntohs(((ip6_t *)ip)->ip6_plen); 2019 fin->fin_dlen = fin->fin_plen; 2020 fin->fin_plen += hlen; 2021 2022 ipf_pr_ipv6hdr(fin); 2023#endif 2024 } 2025 if (fin->fin_ip == NULL) { 2026 LBUMP(ipf_stats[fin->fin_out].fr_ip_freed); 2027 return (-1); 2028 } 2029 return (0); 2030} 2031 2032 2033/* ------------------------------------------------------------------------ */ 2034/* Function: ipf_portcheck */ 2035/* Returns: int - 1 == port matched, 0 == port match failed */ 2036/* Parameters: frp(I) - pointer to port check `expression' */ 2037/* pop(I) - port number to evaluate */ 2038/* */ 2039/* Perform a comparison of a port number against some other(s), using a */ 2040/* structure with compare information stored in it. */ 2041/* ------------------------------------------------------------------------ */ 2042static inline int 2043ipf_portcheck(frpcmp_t *frp, u_32_t pop) 2044{ 2045 int err = 1; 2046 u_32_t po; 2047 2048 po = frp->frp_port; 2049 2050 /* 2051 * Do opposite test to that required and continue if that succeeds. 2052 */ 2053 switch (frp->frp_cmp) 2054 { 2055 case FR_EQUAL : 2056 if (pop != po) /* EQUAL */ 2057 err = 0; 2058 break; 2059 case FR_NEQUAL : 2060 if (pop == po) /* NOTEQUAL */ 2061 err = 0; 2062 break; 2063 case FR_LESST : 2064 if (pop >= po) /* LESSTHAN */ 2065 err = 0; 2066 break; 2067 case FR_GREATERT : 2068 if (pop <= po) /* GREATERTHAN */ 2069 err = 0; 2070 break; 2071 case FR_LESSTE : 2072 if (pop > po) /* LT or EQ */ 2073 err = 0; 2074 break; 2075 case FR_GREATERTE : 2076 if (pop < po) /* GT or EQ */ 2077 err = 0; 2078 break; 2079 case FR_OUTRANGE : 2080 if (pop >= po && pop <= frp->frp_top) /* Out of range */ 2081 err = 0; 2082 break; 2083 case FR_INRANGE : 2084 if (pop <= po || pop >= frp->frp_top) /* In range */ 2085 err = 0; 2086 break; 2087 case FR_INCRANGE : 2088 if (pop < po || pop > frp->frp_top) /* Inclusive range */ 2089 err = 0; 2090 break; 2091 default : 2092 break; 2093 } 2094 return (err); 2095} 2096 2097 2098/* ------------------------------------------------------------------------ */ 2099/* Function: ipf_tcpudpchk */ 2100/* Returns: int - 1 == protocol matched, 0 == check failed */ 2101/* Parameters: fda(I) - pointer to packet information */ 2102/* ft(I) - pointer to structure with comparison data */ 2103/* */ 2104/* Compares the current pcket (assuming it is TCP/UDP) information with a */ 2105/* structure containing information that we want to match against. */ 2106/* ------------------------------------------------------------------------ */ 2107int 2108ipf_tcpudpchk(fr_ip_t *fi, frtuc_t *ft) 2109{ 2110 int err = 1; 2111 2112 /* 2113 * Both ports should *always* be in the first fragment. 2114 * So far, I cannot find any cases where they can not be. 2115 * 2116 * compare destination ports 2117 */ 2118 if (ft->ftu_dcmp) 2119 err = ipf_portcheck(&ft->ftu_dst, fi->fi_ports[1]); 2120 2121 /* 2122 * compare source ports 2123 */ 2124 if (err && ft->ftu_scmp) 2125 err = ipf_portcheck(&ft->ftu_src, fi->fi_ports[0]); 2126 2127 /* 2128 * If we don't have all the TCP/UDP header, then how can we 2129 * expect to do any sort of match on it ? If we were looking for 2130 * TCP flags, then NO match. If not, then match (which should 2131 * satisfy the "short" class too). 2132 */ 2133 if (err && (fi->fi_p == IPPROTO_TCP)) { 2134 if (fi->fi_flx & FI_SHORT) 2135 return (!(ft->ftu_tcpf | ft->ftu_tcpfm)); 2136 /* 2137 * Match the flags ? If not, abort this match. 2138 */ 2139 if (ft->ftu_tcpfm && 2140 ft->ftu_tcpf != (fi->fi_tcpf & ft->ftu_tcpfm)) { 2141 FR_DEBUG(("f. %#x & %#x != %#x\n", fi->fi_tcpf, 2142 ft->ftu_tcpfm, ft->ftu_tcpf)); 2143 err = 0; 2144 } 2145 } 2146 return (err); 2147} 2148 2149 2150/* ------------------------------------------------------------------------ */ 2151/* Function: ipf_check_ipf */ 2152/* Returns: int - 0 == match, else no match */ 2153/* Parameters: fin(I) - pointer to packet information */ 2154/* fr(I) - pointer to filter rule */ 2155/* portcmp(I) - flag indicating whether to attempt matching on */ 2156/* TCP/UDP port data. */ 2157/* */ 2158/* Check to see if a packet matches an IPFilter rule. Checks of addresses, */ 2159/* port numbers, etc, for "standard" IPFilter rules are all orchestrated in */ 2160/* this function. */ 2161/* ------------------------------------------------------------------------ */ 2162static inline int 2163ipf_check_ipf(fr_info_t *fin, frentry_t *fr, int portcmp) 2164{ 2165 u_32_t *ld, *lm, *lip; 2166 fripf_t *fri; 2167 fr_ip_t *fi; 2168 int i; 2169 2170 fi = &fin->fin_fi; 2171 fri = fr->fr_ipf; 2172 lip = (u_32_t *)fi; 2173 lm = (u_32_t *)&fri->fri_mip; 2174 ld = (u_32_t *)&fri->fri_ip; 2175 2176 /* 2177 * first 32 bits to check coversion: 2178 * IP version, TOS, TTL, protocol 2179 */ 2180 i = ((*lip & *lm) != *ld); 2181 FR_DEBUG(("0. %#08x & %#08x != %#08x\n", 2182 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2183 if (i) 2184 return (1); 2185 2186 /* 2187 * Next 32 bits is a constructed bitmask indicating which IP options 2188 * are present (if any) in this packet. 2189 */ 2190 lip++, lm++, ld++; 2191 i = ((*lip & *lm) != *ld); 2192 FR_DEBUG(("1. %#08x & %#08x != %#08x\n", 2193 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2194 if (i != 0) 2195 return (1); 2196 2197 lip++, lm++, ld++; 2198 /* 2199 * Unrolled loops (4 each, for 32 bits) for address checks. 2200 */ 2201 /* 2202 * Check the source address. 2203 */ 2204 if (fr->fr_satype == FRI_LOOKUP) { 2205 i = (*fr->fr_srcfunc)(fin->fin_main_soft, fr->fr_srcptr, 2206 fi->fi_v, lip, fin->fin_plen); 2207 if (i == -1) 2208 return (1); 2209 lip += 3; 2210 lm += 3; 2211 ld += 3; 2212 } else { 2213 i = ((*lip & *lm) != *ld); 2214 FR_DEBUG(("2a. %#08x & %#08x != %#08x\n", 2215 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2216 if (fi->fi_v == 6) { 2217 lip++, lm++, ld++; 2218 i |= ((*lip & *lm) != *ld); 2219 FR_DEBUG(("2b. %#08x & %#08x != %#08x\n", 2220 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2221 lip++, lm++, ld++; 2222 i |= ((*lip & *lm) != *ld); 2223 FR_DEBUG(("2c. %#08x & %#08x != %#08x\n", 2224 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2225 lip++, lm++, ld++; 2226 i |= ((*lip & *lm) != *ld); 2227 FR_DEBUG(("2d. %#08x & %#08x != %#08x\n", 2228 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2229 } else { 2230 lip += 3; 2231 lm += 3; 2232 ld += 3; 2233 } 2234 } 2235 i ^= (fr->fr_flags & FR_NOTSRCIP) >> 6; 2236 if (i != 0) 2237 return (1); 2238 2239 /* 2240 * Check the destination address. 2241 */ 2242 lip++, lm++, ld++; 2243 if (fr->fr_datype == FRI_LOOKUP) { 2244 i = (*fr->fr_dstfunc)(fin->fin_main_soft, fr->fr_dstptr, 2245 fi->fi_v, lip, fin->fin_plen); 2246 if (i == -1) 2247 return (1); 2248 lip += 3; 2249 lm += 3; 2250 ld += 3; 2251 } else { 2252 i = ((*lip & *lm) != *ld); 2253 FR_DEBUG(("3a. %#08x & %#08x != %#08x\n", 2254 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2255 if (fi->fi_v == 6) { 2256 lip++, lm++, ld++; 2257 i |= ((*lip & *lm) != *ld); 2258 FR_DEBUG(("3b. %#08x & %#08x != %#08x\n", 2259 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2260 lip++, lm++, ld++; 2261 i |= ((*lip & *lm) != *ld); 2262 FR_DEBUG(("3c. %#08x & %#08x != %#08x\n", 2263 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2264 lip++, lm++, ld++; 2265 i |= ((*lip & *lm) != *ld); 2266 FR_DEBUG(("3d. %#08x & %#08x != %#08x\n", 2267 ntohl(*lip), ntohl(*lm), ntohl(*ld))); 2268 } else { 2269 lip += 3; 2270 lm += 3; 2271 ld += 3; 2272 } 2273 } 2274 i ^= (fr->fr_flags & FR_NOTDSTIP) >> 7; 2275 if (i != 0) 2276 return (1); 2277 /* 2278 * IP addresses matched. The next 32bits contains: 2279 * mast of old IP header security & authentication bits. 2280 */ 2281 lip++, lm++, ld++; 2282 i = (*ld - (*lip & *lm)); 2283 FR_DEBUG(("4. %#08x & %#08x != %#08x\n", *lip, *lm, *ld)); 2284 2285 /* 2286 * Next we have 32 bits of packet flags. 2287 */ 2288 lip++, lm++, ld++; 2289 i |= (*ld - (*lip & *lm)); 2290 FR_DEBUG(("5. %#08x & %#08x != %#08x\n", *lip, *lm, *ld)); 2291 2292 if (i == 0) { 2293 /* 2294 * If a fragment, then only the first has what we're 2295 * looking for here... 2296 */ 2297 if (portcmp) { 2298 if (!ipf_tcpudpchk(&fin->fin_fi, &fr->fr_tuc)) 2299 i = 1; 2300 } else { 2301 if (fr->fr_dcmp || fr->fr_scmp || 2302 fr->fr_tcpf || fr->fr_tcpfm) 2303 i = 1; 2304 if (fr->fr_icmpm || fr->fr_icmp) { 2305 if (((fi->fi_p != IPPROTO_ICMP) && 2306 (fi->fi_p != IPPROTO_ICMPV6)) || 2307 fin->fin_off || (fin->fin_dlen < 2)) 2308 i = 1; 2309 else if ((fin->fin_data[0] & fr->fr_icmpm) != 2310 fr->fr_icmp) { 2311 FR_DEBUG(("i. %#x & %#x != %#x\n", 2312 fin->fin_data[0], 2313 fr->fr_icmpm, fr->fr_icmp)); 2314 i = 1; 2315 } 2316 } 2317 } 2318 } 2319 return (i); 2320} 2321 2322 2323/* ------------------------------------------------------------------------ */ 2324/* Function: ipf_scanlist */ 2325/* Returns: int - result flags of scanning filter list */ 2326/* Parameters: fin(I) - pointer to packet information */ 2327/* pass(I) - default result to return for filtering */ 2328/* */ 2329/* Check the input/output list of rules for a match to the current packet. */ 2330/* If a match is found, the value of fr_flags from the rule becomes the */ 2331/* return value and fin->fin_fr points to the matched rule. */ 2332/* */ 2333/* This function may be called recursively upto 16 times (limit inbuilt.) */ 2334/* When unwinding, it should finish up with fin_depth as 0. */ 2335/* */ 2336/* Could be per interface, but this gets real nasty when you don't have, */ 2337/* or can't easily change, the kernel source code to . */ 2338/* ------------------------------------------------------------------------ */ 2339int 2340ipf_scanlist(fr_info_t *fin, u_32_t pass) 2341{ 2342 ipf_main_softc_t *softc = fin->fin_main_soft; 2343 int rulen, portcmp, off, skip; 2344 struct frentry *fr, *fnext; 2345 u_32_t passt, passo; 2346 2347 /* 2348 * Do not allow nesting deeper than 16 levels. 2349 */ 2350 if (fin->fin_depth >= 16) 2351 return (pass); 2352 2353 fr = fin->fin_fr; 2354 2355 /* 2356 * If there are no rules in this list, return now. 2357 */ 2358 if (fr == NULL) 2359 return (pass); 2360 2361 skip = 0; 2362 portcmp = 0; 2363 fin->fin_depth++; 2364 fin->fin_fr = NULL; 2365 off = fin->fin_off; 2366 2367 if ((fin->fin_flx & FI_TCPUDP) && (fin->fin_dlen > 3) && !off) 2368 portcmp = 1; 2369 2370 for (rulen = 0; fr; fr = fnext, rulen++) { 2371 fnext = fr->fr_next; 2372 if (skip != 0) { 2373 FR_VERBOSE(("SKIP %d (%#x)\n", skip, fr->fr_flags)); 2374 skip--; 2375 continue; 2376 } 2377 2378 /* 2379 * In all checks below, a null (zero) value in the 2380 * filter struture is taken to mean a wildcard. 2381 * 2382 * check that we are working for the right interface 2383 */ 2384#ifdef _KERNEL 2385 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) 2386 continue; 2387#else 2388 if (opts & (OPT_VERBOSE|OPT_DEBUG)) 2389 printf("\n"); 2390 FR_VERBOSE(("%c", FR_ISSKIP(pass) ? 's' : 2391 FR_ISPASS(pass) ? 'p' : 2392 FR_ISACCOUNT(pass) ? 'A' : 2393 FR_ISAUTH(pass) ? 'a' : 2394 (pass & FR_NOMATCH) ? 'n' :'b')); 2395 if (fr->fr_ifa && fr->fr_ifa != fin->fin_ifp) 2396 continue; 2397 FR_VERBOSE((":i")); 2398#endif 2399 2400 switch (fr->fr_type) 2401 { 2402 case FR_T_IPF : 2403 case FR_T_IPF_BUILTIN : 2404 if (ipf_check_ipf(fin, fr, portcmp)) 2405 continue; 2406 break; 2407#if defined(IPFILTER_BPF) 2408 case FR_T_BPFOPC : 2409 case FR_T_BPFOPC_BUILTIN : 2410 { 2411 u_char *mc; 2412 int wlen; 2413 2414 if (*fin->fin_mp == NULL) 2415 continue; 2416 if (fin->fin_family != fr->fr_family) 2417 continue; 2418 mc = (u_char *)fin->fin_m; 2419 wlen = fin->fin_dlen + fin->fin_hlen; 2420 if (!bpf_filter(fr->fr_data, mc, wlen, 0)) 2421 continue; 2422 break; 2423 } 2424#endif 2425 case FR_T_CALLFUNC_BUILTIN : 2426 { 2427 frentry_t *f; 2428 2429 f = (*fr->fr_func)(fin, &pass); 2430 if (f != NULL) 2431 fr = f; 2432 else 2433 continue; 2434 break; 2435 } 2436 2437 case FR_T_IPFEXPR : 2438 case FR_T_IPFEXPR_BUILTIN : 2439 if (fin->fin_family != fr->fr_family) 2440 continue; 2441 if (ipf_fr_matcharray(fin, fr->fr_data) == 0) 2442 continue; 2443 break; 2444 2445 default : 2446 break; 2447 } 2448 2449 if ((fin->fin_out == 0) && (fr->fr_nattag.ipt_num[0] != 0)) { 2450 if (fin->fin_nattag == NULL) 2451 continue; 2452 if (ipf_matchtag(&fr->fr_nattag, fin->fin_nattag) == 0) 2453 continue; 2454 } 2455 FR_VERBOSE(("=%d/%d.%d *", fr->fr_grhead, fr->fr_group, rulen)); 2456 2457 passt = fr->fr_flags; 2458 2459 /* 2460 * If the rule is a "call now" rule, then call the function 2461 * in the rule, if it exists and use the results from that. 2462 * If the function pointer is bad, just make like we ignore 2463 * it, except for increasing the hit counter. 2464 */ 2465 if ((passt & FR_CALLNOW) != 0) { 2466 frentry_t *frs; 2467 2468 ATOMIC_INC64(fr->fr_hits); 2469 if ((fr->fr_func == NULL) || 2470 (fr->fr_func == (ipfunc_t)-1)) 2471 continue; 2472 2473 frs = fin->fin_fr; 2474 fin->fin_fr = fr; 2475 fr = (*fr->fr_func)(fin, &passt); 2476 if (fr == NULL) { 2477 fin->fin_fr = frs; 2478 continue; 2479 } 2480 passt = fr->fr_flags; 2481 } 2482 fin->fin_fr = fr; 2483 2484#ifdef IPFILTER_LOG 2485 /* 2486 * Just log this packet... 2487 */ 2488 if ((passt & FR_LOGMASK) == FR_LOG) { 2489 if (ipf_log_pkt(fin, passt) == -1) { 2490 if (passt & FR_LOGORBLOCK) { 2491 DT(frb_logfail); 2492 passt &= ~FR_CMDMASK; 2493 passt |= FR_BLOCK|FR_QUICK; 2494 fin->fin_reason = FRB_LOGFAIL; 2495 } 2496 } 2497 } 2498#endif /* IPFILTER_LOG */ 2499 2500 MUTEX_ENTER(&fr->fr_lock); 2501 fr->fr_bytes += (U_QUAD_T)fin->fin_plen; 2502 fr->fr_hits++; 2503 MUTEX_EXIT(&fr->fr_lock); 2504 fin->fin_rule = rulen; 2505 2506 passo = pass; 2507 if (FR_ISSKIP(passt)) { 2508 skip = fr->fr_arg; 2509 continue; 2510 } else if (((passt & FR_LOGMASK) != FR_LOG) && 2511 ((passt & FR_LOGMASK) != FR_DECAPSULATE)) { 2512 pass = passt; 2513 } 2514 2515 if (passt & (FR_RETICMP|FR_FAKEICMP)) 2516 fin->fin_icode = fr->fr_icode; 2517 2518 if (fr->fr_group != -1) { 2519 (void) strncpy(fin->fin_group, 2520 FR_NAME(fr, fr_group), 2521 strlen(FR_NAME(fr, fr_group))); 2522 } else { 2523 fin->fin_group[0] = '\0'; 2524 } 2525 2526 FR_DEBUG(("pass %#x/%#x/%x\n", passo, pass, passt)); 2527 2528 if (fr->fr_grphead != NULL) { 2529 fin->fin_fr = fr->fr_grphead->fg_start; 2530 FR_VERBOSE(("group %s\n", FR_NAME(fr, fr_grhead))); 2531 2532 if (FR_ISDECAPS(passt)) 2533 passt = ipf_decaps(fin, pass, fr->fr_icode); 2534 else 2535 passt = ipf_scanlist(fin, pass); 2536 2537 if (fin->fin_fr == NULL) { 2538 fin->fin_rule = rulen; 2539 if (fr->fr_group != -1) 2540 (void) strncpy(fin->fin_group, 2541 fr->fr_names + 2542 fr->fr_group, 2543 strlen(fr->fr_names + 2544 fr->fr_group)); 2545 fin->fin_fr = fr; 2546 passt = pass; 2547 } 2548 pass = passt; 2549 } 2550 2551 if (pass & FR_QUICK) { 2552 /* 2553 * Finally, if we've asked to track state for this 2554 * packet, set it up. Add state for "quick" rules 2555 * here so that if the action fails we can consider 2556 * the rule to "not match" and keep on processing 2557 * filter rules. 2558 */ 2559 if ((pass & FR_KEEPSTATE) && !FR_ISAUTH(pass) && 2560 !(fin->fin_flx & FI_STATE)) { 2561 int out = fin->fin_out; 2562 2563 fin->fin_fr = fr; 2564 if (ipf_state_add(softc, fin, NULL, 0) == 0) { 2565 LBUMPD(ipf_stats[out], fr_ads); 2566 } else { 2567 LBUMPD(ipf_stats[out], fr_bads); 2568 pass = passo; 2569 continue; 2570 } 2571 } 2572 break; 2573 } 2574 } 2575 fin->fin_depth--; 2576 return (pass); 2577} 2578 2579 2580/* ------------------------------------------------------------------------ */ 2581/* Function: ipf_acctpkt */ 2582/* Returns: frentry_t* - always returns NULL */ 2583/* Parameters: fin(I) - pointer to packet information */ 2584/* passp(IO) - pointer to current/new filter decision (unused) */ 2585/* */ 2586/* Checks a packet against accounting rules, if there are any for the given */ 2587/* IP protocol version. */ 2588/* */ 2589/* N.B.: this function returns NULL to match the prototype used by other */ 2590/* functions called from the IPFilter "mainline" in ipf_check(). */ 2591/* ------------------------------------------------------------------------ */ 2592frentry_t * 2593ipf_acctpkt(fr_info_t *fin, u_32_t *passp) 2594{ 2595 ipf_main_softc_t *softc = fin->fin_main_soft; 2596 char group[FR_GROUPLEN]; 2597 frentry_t *fr, *frsave; 2598 u_32_t pass, rulen; 2599 2600 passp = passp; 2601 fr = softc->ipf_acct[fin->fin_out][softc->ipf_active]; 2602 2603 if (fr != NULL) { 2604 frsave = fin->fin_fr; 2605 bcopy(fin->fin_group, group, FR_GROUPLEN); 2606 rulen = fin->fin_rule; 2607 fin->fin_fr = fr; 2608 pass = ipf_scanlist(fin, FR_NOMATCH); 2609 if (FR_ISACCOUNT(pass)) { 2610 LBUMPD(ipf_stats[0], fr_acct); 2611 } 2612 fin->fin_fr = frsave; 2613 bcopy(group, fin->fin_group, FR_GROUPLEN); 2614 fin->fin_rule = rulen; 2615 } 2616 return (NULL); 2617} 2618 2619 2620/* ------------------------------------------------------------------------ */ 2621/* Function: ipf_firewall */ 2622/* Returns: frentry_t* - returns pointer to matched rule, if no matches */ 2623/* were found, returns NULL. */ 2624/* Parameters: fin(I) - pointer to packet information */ 2625/* passp(IO) - pointer to current/new filter decision (unused) */ 2626/* */ 2627/* Applies an appropriate set of firewall rules to the packet, to see if */ 2628/* there are any matches. The first check is to see if a match can be seen */ 2629/* in the cache. If not, then search an appropriate list of rules. Once a */ 2630/* matching rule is found, take any appropriate actions as defined by the */ 2631/* rule - except logging. */ 2632/* ------------------------------------------------------------------------ */ 2633static frentry_t * 2634ipf_firewall(fr_info_t *fin, u_32_t *passp) 2635{ 2636 ipf_main_softc_t *softc = fin->fin_main_soft; 2637 frentry_t *fr; 2638 u_32_t pass; 2639 int out; 2640 2641 out = fin->fin_out; 2642 pass = *passp; 2643 2644 /* 2645 * This rule cache will only affect packets that are not being 2646 * statefully filtered. 2647 */ 2648 fin->fin_fr = softc->ipf_rules[out][softc->ipf_active]; 2649 if (fin->fin_fr != NULL) 2650 pass = ipf_scanlist(fin, softc->ipf_pass); 2651 2652 if ((pass & FR_NOMATCH)) { 2653 LBUMPD(ipf_stats[out], fr_nom); 2654 } 2655 fr = fin->fin_fr; 2656 2657 /* 2658 * Apply packets per second rate-limiting to a rule as required. 2659 */ 2660 if ((fr != NULL) && (fr->fr_pps != 0) && 2661 !ppsratecheck(&fr->fr_lastpkt, &fr->fr_curpps, fr->fr_pps)) { 2662 DT2(frb_ppsrate, fr_info_t *, fin, frentry_t *, fr); 2663 pass &= ~(FR_CMDMASK|FR_RETICMP|FR_RETRST); 2664 pass |= FR_BLOCK; 2665 LBUMPD(ipf_stats[out], fr_ppshit); 2666 fin->fin_reason = FRB_PPSRATE; 2667 } 2668 2669 /* 2670 * If we fail to add a packet to the authorization queue, then we 2671 * drop the packet later. However, if it was added then pretend 2672 * we've dropped it already. 2673 */ 2674 if (FR_ISAUTH(pass)) { 2675 if (ipf_auth_new(fin->fin_m, fin) != 0) { 2676 DT1(frb_authnew, fr_info_t *, fin); 2677 fin->fin_m = *fin->fin_mp = NULL; 2678 fin->fin_reason = FRB_AUTHNEW; 2679 fin->fin_error = 0; 2680 } else { 2681 IPFERROR(1); 2682 fin->fin_error = ENOSPC; 2683 } 2684 } 2685 2686 if ((fr != NULL) && (fr->fr_func != NULL) && 2687 (fr->fr_func != (ipfunc_t)-1) && !(pass & FR_CALLNOW)) 2688 (void) (*fr->fr_func)(fin, &pass); 2689 2690 /* 2691 * If a rule is a pre-auth rule, check again in the list of rules 2692 * loaded for authenticated use. It does not particulary matter 2693 * if this search fails because a "preauth" result, from a rule, 2694 * is treated as "not a pass", hence the packet is blocked. 2695 */ 2696 if (FR_ISPREAUTH(pass)) { 2697 pass = ipf_auth_pre_scanlist(softc, fin, pass); 2698 } 2699 2700 /* 2701 * If the rule has "keep frag" and the packet is actually a fragment, 2702 * then create a fragment state entry. 2703 */ 2704 if (pass & FR_KEEPFRAG) { 2705 if (fin->fin_flx & FI_FRAG) { 2706 if (ipf_frag_new(softc, fin, pass) == -1) { 2707 LBUMP(ipf_stats[out].fr_bnfr); 2708 } else { 2709 LBUMP(ipf_stats[out].fr_nfr); 2710 } 2711 } else { 2712 LBUMP(ipf_stats[out].fr_cfr); 2713 } 2714 } 2715 2716 fr = fin->fin_fr; 2717 *passp = pass; 2718 2719 return (fr); 2720} 2721 2722 2723/* ------------------------------------------------------------------------ */ 2724/* Function: ipf_check */ 2725/* Returns: int - 0 == packet allowed through, */ 2726/* User space: */ 2727/* -1 == packet blocked */ 2728/* 1 == packet not matched */ 2729/* -2 == requires authentication */ 2730/* Kernel: */ 2731/* > 0 == filter error # for packet */ 2732/* Parameters: ctx(I) - pointer to the instance context */ 2733/* ip(I) - pointer to start of IPv4/6 packet */ 2734/* hlen(I) - length of header */ 2735/* ifp(I) - pointer to interface this packet is on */ 2736/* out(I) - 0 == packet going in, 1 == packet going out */ 2737/* mp(IO) - pointer to caller's buffer pointer that holds this */ 2738/* IP packet. */ 2739/* Solaris: */ 2740/* qpi(I) - pointer to STREAMS queue information for this */ 2741/* interface & direction. */ 2742/* */ 2743/* ipf_check() is the master function for all IPFilter packet processing. */ 2744/* It orchestrates: Network Address Translation (NAT), checking for packet */ 2745/* authorisation (or pre-authorisation), presence of related state info., */ 2746/* generating log entries, IP packet accounting, routing of packets as */ 2747/* directed by firewall rules and of course whether or not to allow the */ 2748/* packet to be further processed by the kernel. */ 2749/* */ 2750/* For packets blocked, the contents of "mp" will be NULL'd and the buffer */ 2751/* freed. Packets passed may be returned with the pointer pointed to by */ 2752/* by "mp" changed to a new buffer. */ 2753/* ------------------------------------------------------------------------ */ 2754int 2755ipf_check(void *ctx, ip_t *ip, int hlen, struct ifnet *ifp, int out 2756#if defined(_KERNEL) && SOLARIS 2757 , void* qif, mb_t **mp) 2758#else 2759 , mb_t **mp) 2760#endif 2761{ 2762 /* 2763 * The above really sucks, but short of writing a diff 2764 */ 2765 ipf_main_softc_t *softc = ctx; 2766 fr_info_t frinfo; 2767 fr_info_t *fin = &frinfo; 2768 u_32_t pass = softc->ipf_pass; 2769 frentry_t *fr = NULL; 2770 int v = IP_V(ip); 2771 mb_t *mc = NULL; 2772 mb_t *m; 2773 /* 2774 * The first part of ipf_check() deals with making sure that what goes 2775 * into the filtering engine makes some sense. Information about the 2776 * the packet is distilled, collected into a fr_info_t structure and 2777 * the an attempt to ensure the buffer the packet is in is big enough 2778 * to hold all the required packet headers. 2779 */ 2780#ifdef _KERNEL 2781# if SOLARIS 2782 qpktinfo_t *qpi = qif; 2783 2784# ifdef __sparc 2785 if ((u_int)ip & 0x3) 2786 return (2); 2787# endif 2788# else 2789 SPL_INT(s); 2790# endif 2791 2792 if (softc->ipf_running <= 0) { 2793 return (0); 2794 } 2795 2796 bzero((char *)fin, sizeof(*fin)); 2797 2798# if SOLARIS 2799 if (qpi->qpi_flags & QF_BROADCAST) 2800 fin->fin_flx |= FI_MBCAST|FI_BROADCAST; 2801 if (qpi->qpi_flags & QF_MULTICAST) 2802 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2803 m = qpi->qpi_m; 2804 fin->fin_qfm = m; 2805 fin->fin_qpi = qpi; 2806# else /* SOLARIS */ 2807 2808 m = *mp; 2809 2810# if defined(M_MCAST) 2811 if ((m->m_flags & M_MCAST) != 0) 2812 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2813# endif 2814# if defined(M_MLOOP) 2815 if ((m->m_flags & M_MLOOP) != 0) 2816 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2817# endif 2818# if defined(M_BCAST) 2819 if ((m->m_flags & M_BCAST) != 0) 2820 fin->fin_flx |= FI_MBCAST|FI_BROADCAST; 2821# endif 2822# ifdef M_CANFASTFWD 2823 /* 2824 * XXX For now, IP Filter and fast-forwarding of cached flows 2825 * XXX are mutually exclusive. Eventually, IP Filter should 2826 * XXX get a "can-fast-forward" filter rule. 2827 */ 2828 m->m_flags &= ~M_CANFASTFWD; 2829# endif /* M_CANFASTFWD */ 2830# if defined(CSUM_DELAY_DATA) && !defined(__FreeBSD__) 2831 /* 2832 * disable delayed checksums. 2833 */ 2834 if (m->m_pkthdr.csum_flags & CSUM_DELAY_DATA) { 2835 in_delayed_cksum(m); 2836 m->m_pkthdr.csum_flags &= ~CSUM_DELAY_DATA; 2837 } 2838# endif /* CSUM_DELAY_DATA */ 2839# endif /* SOLARIS */ 2840#else 2841 bzero((char *)fin, sizeof(*fin)); 2842 m = *mp; 2843# if defined(M_MCAST) 2844 if ((m->m_flags & M_MCAST) != 0) 2845 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2846# endif 2847# if defined(M_MLOOP) 2848 if ((m->m_flags & M_MLOOP) != 0) 2849 fin->fin_flx |= FI_MBCAST|FI_MULTICAST; 2850# endif 2851# if defined(M_BCAST) 2852 if ((m->m_flags & M_BCAST) != 0) 2853 fin->fin_flx |= FI_MBCAST|FI_BROADCAST; 2854# endif 2855#endif /* _KERNEL */ 2856 2857 fin->fin_v = v; 2858 fin->fin_m = m; 2859 fin->fin_ip = ip; 2860 fin->fin_mp = mp; 2861 fin->fin_out = out; 2862 fin->fin_ifp = ifp; 2863 fin->fin_error = ENETUNREACH; 2864 fin->fin_hlen = (u_short)hlen; 2865 fin->fin_dp = (char *)ip + hlen; 2866 fin->fin_main_soft = softc; 2867 2868 fin->fin_ipoff = (char *)ip - MTOD(m, char *); 2869 2870 SPL_NET(s); 2871 2872#ifdef USE_INET6 2873 if (v == 6) { 2874 LBUMP(ipf_stats[out].fr_ipv6); 2875 /* 2876 * Jumbo grams are quite likely too big for internal buffer 2877 * structures to handle comfortably, for now, so just drop 2878 * them. 2879 */ 2880 if (((ip6_t *)ip)->ip6_plen == 0) { 2881 DT1(frb_jumbo, ip6_t *, (ip6_t *)ip); 2882 pass = FR_BLOCK|FR_NOMATCH; 2883 fin->fin_reason = FRB_JUMBO; 2884 goto finished; 2885 } 2886 fin->fin_family = AF_INET6; 2887 } else 2888#endif 2889 { 2890 fin->fin_family = AF_INET; 2891 } 2892 2893 if (ipf_makefrip(hlen, ip, fin) == -1) { 2894 DT1(frb_makefrip, fr_info_t *, fin); 2895 pass = FR_BLOCK|FR_NOMATCH; 2896 fin->fin_reason = FRB_MAKEFRIP; 2897 goto finished; 2898 } 2899 2900 /* 2901 * For at least IPv6 packets, if a m_pullup() fails then this pointer 2902 * becomes NULL and so we have no packet to free. 2903 */ 2904 if (*fin->fin_mp == NULL) 2905 goto finished; 2906 2907 if (!out) { 2908 if (v == 4) { 2909 if (softc->ipf_chksrc && !ipf_verifysrc(fin)) { 2910 LBUMPD(ipf_stats[0], fr_v4_badsrc); 2911 fin->fin_flx |= FI_BADSRC; 2912 } 2913 if (fin->fin_ip->ip_ttl < softc->ipf_minttl) { 2914 LBUMPD(ipf_stats[0], fr_v4_badttl); 2915 fin->fin_flx |= FI_LOWTTL; 2916 } 2917 } 2918#ifdef USE_INET6 2919 else if (v == 6) { 2920 if (((ip6_t *)ip)->ip6_hlim < softc->ipf_minttl) { 2921 LBUMPD(ipf_stats[0], fr_v6_badttl); 2922 fin->fin_flx |= FI_LOWTTL; 2923 } 2924 } 2925#endif 2926 } 2927 2928 if (fin->fin_flx & FI_SHORT) { 2929 LBUMPD(ipf_stats[out], fr_short); 2930 } 2931 2932 READ_ENTER(&softc->ipf_mutex); 2933 2934 if (!out) { 2935 switch (fin->fin_v) 2936 { 2937 case 4 : 2938 if (ipf_nat_checkin(fin, &pass) == -1) { 2939 goto filterdone; 2940 } 2941 break; 2942#ifdef USE_INET6 2943 case 6 : 2944 if (ipf_nat6_checkin(fin, &pass) == -1) { 2945 goto filterdone; 2946 } 2947 break; 2948#endif 2949 default : 2950 break; 2951 } 2952 } 2953 /* 2954 * Check auth now. 2955 * If a packet is found in the auth table, then skip checking 2956 * the access lists for permission but we do need to consider 2957 * the result as if it were from the ACL's. In addition, being 2958 * found in the auth table means it has been seen before, so do 2959 * not pass it through accounting (again), lest it be counted twice. 2960 */ 2961 fr = ipf_auth_check(fin, &pass); 2962 if (!out && (fr == NULL)) 2963 (void) ipf_acctpkt(fin, NULL); 2964 2965 if (fr == NULL) { 2966 if ((fin->fin_flx & FI_FRAG) != 0) 2967 fr = ipf_frag_known(fin, &pass); 2968 2969 if (fr == NULL) 2970 fr = ipf_state_check(fin, &pass); 2971 } 2972 2973 if ((pass & FR_NOMATCH) || (fr == NULL)) 2974 fr = ipf_firewall(fin, &pass); 2975 2976 /* 2977 * If we've asked to track state for this packet, set it up. 2978 * Here rather than ipf_firewall because ipf_checkauth may decide 2979 * to return a packet for "keep state" 2980 */ 2981 if ((pass & FR_KEEPSTATE) && (fin->fin_m != NULL) && 2982 !(fin->fin_flx & FI_STATE)) { 2983 if (ipf_state_add(softc, fin, NULL, 0) == 0) { 2984 LBUMP(ipf_stats[out].fr_ads); 2985 } else { 2986 LBUMP(ipf_stats[out].fr_bads); 2987 if (FR_ISPASS(pass)) { 2988 DT(frb_stateadd); 2989 pass &= ~FR_CMDMASK; 2990 pass |= FR_BLOCK; 2991 fin->fin_reason = FRB_STATEADD; 2992 } 2993 } 2994 } 2995 2996 fin->fin_fr = fr; 2997 if ((fr != NULL) && !(fin->fin_flx & FI_STATE)) { 2998 fin->fin_dif = &fr->fr_dif; 2999 fin->fin_tif = &fr->fr_tifs[fin->fin_rev]; 3000 } 3001 3002 /* 3003 * Only count/translate packets which will be passed on, out the 3004 * interface. 3005 */ 3006 if (out && FR_ISPASS(pass)) { 3007 (void) ipf_acctpkt(fin, NULL); 3008 3009 switch (fin->fin_v) 3010 { 3011 case 4 : 3012 if (ipf_nat_checkout(fin, &pass) == -1) { 3013 ; 3014 } else if ((softc->ipf_update_ipid != 0) && (v == 4)) { 3015 if (ipf_updateipid(fin) == -1) { 3016 DT(frb_updateipid); 3017 LBUMP(ipf_stats[1].fr_ipud); 3018 pass &= ~FR_CMDMASK; 3019 pass |= FR_BLOCK; 3020 fin->fin_reason = FRB_UPDATEIPID; 3021 } else { 3022 LBUMP(ipf_stats[0].fr_ipud); 3023 } 3024 } 3025 break; 3026#ifdef USE_INET6 3027 case 6 : 3028 (void) ipf_nat6_checkout(fin, &pass); 3029 break; 3030#endif 3031 default : 3032 break; 3033 } 3034 } 3035 3036filterdone: 3037#ifdef IPFILTER_LOG 3038 if ((softc->ipf_flags & FF_LOGGING) || (pass & FR_LOGMASK)) { 3039 (void) ipf_dolog(fin, &pass); 3040 } 3041#endif 3042 3043 /* 3044 * The FI_STATE flag is cleared here so that calling ipf_state_check 3045 * will work when called from inside of fr_fastroute. Although 3046 * there is a similar flag, FI_NATED, for NAT, it does have the same 3047 * impact on code execution. 3048 */ 3049 fin->fin_flx &= ~FI_STATE; 3050 3051#if defined(FASTROUTE_RECURSION) 3052 /* 3053 * Up the reference on fr_lock and exit ipf_mutex. The generation of 3054 * a packet below can sometimes cause a recursive call into IPFilter. 3055 * On those platforms where that does happen, we need to hang onto 3056 * the filter rule just in case someone decides to remove or flush it 3057 * in the meantime. 3058 */ 3059 if (fr != NULL) { 3060 MUTEX_ENTER(&fr->fr_lock); 3061 fr->fr_ref++; 3062 MUTEX_EXIT(&fr->fr_lock); 3063 } 3064 3065 RWLOCK_EXIT(&softc->ipf_mutex); 3066#endif 3067 3068 if ((pass & FR_RETMASK) != 0) { 3069 /* 3070 * Should we return an ICMP packet to indicate error 3071 * status passing through the packet filter ? 3072 * WARNING: ICMP error packets AND TCP RST packets should 3073 * ONLY be sent in repsonse to incoming packets. Sending 3074 * them in response to outbound packets can result in a 3075 * panic on some operating systems. 3076 */ 3077 if (!out) { 3078 if (pass & FR_RETICMP) { 3079 int dst; 3080 3081 if ((pass & FR_RETMASK) == FR_FAKEICMP) 3082 dst = 1; 3083 else 3084 dst = 0; 3085 (void) ipf_send_icmp_err(ICMP_UNREACH, fin, 3086 dst); 3087 LBUMP(ipf_stats[0].fr_ret); 3088 } else if (((pass & FR_RETMASK) == FR_RETRST) && 3089 !(fin->fin_flx & FI_SHORT)) { 3090 if (((fin->fin_flx & FI_OOW) != 0) || 3091 (ipf_send_reset(fin) == 0)) { 3092 LBUMP(ipf_stats[1].fr_ret); 3093 } 3094 } 3095 3096 /* 3097 * When using return-* with auth rules, the auth code 3098 * takes over disposing of this packet. 3099 */ 3100 if (FR_ISAUTH(pass) && (fin->fin_m != NULL)) { 3101 DT1(frb_authcapture, fr_info_t *, fin); 3102 fin->fin_m = *fin->fin_mp = NULL; 3103 fin->fin_reason = FRB_AUTHCAPTURE; 3104 m = NULL; 3105 } 3106 } else { 3107 if (pass & FR_RETRST) { 3108 fin->fin_error = ECONNRESET; 3109 } 3110 } 3111 } 3112 3113 /* 3114 * After the above so that ICMP unreachables and TCP RSTs get 3115 * created properly. 3116 */ 3117 if (FR_ISBLOCK(pass) && (fin->fin_flx & FI_NEWNAT)) 3118 ipf_nat_uncreate(fin); 3119 3120 /* 3121 * If we didn't drop off the bottom of the list of rules (and thus 3122 * the 'current' rule fr is not NULL), then we may have some extra 3123 * instructions about what to do with a packet. 3124 * Once we're finished return to our caller, freeing the packet if 3125 * we are dropping it. 3126 */ 3127 if (fr != NULL) { 3128 frdest_t *fdp; 3129 3130 /* 3131 * Generate a duplicated packet first because ipf_fastroute 3132 * can lead to fin_m being free'd... not good. 3133 */ 3134 fdp = fin->fin_dif; 3135 if ((fdp != NULL) && (fdp->fd_ptr != NULL) && 3136 (fdp->fd_ptr != (void *)-1)) { 3137 mc = M_COPY(fin->fin_m); 3138 if (mc != NULL) 3139 ipf_fastroute(mc, &mc, fin, fdp); 3140 } 3141 3142 fdp = fin->fin_tif; 3143 if (!out && (pass & FR_FASTROUTE)) { 3144 /* 3145 * For fastroute rule, no destination interface defined 3146 * so pass NULL as the frdest_t parameter 3147 */ 3148 (void) ipf_fastroute(fin->fin_m, mp, fin, NULL); 3149 m = *mp = NULL; 3150 } else if ((fdp != NULL) && (fdp->fd_ptr != NULL) && 3151 (fdp->fd_ptr != (struct ifnet *)-1)) { 3152 /* this is for to rules: */ 3153 ipf_fastroute(fin->fin_m, mp, fin, fdp); 3154 m = *mp = NULL; 3155 } 3156 3157#if defined(FASTROUTE_RECURSION) 3158 (void) ipf_derefrule(softc, &fr); 3159#endif 3160 } 3161#if !defined(FASTROUTE_RECURSION) 3162 RWLOCK_EXIT(&softc->ipf_mutex); 3163#endif 3164 3165finished: 3166 if (!FR_ISPASS(pass)) { 3167 LBUMP(ipf_stats[out].fr_block); 3168 if (*mp != NULL) { 3169#ifdef _KERNEL 3170 FREE_MB_T(*mp); 3171#endif 3172 m = *mp = NULL; 3173 } 3174 } else { 3175 LBUMP(ipf_stats[out].fr_pass); 3176 } 3177 3178 SPL_X(s); 3179 3180 if (fin->fin_m == NULL && fin->fin_flx & FI_BAD && 3181 fin->fin_reason == FRB_PULLUP) { 3182 /* m_pullup() has freed the mbuf */ 3183 LBUMP(ipf_stats[out].fr_blocked[fin->fin_reason]); 3184 return (-1); 3185 } 3186 3187 3188#ifdef _KERNEL 3189 if (FR_ISPASS(pass)) 3190 return (0); 3191 LBUMP(ipf_stats[out].fr_blocked[fin->fin_reason]); 3192 return (fin->fin_error); 3193#else /* _KERNEL */ 3194 if (*mp != NULL) 3195 (*mp)->mb_ifp = fin->fin_ifp; 3196 blockreason = fin->fin_reason; 3197 FR_VERBOSE(("fin_flx %#x pass %#x ", fin->fin_flx, pass)); 3198 /*if ((pass & FR_CMDMASK) == (softc->ipf_pass & FR_CMDMASK))*/ 3199 if ((pass & FR_NOMATCH) != 0) 3200 return (1); 3201 3202 if ((pass & FR_RETMASK) != 0) 3203 switch (pass & FR_RETMASK) 3204 { 3205 case FR_RETRST : 3206 return (3); 3207 case FR_RETICMP : 3208 return (4); 3209 case FR_FAKEICMP : 3210 return (5); 3211 } 3212 3213 switch (pass & FR_CMDMASK) 3214 { 3215 case FR_PASS : 3216 return (0); 3217 case FR_BLOCK : 3218 return (-1); 3219 case FR_AUTH : 3220 return (-2); 3221 case FR_ACCOUNT : 3222 return (-3); 3223 case FR_PREAUTH : 3224 return (-4); 3225 } 3226 return (2); 3227#endif /* _KERNEL */ 3228} 3229 3230 3231#ifdef IPFILTER_LOG 3232/* ------------------------------------------------------------------------ */ 3233/* Function: ipf_dolog */ 3234/* Returns: frentry_t* - returns contents of fin_fr (no change made) */ 3235/* Parameters: fin(I) - pointer to packet information */ 3236/* passp(IO) - pointer to current/new filter decision (unused) */ 3237/* */ 3238/* Checks flags set to see how a packet should be logged, if it is to be */ 3239/* logged. Adjust statistics based on its success or not. */ 3240/* ------------------------------------------------------------------------ */ 3241frentry_t * 3242ipf_dolog(fr_info_t *fin, u_32_t *passp) 3243{ 3244 ipf_main_softc_t *softc = fin->fin_main_soft; 3245 u_32_t pass; 3246 int out; 3247 3248 out = fin->fin_out; 3249 pass = *passp; 3250 3251 if ((softc->ipf_flags & FF_LOGNOMATCH) && (pass & FR_NOMATCH)) { 3252 pass |= FF_LOGNOMATCH; 3253 LBUMPD(ipf_stats[out], fr_npkl); 3254 goto logit; 3255 3256 } else if (((pass & FR_LOGMASK) == FR_LOGP) || 3257 (FR_ISPASS(pass) && (softc->ipf_flags & FF_LOGPASS))) { 3258 if ((pass & FR_LOGMASK) != FR_LOGP) 3259 pass |= FF_LOGPASS; 3260 LBUMPD(ipf_stats[out], fr_ppkl); 3261 goto logit; 3262 3263 } else if (((pass & FR_LOGMASK) == FR_LOGB) || 3264 (FR_ISBLOCK(pass) && (softc->ipf_flags & FF_LOGBLOCK))) { 3265 if ((pass & FR_LOGMASK) != FR_LOGB) 3266 pass |= FF_LOGBLOCK; 3267 LBUMPD(ipf_stats[out], fr_bpkl); 3268 3269logit: 3270 if (ipf_log_pkt(fin, pass) == -1) { 3271 /* 3272 * If the "or-block" option has been used then 3273 * block the packet if we failed to log it. 3274 */ 3275 if ((pass & FR_LOGORBLOCK) && FR_ISPASS(pass)) { 3276 DT1(frb_logfail2, u_int, pass); 3277 pass &= ~FR_CMDMASK; 3278 pass |= FR_BLOCK; 3279 fin->fin_reason = FRB_LOGFAIL2; 3280 } 3281 } 3282 *passp = pass; 3283 } 3284 3285 return (fin->fin_fr); 3286} 3287#endif /* IPFILTER_LOG */ 3288 3289 3290/* ------------------------------------------------------------------------ */ 3291/* Function: ipf_cksum */ 3292/* Returns: u_short - IP header checksum */ 3293/* Parameters: addr(I) - pointer to start of buffer to checksum */ 3294/* len(I) - length of buffer in bytes */ 3295/* */ 3296/* Calculate the two's complement 16 bit checksum of the buffer passed. */ 3297/* */ 3298/* N.B.: addr should be 16bit aligned. */ 3299/* ------------------------------------------------------------------------ */ 3300u_short 3301ipf_cksum(u_short *addr, int len) 3302{ 3303 u_32_t sum = 0; 3304 3305 for (sum = 0; len > 1; len -= 2) 3306 sum += *addr++; 3307 3308 /* mop up an odd byte, if necessary */ 3309 if (len == 1) 3310 sum += *(u_char *)addr; 3311 3312 /* 3313 * add back carry outs from top 16 bits to low 16 bits 3314 */ 3315 sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ 3316 sum += (sum >> 16); /* add carry */ 3317 return (u_short)(~sum); 3318} 3319 3320 3321/* ------------------------------------------------------------------------ */ 3322/* Function: fr_cksum */ 3323/* Returns: u_short - layer 4 checksum */ 3324/* Parameters: fin(I) - pointer to packet information */ 3325/* ip(I) - pointer to IP header */ 3326/* l4proto(I) - protocol to caclulate checksum for */ 3327/* l4hdr(I) - pointer to layer 4 header */ 3328/* */ 3329/* Calculates the TCP checksum for the packet held in "m", using the data */ 3330/* in the IP header "ip" to seed it. */ 3331/* */ 3332/* NB: This function assumes we've pullup'd enough for all of the IP header */ 3333/* and the TCP header. We also assume that data blocks aren't allocated in */ 3334/* odd sizes. */ 3335/* */ 3336/* Expects ip_len and ip_off to be in network byte order when called. */ 3337/* ------------------------------------------------------------------------ */ 3338u_short 3339fr_cksum(fr_info_t *fin, ip_t *ip, int l4proto, void *l4hdr) 3340{ 3341 u_short *sp, slen, sumsave, *csump; 3342 u_int sum, sum2; 3343 int hlen; 3344 int off; 3345#ifdef USE_INET6 3346 ip6_t *ip6; 3347#endif 3348 3349 csump = NULL; 3350 sumsave = 0; 3351 sp = NULL; 3352 slen = 0; 3353 hlen = 0; 3354 sum = 0; 3355 3356 sum = htons((u_short)l4proto); 3357 /* 3358 * Add up IP Header portion 3359 */ 3360#ifdef USE_INET6 3361 if (IP_V(ip) == 4) { 3362#endif 3363 hlen = IP_HL(ip) << 2; 3364 off = hlen; 3365 sp = (u_short *)&ip->ip_src; 3366 sum += *sp++; /* ip_src */ 3367 sum += *sp++; 3368 sum += *sp++; /* ip_dst */ 3369 sum += *sp++; 3370 slen = fin->fin_plen - off; 3371 sum += htons(slen); 3372#ifdef USE_INET6 3373 } else if (IP_V(ip) == 6) { 3374 mb_t *m; 3375 3376 m = fin->fin_m; 3377 ip6 = (ip6_t *)ip; 3378 off = ((caddr_t)ip6 - m->m_data) + sizeof(struct ip6_hdr); 3379 int len = ntohs(ip6->ip6_plen) - (off - sizeof(*ip6)); 3380 return (ipf_pcksum6(m, ip6, off, len)); 3381 } else { 3382 return (0xffff); 3383 } 3384#endif 3385 3386 switch (l4proto) 3387 { 3388 case IPPROTO_UDP : 3389 csump = &((udphdr_t *)l4hdr)->uh_sum; 3390 break; 3391 3392 case IPPROTO_TCP : 3393 csump = &((tcphdr_t *)l4hdr)->th_sum; 3394 break; 3395 case IPPROTO_ICMP : 3396 csump = &((icmphdr_t *)l4hdr)->icmp_cksum; 3397 sum = 0; /* Pseudo-checksum is not included */ 3398 break; 3399#ifdef USE_INET6 3400 case IPPROTO_ICMPV6 : 3401 csump = &((struct icmp6_hdr *)l4hdr)->icmp6_cksum; 3402 break; 3403#endif 3404 default : 3405 break; 3406 } 3407 3408 if (csump != NULL) { 3409 sumsave = *csump; 3410 *csump = 0; 3411 } 3412 3413 sum2 = ipf_pcksum(fin, off, sum); 3414 if (csump != NULL) 3415 *csump = sumsave; 3416 return (sum2); 3417} 3418 3419 3420/* ------------------------------------------------------------------------ */ 3421/* Function: ipf_findgroup */ 3422/* Returns: frgroup_t * - NULL = group not found, else pointer to group */ 3423/* Parameters: softc(I) - pointer to soft context main structure */ 3424/* group(I) - group name to search for */ 3425/* unit(I) - device to which this group belongs */ 3426/* set(I) - which set of rules (inactive/inactive) this is */ 3427/* fgpp(O) - pointer to place to store pointer to the pointer */ 3428/* to where to add the next (last) group or where */ 3429/* to delete group from. */ 3430/* */ 3431/* Search amongst the defined groups for a particular group number. */ 3432/* ------------------------------------------------------------------------ */ 3433frgroup_t * 3434ipf_findgroup(ipf_main_softc_t *softc, char *group, minor_t unit, int set, 3435 frgroup_t ***fgpp) 3436{ 3437 frgroup_t *fg, **fgp; 3438 3439 /* 3440 * Which list of groups to search in is dependent on which list of 3441 * rules are being operated on. 3442 */ 3443 fgp = &softc->ipf_groups[unit][set]; 3444 3445 while ((fg = *fgp) != NULL) { 3446 if (strncmp(group, fg->fg_name, FR_GROUPLEN) == 0) 3447 break; 3448 else 3449 fgp = &fg->fg_next; 3450 } 3451 if (fgpp != NULL) 3452 *fgpp = fgp; 3453 return (fg); 3454} 3455 3456 3457/* ------------------------------------------------------------------------ */ 3458/* Function: ipf_group_add */ 3459/* Returns: frgroup_t * - NULL == did not create group, */ 3460/* != NULL == pointer to the group */ 3461/* Parameters: softc(I) - pointer to soft context main structure */ 3462/* num(I) - group number to add */ 3463/* head(I) - rule pointer that is using this as the head */ 3464/* flags(I) - rule flags which describe the type of rule it is */ 3465/* unit(I) - device to which this group will belong to */ 3466/* set(I) - which set of rules (inactive/inactive) this is */ 3467/* Write Locks: ipf_mutex */ 3468/* */ 3469/* Add a new group head, or if it already exists, increase the reference */ 3470/* count to it. */ 3471/* ------------------------------------------------------------------------ */ 3472frgroup_t * 3473ipf_group_add(ipf_main_softc_t *softc, char *group, void *head, u_32_t flags, 3474 minor_t unit, int set) 3475{ 3476 frgroup_t *fg, **fgp; 3477 u_32_t gflags; 3478 3479 if (group == NULL) 3480 return (NULL); 3481 3482 if (unit == IPL_LOGIPF && *group == '\0') 3483 return (NULL); 3484 3485 fgp = NULL; 3486 gflags = flags & FR_INOUT; 3487 3488 fg = ipf_findgroup(softc, group, unit, set, &fgp); 3489 if (fg != NULL) { 3490 if (fg->fg_head == NULL && head != NULL) 3491 fg->fg_head = head; 3492 if (fg->fg_flags == 0) 3493 fg->fg_flags = gflags; 3494 else if (gflags != fg->fg_flags) 3495 return (NULL); 3496 fg->fg_ref++; 3497 return (fg); 3498 } 3499 3500 KMALLOC(fg, frgroup_t *); 3501 if (fg != NULL) { 3502 fg->fg_head = head; 3503 fg->fg_start = NULL; 3504 fg->fg_next = *fgp; 3505 bcopy(group, fg->fg_name, strlen(group) + 1); 3506 fg->fg_flags = gflags; 3507 fg->fg_ref = 1; 3508 fg->fg_set = &softc->ipf_groups[unit][set]; 3509 *fgp = fg; 3510 } 3511 return (fg); 3512} 3513 3514 3515/* ------------------------------------------------------------------------ */ 3516/* Function: ipf_group_del */ 3517/* Returns: int - number of rules deleted */ 3518/* Parameters: softc(I) - pointer to soft context main structure */ 3519/* group(I) - group name to delete */ 3520/* fr(I) - filter rule from which group is referenced */ 3521/* Write Locks: ipf_mutex */ 3522/* */ 3523/* This function is called whenever a reference to a group is to be dropped */ 3524/* and thus its reference count needs to be lowered and the group free'd if */ 3525/* the reference count reaches zero. Passing in fr is really for the sole */ 3526/* purpose of knowing when the head rule is being deleted. */ 3527/* ------------------------------------------------------------------------ */ 3528void 3529ipf_group_del(ipf_main_softc_t *softc, frgroup_t *group, frentry_t *fr) 3530{ 3531 3532 if (group->fg_head == fr) 3533 group->fg_head = NULL; 3534 3535 group->fg_ref--; 3536 if ((group->fg_ref == 0) && (group->fg_start == NULL)) 3537 ipf_group_free(group); 3538} 3539 3540 3541/* ------------------------------------------------------------------------ */ 3542/* Function: ipf_group_free */ 3543/* Returns: Nil */ 3544/* Parameters: group(I) - pointer to filter rule group */ 3545/* */ 3546/* Remove the group from the list of groups and free it. */ 3547/* ------------------------------------------------------------------------ */ 3548static void 3549ipf_group_free(frgroup_t *group) 3550{ 3551 frgroup_t **gp; 3552 3553 for (gp = group->fg_set; *gp != NULL; gp = &(*gp)->fg_next) { 3554 if (*gp == group) { 3555 *gp = group->fg_next; 3556 break; 3557 } 3558 } 3559 KFREE(group); 3560} 3561 3562 3563/* ------------------------------------------------------------------------ */ 3564/* Function: ipf_group_flush */ 3565/* Returns: int - number of rules flush from group */ 3566/* Parameters: softc(I) - pointer to soft context main structure */ 3567/* Parameters: group(I) - pointer to filter rule group */ 3568/* */ 3569/* Remove all of the rules that currently are listed under the given group. */ 3570/* ------------------------------------------------------------------------ */ 3571static int 3572ipf_group_flush(ipf_main_softc_t *softc, frgroup_t *group) 3573{ 3574 int gone = 0; 3575 3576 (void) ipf_flushlist(softc, &gone, &group->fg_start); 3577 3578 return (gone); 3579} 3580 3581 3582/* ------------------------------------------------------------------------ */ 3583/* Function: ipf_getrulen */ 3584/* Returns: frentry_t * - NULL == not found, else pointer to rule n */ 3585/* Parameters: softc(I) - pointer to soft context main structure */ 3586/* Parameters: unit(I) - device for which to count the rule's number */ 3587/* flags(I) - which set of rules to find the rule in */ 3588/* group(I) - group name */ 3589/* n(I) - rule number to find */ 3590/* */ 3591/* Find rule # n in group # g and return a pointer to it. Return NULl if */ 3592/* group # g doesn't exist or there are less than n rules in the group. */ 3593/* ------------------------------------------------------------------------ */ 3594frentry_t * 3595ipf_getrulen(ipf_main_softc_t *softc, int unit, char *group, u_32_t n) 3596{ 3597 frentry_t *fr; 3598 frgroup_t *fg; 3599 3600 fg = ipf_findgroup(softc, group, unit, softc->ipf_active, NULL); 3601 if (fg == NULL) 3602 return (NULL); 3603 for (fr = fg->fg_start; fr && n; fr = fr->fr_next, n--) 3604 ; 3605 if (n != 0) 3606 return (NULL); 3607 return (fr); 3608} 3609 3610 3611/* ------------------------------------------------------------------------ */ 3612/* Function: ipf_flushlist */ 3613/* Returns: int - >= 0 - number of flushed rules */ 3614/* Parameters: softc(I) - pointer to soft context main structure */ 3615/* nfreedp(O) - pointer to int where flush count is stored */ 3616/* listp(I) - pointer to list to flush pointer */ 3617/* Write Locks: ipf_mutex */ 3618/* */ 3619/* Recursively flush rules from the list, descending groups as they are */ 3620/* encountered. if a rule is the head of a group and it has lost all its */ 3621/* group members, then also delete the group reference. nfreedp is needed */ 3622/* to store the accumulating count of rules removed, whereas the returned */ 3623/* value is just the number removed from the current list. The latter is */ 3624/* needed to correctly adjust reference counts on rules that define groups. */ 3625/* */ 3626/* NOTE: Rules not loaded from user space cannot be flushed. */ 3627/* ------------------------------------------------------------------------ */ 3628static int 3629ipf_flushlist(ipf_main_softc_t *softc, int *nfreedp, frentry_t **listp) 3630{ 3631 int freed = 0; 3632 frentry_t *fp; 3633 3634 while ((fp = *listp) != NULL) { 3635 if ((fp->fr_type & FR_T_BUILTIN) || 3636 !(fp->fr_flags & FR_COPIED)) { 3637 listp = &fp->fr_next; 3638 continue; 3639 } 3640 *listp = fp->fr_next; 3641 if (fp->fr_next != NULL) 3642 fp->fr_next->fr_pnext = fp->fr_pnext; 3643 fp->fr_pnext = NULL; 3644 3645 if (fp->fr_grphead != NULL) { 3646 freed += ipf_group_flush(softc, fp->fr_grphead); 3647 fp->fr_names[fp->fr_grhead] = '\0'; 3648 } 3649 3650 if (fp->fr_icmpgrp != NULL) { 3651 freed += ipf_group_flush(softc, fp->fr_icmpgrp); 3652 fp->fr_names[fp->fr_icmphead] = '\0'; 3653 } 3654 3655 if (fp->fr_srctrack.ht_max_nodes) 3656 ipf_rb_ht_flush(&fp->fr_srctrack); 3657 3658 fp->fr_next = NULL; 3659 3660 ASSERT(fp->fr_ref > 0); 3661 if (ipf_derefrule(softc, &fp) == 0) 3662 freed++; 3663 } 3664 *nfreedp += freed; 3665 return (freed); 3666} 3667 3668 3669/* ------------------------------------------------------------------------ */ 3670/* Function: ipf_flush */ 3671/* Returns: int - >= 0 - number of flushed rules */ 3672/* Parameters: softc(I) - pointer to soft context main structure */ 3673/* unit(I) - device for which to flush rules */ 3674/* flags(I) - which set of rules to flush */ 3675/* */ 3676/* Calls flushlist() for all filter rules (accounting, firewall - both IPv4 */ 3677/* and IPv6) as defined by the value of flags. */ 3678/* ------------------------------------------------------------------------ */ 3679int 3680ipf_flush(ipf_main_softc_t *softc, minor_t unit, int flags) 3681{ 3682 int flushed = 0, set; 3683 3684 WRITE_ENTER(&softc->ipf_mutex); 3685 3686 set = softc->ipf_active; 3687 if ((flags & FR_INACTIVE) == FR_INACTIVE) 3688 set = 1 - set; 3689 3690 if (flags & FR_OUTQUE) { 3691 ipf_flushlist(softc, &flushed, &softc->ipf_rules[1][set]); 3692 ipf_flushlist(softc, &flushed, &softc->ipf_acct[1][set]); 3693 } 3694 if (flags & FR_INQUE) { 3695 ipf_flushlist(softc, &flushed, &softc->ipf_rules[0][set]); 3696 ipf_flushlist(softc, &flushed, &softc->ipf_acct[0][set]); 3697 } 3698 3699 flushed += ipf_flush_groups(softc, &softc->ipf_groups[unit][set], 3700 flags & (FR_INQUE|FR_OUTQUE)); 3701 3702 RWLOCK_EXIT(&softc->ipf_mutex); 3703 3704 if (unit == IPL_LOGIPF) { 3705 int tmp; 3706 3707 tmp = ipf_flush(softc, IPL_LOGCOUNT, flags); 3708 if (tmp >= 0) 3709 flushed += tmp; 3710 } 3711 return (flushed); 3712} 3713 3714 3715/* ------------------------------------------------------------------------ */ 3716/* Function: ipf_flush_groups */ 3717/* Returns: int - >= 0 - number of flushed rules */ 3718/* Parameters: softc(I) - soft context pointerto work with */ 3719/* grhead(I) - pointer to the start of the group list to flush */ 3720/* flags(I) - which set of rules to flush */ 3721/* */ 3722/* Walk through all of the groups under the given group head and remove all */ 3723/* of those that match the flags passed in. The for loop here is bit more */ 3724/* complicated than usual because the removal of a rule with ipf_derefrule */ 3725/* may end up removing not only the structure pointed to by "fg" but also */ 3726/* what is fg_next and fg_next after that. So if a filter rule is actually */ 3727/* removed from the group then it is necessary to start again. */ 3728/* ------------------------------------------------------------------------ */ 3729static int 3730ipf_flush_groups(ipf_main_softc_t *softc, frgroup_t **grhead, int flags) 3731{ 3732 frentry_t *fr, **frp; 3733 frgroup_t *fg, **fgp; 3734 int flushed = 0; 3735 int removed = 0; 3736 3737 for (fgp = grhead; (fg = *fgp) != NULL; ) { 3738 while ((fg != NULL) && ((fg->fg_flags & flags) == 0)) 3739 fg = fg->fg_next; 3740 if (fg == NULL) 3741 break; 3742 removed = 0; 3743 frp = &fg->fg_start; 3744 while ((removed == 0) && ((fr = *frp) != NULL)) { 3745 if ((fr->fr_flags & flags) == 0) { 3746 frp = &fr->fr_next; 3747 } else { 3748 if (fr->fr_next != NULL) 3749 fr->fr_next->fr_pnext = fr->fr_pnext; 3750 *frp = fr->fr_next; 3751 fr->fr_pnext = NULL; 3752 fr->fr_next = NULL; 3753 (void) ipf_derefrule(softc, &fr); 3754 flushed++; 3755 removed++; 3756 } 3757 } 3758 if (removed == 0) 3759 fgp = &fg->fg_next; 3760 } 3761 return (flushed); 3762} 3763 3764 3765/* ------------------------------------------------------------------------ */ 3766/* Function: memstr */ 3767/* Returns: char * - NULL if failed, != NULL pointer to matching bytes */ 3768/* Parameters: src(I) - pointer to byte sequence to match */ 3769/* dst(I) - pointer to byte sequence to search */ 3770/* slen(I) - match length */ 3771/* dlen(I) - length available to search in */ 3772/* */ 3773/* Search dst for a sequence of bytes matching those at src and extend for */ 3774/* slen bytes. */ 3775/* ------------------------------------------------------------------------ */ 3776char * 3777memstr(const char *src, char *dst, size_t slen, size_t dlen) 3778{ 3779 char *s = NULL; 3780 3781 while (dlen >= slen) { 3782 if (bcmp(src, dst, slen) == 0) { 3783 s = dst; 3784 break; 3785 } 3786 dst++; 3787 dlen--; 3788 } 3789 return (s); 3790} 3791/* ------------------------------------------------------------------------ */ 3792/* Function: ipf_fixskip */ 3793/* Returns: Nil */ 3794/* Parameters: listp(IO) - pointer to start of list with skip rule */ 3795/* rp(I) - rule added/removed with skip in it. */ 3796/* addremove(I) - adjustment (-1/+1) to make to skip count, */ 3797/* depending on whether a rule was just added */ 3798/* or removed. */ 3799/* */ 3800/* Adjust all the rules in a list which would have skip'd past the position */ 3801/* where we are inserting to skip to the right place given the change. */ 3802/* ------------------------------------------------------------------------ */ 3803void 3804ipf_fixskip(frentry_t **listp, frentry_t *rp, int addremove) 3805{ 3806 int rules, rn; 3807 frentry_t *fp; 3808 3809 rules = 0; 3810 for (fp = *listp; (fp != NULL) && (fp != rp); fp = fp->fr_next) 3811 rules++; 3812 3813 if (fp == NULL) 3814 return; 3815 3816 for (rn = 0, fp = *listp; fp && (fp != rp); fp = fp->fr_next, rn++) 3817 if (FR_ISSKIP(fp->fr_flags) && (rn + fp->fr_arg >= rules)) 3818 fp->fr_arg += addremove; 3819} 3820 3821 3822#ifdef _KERNEL 3823/* ------------------------------------------------------------------------ */ 3824/* Function: count4bits */ 3825/* Returns: int - >= 0 - number of consecutive bits in input */ 3826/* Parameters: ip(I) - 32bit IP address */ 3827/* */ 3828/* IPv4 ONLY */ 3829/* count consecutive 1's in bit mask. If the mask generated by counting */ 3830/* consecutive 1's is different to that passed, return -1, else return # */ 3831/* of bits. */ 3832/* ------------------------------------------------------------------------ */ 3833int 3834count4bits(u_32_t ip) 3835{ 3836 u_32_t ipn; 3837 int cnt = 0, i, j; 3838 3839 ip = ipn = ntohl(ip); 3840 for (i = 32; i; i--, ipn *= 2) 3841 if (ipn & 0x80000000) 3842 cnt++; 3843 else 3844 break; 3845 ipn = 0; 3846 for (i = 32, j = cnt; i; i--, j--) { 3847 ipn *= 2; 3848 if (j > 0) 3849 ipn++; 3850 } 3851 if (ipn == ip) 3852 return (cnt); 3853 return (-1); 3854} 3855 3856 3857/* ------------------------------------------------------------------------ */ 3858/* Function: count6bits */ 3859/* Returns: int - >= 0 - number of consecutive bits in input */ 3860/* Parameters: msk(I) - pointer to start of IPv6 bitmask */ 3861/* */ 3862/* IPv6 ONLY */ 3863/* count consecutive 1's in bit mask. */ 3864/* ------------------------------------------------------------------------ */ 3865# ifdef USE_INET6 3866int 3867count6bits(u_32_t *msk) 3868{ 3869 int i = 0, k; 3870 u_32_t j; 3871 3872 for (k = 3; k >= 0; k--) 3873 if (msk[k] == 0xffffffff) 3874 i += 32; 3875 else { 3876 for (j = msk[k]; j; j <<= 1) 3877 if (j & 0x80000000) 3878 i++; 3879 } 3880 return (i); 3881} 3882# endif 3883#endif /* _KERNEL */ 3884 3885 3886/* ------------------------------------------------------------------------ */ 3887/* Function: ipf_synclist */ 3888/* Returns: int - 0 = no failures, else indication of first failure */ 3889/* Parameters: fr(I) - start of filter list to sync interface names for */ 3890/* ifp(I) - interface pointer for limiting sync lookups */ 3891/* Write Locks: ipf_mutex */ 3892/* */ 3893/* Walk through a list of filter rules and resolve any interface names into */ 3894/* pointers. Where dynamic addresses are used, also update the IP address */ 3895/* used in the rule. The interface pointer is used to limit the lookups to */ 3896/* a specific set of matching names if it is non-NULL. */ 3897/* Errors can occur when resolving the destination name of to/dup-to fields */ 3898/* when the name points to a pool and that pool doest not exist. If this */ 3899/* does happen then it is necessary to check if there are any lookup refs */ 3900/* that need to be dropped before returning with an error. */ 3901/* ------------------------------------------------------------------------ */ 3902static int 3903ipf_synclist(ipf_main_softc_t *softc, frentry_t *fr, void *ifp) 3904{ 3905 frentry_t *frt, *start = fr; 3906 frdest_t *fdp; 3907 char *name; 3908 int error; 3909 void *ifa; 3910 int v, i; 3911 3912 error = 0; 3913 3914 for (; fr; fr = fr->fr_next) { 3915 if (fr->fr_family == AF_INET) 3916 v = 4; 3917 else if (fr->fr_family == AF_INET6) 3918 v = 6; 3919 else 3920 v = 0; 3921 3922 /* 3923 * Lookup all the interface names that are part of the rule. 3924 */ 3925 for (i = 0; i < FR_NUM(fr->fr_ifas); i++) { 3926 if ((ifp != NULL) && (fr->fr_ifas[i] != ifp)) 3927 continue; 3928 if (fr->fr_ifnames[i] == -1) 3929 continue; 3930 name = FR_NAME(fr, fr_ifnames[i]); 3931 fr->fr_ifas[i] = ipf_resolvenic(softc, name, v); 3932 } 3933 3934 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) { 3935 if (fr->fr_satype != FRI_NORMAL && 3936 fr->fr_satype != FRI_LOOKUP) { 3937 ifa = ipf_resolvenic(softc, fr->fr_names + 3938 fr->fr_sifpidx, v); 3939 ipf_ifpaddr(softc, v, fr->fr_satype, ifa, 3940 &fr->fr_src6, &fr->fr_smsk6); 3941 } 3942 if (fr->fr_datype != FRI_NORMAL && 3943 fr->fr_datype != FRI_LOOKUP) { 3944 ifa = ipf_resolvenic(softc, fr->fr_names + 3945 fr->fr_sifpidx, v); 3946 ipf_ifpaddr(softc, v, fr->fr_datype, ifa, 3947 &fr->fr_dst6, &fr->fr_dmsk6); 3948 } 3949 } 3950 3951 fdp = &fr->fr_tifs[0]; 3952 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) { 3953 error = ipf_resolvedest(softc, fr->fr_names, fdp, v); 3954 if (error != 0) 3955 goto unwind; 3956 } 3957 3958 fdp = &fr->fr_tifs[1]; 3959 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) { 3960 error = ipf_resolvedest(softc, fr->fr_names, fdp, v); 3961 if (error != 0) 3962 goto unwind; 3963 } 3964 3965 fdp = &fr->fr_dif; 3966 if ((ifp == NULL) || (fdp->fd_ptr == ifp)) { 3967 error = ipf_resolvedest(softc, fr->fr_names, fdp, v); 3968 if (error != 0) 3969 goto unwind; 3970 } 3971 3972 if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 3973 (fr->fr_satype == FRI_LOOKUP) && (fr->fr_srcptr == NULL)) { 3974 fr->fr_srcptr = ipf_lookup_res_num(softc, 3975 fr->fr_srctype, 3976 IPL_LOGIPF, 3977 fr->fr_srcnum, 3978 &fr->fr_srcfunc); 3979 } 3980 if (((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 3981 (fr->fr_datype == FRI_LOOKUP) && (fr->fr_dstptr == NULL)) { 3982 fr->fr_dstptr = ipf_lookup_res_num(softc, 3983 fr->fr_dsttype, 3984 IPL_LOGIPF, 3985 fr->fr_dstnum, 3986 &fr->fr_dstfunc); 3987 } 3988 } 3989 return (0); 3990 3991unwind: 3992 for (frt = start; frt != fr; fr = fr->fr_next) { 3993 if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 3994 (frt->fr_satype == FRI_LOOKUP) && (frt->fr_srcptr != NULL)) 3995 ipf_lookup_deref(softc, frt->fr_srctype, 3996 frt->fr_srcptr); 3997 if (((frt->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) && 3998 (frt->fr_datype == FRI_LOOKUP) && (frt->fr_dstptr != NULL)) 3999 ipf_lookup_deref(softc, frt->fr_dsttype, 4000 frt->fr_dstptr); 4001 } 4002 return (error); 4003} 4004 4005 4006/* ------------------------------------------------------------------------ */ 4007/* Function: ipf_sync */ 4008/* Returns: void */ 4009/* Parameters: Nil */ 4010/* */ 4011/* ipf_sync() is called when we suspect that the interface list or */ 4012/* information about interfaces (like IP#) has changed. Go through all */ 4013/* filter rules, NAT entries and the state table and check if anything */ 4014/* needs to be changed/updated. */ 4015/* ------------------------------------------------------------------------ */ 4016int 4017ipf_sync(ipf_main_softc_t *softc, void *ifp) 4018{ 4019 int i; 4020 4021#if !SOLARIS 4022 ipf_nat_sync(softc, ifp); 4023 ipf_state_sync(softc, ifp); 4024 ipf_lookup_sync(softc, ifp); 4025#endif 4026 4027 WRITE_ENTER(&softc->ipf_mutex); 4028 (void) ipf_synclist(softc, softc->ipf_acct[0][softc->ipf_active], ifp); 4029 (void) ipf_synclist(softc, softc->ipf_acct[1][softc->ipf_active], ifp); 4030 (void) ipf_synclist(softc, softc->ipf_rules[0][softc->ipf_active], ifp); 4031 (void) ipf_synclist(softc, softc->ipf_rules[1][softc->ipf_active], ifp); 4032 4033 for (i = 0; i < IPL_LOGSIZE; i++) { 4034 frgroup_t *g; 4035 4036 for (g = softc->ipf_groups[i][0]; g != NULL; g = g->fg_next) 4037 (void) ipf_synclist(softc, g->fg_start, ifp); 4038 for (g = softc->ipf_groups[i][1]; g != NULL; g = g->fg_next) 4039 (void) ipf_synclist(softc, g->fg_start, ifp); 4040 } 4041 RWLOCK_EXIT(&softc->ipf_mutex); 4042 4043 return (0); 4044} 4045 4046 4047/* 4048 * In the functions below, bcopy() is called because the pointer being 4049 * copied _from_ in this instance is a pointer to a char buf (which could 4050 * end up being unaligned) and on the kernel's local stack. 4051 */ 4052/* ------------------------------------------------------------------------ */ 4053/* Function: copyinptr */ 4054/* Returns: int - 0 = success, else failure */ 4055/* Parameters: src(I) - pointer to the source address */ 4056/* dst(I) - destination address */ 4057/* size(I) - number of bytes to copy */ 4058/* */ 4059/* Copy a block of data in from user space, given a pointer to the pointer */ 4060/* to start copying from (src) and a pointer to where to store it (dst). */ 4061/* NB: src - pointer to user space pointer, dst - kernel space pointer */ 4062/* ------------------------------------------------------------------------ */ 4063int 4064copyinptr(ipf_main_softc_t *softc, void *src, void *dst, size_t size) 4065{ 4066 caddr_t ca; 4067 int error; 4068 4069#if SOLARIS 4070 error = COPYIN(src, &ca, sizeof(ca)); 4071 if (error != 0) 4072 return (error); 4073#else 4074 bcopy(src, (caddr_t)&ca, sizeof(ca)); 4075#endif 4076 error = COPYIN(ca, dst, size); 4077 if (error != 0) { 4078 IPFERROR(3); 4079 error = EFAULT; 4080 } 4081 return (error); 4082} 4083 4084 4085/* ------------------------------------------------------------------------ */ 4086/* Function: copyoutptr */ 4087/* Returns: int - 0 = success, else failure */ 4088/* Parameters: src(I) - pointer to the source address */ 4089/* dst(I) - destination address */ 4090/* size(I) - number of bytes to copy */ 4091/* */ 4092/* Copy a block of data out to user space, given a pointer to the pointer */ 4093/* to start copying from (src) and a pointer to where to store it (dst). */ 4094/* NB: src - kernel space pointer, dst - pointer to user space pointer. */ 4095/* ------------------------------------------------------------------------ */ 4096int 4097copyoutptr(ipf_main_softc_t *softc, void *src, void *dst, size_t size) 4098{ 4099 caddr_t ca; 4100 int error; 4101 4102 bcopy(dst, (caddr_t)&ca, sizeof(ca)); 4103 error = COPYOUT(src, ca, size); 4104 if (error != 0) { 4105 IPFERROR(4); 4106 error = EFAULT; 4107 } 4108 return (error); 4109} 4110 4111 4112/* ------------------------------------------------------------------------ */ 4113/* Function: ipf_lock */ 4114/* Returns: int - 0 = success, else error */ 4115/* Parameters: data(I) - pointer to lock value to set */ 4116/* lockp(O) - pointer to location to store old lock value */ 4117/* */ 4118/* Get the new value for the lock integer, set it and return the old value */ 4119/* in *lockp. */ 4120/* ------------------------------------------------------------------------ */ 4121int 4122ipf_lock(caddr_t data, int *lockp) 4123{ 4124 int arg, err; 4125 4126 err = BCOPYIN(data, &arg, sizeof(arg)); 4127 if (err != 0) 4128 return (EFAULT); 4129 err = BCOPYOUT(lockp, data, sizeof(*lockp)); 4130 if (err != 0) 4131 return (EFAULT); 4132 *lockp = arg; 4133 return (0); 4134} 4135 4136 4137/* ------------------------------------------------------------------------ */ 4138/* Function: ipf_getstat */ 4139/* Returns: Nil */ 4140/* Parameters: softc(I) - pointer to soft context main structure */ 4141/* fiop(I) - pointer to ipfilter stats structure */ 4142/* rev(I) - version claim by program doing ioctl */ 4143/* */ 4144/* Stores a copy of current pointers, counters, etc, in the friostat */ 4145/* structure. */ 4146/* If IPFILTER_COMPAT is compiled, we pretend to be whatever version the */ 4147/* program is looking for. This ensure that validation of the version it */ 4148/* expects will always succeed. Thus kernels with IPFILTER_COMPAT will */ 4149/* allow older binaries to work but kernels without it will not. */ 4150/* ------------------------------------------------------------------------ */ 4151/*ARGSUSED*/ 4152static void 4153ipf_getstat(ipf_main_softc_t *softc, friostat_t *fiop, int rev) 4154{ 4155 int i; 4156 4157 bcopy((char *)softc->ipf_stats, (char *)fiop->f_st, 4158 sizeof(ipf_statistics_t) * 2); 4159 fiop->f_locks[IPL_LOGSTATE] = -1; 4160 fiop->f_locks[IPL_LOGNAT] = -1; 4161 fiop->f_locks[IPL_LOGIPF] = -1; 4162 fiop->f_locks[IPL_LOGAUTH] = -1; 4163 4164 fiop->f_ipf[0][0] = softc->ipf_rules[0][0]; 4165 fiop->f_acct[0][0] = softc->ipf_acct[0][0]; 4166 fiop->f_ipf[0][1] = softc->ipf_rules[0][1]; 4167 fiop->f_acct[0][1] = softc->ipf_acct[0][1]; 4168 fiop->f_ipf[1][0] = softc->ipf_rules[1][0]; 4169 fiop->f_acct[1][0] = softc->ipf_acct[1][0]; 4170 fiop->f_ipf[1][1] = softc->ipf_rules[1][1]; 4171 fiop->f_acct[1][1] = softc->ipf_acct[1][1]; 4172 4173 fiop->f_ticks = softc->ipf_ticks; 4174 fiop->f_active = softc->ipf_active; 4175 fiop->f_froute[0] = softc->ipf_frouteok[0]; 4176 fiop->f_froute[1] = softc->ipf_frouteok[1]; 4177 fiop->f_rb_no_mem = softc->ipf_rb_no_mem; 4178 fiop->f_rb_node_max = softc->ipf_rb_node_max; 4179 4180 fiop->f_running = softc->ipf_running; 4181 for (i = 0; i < IPL_LOGSIZE; i++) { 4182 fiop->f_groups[i][0] = softc->ipf_groups[i][0]; 4183 fiop->f_groups[i][1] = softc->ipf_groups[i][1]; 4184 } 4185#ifdef IPFILTER_LOG 4186 fiop->f_log_ok = ipf_log_logok(softc, IPL_LOGIPF); 4187 fiop->f_log_fail = ipf_log_failures(softc, IPL_LOGIPF); 4188 fiop->f_logging = 1; 4189#else 4190 fiop->f_log_ok = 0; 4191 fiop->f_log_fail = 0; 4192 fiop->f_logging = 0; 4193#endif 4194 fiop->f_defpass = softc->ipf_pass; 4195 fiop->f_features = ipf_features; 4196 4197#ifdef IPFILTER_COMPAT 4198 snprintf(fiop->f_version, sizeof(friostat.f_version), "IP Filter: v%d.%d.%d", 4199 (rev / 1000000) % 100, 4200 (rev / 10000) % 100, 4201 (rev / 100) % 100); 4202#else 4203 rev = rev; 4204 (void) strncpy(fiop->f_version, ipfilter_version, 4205 sizeof(fiop->f_version)); 4206#endif 4207} 4208 4209 4210#ifdef USE_INET6 4211int icmptoicmp6types[ICMP_MAXTYPE+1] = { 4212 ICMP6_ECHO_REPLY, /* 0: ICMP_ECHOREPLY */ 4213 -1, /* 1: UNUSED */ 4214 -1, /* 2: UNUSED */ 4215 ICMP6_DST_UNREACH, /* 3: ICMP_UNREACH */ 4216 -1, /* 4: ICMP_SOURCEQUENCH */ 4217 ND_REDIRECT, /* 5: ICMP_REDIRECT */ 4218 -1, /* 6: UNUSED */ 4219 -1, /* 7: UNUSED */ 4220 ICMP6_ECHO_REQUEST, /* 8: ICMP_ECHO */ 4221 -1, /* 9: UNUSED */ 4222 -1, /* 10: UNUSED */ 4223 ICMP6_TIME_EXCEEDED, /* 11: ICMP_TIMXCEED */ 4224 ICMP6_PARAM_PROB, /* 12: ICMP_PARAMPROB */ 4225 -1, /* 13: ICMP_TSTAMP */ 4226 -1, /* 14: ICMP_TSTAMPREPLY */ 4227 -1, /* 15: ICMP_IREQ */ 4228 -1, /* 16: ICMP_IREQREPLY */ 4229 -1, /* 17: ICMP_MASKREQ */ 4230 -1, /* 18: ICMP_MASKREPLY */ 4231}; 4232 4233 4234int icmptoicmp6unreach[ICMP_MAX_UNREACH] = { 4235 ICMP6_DST_UNREACH_ADDR, /* 0: ICMP_UNREACH_NET */ 4236 ICMP6_DST_UNREACH_ADDR, /* 1: ICMP_UNREACH_HOST */ 4237 -1, /* 2: ICMP_UNREACH_PROTOCOL */ 4238 ICMP6_DST_UNREACH_NOPORT, /* 3: ICMP_UNREACH_PORT */ 4239 -1, /* 4: ICMP_UNREACH_NEEDFRAG */ 4240 ICMP6_DST_UNREACH_NOTNEIGHBOR, /* 5: ICMP_UNREACH_SRCFAIL */ 4241 ICMP6_DST_UNREACH_ADDR, /* 6: ICMP_UNREACH_NET_UNKNOWN */ 4242 ICMP6_DST_UNREACH_ADDR, /* 7: ICMP_UNREACH_HOST_UNKNOWN */ 4243 -1, /* 8: ICMP_UNREACH_ISOLATED */ 4244 ICMP6_DST_UNREACH_ADMIN, /* 9: ICMP_UNREACH_NET_PROHIB */ 4245 ICMP6_DST_UNREACH_ADMIN, /* 10: ICMP_UNREACH_HOST_PROHIB */ 4246 -1, /* 11: ICMP_UNREACH_TOSNET */ 4247 -1, /* 12: ICMP_UNREACH_TOSHOST */ 4248 ICMP6_DST_UNREACH_ADMIN, /* 13: ICMP_UNREACH_ADMIN_PROHIBIT */ 4249}; 4250int icmpreplytype6[ICMP6_MAXTYPE + 1]; 4251#endif 4252 4253int icmpreplytype4[ICMP_MAXTYPE + 1]; 4254 4255 4256/* ------------------------------------------------------------------------ */ 4257/* Function: ipf_matchicmpqueryreply */ 4258/* Returns: int - 1 if "icmp" is a valid reply to "ic" else 0. */ 4259/* Parameters: v(I) - IP protocol version (4 or 6) */ 4260/* ic(I) - ICMP information */ 4261/* icmp(I) - ICMP packet header */ 4262/* rev(I) - direction (0 = forward/1 = reverse) of packet */ 4263/* */ 4264/* Check if the ICMP packet defined by the header pointed to by icmp is a */ 4265/* reply to one as described by what's in ic. If it is a match, return 1, */ 4266/* else return 0 for no match. */ 4267/* ------------------------------------------------------------------------ */ 4268int 4269ipf_matchicmpqueryreply(int v, icmpinfo_t *ic, icmphdr_t *icmp, int rev) 4270{ 4271 int ictype; 4272 4273 ictype = ic->ici_type; 4274 4275 if (v == 4) { 4276 /* 4277 * If we matched its type on the way in, then when going out 4278 * it will still be the same type. 4279 */ 4280 if ((!rev && (icmp->icmp_type == ictype)) || 4281 (rev && (icmpreplytype4[ictype] == icmp->icmp_type))) { 4282 if (icmp->icmp_type != ICMP_ECHOREPLY) 4283 return (1); 4284 if (icmp->icmp_id == ic->ici_id) 4285 return (1); 4286 } 4287 } 4288#ifdef USE_INET6 4289 else if (v == 6) { 4290 if ((!rev && (icmp->icmp_type == ictype)) || 4291 (rev && (icmpreplytype6[ictype] == icmp->icmp_type))) { 4292 if (icmp->icmp_type != ICMP6_ECHO_REPLY) 4293 return (1); 4294 if (icmp->icmp_id == ic->ici_id) 4295 return (1); 4296 } 4297 } 4298#endif 4299 return (0); 4300} 4301 4302 4303/* 4304 * IFNAMES are located in the variable length field starting at 4305 * frentry.fr_names. As pointers within the struct cannot be passed 4306 * to the kernel from ipf(8), an offset is used. An offset of -1 means it 4307 * is unused (invalid). If it is used (valid) it is an offset to the 4308 * character string of an interface name or a comment. The following 4309 * macros will assist those who follow to understand the code. 4310 */ 4311#define IPF_IFNAME_VALID(_a) (_a != -1) 4312#define IPF_IFNAME_INVALID(_a) (_a == -1) 4313#define IPF_IFNAMES_DIFFERENT(_a) \ 4314 !((IPF_IFNAME_INVALID(fr1->_a) && \ 4315 IPF_IFNAME_INVALID(fr2->_a)) || \ 4316 (IPF_IFNAME_VALID(fr1->_a) && \ 4317 IPF_IFNAME_VALID(fr2->_a) && \ 4318 !strcmp(FR_NAME(fr1, _a), FR_NAME(fr2, _a)))) 4319#define IPF_FRDEST_DIFFERENT(_a) \ 4320 (memcmp(&fr1->_a.fd_addr, &fr2->_a.fd_addr, \ 4321 offsetof(frdest_t, fd_name) - offsetof(frdest_t, fd_addr)) || \ 4322 IPF_IFNAMES_DIFFERENT(_a.fd_name)) 4323 4324 4325/* ------------------------------------------------------------------------ */ 4326/* Function: ipf_rule_compare */ 4327/* Parameters: fr1(I) - first rule structure to compare */ 4328/* fr2(I) - second rule structure to compare */ 4329/* Returns: int - 0 == rules are the same, else mismatch */ 4330/* */ 4331/* Compare two rules and return 0 if they match or a number indicating */ 4332/* which of the individual checks failed. */ 4333/* ------------------------------------------------------------------------ */ 4334static int 4335ipf_rule_compare(frentry_t *fr1, frentry_t *fr2) 4336{ 4337 int i; 4338 4339 if (fr1->fr_cksum != fr2->fr_cksum) 4340 return (1); 4341 if (fr1->fr_size != fr2->fr_size) 4342 return (2); 4343 if (fr1->fr_dsize != fr2->fr_dsize) 4344 return (3); 4345 if (bcmp((char *)&fr1->fr_func, (char *)&fr2->fr_func, FR_CMPSIZ) 4346 != 0) 4347 return (4); 4348 /* 4349 * XXX: There is still a bug here as different rules with the 4350 * the same interfaces but in a different order will compare 4351 * differently. But since multiple interfaces in a rule doesn't 4352 * work anyway a simple straightforward compare is performed 4353 * here. Ultimately frentry_t creation will need to be 4354 * revisited in ipf_y.y. While the other issue, recognition 4355 * of only the first interface in a list of interfaces will 4356 * need to be separately addressed along with why only four. 4357 */ 4358 for (i = 0; i < FR_NUM(fr1->fr_ifnames); i++) { 4359 /* 4360 * XXX: It's either the same index or uninitialized. 4361 * We assume this because multiple interfaces 4362 * referenced by the same rule doesn't work anyway. 4363 */ 4364 if (IPF_IFNAMES_DIFFERENT(fr_ifnames[i])) 4365 return (5); 4366 } 4367 4368 if (IPF_FRDEST_DIFFERENT(fr_tif)) 4369 return (6); 4370 if (IPF_FRDEST_DIFFERENT(fr_rif)) 4371 return (7); 4372 if (IPF_FRDEST_DIFFERENT(fr_dif)) 4373 return (8); 4374 if (!fr1->fr_data && !fr2->fr_data) 4375 return (0); /* move along, nothing to see here */ 4376 if (fr1->fr_data && fr2->fr_data) { 4377 if (bcmp(fr1->fr_caddr, fr2->fr_caddr, fr1->fr_dsize) == 0) 4378 return (0); /* same */ 4379 } 4380 return (9); 4381} 4382 4383 4384/* ------------------------------------------------------------------------ */ 4385/* Function: frrequest */ 4386/* Returns: int - 0 == success, > 0 == errno value */ 4387/* Parameters: unit(I) - device for which this is for */ 4388/* req(I) - ioctl command (SIOC*) */ 4389/* data(I) - pointr to ioctl data */ 4390/* set(I) - 1 or 0 (filter set) */ 4391/* makecopy(I) - flag indicating whether data points to a rule */ 4392/* in kernel space & hence doesn't need copying. */ 4393/* */ 4394/* This function handles all the requests which operate on the list of */ 4395/* filter rules. This includes adding, deleting, insertion. It is also */ 4396/* responsible for creating groups when a "head" rule is loaded. Interface */ 4397/* names are resolved here and other sanity checks are made on the content */ 4398/* of the rule structure being loaded. If a rule has user defined timeouts */ 4399/* then make sure they are created and initialised before exiting. */ 4400/* ------------------------------------------------------------------------ */ 4401int 4402frrequest(ipf_main_softc_t *softc, int unit, ioctlcmd_t req, caddr_t data, 4403 int set, int makecopy) 4404{ 4405 int error = 0, in, family, need_free = 0; 4406 enum { OP_ADD, /* add rule */ 4407 OP_REM, /* remove rule */ 4408 OP_ZERO /* zero statistics and counters */ } 4409 addrem = OP_ADD; 4410 frentry_t frd, *fp, *f, **fprev, **ftail; 4411 void *ptr, *uptr, *cptr; 4412 u_int *p, *pp; 4413 frgroup_t *fg; 4414 char *group; 4415 4416 ptr = NULL; 4417 cptr = NULL; 4418 fg = NULL; 4419 fp = &frd; 4420 if (makecopy != 0) { 4421 bzero(fp, sizeof(frd)); 4422 error = ipf_inobj(softc, data, NULL, fp, IPFOBJ_FRENTRY); 4423 if (error) { 4424 return (error); 4425 } 4426 if ((fp->fr_type & FR_T_BUILTIN) != 0) { 4427 IPFERROR(6); 4428 return (EINVAL); 4429 } 4430 KMALLOCS(f, frentry_t *, fp->fr_size); 4431 if (f == NULL) { 4432 IPFERROR(131); 4433 return (ENOMEM); 4434 } 4435 bzero(f, fp->fr_size); 4436 error = ipf_inobjsz(softc, data, f, IPFOBJ_FRENTRY, 4437 fp->fr_size); 4438 if (error) { 4439 KFREES(f, fp->fr_size); 4440 return (error); 4441 } 4442 4443 fp = f; 4444 f = NULL; 4445 fp->fr_next = NULL; 4446 fp->fr_dnext = NULL; 4447 fp->fr_pnext = NULL; 4448 fp->fr_pdnext = NULL; 4449 fp->fr_grp = NULL; 4450 fp->fr_grphead = NULL; 4451 fp->fr_icmpgrp = NULL; 4452 fp->fr_isc = (void *)-1; 4453 fp->fr_ptr = NULL; 4454 fp->fr_ref = 0; 4455 fp->fr_flags |= FR_COPIED; 4456 } else { 4457 fp = (frentry_t *)data; 4458 if ((fp->fr_type & FR_T_BUILTIN) == 0) { 4459 IPFERROR(7); 4460 return (EINVAL); 4461 } 4462 fp->fr_flags &= ~FR_COPIED; 4463 } 4464 4465 if (((fp->fr_dsize == 0) && (fp->fr_data != NULL)) || 4466 ((fp->fr_dsize != 0) && (fp->fr_data == NULL))) { 4467 IPFERROR(8); 4468 error = EINVAL; 4469 goto donenolock; 4470 } 4471 4472 family = fp->fr_family; 4473 uptr = fp->fr_data; 4474 4475 if (req == (ioctlcmd_t)SIOCINAFR || req == (ioctlcmd_t)SIOCINIFR || 4476 req == (ioctlcmd_t)SIOCADAFR || req == (ioctlcmd_t)SIOCADIFR) 4477 addrem = OP_ADD; /* Add rule */ 4478 else if (req == (ioctlcmd_t)SIOCRMAFR || req == (ioctlcmd_t)SIOCRMIFR) 4479 addrem = OP_REM; /* Remove rule */ 4480 else if (req == (ioctlcmd_t)SIOCZRLST) 4481 addrem = OP_ZERO; /* Zero statistics and counters */ 4482 else { 4483 IPFERROR(9); 4484 error = EINVAL; 4485 goto donenolock; 4486 } 4487 4488 /* 4489 * Only filter rules for IPv4 or IPv6 are accepted. 4490 */ 4491 if (family == AF_INET) { 4492 /*EMPTY*/; 4493#ifdef USE_INET6 4494 } else if (family == AF_INET6) { 4495 /*EMPTY*/; 4496#endif 4497 } else if (family != 0) { 4498 IPFERROR(10); 4499 error = EINVAL; 4500 goto donenolock; 4501 } 4502 4503 /* 4504 * If the rule is being loaded from user space, i.e. we had to copy it 4505 * into kernel space, then do not trust the function pointer in the 4506 * rule. 4507 */ 4508 if ((makecopy == 1) && (fp->fr_func != NULL)) { 4509 if (ipf_findfunc(fp->fr_func) == NULL) { 4510 IPFERROR(11); 4511 error = ESRCH; 4512 goto donenolock; 4513 } 4514 4515 if (addrem == OP_ADD) { 4516 error = ipf_funcinit(softc, fp); 4517 if (error != 0) 4518 goto donenolock; 4519 } 4520 } 4521 if ((fp->fr_flags & FR_CALLNOW) && 4522 ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) { 4523 IPFERROR(142); 4524 error = ESRCH; 4525 goto donenolock; 4526 } 4527 if (((fp->fr_flags & FR_CMDMASK) == FR_CALL) && 4528 ((fp->fr_func == NULL) || (fp->fr_func == (ipfunc_t)-1))) { 4529 IPFERROR(143); 4530 error = ESRCH; 4531 goto donenolock; 4532 } 4533 4534 ptr = NULL; 4535 cptr = NULL; 4536 4537 if (FR_ISACCOUNT(fp->fr_flags)) 4538 unit = IPL_LOGCOUNT; 4539 4540 /* 4541 * Check that each group name in the rule has a start index that 4542 * is valid. 4543 */ 4544 if (fp->fr_icmphead != -1) { 4545 if ((fp->fr_icmphead < 0) || 4546 (fp->fr_icmphead >= fp->fr_namelen)) { 4547 IPFERROR(136); 4548 error = EINVAL; 4549 goto donenolock; 4550 } 4551 if (!strcmp(FR_NAME(fp, fr_icmphead), "0")) 4552 fp->fr_names[fp->fr_icmphead] = '\0'; 4553 } 4554 4555 if (fp->fr_grhead != -1) { 4556 if ((fp->fr_grhead < 0) || 4557 (fp->fr_grhead >= fp->fr_namelen)) { 4558 IPFERROR(137); 4559 error = EINVAL; 4560 goto donenolock; 4561 } 4562 if (!strcmp(FR_NAME(fp, fr_grhead), "0")) 4563 fp->fr_names[fp->fr_grhead] = '\0'; 4564 } 4565 4566 if (fp->fr_group != -1) { 4567 if ((fp->fr_group < 0) || 4568 (fp->fr_group >= fp->fr_namelen)) { 4569 IPFERROR(138); 4570 error = EINVAL; 4571 goto donenolock; 4572 } 4573 if ((req != (int)SIOCZRLST) && (fp->fr_group != -1)) { 4574 /* 4575 * Allow loading rules that are in groups to cause 4576 * them to be created if they don't already exit. 4577 */ 4578 group = FR_NAME(fp, fr_group); 4579 if (addrem == OP_ADD) { 4580 fg = ipf_group_add(softc, group, NULL, 4581 fp->fr_flags, unit, set); 4582 fp->fr_grp = fg; 4583 } else { 4584 fg = ipf_findgroup(softc, group, unit, 4585 set, NULL); 4586 if (fg == NULL) { 4587 IPFERROR(12); 4588 error = ESRCH; 4589 goto donenolock; 4590 } 4591 } 4592 4593 if (fg->fg_flags == 0) { 4594 fg->fg_flags = fp->fr_flags & FR_INOUT; 4595 } else if (fg->fg_flags != (fp->fr_flags & FR_INOUT)) { 4596 IPFERROR(13); 4597 error = ESRCH; 4598 goto donenolock; 4599 } 4600 } 4601 } else { 4602 /* 4603 * If a rule is going to be part of a group then it does 4604 * not matter whether it is an in or out rule, but if it 4605 * isn't in a group, then it does... 4606 */ 4607 if ((fp->fr_flags & (FR_INQUE|FR_OUTQUE)) == 0) { 4608 IPFERROR(14); 4609 error = EINVAL; 4610 goto donenolock; 4611 } 4612 } 4613 in = (fp->fr_flags & FR_INQUE) ? 0 : 1; 4614 4615 /* 4616 * Work out which rule list this change is being applied to. 4617 */ 4618 ftail = NULL; 4619 fprev = NULL; 4620 if (unit == IPL_LOGAUTH) { 4621 if ((fp->fr_tifs[0].fd_ptr != NULL) || 4622 (fp->fr_tifs[1].fd_ptr != NULL) || 4623 (fp->fr_dif.fd_ptr != NULL) || 4624 (fp->fr_flags & FR_FASTROUTE)) { 4625 softc->ipf_interror = 145; 4626 error = EINVAL; 4627 goto donenolock; 4628 } 4629 fprev = ipf_auth_rulehead(softc); 4630 } else { 4631 if (FR_ISACCOUNT(fp->fr_flags)) 4632 fprev = &softc->ipf_acct[in][set]; 4633 else if ((fp->fr_flags & (FR_OUTQUE|FR_INQUE)) != 0) 4634 fprev = &softc->ipf_rules[in][set]; 4635 } 4636 if (fprev == NULL) { 4637 IPFERROR(15); 4638 error = ESRCH; 4639 goto donenolock; 4640 } 4641 4642 if (fg != NULL) 4643 fprev = &fg->fg_start; 4644 4645 /* 4646 * Copy in extra data for the rule. 4647 */ 4648 if (fp->fr_dsize != 0) { 4649 if (makecopy != 0) { 4650 KMALLOCS(ptr, void *, fp->fr_dsize); 4651 if (ptr == NULL) { 4652 IPFERROR(16); 4653 error = ENOMEM; 4654 goto donenolock; 4655 } 4656 4657 /* 4658 * The bcopy case is for when the data is appended 4659 * to the rule by ipf_in_compat(). 4660 */ 4661 if (uptr >= (void *)fp && 4662 uptr < (void *)((char *)fp + fp->fr_size)) { 4663 bcopy(uptr, ptr, fp->fr_dsize); 4664 error = 0; 4665 } else { 4666 error = COPYIN(uptr, ptr, fp->fr_dsize); 4667 if (error != 0) { 4668 IPFERROR(17); 4669 error = EFAULT; 4670 goto donenolock; 4671 } 4672 } 4673 } else { 4674 ptr = uptr; 4675 } 4676 fp->fr_data = ptr; 4677 } else { 4678 fp->fr_data = NULL; 4679 } 4680 4681 /* 4682 * Perform per-rule type sanity checks of their members. 4683 * All code after this needs to be aware that allocated memory 4684 * may need to be free'd before exiting. 4685 */ 4686 switch (fp->fr_type & ~FR_T_BUILTIN) 4687 { 4688#if defined(IPFILTER_BPF) 4689 case FR_T_BPFOPC : 4690 if (fp->fr_dsize == 0) { 4691 IPFERROR(19); 4692 error = EINVAL; 4693 break; 4694 } 4695 if (!bpf_validate(ptr, fp->fr_dsize/sizeof(struct bpf_insn))) { 4696 IPFERROR(20); 4697 error = EINVAL; 4698 break; 4699 } 4700 break; 4701#endif 4702 case FR_T_IPF : 4703 /* 4704 * Preparation for error case at the bottom of this function. 4705 */ 4706 if (fp->fr_datype == FRI_LOOKUP) 4707 fp->fr_dstptr = NULL; 4708 if (fp->fr_satype == FRI_LOOKUP) 4709 fp->fr_srcptr = NULL; 4710 4711 if (fp->fr_dsize != sizeof(fripf_t)) { 4712 IPFERROR(21); 4713 error = EINVAL; 4714 break; 4715 } 4716 4717 /* 4718 * Allowing a rule with both "keep state" and "with oow" is 4719 * pointless because adding a state entry to the table will 4720 * fail with the out of window (oow) flag set. 4721 */ 4722 if ((fp->fr_flags & FR_KEEPSTATE) && (fp->fr_flx & FI_OOW)) { 4723 IPFERROR(22); 4724 error = EINVAL; 4725 break; 4726 } 4727 4728 switch (fp->fr_satype) 4729 { 4730 case FRI_BROADCAST : 4731 case FRI_DYNAMIC : 4732 case FRI_NETWORK : 4733 case FRI_NETMASKED : 4734 case FRI_PEERADDR : 4735 if (fp->fr_sifpidx < 0) { 4736 IPFERROR(23); 4737 error = EINVAL; 4738 } 4739 break; 4740 case FRI_LOOKUP : 4741 fp->fr_srcptr = ipf_findlookup(softc, unit, fp, 4742 &fp->fr_src6, 4743 &fp->fr_smsk6); 4744 if (fp->fr_srcfunc == NULL) { 4745 IPFERROR(132); 4746 error = ESRCH; 4747 break; 4748 } 4749 break; 4750 case FRI_NORMAL : 4751 break; 4752 default : 4753 IPFERROR(133); 4754 error = EINVAL; 4755 break; 4756 } 4757 if (error != 0) 4758 break; 4759 4760 switch (fp->fr_datype) 4761 { 4762 case FRI_BROADCAST : 4763 case FRI_DYNAMIC : 4764 case FRI_NETWORK : 4765 case FRI_NETMASKED : 4766 case FRI_PEERADDR : 4767 if (fp->fr_difpidx < 0) { 4768 IPFERROR(24); 4769 error = EINVAL; 4770 } 4771 break; 4772 case FRI_LOOKUP : 4773 fp->fr_dstptr = ipf_findlookup(softc, unit, fp, 4774 &fp->fr_dst6, 4775 &fp->fr_dmsk6); 4776 if (fp->fr_dstfunc == NULL) { 4777 IPFERROR(134); 4778 error = ESRCH; 4779 } 4780 break; 4781 case FRI_NORMAL : 4782 break; 4783 default : 4784 IPFERROR(135); 4785 error = EINVAL; 4786 } 4787 break; 4788 4789 case FR_T_NONE : 4790 case FR_T_CALLFUNC : 4791 case FR_T_COMPIPF : 4792 break; 4793 4794 case FR_T_IPFEXPR : 4795 if (ipf_matcharray_verify(fp->fr_data, fp->fr_dsize) == -1) { 4796 IPFERROR(25); 4797 error = EINVAL; 4798 } 4799 break; 4800 4801 default : 4802 IPFERROR(26); 4803 error = EINVAL; 4804 break; 4805 } 4806 if (error != 0) 4807 goto donenolock; 4808 4809 if (fp->fr_tif.fd_name != -1) { 4810 if ((fp->fr_tif.fd_name < 0) || 4811 (fp->fr_tif.fd_name >= fp->fr_namelen)) { 4812 IPFERROR(139); 4813 error = EINVAL; 4814 goto donenolock; 4815 } 4816 } 4817 4818 if (fp->fr_dif.fd_name != -1) { 4819 if ((fp->fr_dif.fd_name < 0) || 4820 (fp->fr_dif.fd_name >= fp->fr_namelen)) { 4821 IPFERROR(140); 4822 error = EINVAL; 4823 goto donenolock; 4824 } 4825 } 4826 4827 if (fp->fr_rif.fd_name != -1) { 4828 if ((fp->fr_rif.fd_name < 0) || 4829 (fp->fr_rif.fd_name >= fp->fr_namelen)) { 4830 IPFERROR(141); 4831 error = EINVAL; 4832 goto donenolock; 4833 } 4834 } 4835 4836 /* 4837 * Lookup all the interface names that are part of the rule. 4838 */ 4839 error = ipf_synclist(softc, fp, NULL); 4840 if (error != 0) 4841 goto donenolock; 4842 fp->fr_statecnt = 0; 4843 if (fp->fr_srctrack.ht_max_nodes != 0) 4844 ipf_rb_ht_init(&fp->fr_srctrack); 4845 4846 /* 4847 * Look for an existing matching filter rule, but don't include the 4848 * next or interface pointer in the comparison (fr_next, fr_ifa). 4849 * This elminates rules which are indentical being loaded. Checksum 4850 * the constant part of the filter rule to make comparisons quicker 4851 * (this meaning no pointers are included). 4852 */ 4853 pp = (u_int *)(fp->fr_caddr + fp->fr_dsize); 4854 for (fp->fr_cksum = 0, p = (u_int *)fp->fr_data; p < pp; p++) 4855 fp->fr_cksum += *p; 4856 4857 WRITE_ENTER(&softc->ipf_mutex); 4858 4859 /* 4860 * Now that the filter rule lists are locked, we can walk the 4861 * chain of them without fear. 4862 */ 4863 ftail = fprev; 4864 for (f = *ftail; (f = *ftail) != NULL; ftail = &f->fr_next) { 4865 if (fp->fr_collect <= f->fr_collect) { 4866 ftail = fprev; 4867 f = NULL; 4868 break; 4869 } 4870 fprev = ftail; 4871 } 4872 4873 for (; (f = *ftail) != NULL; ftail = &f->fr_next) { 4874 if (ipf_rule_compare(fp, f) == 0) 4875 break; 4876 } 4877 4878 /* 4879 * If zero'ing statistics, copy current to caller and zero. 4880 */ 4881 if (addrem == OP_ZERO) { 4882 if (f == NULL) { 4883 IPFERROR(27); 4884 error = ESRCH; 4885 } else { 4886 /* 4887 * Copy and reduce lock because of impending copyout. 4888 * Well we should, but if we do then the atomicity of 4889 * this call and the correctness of fr_hits and 4890 * fr_bytes cannot be guaranteed. As it is, this code 4891 * only resets them to 0 if they are successfully 4892 * copied out into user space. 4893 */ 4894 bcopy((char *)f, (char *)fp, f->fr_size); 4895 /* MUTEX_DOWNGRADE(&softc->ipf_mutex); */ 4896 4897 /* 4898 * When we copy this rule back out, set the data 4899 * pointer to be what it was in user space. 4900 */ 4901 fp->fr_data = uptr; 4902 error = ipf_outobj(softc, data, fp, IPFOBJ_FRENTRY); 4903 4904 if (error == 0) { 4905 if ((f->fr_dsize != 0) && (uptr != NULL)) { 4906 error = COPYOUT(f->fr_data, uptr, 4907 f->fr_dsize); 4908 if (error == 0) { 4909 f->fr_hits = 0; 4910 f->fr_bytes = 0; 4911 } else { 4912 IPFERROR(28); 4913 error = EFAULT; 4914 } 4915 } 4916 } 4917 } 4918 4919 if (makecopy != 0) { 4920 if (ptr != NULL) { 4921 KFREES(ptr, fp->fr_dsize); 4922 } 4923 KFREES(fp, fp->fr_size); 4924 } 4925 RWLOCK_EXIT(&softc->ipf_mutex); 4926 return (error); 4927 } 4928 4929 if (f == NULL) { 4930 /* 4931 * At the end of this, ftail must point to the place where the 4932 * new rule is to be saved/inserted/added. 4933 * For SIOCAD*FR, this should be the last rule in the group of 4934 * rules that have equal fr_collect fields. 4935 * For SIOCIN*FR, ... 4936 */ 4937 if (req == (ioctlcmd_t)SIOCADAFR || 4938 req == (ioctlcmd_t)SIOCADIFR) { 4939 4940 for (ftail = fprev; (f = *ftail) != NULL; ) { 4941 if (f->fr_collect > fp->fr_collect) 4942 break; 4943 ftail = &f->fr_next; 4944 fprev = ftail; 4945 } 4946 ftail = fprev; 4947 f = NULL; 4948 ptr = NULL; 4949 } else if (req == (ioctlcmd_t)SIOCINAFR || 4950 req == (ioctlcmd_t)SIOCINIFR) { 4951 while ((f = *fprev) != NULL) { 4952 if (f->fr_collect >= fp->fr_collect) 4953 break; 4954 fprev = &f->fr_next; 4955 } 4956 ftail = fprev; 4957 if (fp->fr_hits != 0) { 4958 while (fp->fr_hits && (f = *ftail)) { 4959 if (f->fr_collect != fp->fr_collect) 4960 break; 4961 fprev = ftail; 4962 ftail = &f->fr_next; 4963 fp->fr_hits--; 4964 } 4965 } 4966 f = NULL; 4967 ptr = NULL; 4968 } 4969 } 4970 4971 /* 4972 * Request to remove a rule. 4973 */ 4974 if (addrem == OP_REM) { 4975 if (f == NULL) { 4976 IPFERROR(29); 4977 error = ESRCH; 4978 } else { 4979 /* 4980 * Do not allow activity from user space to interfere 4981 * with rules not loaded that way. 4982 */ 4983 if ((makecopy == 1) && !(f->fr_flags & FR_COPIED)) { 4984 IPFERROR(30); 4985 error = EPERM; 4986 goto done; 4987 } 4988 4989 /* 4990 * Return EBUSY if the rule is being reference by 4991 * something else (eg state information.) 4992 */ 4993 if (f->fr_ref > 1) { 4994 IPFERROR(31); 4995 error = EBUSY; 4996 goto done; 4997 } 4998#ifdef IPFILTER_SCAN 4999 if (f->fr_isctag != -1 && 5000 (f->fr_isc != (struct ipscan *)-1)) 5001 ipf_scan_detachfr(f); 5002#endif 5003 5004 if (unit == IPL_LOGAUTH) { 5005 error = ipf_auth_precmd(softc, req, f, ftail); 5006 goto done; 5007 } 5008 5009 ipf_rule_delete(softc, f, unit, set); 5010 5011 need_free = makecopy; 5012 } 5013 } else { 5014 /* 5015 * Not removing, so we must be adding/inserting a rule. 5016 */ 5017 if (f != NULL) { 5018 IPFERROR(32); 5019 error = EEXIST; 5020 goto done; 5021 } 5022 if (unit == IPL_LOGAUTH) { 5023 error = ipf_auth_precmd(softc, req, fp, ftail); 5024 goto done; 5025 } 5026 5027 MUTEX_NUKE(&fp->fr_lock); 5028 MUTEX_INIT(&fp->fr_lock, "filter rule lock"); 5029 if (fp->fr_die != 0) 5030 ipf_rule_expire_insert(softc, fp, set); 5031 5032 fp->fr_hits = 0; 5033 if (makecopy != 0) 5034 fp->fr_ref = 1; 5035 fp->fr_pnext = ftail; 5036 fp->fr_next = *ftail; 5037 if (fp->fr_next != NULL) 5038 fp->fr_next->fr_pnext = &fp->fr_next; 5039 *ftail = fp; 5040 ipf_fixskip(ftail, fp, 1); 5041 5042 fp->fr_icmpgrp = NULL; 5043 if (fp->fr_icmphead != -1) { 5044 group = FR_NAME(fp, fr_icmphead); 5045 fg = ipf_group_add(softc, group, fp, 0, unit, set); 5046 fp->fr_icmpgrp = fg; 5047 } 5048 5049 fp->fr_grphead = NULL; 5050 if (fp->fr_grhead != -1) { 5051 group = FR_NAME(fp, fr_grhead); 5052 fg = ipf_group_add(softc, group, fp, fp->fr_flags, 5053 unit, set); 5054 fp->fr_grphead = fg; 5055 } 5056 } 5057done: 5058 RWLOCK_EXIT(&softc->ipf_mutex); 5059donenolock: 5060 if (need_free || (error != 0)) { 5061 if ((fp->fr_type & ~FR_T_BUILTIN) == FR_T_IPF) { 5062 if ((fp->fr_satype == FRI_LOOKUP) && 5063 (fp->fr_srcptr != NULL)) 5064 ipf_lookup_deref(softc, fp->fr_srctype, 5065 fp->fr_srcptr); 5066 if ((fp->fr_datype == FRI_LOOKUP) && 5067 (fp->fr_dstptr != NULL)) 5068 ipf_lookup_deref(softc, fp->fr_dsttype, 5069 fp->fr_dstptr); 5070 } 5071 if (fp->fr_grp != NULL) { 5072 WRITE_ENTER(&softc->ipf_mutex); 5073 ipf_group_del(softc, fp->fr_grp, fp); 5074 RWLOCK_EXIT(&softc->ipf_mutex); 5075 } 5076 if ((ptr != NULL) && (makecopy != 0)) { 5077 KFREES(ptr, fp->fr_dsize); 5078 } 5079 KFREES(fp, fp->fr_size); 5080 } 5081 return (error); 5082} 5083 5084 5085/* ------------------------------------------------------------------------ */ 5086/* Function: ipf_rule_delete */ 5087/* Returns: Nil */ 5088/* Parameters: softc(I) - pointer to soft context main structure */ 5089/* f(I) - pointer to the rule being deleted */ 5090/* ftail(I) - pointer to the pointer to f */ 5091/* unit(I) - device for which this is for */ 5092/* set(I) - 1 or 0 (filter set) */ 5093/* */ 5094/* This function attempts to do what it can to delete a filter rule: remove */ 5095/* it from any linked lists and remove any groups it is responsible for. */ 5096/* But in the end, removing a rule can only drop the reference count - we */ 5097/* must use that as the guide for whether or not it can be freed. */ 5098/* ------------------------------------------------------------------------ */ 5099static void 5100ipf_rule_delete(ipf_main_softc_t *softc, frentry_t *f, int unit, int set) 5101{ 5102 5103 /* 5104 * If fr_pdnext is set, then the rule is on the expire list, so 5105 * remove it from there. 5106 */ 5107 if (f->fr_pdnext != NULL) { 5108 *f->fr_pdnext = f->fr_dnext; 5109 if (f->fr_dnext != NULL) 5110 f->fr_dnext->fr_pdnext = f->fr_pdnext; 5111 f->fr_pdnext = NULL; 5112 f->fr_dnext = NULL; 5113 } 5114 5115 ipf_fixskip(f->fr_pnext, f, -1); 5116 if (f->fr_pnext != NULL) 5117 *f->fr_pnext = f->fr_next; 5118 if (f->fr_next != NULL) 5119 f->fr_next->fr_pnext = f->fr_pnext; 5120 f->fr_pnext = NULL; 5121 f->fr_next = NULL; 5122 5123 (void) ipf_derefrule(softc, &f); 5124} 5125 5126/* ------------------------------------------------------------------------ */ 5127/* Function: ipf_rule_expire_insert */ 5128/* Returns: Nil */ 5129/* Parameters: softc(I) - pointer to soft context main structure */ 5130/* f(I) - pointer to rule to be added to expire list */ 5131/* set(I) - 1 or 0 (filter set) */ 5132/* */ 5133/* If the new rule has a given expiration time, insert it into the list of */ 5134/* expiring rules with the ones to be removed first added to the front of */ 5135/* the list. The insertion is O(n) but it is kept sorted for quick scans at */ 5136/* expiration interval checks. */ 5137/* ------------------------------------------------------------------------ */ 5138static void 5139ipf_rule_expire_insert(ipf_main_softc_t *softc, frentry_t *f, int set) 5140{ 5141 frentry_t *fr; 5142 5143 /* 5144 */ 5145 5146 f->fr_die = softc->ipf_ticks + IPF_TTLVAL(f->fr_die); 5147 for (fr = softc->ipf_rule_explist[set]; fr != NULL; 5148 fr = fr->fr_dnext) { 5149 if (f->fr_die < fr->fr_die) 5150 break; 5151 if (fr->fr_dnext == NULL) { 5152 /* 5153 * We've got to the last rule and everything 5154 * wanted to be expired before this new node, 5155 * so we have to tack it on the end... 5156 */ 5157 fr->fr_dnext = f; 5158 f->fr_pdnext = &fr->fr_dnext; 5159 fr = NULL; 5160 break; 5161 } 5162 } 5163 5164 if (softc->ipf_rule_explist[set] == NULL) { 5165 softc->ipf_rule_explist[set] = f; 5166 f->fr_pdnext = &softc->ipf_rule_explist[set]; 5167 } else if (fr != NULL) { 5168 f->fr_dnext = fr; 5169 f->fr_pdnext = fr->fr_pdnext; 5170 fr->fr_pdnext = &f->fr_dnext; 5171 } 5172} 5173 5174 5175/* ------------------------------------------------------------------------ */ 5176/* Function: ipf_findlookup */ 5177/* Returns: NULL = failure, else success */ 5178/* Parameters: softc(I) - pointer to soft context main structure */ 5179/* unit(I) - ipf device we want to find match for */ 5180/* fp(I) - rule for which lookup is for */ 5181/* addrp(I) - pointer to lookup information in address struct */ 5182/* maskp(O) - pointer to lookup information for storage */ 5183/* */ 5184/* When using pools and hash tables to store addresses for matching in */ 5185/* rules, it is necessary to resolve both the object referred to by the */ 5186/* name or address (and return that pointer) and also provide the means by */ 5187/* which to determine if an address belongs to that object to make the */ 5188/* packet matching quicker. */ 5189/* ------------------------------------------------------------------------ */ 5190static void * 5191ipf_findlookup(ipf_main_softc_t *softc, int unit, frentry_t *fr, 5192 i6addr_t *addrp, i6addr_t *maskp) 5193{ 5194 void *ptr = NULL; 5195 5196 switch (addrp->iplookupsubtype) 5197 { 5198 case 0 : 5199 ptr = ipf_lookup_res_num(softc, unit, addrp->iplookuptype, 5200 addrp->iplookupnum, 5201 &maskp->iplookupfunc); 5202 break; 5203 case 1 : 5204 if (addrp->iplookupname < 0) 5205 break; 5206 if (addrp->iplookupname >= fr->fr_namelen) 5207 break; 5208 ptr = ipf_lookup_res_name(softc, unit, addrp->iplookuptype, 5209 fr->fr_names + addrp->iplookupname, 5210 &maskp->iplookupfunc); 5211 break; 5212 default : 5213 break; 5214 } 5215 5216 return (ptr); 5217} 5218 5219 5220/* ------------------------------------------------------------------------ */ 5221/* Function: ipf_funcinit */ 5222/* Returns: int - 0 == success, else ESRCH: cannot resolve rule details */ 5223/* Parameters: softc(I) - pointer to soft context main structure */ 5224/* fr(I) - pointer to filter rule */ 5225/* */ 5226/* If a rule is a call rule, then check if the function it points to needs */ 5227/* an init function to be called now the rule has been loaded. */ 5228/* ------------------------------------------------------------------------ */ 5229static int 5230ipf_funcinit(ipf_main_softc_t *softc, frentry_t *fr) 5231{ 5232 ipfunc_resolve_t *ft; 5233 int err; 5234 5235 IPFERROR(34); 5236 err = ESRCH; 5237 5238 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5239 if (ft->ipfu_addr == fr->fr_func) { 5240 err = 0; 5241 if (ft->ipfu_init != NULL) 5242 err = (*ft->ipfu_init)(softc, fr); 5243 break; 5244 } 5245 return (err); 5246} 5247 5248 5249/* ------------------------------------------------------------------------ */ 5250/* Function: ipf_funcfini */ 5251/* Returns: Nil */ 5252/* Parameters: softc(I) - pointer to soft context main structure */ 5253/* fr(I) - pointer to filter rule */ 5254/* */ 5255/* For a given filter rule, call the matching "fini" function if the rule */ 5256/* is using a known function that would have resulted in the "init" being */ 5257/* called for ealier. */ 5258/* ------------------------------------------------------------------------ */ 5259static void 5260ipf_funcfini(ipf_main_softc_t *softc, frentry_t *fr) 5261{ 5262 ipfunc_resolve_t *ft; 5263 5264 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5265 if (ft->ipfu_addr == fr->fr_func) { 5266 if (ft->ipfu_fini != NULL) 5267 (void) (*ft->ipfu_fini)(softc, fr); 5268 break; 5269 } 5270} 5271 5272 5273/* ------------------------------------------------------------------------ */ 5274/* Function: ipf_findfunc */ 5275/* Returns: ipfunc_t - pointer to function if found, else NULL */ 5276/* Parameters: funcptr(I) - function pointer to lookup */ 5277/* */ 5278/* Look for a function in the table of known functions. */ 5279/* ------------------------------------------------------------------------ */ 5280static ipfunc_t 5281ipf_findfunc(ipfunc_t funcptr) 5282{ 5283 ipfunc_resolve_t *ft; 5284 5285 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5286 if (ft->ipfu_addr == funcptr) 5287 return (funcptr); 5288 return (NULL); 5289} 5290 5291 5292/* ------------------------------------------------------------------------ */ 5293/* Function: ipf_resolvefunc */ 5294/* Returns: int - 0 == success, else error */ 5295/* Parameters: data(IO) - ioctl data pointer to ipfunc_resolve_t struct */ 5296/* */ 5297/* Copy in a ipfunc_resolve_t structure and then fill in the missing field. */ 5298/* This will either be the function name (if the pointer is set) or the */ 5299/* function pointer if the name is set. When found, fill in the other one */ 5300/* so that the entire, complete, structure can be copied back to user space.*/ 5301/* ------------------------------------------------------------------------ */ 5302int 5303ipf_resolvefunc(ipf_main_softc_t *softc, void *data) 5304{ 5305 ipfunc_resolve_t res, *ft; 5306 int error; 5307 5308 error = BCOPYIN(data, &res, sizeof(res)); 5309 if (error != 0) { 5310 IPFERROR(123); 5311 return (EFAULT); 5312 } 5313 5314 if (res.ipfu_addr == NULL && res.ipfu_name[0] != '\0') { 5315 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5316 if (strncmp(res.ipfu_name, ft->ipfu_name, 5317 sizeof(res.ipfu_name)) == 0) { 5318 res.ipfu_addr = ft->ipfu_addr; 5319 res.ipfu_init = ft->ipfu_init; 5320 if (COPYOUT(&res, data, sizeof(res)) != 0) { 5321 IPFERROR(35); 5322 return (EFAULT); 5323 } 5324 return (0); 5325 } 5326 } 5327 if (res.ipfu_addr != NULL && res.ipfu_name[0] == '\0') { 5328 for (ft = ipf_availfuncs; ft->ipfu_addr != NULL; ft++) 5329 if (ft->ipfu_addr == res.ipfu_addr) { 5330 (void) strncpy(res.ipfu_name, ft->ipfu_name, 5331 sizeof(res.ipfu_name)); 5332 res.ipfu_init = ft->ipfu_init; 5333 if (COPYOUT(&res, data, sizeof(res)) != 0) { 5334 IPFERROR(36); 5335 return (EFAULT); 5336 } 5337 return (0); 5338 } 5339 } 5340 IPFERROR(37); 5341 return (ESRCH); 5342} 5343 5344 5345#if !defined(_KERNEL) || SOLARIS 5346/* 5347 * From: NetBSD 5348 * ppsratecheck(): packets (or events) per second limitation. 5349 */ 5350int 5351ppsratecheck(struct timeval *lasttime, int *curpps, int maxpps) 5352 /* maxpps: maximum pps allowed */ 5353{ 5354 struct timeval tv, delta; 5355 int rv; 5356 5357 GETKTIME(&tv); 5358 5359 delta.tv_sec = tv.tv_sec - lasttime->tv_sec; 5360 delta.tv_usec = tv.tv_usec - lasttime->tv_usec; 5361 if (delta.tv_usec < 0) { 5362 delta.tv_sec--; 5363 delta.tv_usec += 1000000; 5364 } 5365 5366 /* 5367 * check for 0,0 is so that the message will be seen at least once. 5368 * if more than one second have passed since the last update of 5369 * lasttime, reset the counter. 5370 * 5371 * we do increment *curpps even in *curpps < maxpps case, as some may 5372 * try to use *curpps for stat purposes as well. 5373 */ 5374 if ((lasttime->tv_sec == 0 && lasttime->tv_usec == 0) || 5375 delta.tv_sec >= 1) { 5376 *lasttime = tv; 5377 *curpps = 0; 5378 rv = 1; 5379 } else if (maxpps < 0) 5380 rv = 1; 5381 else if (*curpps < maxpps) 5382 rv = 1; 5383 else 5384 rv = 0; 5385 *curpps = *curpps + 1; 5386 5387 return (rv); 5388} 5389#endif 5390 5391 5392/* ------------------------------------------------------------------------ */ 5393/* Function: ipf_derefrule */ 5394/* Returns: int - 0 == rule freed up, else rule not freed */ 5395/* Parameters: fr(I) - pointer to filter rule */ 5396/* */ 5397/* Decrement the reference counter to a rule by one. If it reaches zero, */ 5398/* free it and any associated storage space being used by it. */ 5399/* ------------------------------------------------------------------------ */ 5400int 5401ipf_derefrule(ipf_main_softc_t *softc, frentry_t **frp) 5402{ 5403 frentry_t *fr; 5404 frdest_t *fdp; 5405 5406 fr = *frp; 5407 *frp = NULL; 5408 5409 MUTEX_ENTER(&fr->fr_lock); 5410 fr->fr_ref--; 5411 if (fr->fr_ref == 0) { 5412 MUTEX_EXIT(&fr->fr_lock); 5413 MUTEX_DESTROY(&fr->fr_lock); 5414 5415 ipf_funcfini(softc, fr); 5416 5417 fdp = &fr->fr_tif; 5418 if (fdp->fd_type == FRD_DSTLIST) 5419 ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr); 5420 5421 fdp = &fr->fr_rif; 5422 if (fdp->fd_type == FRD_DSTLIST) 5423 ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr); 5424 5425 fdp = &fr->fr_dif; 5426 if (fdp->fd_type == FRD_DSTLIST) 5427 ipf_lookup_deref(softc, IPLT_DSTLIST, fdp->fd_ptr); 5428 5429 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF && 5430 fr->fr_satype == FRI_LOOKUP) 5431 ipf_lookup_deref(softc, fr->fr_srctype, fr->fr_srcptr); 5432 if ((fr->fr_type & ~FR_T_BUILTIN) == FR_T_IPF && 5433 fr->fr_datype == FRI_LOOKUP) 5434 ipf_lookup_deref(softc, fr->fr_dsttype, fr->fr_dstptr); 5435 5436 if (fr->fr_grp != NULL) 5437 ipf_group_del(softc, fr->fr_grp, fr); 5438 5439 if (fr->fr_grphead != NULL) 5440 ipf_group_del(softc, fr->fr_grphead, fr); 5441 5442 if (fr->fr_icmpgrp != NULL) 5443 ipf_group_del(softc, fr->fr_icmpgrp, fr); 5444 5445 if ((fr->fr_flags & FR_COPIED) != 0) { 5446 if (fr->fr_dsize) { 5447 KFREES(fr->fr_data, fr->fr_dsize); 5448 } 5449 KFREES(fr, fr->fr_size); 5450 return (0); 5451 } 5452 return (1); 5453 } else { 5454 MUTEX_EXIT(&fr->fr_lock); 5455 } 5456 return (-1); 5457} 5458 5459 5460/* ------------------------------------------------------------------------ */ 5461/* Function: ipf_grpmapinit */ 5462/* Returns: int - 0 == success, else ESRCH because table entry not found*/ 5463/* Parameters: fr(I) - pointer to rule to find hash table for */ 5464/* */ 5465/* Looks for group hash table fr_arg and stores a pointer to it in fr_ptr. */ 5466/* fr_ptr is later used by ipf_srcgrpmap and ipf_dstgrpmap. */ 5467/* ------------------------------------------------------------------------ */ 5468static int 5469ipf_grpmapinit(ipf_main_softc_t *softc, frentry_t *fr) 5470{ 5471 char name[FR_GROUPLEN]; 5472 iphtable_t *iph; 5473 5474 (void) snprintf(name, sizeof(name), "%d", fr->fr_arg); 5475 iph = ipf_lookup_find_htable(softc, IPL_LOGIPF, name); 5476 if (iph == NULL) { 5477 IPFERROR(38); 5478 return (ESRCH); 5479 } 5480 if ((iph->iph_flags & FR_INOUT) != (fr->fr_flags & FR_INOUT)) { 5481 IPFERROR(39); 5482 return (ESRCH); 5483 } 5484 iph->iph_ref++; 5485 fr->fr_ptr = iph; 5486 return (0); 5487} 5488 5489 5490/* ------------------------------------------------------------------------ */ 5491/* Function: ipf_grpmapfini */ 5492/* Returns: int - 0 == success, else ESRCH because table entry not found*/ 5493/* Parameters: softc(I) - pointer to soft context main structure */ 5494/* fr(I) - pointer to rule to release hash table for */ 5495/* */ 5496/* For rules that have had ipf_grpmapinit called, ipf_lookup_deref needs to */ 5497/* be called to undo what ipf_grpmapinit caused to be done. */ 5498/* ------------------------------------------------------------------------ */ 5499static int 5500ipf_grpmapfini(ipf_main_softc_t *softc, frentry_t *fr) 5501{ 5502 iphtable_t *iph; 5503 iph = fr->fr_ptr; 5504 if (iph != NULL) 5505 ipf_lookup_deref(softc, IPLT_HASH, iph); 5506 return (0); 5507} 5508 5509 5510/* ------------------------------------------------------------------------ */ 5511/* Function: ipf_srcgrpmap */ 5512/* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ 5513/* Parameters: fin(I) - pointer to packet information */ 5514/* passp(IO) - pointer to current/new filter decision (unused) */ 5515/* */ 5516/* Look for a rule group head in a hash table, using the source address as */ 5517/* the key, and descend into that group and continue matching rules against */ 5518/* the packet. */ 5519/* ------------------------------------------------------------------------ */ 5520frentry_t * 5521ipf_srcgrpmap(fr_info_t *fin, u_32_t *passp) 5522{ 5523 frgroup_t *fg; 5524 void *rval; 5525 5526 rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr, 5527 &fin->fin_src); 5528 if (rval == NULL) 5529 return (NULL); 5530 5531 fg = rval; 5532 fin->fin_fr = fg->fg_start; 5533 (void) ipf_scanlist(fin, *passp); 5534 return (fin->fin_fr); 5535} 5536 5537 5538/* ------------------------------------------------------------------------ */ 5539/* Function: ipf_dstgrpmap */ 5540/* Returns: frentry_t * - pointer to "new last matching" rule or NULL */ 5541/* Parameters: fin(I) - pointer to packet information */ 5542/* passp(IO) - pointer to current/new filter decision (unused) */ 5543/* */ 5544/* Look for a rule group head in a hash table, using the destination */ 5545/* address as the key, and descend into that group and continue matching */ 5546/* rules against the packet. */ 5547/* ------------------------------------------------------------------------ */ 5548frentry_t * 5549ipf_dstgrpmap(fr_info_t *fin, u_32_t *passp) 5550{ 5551 frgroup_t *fg; 5552 void *rval; 5553 5554 rval = ipf_iphmfindgroup(fin->fin_main_soft, fin->fin_fr->fr_ptr, 5555 &fin->fin_dst); 5556 if (rval == NULL) 5557 return (NULL); 5558 5559 fg = rval; 5560 fin->fin_fr = fg->fg_start; 5561 (void) ipf_scanlist(fin, *passp); 5562 return (fin->fin_fr); 5563} 5564 5565/* 5566 * Queue functions 5567 * =============== 5568 * These functions manage objects on queues for efficient timeouts. There 5569 * are a number of system defined queues as well as user defined timeouts. 5570 * It is expected that a lock is held in the domain in which the queue 5571 * belongs (i.e. either state or NAT) when calling any of these functions 5572 * that prevents ipf_freetimeoutqueue() from being called at the same time 5573 * as any other. 5574 */ 5575 5576 5577/* ------------------------------------------------------------------------ */ 5578/* Function: ipf_addtimeoutqueue */ 5579/* Returns: struct ifqtq * - NULL if malloc fails, else pointer to */ 5580/* timeout queue with given interval. */ 5581/* Parameters: parent(I) - pointer to pointer to parent node of this list */ 5582/* of interface queues. */ 5583/* seconds(I) - timeout value in seconds for this queue. */ 5584/* */ 5585/* This routine first looks for a timeout queue that matches the interval */ 5586/* being requested. If it finds one, increments the reference counter and */ 5587/* returns a pointer to it. If none are found, it allocates a new one and */ 5588/* inserts it at the top of the list. */ 5589/* */ 5590/* Locking. */ 5591/* It is assumed that the caller of this function has an appropriate lock */ 5592/* held (exclusively) in the domain that encompases 'parent'. */ 5593/* ------------------------------------------------------------------------ */ 5594ipftq_t * 5595ipf_addtimeoutqueue(ipf_main_softc_t *softc, ipftq_t **parent, u_int seconds) 5596{ 5597 ipftq_t *ifq; 5598 u_int period; 5599 5600 period = seconds * IPF_HZ_DIVIDE; 5601 5602 MUTEX_ENTER(&softc->ipf_timeoutlock); 5603 for (ifq = *parent; ifq != NULL; ifq = ifq->ifq_next) { 5604 if (ifq->ifq_ttl == period) { 5605 /* 5606 * Reset the delete flag, if set, so the structure 5607 * gets reused rather than freed and reallocated. 5608 */ 5609 MUTEX_ENTER(&ifq->ifq_lock); 5610 ifq->ifq_flags &= ~IFQF_DELETE; 5611 ifq->ifq_ref++; 5612 MUTEX_EXIT(&ifq->ifq_lock); 5613 MUTEX_EXIT(&softc->ipf_timeoutlock); 5614 5615 return (ifq); 5616 } 5617 } 5618 5619 KMALLOC(ifq, ipftq_t *); 5620 if (ifq != NULL) { 5621 MUTEX_NUKE(&ifq->ifq_lock); 5622 IPFTQ_INIT(ifq, period, "ipftq mutex"); 5623 ifq->ifq_next = *parent; 5624 ifq->ifq_pnext = parent; 5625 ifq->ifq_flags = IFQF_USER; 5626 ifq->ifq_ref++; 5627 *parent = ifq; 5628 softc->ipf_userifqs++; 5629 } 5630 MUTEX_EXIT(&softc->ipf_timeoutlock); 5631 return (ifq); 5632} 5633 5634 5635/* ------------------------------------------------------------------------ */ 5636/* Function: ipf_deletetimeoutqueue */ 5637/* Returns: int - new reference count value of the timeout queue */ 5638/* Parameters: ifq(I) - timeout queue which is losing a reference. */ 5639/* Locks: ifq->ifq_lock */ 5640/* */ 5641/* This routine must be called when we're discarding a pointer to a timeout */ 5642/* queue object, taking care of the reference counter. */ 5643/* */ 5644/* Now that this just sets a DELETE flag, it requires the expire code to */ 5645/* check the list of user defined timeout queues and call the free function */ 5646/* below (currently commented out) to stop memory leaking. It is done this */ 5647/* way because the locking may not be sufficient to safely do a free when */ 5648/* this function is called. */ 5649/* ------------------------------------------------------------------------ */ 5650int 5651ipf_deletetimeoutqueue(ipftq_t *ifq) 5652{ 5653 5654 ifq->ifq_ref--; 5655 if ((ifq->ifq_ref == 0) && ((ifq->ifq_flags & IFQF_USER) != 0)) { 5656 ifq->ifq_flags |= IFQF_DELETE; 5657 } 5658 5659 return (ifq->ifq_ref); 5660} 5661 5662 5663/* ------------------------------------------------------------------------ */ 5664/* Function: ipf_freetimeoutqueue */ 5665/* Parameters: ifq(I) - timeout queue which is losing a reference. */ 5666/* Returns: Nil */ 5667/* */ 5668/* Locking: */ 5669/* It is assumed that the caller of this function has an appropriate lock */ 5670/* held (exclusively) in the domain that encompases the callers "domain". */ 5671/* The ifq_lock for this structure should not be held. */ 5672/* */ 5673/* Remove a user defined timeout queue from the list of queues it is in and */ 5674/* tidy up after this is done. */ 5675/* ------------------------------------------------------------------------ */ 5676void 5677ipf_freetimeoutqueue(ipf_main_softc_t *softc, ipftq_t *ifq) 5678{ 5679 5680 if (((ifq->ifq_flags & IFQF_DELETE) == 0) || (ifq->ifq_ref != 0) || 5681 ((ifq->ifq_flags & IFQF_USER) == 0)) { 5682 printf("ipf_freetimeoutqueue(%lx) flags 0x%x ttl %d ref %d\n", 5683 (u_long)ifq, ifq->ifq_flags, ifq->ifq_ttl, 5684 ifq->ifq_ref); 5685 return; 5686 } 5687 5688 /* 5689 * Remove from its position in the list. 5690 */ 5691 *ifq->ifq_pnext = ifq->ifq_next; 5692 if (ifq->ifq_next != NULL) 5693 ifq->ifq_next->ifq_pnext = ifq->ifq_pnext; 5694 ifq->ifq_next = NULL; 5695 ifq->ifq_pnext = NULL; 5696 5697 MUTEX_DESTROY(&ifq->ifq_lock); 5698 ATOMIC_DEC(softc->ipf_userifqs); 5699 KFREE(ifq); 5700} 5701 5702 5703/* ------------------------------------------------------------------------ */ 5704/* Function: ipf_deletequeueentry */ 5705/* Returns: Nil */ 5706/* Parameters: tqe(I) - timeout queue entry to delete */ 5707/* */ 5708/* Remove a tail queue entry from its queue and make it an orphan. */ 5709/* ipf_deletetimeoutqueue is called to make sure the reference count on the */ 5710/* queue is correct. We can't, however, call ipf_freetimeoutqueue because */ 5711/* the correct lock(s) may not be held that would make it safe to do so. */ 5712/* ------------------------------------------------------------------------ */ 5713void 5714ipf_deletequeueentry(ipftqent_t *tqe) 5715{ 5716 ipftq_t *ifq; 5717 5718 ifq = tqe->tqe_ifq; 5719 5720 MUTEX_ENTER(&ifq->ifq_lock); 5721 5722 if (tqe->tqe_pnext != NULL) { 5723 *tqe->tqe_pnext = tqe->tqe_next; 5724 if (tqe->tqe_next != NULL) 5725 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5726 else /* we must be the tail anyway */ 5727 ifq->ifq_tail = tqe->tqe_pnext; 5728 5729 tqe->tqe_pnext = NULL; 5730 tqe->tqe_ifq = NULL; 5731 } 5732 5733 (void) ipf_deletetimeoutqueue(ifq); 5734 ASSERT(ifq->ifq_ref > 0); 5735 5736 MUTEX_EXIT(&ifq->ifq_lock); 5737} 5738 5739 5740/* ------------------------------------------------------------------------ */ 5741/* Function: ipf_queuefront */ 5742/* Returns: Nil */ 5743/* Parameters: tqe(I) - pointer to timeout queue entry */ 5744/* */ 5745/* Move a queue entry to the front of the queue, if it isn't already there. */ 5746/* ------------------------------------------------------------------------ */ 5747void 5748ipf_queuefront(ipftqent_t *tqe) 5749{ 5750 ipftq_t *ifq; 5751 5752 ifq = tqe->tqe_ifq; 5753 if (ifq == NULL) 5754 return; 5755 5756 MUTEX_ENTER(&ifq->ifq_lock); 5757 if (ifq->ifq_head != tqe) { 5758 *tqe->tqe_pnext = tqe->tqe_next; 5759 if (tqe->tqe_next) 5760 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5761 else 5762 ifq->ifq_tail = tqe->tqe_pnext; 5763 5764 tqe->tqe_next = ifq->ifq_head; 5765 ifq->ifq_head->tqe_pnext = &tqe->tqe_next; 5766 ifq->ifq_head = tqe; 5767 tqe->tqe_pnext = &ifq->ifq_head; 5768 } 5769 MUTEX_EXIT(&ifq->ifq_lock); 5770} 5771 5772 5773/* ------------------------------------------------------------------------ */ 5774/* Function: ipf_queueback */ 5775/* Returns: Nil */ 5776/* Parameters: ticks(I) - ipf tick time to use with this call */ 5777/* tqe(I) - pointer to timeout queue entry */ 5778/* */ 5779/* Move a queue entry to the back of the queue, if it isn't already there. */ 5780/* We use use ticks to calculate the expiration and mark for when we last */ 5781/* touched the structure. */ 5782/* ------------------------------------------------------------------------ */ 5783void 5784ipf_queueback(u_long ticks, ipftqent_t *tqe) 5785{ 5786 ipftq_t *ifq; 5787 5788 ifq = tqe->tqe_ifq; 5789 if (ifq == NULL) 5790 return; 5791 tqe->tqe_die = ticks + ifq->ifq_ttl; 5792 tqe->tqe_touched = ticks; 5793 5794 MUTEX_ENTER(&ifq->ifq_lock); 5795 if (tqe->tqe_next != NULL) { /* at the end already ? */ 5796 /* 5797 * Remove from list 5798 */ 5799 *tqe->tqe_pnext = tqe->tqe_next; 5800 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5801 5802 /* 5803 * Make it the last entry. 5804 */ 5805 tqe->tqe_next = NULL; 5806 tqe->tqe_pnext = ifq->ifq_tail; 5807 *ifq->ifq_tail = tqe; 5808 ifq->ifq_tail = &tqe->tqe_next; 5809 } 5810 MUTEX_EXIT(&ifq->ifq_lock); 5811} 5812 5813 5814/* ------------------------------------------------------------------------ */ 5815/* Function: ipf_queueappend */ 5816/* Returns: Nil */ 5817/* Parameters: ticks(I) - ipf tick time to use with this call */ 5818/* tqe(I) - pointer to timeout queue entry */ 5819/* ifq(I) - pointer to timeout queue */ 5820/* parent(I) - owing object pointer */ 5821/* */ 5822/* Add a new item to this queue and put it on the very end. */ 5823/* We use use ticks to calculate the expiration and mark for when we last */ 5824/* touched the structure. */ 5825/* ------------------------------------------------------------------------ */ 5826void 5827ipf_queueappend(u_long ticks, ipftqent_t *tqe, ipftq_t *ifq, void *parent) 5828{ 5829 5830 MUTEX_ENTER(&ifq->ifq_lock); 5831 tqe->tqe_parent = parent; 5832 tqe->tqe_pnext = ifq->ifq_tail; 5833 *ifq->ifq_tail = tqe; 5834 ifq->ifq_tail = &tqe->tqe_next; 5835 tqe->tqe_next = NULL; 5836 tqe->tqe_ifq = ifq; 5837 tqe->tqe_die = ticks + ifq->ifq_ttl; 5838 tqe->tqe_touched = ticks; 5839 ifq->ifq_ref++; 5840 MUTEX_EXIT(&ifq->ifq_lock); 5841} 5842 5843 5844/* ------------------------------------------------------------------------ */ 5845/* Function: ipf_movequeue */ 5846/* Returns: Nil */ 5847/* Parameters: tq(I) - pointer to timeout queue information */ 5848/* oifp(I) - old timeout queue entry was on */ 5849/* nifp(I) - new timeout queue to put entry on */ 5850/* */ 5851/* Move a queue entry from one timeout queue to another timeout queue. */ 5852/* If it notices that the current entry is already last and does not need */ 5853/* to move queue, the return. */ 5854/* ------------------------------------------------------------------------ */ 5855void 5856ipf_movequeue(u_long ticks, ipftqent_t *tqe, ipftq_t *oifq, ipftq_t *nifq) 5857{ 5858 5859 /* 5860 * If the queue hasn't changed and we last touched this entry at the 5861 * same ipf time, then we're not going to achieve anything by either 5862 * changing the ttl or moving it on the queue. 5863 */ 5864 if (oifq == nifq && tqe->tqe_touched == ticks) 5865 return; 5866 5867 /* 5868 * For any of this to be outside the lock, there is a risk that two 5869 * packets entering simultaneously, with one changing to a different 5870 * queue and one not, could end up with things in a bizarre state. 5871 */ 5872 MUTEX_ENTER(&oifq->ifq_lock); 5873 5874 tqe->tqe_touched = ticks; 5875 tqe->tqe_die = ticks + nifq->ifq_ttl; 5876 /* 5877 * Is the operation here going to be a no-op ? 5878 */ 5879 if (oifq == nifq) { 5880 if ((tqe->tqe_next == NULL) || 5881 (tqe->tqe_next->tqe_die == tqe->tqe_die)) { 5882 MUTEX_EXIT(&oifq->ifq_lock); 5883 return; 5884 } 5885 } 5886 5887 /* 5888 * Remove from the old queue 5889 */ 5890 *tqe->tqe_pnext = tqe->tqe_next; 5891 if (tqe->tqe_next) 5892 tqe->tqe_next->tqe_pnext = tqe->tqe_pnext; 5893 else 5894 oifq->ifq_tail = tqe->tqe_pnext; 5895 tqe->tqe_next = NULL; 5896 5897 /* 5898 * If we're moving from one queue to another, release the 5899 * lock on the old queue and get a lock on the new queue. 5900 * For user defined queues, if we're moving off it, call 5901 * delete in case it can now be freed. 5902 */ 5903 if (oifq != nifq) { 5904 tqe->tqe_ifq = NULL; 5905 5906 (void) ipf_deletetimeoutqueue(oifq); 5907 5908 MUTEX_EXIT(&oifq->ifq_lock); 5909 5910 MUTEX_ENTER(&nifq->ifq_lock); 5911 5912 tqe->tqe_ifq = nifq; 5913 nifq->ifq_ref++; 5914 } 5915 5916 /* 5917 * Add to the bottom of the new queue 5918 */ 5919 tqe->tqe_pnext = nifq->ifq_tail; 5920 *nifq->ifq_tail = tqe; 5921 nifq->ifq_tail = &tqe->tqe_next; 5922 MUTEX_EXIT(&nifq->ifq_lock); 5923} 5924 5925 5926/* ------------------------------------------------------------------------ */ 5927/* Function: ipf_updateipid */ 5928/* Returns: int - 0 == success, -1 == error (packet should be droppped) */ 5929/* Parameters: fin(I) - pointer to packet information */ 5930/* */ 5931/* When we are doing NAT, change the IP of every packet to represent a */ 5932/* single sequence of packets coming from the host, hiding any host */ 5933/* specific sequencing that might otherwise be revealed. If the packet is */ 5934/* a fragment, then store the 'new' IPid in the fragment cache and look up */ 5935/* the fragment cache for non-leading fragments. If a non-leading fragment */ 5936/* has no match in the cache, return an error. */ 5937/* ------------------------------------------------------------------------ */ 5938static int 5939ipf_updateipid(fr_info_t *fin) 5940{ 5941 u_short id, ido, sums; 5942 u_32_t sumd, sum; 5943 ip_t *ip; 5944 5945 ip = fin->fin_ip; 5946 ido = ntohs(ip->ip_id); 5947 if (fin->fin_off != 0) { 5948 sum = ipf_frag_ipidknown(fin); 5949 if (sum == 0xffffffff) 5950 return (-1); 5951 sum &= 0xffff; 5952 id = (u_short)sum; 5953 ip->ip_id = htons(id); 5954 } else { 5955 ip_fillid(ip); 5956 id = ntohs(ip->ip_id); 5957 if ((fin->fin_flx & FI_FRAG) != 0) 5958 (void) ipf_frag_ipidnew(fin, (u_32_t)id); 5959 } 5960 5961 if (id == ido) 5962 return (0); 5963 CALC_SUMD(ido, id, sumd); /* DESTRUCTIVE MACRO! id,ido change */ 5964 sum = (~ntohs(ip->ip_sum)) & 0xffff; 5965 sum += sumd; 5966 sum = (sum >> 16) + (sum & 0xffff); 5967 sum = (sum >> 16) + (sum & 0xffff); 5968 sums = ~(u_short)sum; 5969 ip->ip_sum = htons(sums); 5970 return (0); 5971} 5972 5973 5974#ifdef NEED_FRGETIFNAME 5975/* ------------------------------------------------------------------------ */ 5976/* Function: ipf_getifname */ 5977/* Returns: char * - pointer to interface name */ 5978/* Parameters: ifp(I) - pointer to network interface */ 5979/* buffer(O) - pointer to where to store interface name */ 5980/* */ 5981/* Constructs an interface name in the buffer passed. The buffer passed is */ 5982/* expected to be at least LIFNAMSIZ in bytes big. If buffer is passed in */ 5983/* as a NULL pointer then return a pointer to a static array. */ 5984/* ------------------------------------------------------------------------ */ 5985char * 5986ipf_getifname(struct ifnet *ifp, char *buffer) 5987{ 5988 static char namebuf[LIFNAMSIZ]; 5989# if SOLARIS || defined(__FreeBSD__) 5990 int unit, space; 5991 char temp[20]; 5992 char *s; 5993# endif 5994 5995 if (buffer == NULL) 5996 buffer = namebuf; 5997 (void) strncpy(buffer, ifp->if_name, LIFNAMSIZ); 5998 buffer[LIFNAMSIZ - 1] = '\0'; 5999# if SOLARIS || defined(__FreeBSD__) 6000 for (s = buffer; *s; s++) 6001 ; 6002 unit = ifp->if_unit; 6003 space = LIFNAMSIZ - (s - buffer); 6004 if ((space > 0) && (unit >= 0)) { 6005 (void) snprintf(temp, sizeof(name), "%d", unit); 6006 (void) strncpy(s, temp, space); 6007 } 6008# endif 6009 return (buffer); 6010} 6011#endif 6012 6013 6014/* ------------------------------------------------------------------------ */ 6015/* Function: ipf_ioctlswitch */ 6016/* Returns: int - -1 continue processing, else ioctl return value */ 6017/* Parameters: unit(I) - device unit opened */ 6018/* data(I) - pointer to ioctl data */ 6019/* cmd(I) - ioctl command */ 6020/* mode(I) - mode value */ 6021/* uid(I) - uid making the ioctl call */ 6022/* ctx(I) - pointer to context data */ 6023/* */ 6024/* Based on the value of unit, call the appropriate ioctl handler or return */ 6025/* EIO if ipfilter is not running. Also checks if write perms are req'd */ 6026/* for the device in order to execute the ioctl. A special case is made */ 6027/* SIOCIPFINTERROR so that the same code isn't required in every handler. */ 6028/* The context data pointer is passed through as this is used as the key */ 6029/* for locating a matching token for continued access for walking lists, */ 6030/* etc. */ 6031/* ------------------------------------------------------------------------ */ 6032int 6033ipf_ioctlswitch(ipf_main_softc_t *softc, int unit, void *data, ioctlcmd_t cmd, 6034 int mode, int uid, void *ctx) 6035{ 6036 int error = 0; 6037 6038 switch (cmd) 6039 { 6040 case SIOCIPFINTERROR : 6041 error = BCOPYOUT(&softc->ipf_interror, data, 6042 sizeof(softc->ipf_interror)); 6043 if (error != 0) { 6044 IPFERROR(40); 6045 error = EFAULT; 6046 } 6047 return (error); 6048 default : 6049 break; 6050 } 6051 6052 switch (unit) 6053 { 6054 case IPL_LOGIPF : 6055 error = ipf_ipf_ioctl(softc, data, cmd, mode, uid, ctx); 6056 break; 6057 case IPL_LOGNAT : 6058 if (softc->ipf_running > 0) { 6059 error = ipf_nat_ioctl(softc, data, cmd, mode, 6060 uid, ctx); 6061 } else { 6062 IPFERROR(42); 6063 error = EIO; 6064 } 6065 break; 6066 case IPL_LOGSTATE : 6067 if (softc->ipf_running > 0) { 6068 error = ipf_state_ioctl(softc, data, cmd, mode, 6069 uid, ctx); 6070 } else { 6071 IPFERROR(43); 6072 error = EIO; 6073 } 6074 break; 6075 case IPL_LOGAUTH : 6076 if (softc->ipf_running > 0) { 6077 error = ipf_auth_ioctl(softc, data, cmd, mode, 6078 uid, ctx); 6079 } else { 6080 IPFERROR(44); 6081 error = EIO; 6082 } 6083 break; 6084 case IPL_LOGSYNC : 6085 if (softc->ipf_running > 0) { 6086 error = ipf_sync_ioctl(softc, data, cmd, mode, 6087 uid, ctx); 6088 } else { 6089 error = EIO; 6090 IPFERROR(45); 6091 } 6092 break; 6093 case IPL_LOGSCAN : 6094#ifdef IPFILTER_SCAN 6095 if (softc->ipf_running > 0) 6096 error = ipf_scan_ioctl(softc, data, cmd, mode, 6097 uid, ctx); 6098 else 6099#endif 6100 { 6101 error = EIO; 6102 IPFERROR(46); 6103 } 6104 break; 6105 case IPL_LOGLOOKUP : 6106 if (softc->ipf_running > 0) { 6107 error = ipf_lookup_ioctl(softc, data, cmd, mode, 6108 uid, ctx); 6109 } else { 6110 error = EIO; 6111 IPFERROR(47); 6112 } 6113 break; 6114 default : 6115 IPFERROR(48); 6116 error = EIO; 6117 break; 6118 } 6119 6120 return (error); 6121} 6122 6123 6124/* 6125 * This array defines the expected size of objects coming into the kernel 6126 * for the various recognised object types. The first column is flags (see 6127 * below), 2nd column is current size, 3rd column is the version number of 6128 * when the current size became current. 6129 * Flags: 6130 * 1 = minimum size, not absolute size 6131 */ 6132static const int ipf_objbytes[IPFOBJ_COUNT][3] = { 6133 { 1, sizeof(struct frentry), 5010000 }, /* 0 */ 6134 { 1, sizeof(struct friostat), 5010000 }, 6135 { 0, sizeof(struct fr_info), 5010000 }, 6136 { 0, sizeof(struct ipf_authstat), 4010100 }, 6137 { 0, sizeof(struct ipfrstat), 5010000 }, 6138 { 1, sizeof(struct ipnat), 5010000 }, /* 5 */ 6139 { 0, sizeof(struct natstat), 5010000 }, 6140 { 0, sizeof(struct ipstate_save), 5010000 }, 6141 { 1, sizeof(struct nat_save), 5010000 }, 6142 { 0, sizeof(struct natlookup), 5010000 }, 6143 { 1, sizeof(struct ipstate), 5010000 }, /* 10 */ 6144 { 0, sizeof(struct ips_stat), 5010000 }, 6145 { 0, sizeof(struct frauth), 5010000 }, 6146 { 0, sizeof(struct ipftune), 4010100 }, 6147 { 0, sizeof(struct nat), 5010000 }, 6148 { 0, sizeof(struct ipfruleiter), 4011400 }, /* 15 */ 6149 { 0, sizeof(struct ipfgeniter), 4011400 }, 6150 { 0, sizeof(struct ipftable), 4011400 }, 6151 { 0, sizeof(struct ipflookupiter), 4011400 }, 6152 { 0, sizeof(struct ipftq) * IPF_TCP_NSTATES }, 6153 { 1, 0, 0 }, /* IPFEXPR */ 6154 { 0, 0, 0 }, /* PROXYCTL */ 6155 { 0, sizeof (struct fripf), 5010000 } 6156}; 6157 6158 6159/* ------------------------------------------------------------------------ */ 6160/* Function: ipf_inobj */ 6161/* Returns: int - 0 = success, else failure */ 6162/* Parameters: softc(I) - soft context pointerto work with */ 6163/* data(I) - pointer to ioctl data */ 6164/* objp(O) - where to store ipfobj structure */ 6165/* ptr(I) - pointer to data to copy out */ 6166/* type(I) - type of structure being moved */ 6167/* */ 6168/* Copy in the contents of what the ipfobj_t points to. In future, we */ 6169/* add things to check for version numbers, sizes, etc, to make it backward */ 6170/* compatible at the ABI for user land. */ 6171/* If objp is not NULL then we assume that the caller wants to see what is */ 6172/* in the ipfobj_t structure being copied in. As an example, this can tell */ 6173/* the caller what version of ipfilter the ioctl program was written to. */ 6174/* ------------------------------------------------------------------------ */ 6175int 6176ipf_inobj(ipf_main_softc_t *softc, void *data, ipfobj_t *objp, void *ptr, 6177 int type) 6178{ 6179 ipfobj_t obj; 6180 int error; 6181 int size; 6182 6183 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6184 IPFERROR(49); 6185 return (EINVAL); 6186 } 6187 6188 if (objp == NULL) 6189 objp = &obj; 6190 error = BCOPYIN(data, objp, sizeof(*objp)); 6191 if (error != 0) { 6192 IPFERROR(124); 6193 return (EFAULT); 6194 } 6195 6196 if (objp->ipfo_type != type) { 6197 IPFERROR(50); 6198 return (EINVAL); 6199 } 6200 6201 if (objp->ipfo_rev >= ipf_objbytes[type][2]) { 6202 if ((ipf_objbytes[type][0] & 1) != 0) { 6203 if (objp->ipfo_size < ipf_objbytes[type][1]) { 6204 IPFERROR(51); 6205 return (EINVAL); 6206 } 6207 size = ipf_objbytes[type][1]; 6208 } else if (objp->ipfo_size == ipf_objbytes[type][1]) { 6209 size = objp->ipfo_size; 6210 } else { 6211 IPFERROR(52); 6212 return (EINVAL); 6213 } 6214 error = COPYIN(objp->ipfo_ptr, ptr, size); 6215 if (error != 0) { 6216 IPFERROR(55); 6217 error = EFAULT; 6218 } 6219 } else { 6220#ifdef IPFILTER_COMPAT 6221 error = ipf_in_compat(softc, objp, ptr, 0); 6222#else 6223 IPFERROR(54); 6224 error = EINVAL; 6225#endif 6226 } 6227 return (error); 6228} 6229 6230 6231/* ------------------------------------------------------------------------ */ 6232/* Function: ipf_inobjsz */ 6233/* Returns: int - 0 = success, else failure */ 6234/* Parameters: softc(I) - soft context pointerto work with */ 6235/* data(I) - pointer to ioctl data */ 6236/* ptr(I) - pointer to store real data in */ 6237/* type(I) - type of structure being moved */ 6238/* sz(I) - size of data to copy */ 6239/* */ 6240/* As per ipf_inobj, except the size of the object to copy in is passed in */ 6241/* but it must not be smaller than the size defined for the type and the */ 6242/* type must allow for varied sized objects. The extra requirement here is */ 6243/* that sz must match the size of the object being passed in - this is not */ 6244/* not possible nor required in ipf_inobj(). */ 6245/* ------------------------------------------------------------------------ */ 6246int 6247ipf_inobjsz(ipf_main_softc_t *softc, void *data, void *ptr, int type, int sz) 6248{ 6249 ipfobj_t obj; 6250 int error; 6251 6252 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6253 IPFERROR(56); 6254 return (EINVAL); 6255 } 6256 6257 error = BCOPYIN(data, &obj, sizeof(obj)); 6258 if (error != 0) { 6259 IPFERROR(125); 6260 return (EFAULT); 6261 } 6262 6263 if (obj.ipfo_type != type) { 6264 IPFERROR(58); 6265 return (EINVAL); 6266 } 6267 6268 if (obj.ipfo_rev >= ipf_objbytes[type][2]) { 6269 if (((ipf_objbytes[type][0] & 1) == 0) || 6270 (sz < ipf_objbytes[type][1])) { 6271 IPFERROR(57); 6272 return (EINVAL); 6273 } 6274 error = COPYIN(obj.ipfo_ptr, ptr, sz); 6275 if (error != 0) { 6276 IPFERROR(61); 6277 error = EFAULT; 6278 } 6279 } else { 6280#ifdef IPFILTER_COMPAT 6281 error = ipf_in_compat(softc, &obj, ptr, sz); 6282#else 6283 IPFERROR(60); 6284 error = EINVAL; 6285#endif 6286 } 6287 return (error); 6288} 6289 6290 6291/* ------------------------------------------------------------------------ */ 6292/* Function: ipf_outobjsz */ 6293/* Returns: int - 0 = success, else failure */ 6294/* Parameters: data(I) - pointer to ioctl data */ 6295/* ptr(I) - pointer to store real data in */ 6296/* type(I) - type of structure being moved */ 6297/* sz(I) - size of data to copy */ 6298/* */ 6299/* As per ipf_outobj, except the size of the object to copy out is passed in*/ 6300/* but it must not be smaller than the size defined for the type and the */ 6301/* type must allow for varied sized objects. The extra requirement here is */ 6302/* that sz must match the size of the object being passed in - this is not */ 6303/* not possible nor required in ipf_outobj(). */ 6304/* ------------------------------------------------------------------------ */ 6305int 6306ipf_outobjsz(ipf_main_softc_t *softc, void *data, void *ptr, int type, int sz) 6307{ 6308 ipfobj_t obj; 6309 int error; 6310 6311 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6312 IPFERROR(62); 6313 return (EINVAL); 6314 } 6315 6316 error = BCOPYIN(data, &obj, sizeof(obj)); 6317 if (error != 0) { 6318 IPFERROR(127); 6319 return (EFAULT); 6320 } 6321 6322 if (obj.ipfo_type != type) { 6323 IPFERROR(63); 6324 return (EINVAL); 6325 } 6326 6327 if (obj.ipfo_rev >= ipf_objbytes[type][2]) { 6328 if (((ipf_objbytes[type][0] & 1) == 0) || 6329 (sz < ipf_objbytes[type][1])) { 6330 IPFERROR(146); 6331 return (EINVAL); 6332 } 6333 error = COPYOUT(ptr, obj.ipfo_ptr, sz); 6334 if (error != 0) { 6335 IPFERROR(66); 6336 error = EFAULT; 6337 } 6338 } else { 6339#ifdef IPFILTER_COMPAT 6340 error = ipf_out_compat(softc, &obj, ptr); 6341#else 6342 IPFERROR(65); 6343 error = EINVAL; 6344#endif 6345 } 6346 return (error); 6347} 6348 6349 6350/* ------------------------------------------------------------------------ */ 6351/* Function: ipf_outobj */ 6352/* Returns: int - 0 = success, else failure */ 6353/* Parameters: data(I) - pointer to ioctl data */ 6354/* ptr(I) - pointer to store real data in */ 6355/* type(I) - type of structure being moved */ 6356/* */ 6357/* Copy out the contents of what ptr is to where ipfobj points to. In */ 6358/* future, we add things to check for version numbers, sizes, etc, to make */ 6359/* it backward compatible at the ABI for user land. */ 6360/* ------------------------------------------------------------------------ */ 6361int 6362ipf_outobj(ipf_main_softc_t *softc, void *data, void *ptr, int type) 6363{ 6364 ipfobj_t obj; 6365 int error; 6366 6367 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6368 IPFERROR(67); 6369 return (EINVAL); 6370 } 6371 6372 error = BCOPYIN(data, &obj, sizeof(obj)); 6373 if (error != 0) { 6374 IPFERROR(126); 6375 return (EFAULT); 6376 } 6377 6378 if (obj.ipfo_type != type) { 6379 IPFERROR(68); 6380 return (EINVAL); 6381 } 6382 6383 if (obj.ipfo_rev >= ipf_objbytes[type][2]) { 6384 if ((ipf_objbytes[type][0] & 1) != 0) { 6385 if (obj.ipfo_size < ipf_objbytes[type][1]) { 6386 IPFERROR(69); 6387 return (EINVAL); 6388 } 6389 } else if (obj.ipfo_size != ipf_objbytes[type][1]) { 6390 IPFERROR(70); 6391 return (EINVAL); 6392 } 6393 6394 error = COPYOUT(ptr, obj.ipfo_ptr, obj.ipfo_size); 6395 if (error != 0) { 6396 IPFERROR(73); 6397 error = EFAULT; 6398 } 6399 } else { 6400#ifdef IPFILTER_COMPAT 6401 error = ipf_out_compat(softc, &obj, ptr); 6402#else 6403 IPFERROR(72); 6404 error = EINVAL; 6405#endif 6406 } 6407 return (error); 6408} 6409 6410 6411/* ------------------------------------------------------------------------ */ 6412/* Function: ipf_outobjk */ 6413/* Returns: int - 0 = success, else failure */ 6414/* Parameters: obj(I) - pointer to data description structure */ 6415/* ptr(I) - pointer to kernel data to copy out */ 6416/* */ 6417/* In the above functions, the ipfobj_t structure is copied into the kernel,*/ 6418/* telling ipfilter how to copy out data. In this instance, the ipfobj_t is */ 6419/* already populated with information and now we just need to use it. */ 6420/* There is no need for this function to have a "type" parameter as there */ 6421/* is no point in validating information that comes from the kernel with */ 6422/* itself. */ 6423/* ------------------------------------------------------------------------ */ 6424int 6425ipf_outobjk(ipf_main_softc_t *softc, ipfobj_t *obj, void *ptr) 6426{ 6427 int type = obj->ipfo_type; 6428 int error; 6429 6430 if ((type < 0) || (type >= IPFOBJ_COUNT)) { 6431 IPFERROR(147); 6432 return (EINVAL); 6433 } 6434 6435 if (obj->ipfo_rev >= ipf_objbytes[type][2]) { 6436 if ((ipf_objbytes[type][0] & 1) != 0) { 6437 if (obj->ipfo_size < ipf_objbytes[type][1]) { 6438 IPFERROR(148); 6439 return (EINVAL); 6440 } 6441 6442 } else if (obj->ipfo_size != ipf_objbytes[type][1]) { 6443 IPFERROR(149); 6444 return (EINVAL); 6445 } 6446 6447 error = COPYOUT(ptr, obj->ipfo_ptr, obj->ipfo_size); 6448 if (error != 0) { 6449 IPFERROR(150); 6450 error = EFAULT; 6451 } 6452 } else { 6453#ifdef IPFILTER_COMPAT 6454 error = ipf_out_compat(softc, obj, ptr); 6455#else 6456 IPFERROR(151); 6457 error = EINVAL; 6458#endif 6459 } 6460 return (error); 6461} 6462 6463 6464/* ------------------------------------------------------------------------ */ 6465/* Function: ipf_checkl4sum */ 6466/* Returns: int - 0 = good, -1 = bad, 1 = cannot check */ 6467/* Parameters: fin(I) - pointer to packet information */ 6468/* */ 6469/* If possible, calculate the layer 4 checksum for the packet. If this is */ 6470/* not possible, return without indicating a failure or success but in a */ 6471/* way that is ditinguishable. This function should only be called by the */ 6472/* ipf_checkv6sum() for each platform. */ 6473/* ------------------------------------------------------------------------ */ 6474inline int 6475ipf_checkl4sum(fr_info_t *fin) 6476{ 6477 u_short sum, hdrsum, *csump; 6478 udphdr_t *udp; 6479 int dosum; 6480 6481 /* 6482 * If the TCP packet isn't a fragment, isn't too short and otherwise 6483 * isn't already considered "bad", then validate the checksum. If 6484 * this check fails then considered the packet to be "bad". 6485 */ 6486 if ((fin->fin_flx & (FI_FRAG|FI_SHORT|FI_BAD)) != 0) 6487 return (1); 6488 6489 DT2(l4sumo, int, fin->fin_out, int, (int)fin->fin_p); 6490 if (fin->fin_out == 1) { 6491 fin->fin_cksum = FI_CK_SUMOK; 6492 return (0); 6493 } 6494 6495 csump = NULL; 6496 hdrsum = 0; 6497 dosum = 0; 6498 sum = 0; 6499 6500 switch (fin->fin_p) 6501 { 6502 case IPPROTO_TCP : 6503 csump = &((tcphdr_t *)fin->fin_dp)->th_sum; 6504 dosum = 1; 6505 break; 6506 6507 case IPPROTO_UDP : 6508 udp = fin->fin_dp; 6509 if (udp->uh_sum != 0) { 6510 csump = &udp->uh_sum; 6511 dosum = 1; 6512 } 6513 break; 6514 6515#ifdef USE_INET6 6516 case IPPROTO_ICMPV6 : 6517 csump = &((struct icmp6_hdr *)fin->fin_dp)->icmp6_cksum; 6518 dosum = 1; 6519 break; 6520#endif 6521 6522 case IPPROTO_ICMP : 6523 csump = &((struct icmp *)fin->fin_dp)->icmp_cksum; 6524 dosum = 1; 6525 break; 6526 6527 default : 6528 return (1); 6529 /*NOTREACHED*/ 6530 } 6531 6532 if (csump != NULL) { 6533 hdrsum = *csump; 6534 if (fin->fin_p == IPPROTO_UDP && hdrsum == 0xffff) 6535 hdrsum = 0x0000; 6536 } 6537 6538 if (dosum) { 6539 sum = fr_cksum(fin, fin->fin_ip, fin->fin_p, fin->fin_dp); 6540 } 6541#if !defined(_KERNEL) 6542 if (sum == hdrsum) { 6543 FR_DEBUG(("checkl4sum: %hx == %hx\n", sum, hdrsum)); 6544 } else { 6545 FR_DEBUG(("checkl4sum: %hx != %hx\n", sum, hdrsum)); 6546 } 6547#endif 6548 DT3(l4sums, u_short, hdrsum, u_short, sum, fr_info_t *, fin); 6549#ifdef USE_INET6 6550 if (hdrsum == sum || (sum == 0 && IP_V(fin->fin_ip) == 6)) { 6551#else 6552 if (hdrsum == sum) { 6553#endif 6554 fin->fin_cksum = FI_CK_SUMOK; 6555 return (0); 6556 } 6557 fin->fin_cksum = FI_CK_BAD; 6558 return (-1); 6559} 6560 6561 6562/* ------------------------------------------------------------------------ */ 6563/* Function: ipf_ifpfillv4addr */ 6564/* Returns: int - 0 = address update, -1 = address not updated */ 6565/* Parameters: atype(I) - type of network address update to perform */ 6566/* sin(I) - pointer to source of address information */ 6567/* mask(I) - pointer to source of netmask information */ 6568/* inp(I) - pointer to destination address store */ 6569/* inpmask(I) - pointer to destination netmask store */ 6570/* */ 6571/* Given a type of network address update (atype) to perform, copy */ 6572/* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ 6573/* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ 6574/* which case the operation fails. For all values of atype other than */ 6575/* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ 6576/* value. */ 6577/* ------------------------------------------------------------------------ */ 6578int 6579ipf_ifpfillv4addr(int atype, struct sockaddr_in *sin, struct sockaddr_in *mask, 6580 struct in_addr *inp, struct in_addr *inpmask) 6581{ 6582 if (inpmask != NULL && atype != FRI_NETMASKED) 6583 inpmask->s_addr = 0xffffffff; 6584 6585 if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { 6586 if (atype == FRI_NETMASKED) { 6587 if (inpmask == NULL) 6588 return (-1); 6589 inpmask->s_addr = mask->sin_addr.s_addr; 6590 } 6591 inp->s_addr = sin->sin_addr.s_addr & mask->sin_addr.s_addr; 6592 } else { 6593 inp->s_addr = sin->sin_addr.s_addr; 6594 } 6595 return (0); 6596} 6597 6598 6599#ifdef USE_INET6 6600/* ------------------------------------------------------------------------ */ 6601/* Function: ipf_ifpfillv6addr */ 6602/* Returns: int - 0 = address update, -1 = address not updated */ 6603/* Parameters: atype(I) - type of network address update to perform */ 6604/* sin(I) - pointer to source of address information */ 6605/* mask(I) - pointer to source of netmask information */ 6606/* inp(I) - pointer to destination address store */ 6607/* inpmask(I) - pointer to destination netmask store */ 6608/* */ 6609/* Given a type of network address update (atype) to perform, copy */ 6610/* information from sin/mask into inp/inpmask. If ipnmask is NULL then no */ 6611/* netmask update is performed unless FRI_NETMASKED is passed as atype, in */ 6612/* which case the operation fails. For all values of atype other than */ 6613/* FRI_NETMASKED, if inpmask is non-NULL then the mask is set to an all 1s */ 6614/* value. */ 6615/* ------------------------------------------------------------------------ */ 6616int 6617ipf_ifpfillv6addr(int atype, struct sockaddr_in6 *sin, 6618 struct sockaddr_in6 *mask, i6addr_t *inp, i6addr_t *inpmask) 6619{ 6620 i6addr_t *src, *and; 6621 6622 src = (i6addr_t *)&sin->sin6_addr; 6623 and = (i6addr_t *)&mask->sin6_addr; 6624 6625 if (inpmask != NULL && atype != FRI_NETMASKED) { 6626 inpmask->i6[0] = 0xffffffff; 6627 inpmask->i6[1] = 0xffffffff; 6628 inpmask->i6[2] = 0xffffffff; 6629 inpmask->i6[3] = 0xffffffff; 6630 } 6631 6632 if (atype == FRI_NETWORK || atype == FRI_NETMASKED) { 6633 if (atype == FRI_NETMASKED) { 6634 if (inpmask == NULL) 6635 return (-1); 6636 inpmask->i6[0] = and->i6[0]; 6637 inpmask->i6[1] = and->i6[1]; 6638 inpmask->i6[2] = and->i6[2]; 6639 inpmask->i6[3] = and->i6[3]; 6640 } 6641 6642 inp->i6[0] = src->i6[0] & and->i6[0]; 6643 inp->i6[1] = src->i6[1] & and->i6[1]; 6644 inp->i6[2] = src->i6[2] & and->i6[2]; 6645 inp->i6[3] = src->i6[3] & and->i6[3]; 6646 } else { 6647 inp->i6[0] = src->i6[0]; 6648 inp->i6[1] = src->i6[1]; 6649 inp->i6[2] = src->i6[2]; 6650 inp->i6[3] = src->i6[3]; 6651 } 6652 return (0); 6653} 6654#endif 6655 6656 6657/* ------------------------------------------------------------------------ */ 6658/* Function: ipf_matchtag */ 6659/* Returns: 0 == mismatch, 1 == match. */ 6660/* Parameters: tag1(I) - pointer to first tag to compare */ 6661/* tag2(I) - pointer to second tag to compare */ 6662/* */ 6663/* Returns true (non-zero) or false(0) if the two tag structures can be */ 6664/* considered to be a match or not match, respectively. The tag is 16 */ 6665/* bytes long (16 characters) but that is overlayed with 4 32bit ints so */ 6666/* compare the ints instead, for speed. tag1 is the master of the */ 6667/* comparison. This function should only be called with both tag1 and tag2 */ 6668/* as non-NULL pointers. */ 6669/* ------------------------------------------------------------------------ */ 6670int 6671ipf_matchtag(ipftag_t *tag1, ipftag_t *tag2) 6672{ 6673 if (tag1 == tag2) 6674 return (1); 6675 6676 if ((tag1->ipt_num[0] == 0) && (tag2->ipt_num[0] == 0)) 6677 return (1); 6678 6679 if ((tag1->ipt_num[0] == tag2->ipt_num[0]) && 6680 (tag1->ipt_num[1] == tag2->ipt_num[1]) && 6681 (tag1->ipt_num[2] == tag2->ipt_num[2]) && 6682 (tag1->ipt_num[3] == tag2->ipt_num[3])) 6683 return (1); 6684 return (0); 6685} 6686 6687 6688/* ------------------------------------------------------------------------ */ 6689/* Function: ipf_coalesce */ 6690/* Returns: 1 == success, -1 == failure, 0 == no change */ 6691/* Parameters: fin(I) - pointer to packet information */ 6692/* */ 6693/* Attempt to get all of the packet data into a single, contiguous buffer. */ 6694/* If this call returns a failure then the buffers have also been freed. */ 6695/* ------------------------------------------------------------------------ */ 6696int 6697ipf_coalesce(fr_info_t *fin) 6698{ 6699 6700 if ((fin->fin_flx & FI_COALESCE) != 0) 6701 return (1); 6702 6703 /* 6704 * If the mbuf pointers indicate that there is no mbuf to work with, 6705 * return but do not indicate success or failure. 6706 */ 6707 if (fin->fin_m == NULL || fin->fin_mp == NULL) 6708 return (0); 6709 6710#if defined(_KERNEL) 6711 if (ipf_pullup(fin->fin_m, fin, fin->fin_plen) == NULL) { 6712 ipf_main_softc_t *softc = fin->fin_main_soft; 6713 6714 DT1(frb_coalesce, fr_info_t *, fin); 6715 LBUMP(ipf_stats[fin->fin_out].fr_badcoalesces); 6716# if SOLARIS 6717 FREE_MB_T(*fin->fin_mp); 6718# endif 6719 fin->fin_reason = FRB_COALESCE; 6720 *fin->fin_mp = NULL; 6721 fin->fin_m = NULL; 6722 return (-1); 6723 } 6724#else 6725 fin = fin; /* LINT */ 6726#endif 6727 return (1); 6728} 6729 6730 6731/* 6732 * The following table lists all of the tunable variables that can be 6733 * accessed via SIOCIPFGET/SIOCIPFSET/SIOCIPFGETNEXt. The format of each row 6734 * in the table below is as follows: 6735 * 6736 * pointer to value, name of value, minimum, maximum, size of the value's 6737 * container, value attribute flags 6738 * 6739 * For convienience, IPFT_RDONLY means the value is read-only, IPFT_WRDISABLED 6740 * means the value can only be written to when IPFilter is loaded but disabled. 6741 * The obvious implication is if neither of these are set then the value can be 6742 * changed at any time without harm. 6743 */ 6744 6745 6746/* ------------------------------------------------------------------------ */ 6747/* Function: ipf_tune_findbycookie */ 6748/* Returns: NULL = search failed, else pointer to tune struct */ 6749/* Parameters: cookie(I) - cookie value to search for amongst tuneables */ 6750/* next(O) - pointer to place to store the cookie for the */ 6751/* "next" tuneable, if it is desired. */ 6752/* */ 6753/* This function is used to walk through all of the existing tunables with */ 6754/* successive calls. It searches the known tunables for the one which has */ 6755/* a matching value for "cookie" - ie its address. When returning a match, */ 6756/* the next one to be found may be returned inside next. */ 6757/* ------------------------------------------------------------------------ */ 6758static ipftuneable_t * 6759ipf_tune_findbycookie(ipftuneable_t **ptop, void *cookie, void **next) 6760{ 6761 ipftuneable_t *ta, **tap; 6762 6763 for (ta = *ptop; ta->ipft_name != NULL; ta++) 6764 if (ta == cookie) { 6765 if (next != NULL) { 6766 /* 6767 * If the next entry in the array has a name 6768 * present, then return a pointer to it for 6769 * where to go next, else return a pointer to 6770 * the dynaminc list as a key to search there 6771 * next. This facilitates a weak linking of 6772 * the two "lists" together. 6773 */ 6774 if ((ta + 1)->ipft_name != NULL) 6775 *next = ta + 1; 6776 else 6777 *next = ptop; 6778 } 6779 return (ta); 6780 } 6781 6782 for (tap = ptop; (ta = *tap) != NULL; tap = &ta->ipft_next) 6783 if (tap == cookie) { 6784 if (next != NULL) 6785 *next = &ta->ipft_next; 6786 return (ta); 6787 } 6788 6789 if (next != NULL) 6790 *next = NULL; 6791 return (NULL); 6792} 6793 6794 6795/* ------------------------------------------------------------------------ */ 6796/* Function: ipf_tune_findbyname */ 6797/* Returns: NULL = search failed, else pointer to tune struct */ 6798/* Parameters: name(I) - name of the tuneable entry to find. */ 6799/* */ 6800/* Search the static array of tuneables and the list of dynamic tuneables */ 6801/* for an entry with a matching name. If we can find one, return a pointer */ 6802/* to the matching structure. */ 6803/* ------------------------------------------------------------------------ */ 6804static ipftuneable_t * 6805ipf_tune_findbyname(ipftuneable_t *top, const char *name) 6806{ 6807 ipftuneable_t *ta; 6808 6809 for (ta = top; ta != NULL; ta = ta->ipft_next) 6810 if (!strcmp(ta->ipft_name, name)) { 6811 return (ta); 6812 } 6813 6814 return (NULL); 6815} 6816 6817 6818/* ------------------------------------------------------------------------ */ 6819/* Function: ipf_tune_add_array */ 6820/* Returns: int - 0 == success, else failure */ 6821/* Parameters: newtune - pointer to new tune array to add to tuneables */ 6822/* */ 6823/* Appends tune structures from the array passed in (newtune) to the end of */ 6824/* the current list of "dynamic" tuneable parameters. */ 6825/* If any entry to be added is already present (by name) then the operation */ 6826/* is aborted - entries that have been added are removed before returning. */ 6827/* An entry with no name (NULL) is used as the indication that the end of */ 6828/* the array has been reached. */ 6829/* ------------------------------------------------------------------------ */ 6830int 6831ipf_tune_add_array(ipf_main_softc_t *softc, ipftuneable_t *newtune) 6832{ 6833 ipftuneable_t *nt, *dt; 6834 int error = 0; 6835 6836 for (nt = newtune; nt->ipft_name != NULL; nt++) { 6837 error = ipf_tune_add(softc, nt); 6838 if (error != 0) { 6839 for (dt = newtune; dt != nt; dt++) { 6840 (void) ipf_tune_del(softc, dt); 6841 } 6842 } 6843 } 6844 6845 return (error); 6846} 6847 6848 6849/* ------------------------------------------------------------------------ */ 6850/* Function: ipf_tune_array_link */ 6851/* Returns: 0 == success, -1 == failure */ 6852/* Parameters: softc(I) - soft context pointerto work with */ 6853/* array(I) - pointer to an array of tuneables */ 6854/* */ 6855/* Given an array of tunables (array), append them to the current list of */ 6856/* tuneables for this context (softc->ipf_tuners.) To properly prepare the */ 6857/* the array for being appended to the list, initialise all of the next */ 6858/* pointers so we don't need to walk parts of it with ++ and others with */ 6859/* next. The array is expected to have an entry with a NULL name as the */ 6860/* terminator. Trying to add an array with no non-NULL names will return as */ 6861/* a failure. */ 6862/* ------------------------------------------------------------------------ */ 6863int 6864ipf_tune_array_link(ipf_main_softc_t *softc, ipftuneable_t *array) 6865{ 6866 ipftuneable_t *t, **p; 6867 6868 t = array; 6869 if (t->ipft_name == NULL) 6870 return (-1); 6871 6872 for (; t[1].ipft_name != NULL; t++) 6873 t[0].ipft_next = &t[1]; 6874 t->ipft_next = NULL; 6875 6876 /* 6877 * Since a pointer to the last entry isn't kept, we need to find it 6878 * each time we want to add new variables to the list. 6879 */ 6880 for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next) 6881 if (t->ipft_name == NULL) 6882 break; 6883 *p = array; 6884 6885 return (0); 6886} 6887 6888 6889/* ------------------------------------------------------------------------ */ 6890/* Function: ipf_tune_array_unlink */ 6891/* Returns: 0 == success, -1 == failure */ 6892/* Parameters: softc(I) - soft context pointerto work with */ 6893/* array(I) - pointer to an array of tuneables */ 6894/* */ 6895/* ------------------------------------------------------------------------ */ 6896int 6897ipf_tune_array_unlink(ipf_main_softc_t *softc, ipftuneable_t *array) 6898{ 6899 ipftuneable_t *t, **p; 6900 6901 for (p = &softc->ipf_tuners; (t = *p) != NULL; p = &t->ipft_next) 6902 if (t == array) 6903 break; 6904 if (t == NULL) 6905 return (-1); 6906 6907 for (; t[1].ipft_name != NULL; t++) 6908 ; 6909 6910 *p = t->ipft_next; 6911 6912 return (0); 6913} 6914 6915 6916/* ------------------------------------------------------------------------ */ 6917/* Function: ipf_tune_array_copy */ 6918/* Returns: NULL = failure, else pointer to new array */ 6919/* Parameters: base(I) - pointer to structure base */ 6920/* size(I) - size of the array at template */ 6921/* template(I) - original array to copy */ 6922/* */ 6923/* Allocate memory for a new set of tuneable values and copy everything */ 6924/* from template into the new region of memory. The new region is full of */ 6925/* uninitialised pointers (ipft_next) so set them up. Now, ipftp_offset... */ 6926/* */ 6927/* NOTE: the following assumes that sizeof(long) == sizeof(void *) */ 6928/* In the array template, ipftp_offset is the offset (in bytes) of the */ 6929/* location of the tuneable value inside the structure pointed to by base. */ 6930/* As ipftp_offset is a union over the pointers to the tuneable values, if */ 6931/* we add base to the copy's ipftp_offset, copy ends up with a pointer in */ 6932/* ipftp_void that points to the stored value. */ 6933/* ------------------------------------------------------------------------ */ 6934ipftuneable_t * 6935ipf_tune_array_copy(void *base, size_t size, ipftuneable_t *template) 6936{ 6937 ipftuneable_t *copy; 6938 int i; 6939 6940 6941 KMALLOCS(copy, ipftuneable_t *, size); 6942 if (copy == NULL) { 6943 return (NULL); 6944 } 6945 bcopy(template, copy, size); 6946 6947 for (i = 0; copy[i].ipft_name; i++) { 6948 copy[i].ipft_una.ipftp_offset += (u_long)base; 6949 copy[i].ipft_next = copy + i + 1; 6950 } 6951 6952 return (copy); 6953} 6954 6955 6956/* ------------------------------------------------------------------------ */ 6957/* Function: ipf_tune_add */ 6958/* Returns: int - 0 == success, else failure */ 6959/* Parameters: newtune - pointer to new tune entry to add to tuneables */ 6960/* */ 6961/* Appends tune structures from the array passed in (newtune) to the end of */ 6962/* the current list of "dynamic" tuneable parameters. Once added, the */ 6963/* owner of the object is not expected to ever change "ipft_next". */ 6964/* ------------------------------------------------------------------------ */ 6965int 6966ipf_tune_add(ipf_main_softc_t *softc, ipftuneable_t *newtune) 6967{ 6968 ipftuneable_t *ta, **tap; 6969 6970 ta = ipf_tune_findbyname(softc->ipf_tuners, newtune->ipft_name); 6971 if (ta != NULL) { 6972 IPFERROR(74); 6973 return (EEXIST); 6974 } 6975 6976 for (tap = &softc->ipf_tuners; *tap != NULL; tap = &(*tap)->ipft_next) 6977 ; 6978 6979 newtune->ipft_next = NULL; 6980 *tap = newtune; 6981 return (0); 6982} 6983 6984 6985/* ------------------------------------------------------------------------ */ 6986/* Function: ipf_tune_del */ 6987/* Returns: int - 0 == success, else failure */ 6988/* Parameters: oldtune - pointer to tune entry to remove from the list of */ 6989/* current dynamic tuneables */ 6990/* */ 6991/* Search for the tune structure, by pointer, in the list of those that are */ 6992/* dynamically added at run time. If found, adjust the list so that this */ 6993/* structure is no longer part of it. */ 6994/* ------------------------------------------------------------------------ */ 6995int 6996ipf_tune_del(ipf_main_softc_t *softc, ipftuneable_t *oldtune) 6997{ 6998 ipftuneable_t *ta, **tap; 6999 int error = 0; 7000 7001 for (tap = &softc->ipf_tuners; (ta = *tap) != NULL; 7002 tap = &ta->ipft_next) { 7003 if (ta == oldtune) { 7004 *tap = oldtune->ipft_next; 7005 oldtune->ipft_next = NULL; 7006 break; 7007 } 7008 } 7009 7010 if (ta == NULL) { 7011 error = ESRCH; 7012 IPFERROR(75); 7013 } 7014 return (error); 7015} 7016 7017 7018/* ------------------------------------------------------------------------ */ 7019/* Function: ipf_tune_del_array */ 7020/* Returns: int - 0 == success, else failure */ 7021/* Parameters: oldtune - pointer to tuneables array */ 7022/* */ 7023/* Remove each tuneable entry in the array from the list of "dynamic" */ 7024/* tunables. If one entry should fail to be found, an error will be */ 7025/* returned and no further ones removed. */ 7026/* An entry with a NULL name is used as the indicator of the last entry in */ 7027/* the array. */ 7028/* ------------------------------------------------------------------------ */ 7029int 7030ipf_tune_del_array(ipf_main_softc_t *softc, ipftuneable_t *oldtune) 7031{ 7032 ipftuneable_t *ot; 7033 int error = 0; 7034 7035 for (ot = oldtune; ot->ipft_name != NULL; ot++) { 7036 error = ipf_tune_del(softc, ot); 7037 if (error != 0) 7038 break; 7039 } 7040 7041 return (error); 7042 7043} 7044 7045 7046/* ------------------------------------------------------------------------ */ 7047/* Function: ipf_tune */ 7048/* Returns: int - 0 == success, else failure */ 7049/* Parameters: cmd(I) - ioctl command number */ 7050/* data(I) - pointer to ioctl data structure */ 7051/* */ 7052/* Implement handling of SIOCIPFGETNEXT, SIOCIPFGET and SIOCIPFSET. These */ 7053/* three ioctls provide the means to access and control global variables */ 7054/* within IPFilter, allowing (for example) timeouts and table sizes to be */ 7055/* changed without rebooting, reloading or recompiling. The initialisation */ 7056/* and 'destruction' routines of the various components of ipfilter are all */ 7057/* each responsible for handling their own values being too big. */ 7058/* ------------------------------------------------------------------------ */ 7059int 7060ipf_ipftune(ipf_main_softc_t *softc, ioctlcmd_t cmd, void *data) 7061{ 7062 ipftuneable_t *ta; 7063 ipftune_t tu; 7064 void *cookie; 7065 int error; 7066 7067 error = ipf_inobj(softc, data, NULL, &tu, IPFOBJ_TUNEABLE); 7068 if (error != 0) 7069 return (error); 7070 7071 tu.ipft_name[sizeof(tu.ipft_name) - 1] = '\0'; 7072 cookie = tu.ipft_cookie; 7073 ta = NULL; 7074 7075 switch (cmd) 7076 { 7077 case SIOCIPFGETNEXT : 7078 /* 7079 * If cookie is non-NULL, assume it to be a pointer to the last 7080 * entry we looked at, so find it (if possible) and return a 7081 * pointer to the next one after it. The last entry in the 7082 * the table is a NULL entry, so when we get to it, set cookie 7083 * to NULL and return that, indicating end of list, erstwhile 7084 * if we come in with cookie set to NULL, we are starting anew 7085 * at the front of the list. 7086 */ 7087 if (cookie != NULL) { 7088 ta = ipf_tune_findbycookie(&softc->ipf_tuners, 7089 cookie, &tu.ipft_cookie); 7090 } else { 7091 ta = softc->ipf_tuners; 7092 tu.ipft_cookie = ta + 1; 7093 } 7094 if (ta != NULL) { 7095 /* 7096 * Entry found, but does the data pointed to by that 7097 * row fit in what we can return? 7098 */ 7099 if (ta->ipft_sz > sizeof(tu.ipft_un)) { 7100 IPFERROR(76); 7101 return (EINVAL); 7102 } 7103 7104 tu.ipft_vlong = 0; 7105 if (ta->ipft_sz == sizeof(u_long)) 7106 tu.ipft_vlong = *ta->ipft_plong; 7107 else if (ta->ipft_sz == sizeof(u_int)) 7108 tu.ipft_vint = *ta->ipft_pint; 7109 else if (ta->ipft_sz == sizeof(u_short)) 7110 tu.ipft_vshort = *ta->ipft_pshort; 7111 else if (ta->ipft_sz == sizeof(u_char)) 7112 tu.ipft_vchar = *ta->ipft_pchar; 7113 7114 tu.ipft_sz = ta->ipft_sz; 7115 tu.ipft_min = ta->ipft_min; 7116 tu.ipft_max = ta->ipft_max; 7117 tu.ipft_flags = ta->ipft_flags; 7118 bcopy(ta->ipft_name, tu.ipft_name, 7119 MIN(sizeof(tu.ipft_name), 7120 strlen(ta->ipft_name) + 1)); 7121 } 7122 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE); 7123 break; 7124 7125 case SIOCIPFGET : 7126 case SIOCIPFSET : 7127 /* 7128 * Search by name or by cookie value for a particular entry 7129 * in the tuning parameter table. 7130 */ 7131 IPFERROR(77); 7132 error = ESRCH; 7133 if (cookie != NULL) { 7134 ta = ipf_tune_findbycookie(&softc->ipf_tuners, 7135 cookie, NULL); 7136 if (ta != NULL) 7137 error = 0; 7138 } else if (tu.ipft_name[0] != '\0') { 7139 ta = ipf_tune_findbyname(softc->ipf_tuners, 7140 tu.ipft_name); 7141 if (ta != NULL) 7142 error = 0; 7143 } 7144 if (error != 0) 7145 break; 7146 7147 if (cmd == (ioctlcmd_t)SIOCIPFGET) { 7148 /* 7149 * Fetch the tuning parameters for a particular value 7150 */ 7151 tu.ipft_vlong = 0; 7152 if (ta->ipft_sz == sizeof(u_long)) 7153 tu.ipft_vlong = *ta->ipft_plong; 7154 else if (ta->ipft_sz == sizeof(u_int)) 7155 tu.ipft_vint = *ta->ipft_pint; 7156 else if (ta->ipft_sz == sizeof(u_short)) 7157 tu.ipft_vshort = *ta->ipft_pshort; 7158 else if (ta->ipft_sz == sizeof(u_char)) 7159 tu.ipft_vchar = *ta->ipft_pchar; 7160 tu.ipft_cookie = ta; 7161 tu.ipft_sz = ta->ipft_sz; 7162 tu.ipft_min = ta->ipft_min; 7163 tu.ipft_max = ta->ipft_max; 7164 tu.ipft_flags = ta->ipft_flags; 7165 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE); 7166 7167 } else if (cmd == (ioctlcmd_t)SIOCIPFSET) { 7168 /* 7169 * Set an internal parameter. The hard part here is 7170 * getting the new value safely and correctly out of 7171 * the kernel (given we only know its size, not type.) 7172 */ 7173 u_long in; 7174 7175 if (((ta->ipft_flags & IPFT_WRDISABLED) != 0) && 7176 (softc->ipf_running > 0)) { 7177 IPFERROR(78); 7178 error = EBUSY; 7179 break; 7180 } 7181 7182 in = tu.ipft_vlong; 7183 if (in < ta->ipft_min || in > ta->ipft_max) { 7184 IPFERROR(79); 7185 error = EINVAL; 7186 break; 7187 } 7188 7189 if (ta->ipft_func != NULL) { 7190 SPL_INT(s); 7191 7192 SPL_NET(s); 7193 error = (*ta->ipft_func)(softc, ta, 7194 &tu.ipft_un); 7195 SPL_X(s); 7196 7197 } else if (ta->ipft_sz == sizeof(u_long)) { 7198 tu.ipft_vlong = *ta->ipft_plong; 7199 *ta->ipft_plong = in; 7200 7201 } else if (ta->ipft_sz == sizeof(u_int)) { 7202 tu.ipft_vint = *ta->ipft_pint; 7203 *ta->ipft_pint = (u_int)(in & 0xffffffff); 7204 7205 } else if (ta->ipft_sz == sizeof(u_short)) { 7206 tu.ipft_vshort = *ta->ipft_pshort; 7207 *ta->ipft_pshort = (u_short)(in & 0xffff); 7208 7209 } else if (ta->ipft_sz == sizeof(u_char)) { 7210 tu.ipft_vchar = *ta->ipft_pchar; 7211 *ta->ipft_pchar = (u_char)(in & 0xff); 7212 } 7213 error = ipf_outobj(softc, data, &tu, IPFOBJ_TUNEABLE); 7214 } 7215 break; 7216 7217 default : 7218 IPFERROR(80); 7219 error = EINVAL; 7220 break; 7221 } 7222 7223 return (error); 7224} 7225 7226 7227/* ------------------------------------------------------------------------ */ 7228/* Function: ipf_zerostats */ 7229/* Returns: int - 0 = success, else failure */ 7230/* Parameters: data(O) - pointer to pointer for copying data back to */ 7231/* */ 7232/* Copies the current statistics out to userspace and then zero's the */ 7233/* current ones in the kernel. The lock is only held across the bzero() as */ 7234/* the copyout may result in paging (ie network activity.) */ 7235/* ------------------------------------------------------------------------ */ 7236int 7237ipf_zerostats(ipf_main_softc_t *softc, caddr_t data) 7238{ 7239 friostat_t fio; 7240 ipfobj_t obj; 7241 int error; 7242 7243 error = ipf_inobj(softc, data, &obj, &fio, IPFOBJ_IPFSTAT); 7244 if (error != 0) 7245 return (error); 7246 ipf_getstat(softc, &fio, obj.ipfo_rev); 7247 error = ipf_outobj(softc, data, &fio, IPFOBJ_IPFSTAT); 7248 if (error != 0) 7249 return (error); 7250 7251 WRITE_ENTER(&softc->ipf_mutex); 7252 bzero(&softc->ipf_stats, sizeof(softc->ipf_stats)); 7253 RWLOCK_EXIT(&softc->ipf_mutex); 7254 7255 return (0); 7256} 7257 7258 7259/* ------------------------------------------------------------------------ */ 7260/* Function: ipf_resolvedest */ 7261/* Returns: Nil */ 7262/* Parameters: softc(I) - pointer to soft context main structure */ 7263/* base(I) - where strings are stored */ 7264/* fdp(IO) - pointer to destination information to resolve */ 7265/* v(I) - IP protocol version to match */ 7266/* */ 7267/* Looks up an interface name in the frdest structure pointed to by fdp and */ 7268/* if a matching name can be found for the particular IP protocol version */ 7269/* then store the interface pointer in the frdest struct. If no match is */ 7270/* found, then set the interface pointer to be -1 as NULL is considered to */ 7271/* indicate there is no information at all in the structure. */ 7272/* ------------------------------------------------------------------------ */ 7273int 7274ipf_resolvedest(ipf_main_softc_t *softc, char *base, frdest_t *fdp, int v) 7275{ 7276 int errval = 0; 7277 void *ifp; 7278 7279 ifp = NULL; 7280 7281 if (fdp->fd_name != -1) { 7282 if (fdp->fd_type == FRD_DSTLIST) { 7283 ifp = ipf_lookup_res_name(softc, IPL_LOGIPF, 7284 IPLT_DSTLIST, 7285 base + fdp->fd_name, 7286 NULL); 7287 if (ifp == NULL) { 7288 IPFERROR(144); 7289 errval = ESRCH; 7290 } 7291 } else { 7292 ifp = GETIFP(base + fdp->fd_name, v); 7293 if (ifp == NULL) 7294 ifp = (void *)-1; 7295 } 7296 } 7297 fdp->fd_ptr = ifp; 7298 7299 return (errval); 7300} 7301 7302 7303/* ------------------------------------------------------------------------ */ 7304/* Function: ipf_resolvenic */ 7305/* Returns: void* - NULL = wildcard name, -1 = failed to find NIC, else */ 7306/* pointer to interface structure for NIC */ 7307/* Parameters: softc(I)- pointer to soft context main structure */ 7308/* name(I) - complete interface name */ 7309/* v(I) - IP protocol version */ 7310/* */ 7311/* Look for a network interface structure that firstly has a matching name */ 7312/* to that passed in and that is also being used for that IP protocol */ 7313/* version (necessary on some platforms where there are separate listings */ 7314/* for both IPv4 and IPv6 on the same physical NIC. */ 7315/* ------------------------------------------------------------------------ */ 7316void * 7317ipf_resolvenic(ipf_main_softc_t *softc, char *name, int v) 7318{ 7319 void *nic; 7320 7321 softc = softc; /* gcc -Wextra */ 7322 if (name[0] == '\0') 7323 return (NULL); 7324 7325 if ((name[1] == '\0') && ((name[0] == '-') || (name[0] == '*'))) { 7326 return (NULL); 7327 } 7328 7329 nic = GETIFP(name, v); 7330 if (nic == NULL) 7331 nic = (void *)-1; 7332 return (nic); 7333} 7334 7335 7336/* ------------------------------------------------------------------------ */ 7337/* Function: ipf_token_expire */ 7338/* Returns: None. */ 7339/* Parameters: softc(I) - pointer to soft context main structure */ 7340/* */ 7341/* This function is run every ipf tick to see if there are any tokens that */ 7342/* have been held for too long and need to be freed up. */ 7343/* ------------------------------------------------------------------------ */ 7344void 7345ipf_token_expire(ipf_main_softc_t *softc) 7346{ 7347 ipftoken_t *it; 7348 7349 WRITE_ENTER(&softc->ipf_tokens); 7350 while ((it = softc->ipf_token_head) != NULL) { 7351 if (it->ipt_die > softc->ipf_ticks) 7352 break; 7353 7354 ipf_token_deref(softc, it); 7355 } 7356 RWLOCK_EXIT(&softc->ipf_tokens); 7357} 7358 7359 7360/* ------------------------------------------------------------------------ */ 7361/* Function: ipf_token_flush */ 7362/* Returns: None. */ 7363/* Parameters: softc(I) - pointer to soft context main structure */ 7364/* */ 7365/* Loop through all of the existing tokens and call deref to see if they */ 7366/* can be freed. Normally a function like this might just loop on */ 7367/* ipf_token_head but there is a chance that a token might have a ref count */ 7368/* of greater than one and in that case the reference would drop twice */ 7369/* by code that is only entitled to drop it once. */ 7370/* ------------------------------------------------------------------------ */ 7371static void 7372ipf_token_flush(ipf_main_softc_t *softc) 7373{ 7374 ipftoken_t *it, *next; 7375 7376 WRITE_ENTER(&softc->ipf_tokens); 7377 for (it = softc->ipf_token_head; it != NULL; it = next) { 7378 next = it->ipt_next; 7379 (void) ipf_token_deref(softc, it); 7380 } 7381 RWLOCK_EXIT(&softc->ipf_tokens); 7382} 7383 7384 7385/* ------------------------------------------------------------------------ */ 7386/* Function: ipf_token_del */ 7387/* Returns: int - 0 = success, else error */ 7388/* Parameters: softc(I)- pointer to soft context main structure */ 7389/* type(I) - the token type to match */ 7390/* uid(I) - uid owning the token */ 7391/* ptr(I) - context pointer for the token */ 7392/* */ 7393/* This function looks for a token in the current list that matches up */ 7394/* the fields (type, uid, ptr). If none is found, ESRCH is returned, else */ 7395/* call ipf_token_dewref() to remove it from the list. In the event that */ 7396/* the token has a reference held elsewhere, setting ipt_complete to 2 */ 7397/* enables debugging to distinguish between the two paths that ultimately */ 7398/* lead to a token to be deleted. */ 7399/* ------------------------------------------------------------------------ */ 7400int 7401ipf_token_del(ipf_main_softc_t *softc, int type, int uid, void *ptr) 7402{ 7403 ipftoken_t *it; 7404 int error; 7405 7406 IPFERROR(82); 7407 error = ESRCH; 7408 7409 WRITE_ENTER(&softc->ipf_tokens); 7410 for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) { 7411 if (ptr == it->ipt_ctx && type == it->ipt_type && 7412 uid == it->ipt_uid) { 7413 it->ipt_complete = 2; 7414 ipf_token_deref(softc, it); 7415 error = 0; 7416 break; 7417 } 7418 } 7419 RWLOCK_EXIT(&softc->ipf_tokens); 7420 7421 return (error); 7422} 7423 7424 7425/* ------------------------------------------------------------------------ */ 7426/* Function: ipf_token_mark_complete */ 7427/* Returns: None. */ 7428/* Parameters: token(I) - pointer to token structure */ 7429/* */ 7430/* Mark a token as being ineligable for being found with ipf_token_find. */ 7431/* ------------------------------------------------------------------------ */ 7432void 7433ipf_token_mark_complete(ipftoken_t *token) 7434{ 7435 if (token->ipt_complete == 0) 7436 token->ipt_complete = 1; 7437} 7438 7439 7440/* ------------------------------------------------------------------------ */ 7441/* Function: ipf_token_find */ 7442/* Returns: ipftoken_t * - NULL if no memory, else pointer to token */ 7443/* Parameters: softc(I)- pointer to soft context main structure */ 7444/* type(I) - the token type to match */ 7445/* uid(I) - uid owning the token */ 7446/* ptr(I) - context pointer for the token */ 7447/* */ 7448/* This function looks for a live token in the list of current tokens that */ 7449/* matches the tuple (type, uid, ptr). If one cannot be found then one is */ 7450/* allocated. If one is found then it is moved to the top of the list of */ 7451/* currently active tokens. */ 7452/* ------------------------------------------------------------------------ */ 7453ipftoken_t * 7454ipf_token_find(ipf_main_softc_t *softc, int type, int uid, void *ptr) 7455{ 7456 ipftoken_t *it, *new; 7457 7458 WRITE_ENTER(&softc->ipf_tokens); 7459 for (it = softc->ipf_token_head; it != NULL; it = it->ipt_next) { 7460 if ((ptr == it->ipt_ctx) && (type == it->ipt_type) && 7461 (uid == it->ipt_uid) && (it->ipt_complete < 2)) 7462 break; 7463 } 7464 7465 if (it == NULL) { 7466 KMALLOC(new, ipftoken_t *); 7467 if (new != NULL) 7468 bzero((char *)new, sizeof(*new)); 7469 7470 it = new; 7471 new = NULL; 7472 if (it == NULL) { 7473 RWLOCK_EXIT(&softc->ipf_tokens); 7474 return (NULL); 7475 } 7476 it->ipt_ctx = ptr; 7477 it->ipt_uid = uid; 7478 it->ipt_type = type; 7479 it->ipt_ref = 1; 7480 } else { 7481 if (it->ipt_complete > 0) 7482 it = NULL; 7483 else 7484 ipf_token_unlink(softc, it); 7485 } 7486 7487 if (it != NULL) { 7488 it->ipt_pnext = softc->ipf_token_tail; 7489 *softc->ipf_token_tail = it; 7490 softc->ipf_token_tail = &it->ipt_next; 7491 it->ipt_next = NULL; 7492 it->ipt_ref++; 7493 7494 it->ipt_die = softc->ipf_ticks + 20; 7495 } 7496 7497 RWLOCK_EXIT(&softc->ipf_tokens); 7498 7499 return (it); 7500} 7501 7502 7503/* ------------------------------------------------------------------------ */ 7504/* Function: ipf_token_unlink */ 7505/* Returns: None. */ 7506/* Parameters: softc(I) - pointer to soft context main structure */ 7507/* token(I) - pointer to token structure */ 7508/* Write Locks: ipf_tokens */ 7509/* */ 7510/* This function unlinks a token structure from the linked list of tokens */ 7511/* that "own" it. The head pointer never needs to be explicitly adjusted */ 7512/* but the tail does due to the linked list implementation. */ 7513/* ------------------------------------------------------------------------ */ 7514static void 7515ipf_token_unlink(ipf_main_softc_t *softc, ipftoken_t *token) 7516{ 7517 7518 if (softc->ipf_token_tail == &token->ipt_next) 7519 softc->ipf_token_tail = token->ipt_pnext; 7520 7521 *token->ipt_pnext = token->ipt_next; 7522 if (token->ipt_next != NULL) 7523 token->ipt_next->ipt_pnext = token->ipt_pnext; 7524 token->ipt_next = NULL; 7525 token->ipt_pnext = NULL; 7526} 7527 7528 7529/* ------------------------------------------------------------------------ */ 7530/* Function: ipf_token_deref */ 7531/* Returns: int - 0 == token freed, else reference count */ 7532/* Parameters: softc(I) - pointer to soft context main structure */ 7533/* token(I) - pointer to token structure */ 7534/* Write Locks: ipf_tokens */ 7535/* */ 7536/* Drop the reference count on the token structure and if it drops to zero, */ 7537/* call the dereference function for the token type because it is then */ 7538/* possible to free the token data structure. */ 7539/* ------------------------------------------------------------------------ */ 7540int 7541ipf_token_deref(ipf_main_softc_t *softc, ipftoken_t *token) 7542{ 7543 void *data, **datap; 7544 7545 ASSERT(token->ipt_ref > 0); 7546 token->ipt_ref--; 7547 if (token->ipt_ref > 0) 7548 return (token->ipt_ref); 7549 7550 data = token->ipt_data; 7551 datap = &data; 7552 7553 if ((data != NULL) && (data != (void *)-1)) { 7554 switch (token->ipt_type) 7555 { 7556 case IPFGENITER_IPF : 7557 (void) ipf_derefrule(softc, (frentry_t **)datap); 7558 break; 7559 case IPFGENITER_IPNAT : 7560 WRITE_ENTER(&softc->ipf_nat); 7561 ipf_nat_rule_deref(softc, (ipnat_t **)datap); 7562 RWLOCK_EXIT(&softc->ipf_nat); 7563 break; 7564 case IPFGENITER_NAT : 7565 ipf_nat_deref(softc, (nat_t **)datap); 7566 break; 7567 case IPFGENITER_STATE : 7568 ipf_state_deref(softc, (ipstate_t **)datap); 7569 break; 7570 case IPFGENITER_FRAG : 7571 ipf_frag_pkt_deref(softc, (ipfr_t **)datap); 7572 break; 7573 case IPFGENITER_NATFRAG : 7574 ipf_frag_nat_deref(softc, (ipfr_t **)datap); 7575 break; 7576 case IPFGENITER_HOSTMAP : 7577 WRITE_ENTER(&softc->ipf_nat); 7578 ipf_nat_hostmapdel(softc, (hostmap_t **)datap); 7579 RWLOCK_EXIT(&softc->ipf_nat); 7580 break; 7581 default : 7582 ipf_lookup_iterderef(softc, token->ipt_type, data); 7583 break; 7584 } 7585 } 7586 7587 ipf_token_unlink(softc, token); 7588 KFREE(token); 7589 return (0); 7590} 7591 7592 7593/* ------------------------------------------------------------------------ */ 7594/* Function: ipf_nextrule */ 7595/* Returns: frentry_t * - NULL == no more rules, else pointer to next */ 7596/* Parameters: softc(I) - pointer to soft context main structure */ 7597/* fr(I) - pointer to filter rule */ 7598/* out(I) - 1 == out rules, 0 == input rules */ 7599/* */ 7600/* Starting with "fr", find the next rule to visit. This includes visiting */ 7601/* the list of rule groups if either fr is NULL (empty list) or it is the */ 7602/* last rule in the list. When walking rule lists, it is either input or */ 7603/* output rules that are returned, never both. */ 7604/* ------------------------------------------------------------------------ */ 7605static frentry_t * 7606ipf_nextrule(ipf_main_softc_t *softc, int active, int unit, frentry_t *fr, 7607 int out) 7608{ 7609 frentry_t *next; 7610 frgroup_t *fg; 7611 7612 if (fr != NULL && fr->fr_group != -1) { 7613 fg = ipf_findgroup(softc, fr->fr_names + fr->fr_group, 7614 unit, active, NULL); 7615 if (fg != NULL) 7616 fg = fg->fg_next; 7617 } else { 7618 fg = softc->ipf_groups[unit][active]; 7619 } 7620 7621 while (fg != NULL) { 7622 next = fg->fg_start; 7623 while (next != NULL) { 7624 if (out) { 7625 if (next->fr_flags & FR_OUTQUE) 7626 return (next); 7627 } else if (next->fr_flags & FR_INQUE) { 7628 return (next); 7629 } 7630 next = next->fr_next; 7631 } 7632 if (next == NULL) 7633 fg = fg->fg_next; 7634 } 7635 7636 return (NULL); 7637} 7638 7639/* ------------------------------------------------------------------------ */ 7640/* Function: ipf_getnextrule */ 7641/* Returns: int - 0 = success, else error */ 7642/* Parameters: softc(I)- pointer to soft context main structure */ 7643/* t(I) - pointer to destination information to resolve */ 7644/* ptr(I) - pointer to ipfobj_t to copyin from user space */ 7645/* */ 7646/* This function's first job is to bring in the ipfruleiter_t structure via */ 7647/* the ipfobj_t structure to determine what should be the next rule to */ 7648/* return. Once the ipfruleiter_t has been brought in, it then tries to */ 7649/* find the 'next rule'. This may include searching rule group lists or */ 7650/* just be as simple as looking at the 'next' field in the rule structure. */ 7651/* When we have found the rule to return, increase its reference count and */ 7652/* if we used an existing rule to get here, decrease its reference count. */ 7653/* ------------------------------------------------------------------------ */ 7654int 7655ipf_getnextrule(ipf_main_softc_t *softc, ipftoken_t *t, void *ptr) 7656{ 7657 frentry_t *fr, *next, zero; 7658 ipfruleiter_t it; 7659 int error, out; 7660 frgroup_t *fg; 7661 ipfobj_t obj; 7662 int predict; 7663 char *dst; 7664 int unit; 7665 7666 if (t == NULL || ptr == NULL) { 7667 IPFERROR(84); 7668 return (EFAULT); 7669 } 7670 7671 error = ipf_inobj(softc, ptr, &obj, &it, IPFOBJ_IPFITER); 7672 if (error != 0) 7673 return (error); 7674 7675 if ((it.iri_inout < 0) || (it.iri_inout > 3)) { 7676 IPFERROR(85); 7677 return (EINVAL); 7678 } 7679 if ((it.iri_active != 0) && (it.iri_active != 1)) { 7680 IPFERROR(86); 7681 return (EINVAL); 7682 } 7683 if (it.iri_nrules == 0) { 7684 IPFERROR(87); 7685 return (ENOSPC); 7686 } 7687 if (it.iri_rule == NULL) { 7688 IPFERROR(88); 7689 return (EFAULT); 7690 } 7691 7692 fg = NULL; 7693 fr = t->ipt_data; 7694 if ((it.iri_inout & F_OUT) != 0) 7695 out = 1; 7696 else 7697 out = 0; 7698 if ((it.iri_inout & F_ACIN) != 0) 7699 unit = IPL_LOGCOUNT; 7700 else 7701 unit = IPL_LOGIPF; 7702 7703 READ_ENTER(&softc->ipf_mutex); 7704 if (fr == NULL) { 7705 if (*it.iri_group == '\0') { 7706 if (unit == IPL_LOGCOUNT) { 7707 next = softc->ipf_acct[out][it.iri_active]; 7708 } else { 7709 next = softc->ipf_rules[out][it.iri_active]; 7710 } 7711 if (next == NULL) 7712 next = ipf_nextrule(softc, it.iri_active, 7713 unit, NULL, out); 7714 } else { 7715 fg = ipf_findgroup(softc, it.iri_group, unit, 7716 it.iri_active, NULL); 7717 if (fg != NULL) 7718 next = fg->fg_start; 7719 else 7720 next = NULL; 7721 } 7722 } else { 7723 next = fr->fr_next; 7724 if (next == NULL) 7725 next = ipf_nextrule(softc, it.iri_active, unit, 7726 fr, out); 7727 } 7728 7729 if (next != NULL && next->fr_next != NULL) 7730 predict = 1; 7731 else if (ipf_nextrule(softc, it.iri_active, unit, next, out) != NULL) 7732 predict = 1; 7733 else 7734 predict = 0; 7735 7736 if (fr != NULL) 7737 (void) ipf_derefrule(softc, &fr); 7738 7739 obj.ipfo_type = IPFOBJ_FRENTRY; 7740 dst = (char *)it.iri_rule; 7741 7742 if (next != NULL) { 7743 obj.ipfo_size = next->fr_size; 7744 MUTEX_ENTER(&next->fr_lock); 7745 next->fr_ref++; 7746 MUTEX_EXIT(&next->fr_lock); 7747 t->ipt_data = next; 7748 } else { 7749 obj.ipfo_size = sizeof(frentry_t); 7750 bzero(&zero, sizeof(zero)); 7751 next = &zero; 7752 t->ipt_data = NULL; 7753 } 7754 it.iri_rule = predict ? next : NULL; 7755 if (predict == 0) 7756 ipf_token_mark_complete(t); 7757 7758 RWLOCK_EXIT(&softc->ipf_mutex); 7759 7760 obj.ipfo_ptr = dst; 7761 error = ipf_outobjk(softc, &obj, next); 7762 if (error == 0 && t->ipt_data != NULL) { 7763 dst += obj.ipfo_size; 7764 if (next->fr_data != NULL) { 7765 ipfobj_t dobj; 7766 7767 if (next->fr_type == FR_T_IPFEXPR) 7768 dobj.ipfo_type = IPFOBJ_IPFEXPR; 7769 else 7770 dobj.ipfo_type = IPFOBJ_FRIPF; 7771 dobj.ipfo_size = next->fr_dsize; 7772 dobj.ipfo_rev = obj.ipfo_rev; 7773 dobj.ipfo_ptr = dst; 7774 error = ipf_outobjk(softc, &dobj, next->fr_data); 7775 } 7776 } 7777 7778 if ((fr != NULL) && (next == &zero)) 7779 (void) ipf_derefrule(softc, &fr); 7780 7781 return (error); 7782} 7783 7784 7785/* ------------------------------------------------------------------------ */ 7786/* Function: ipf_frruleiter */ 7787/* Returns: int - 0 = success, else error */ 7788/* Parameters: softc(I)- pointer to soft context main structure */ 7789/* data(I) - the token type to match */ 7790/* uid(I) - uid owning the token */ 7791/* ptr(I) - context pointer for the token */ 7792/* */ 7793/* This function serves as a stepping stone between ipf_ipf_ioctl and */ 7794/* ipf_getnextrule. It's role is to find the right token in the kernel for */ 7795/* the process doing the ioctl and use that to ask for the next rule. */ 7796/* ------------------------------------------------------------------------ */ 7797static int 7798ipf_frruleiter(ipf_main_softc_t *softc, void *data, int uid, void *ctx) 7799{ 7800 ipftoken_t *token; 7801 ipfruleiter_t it; 7802 ipfobj_t obj; 7803 int error; 7804 7805 token = ipf_token_find(softc, IPFGENITER_IPF, uid, ctx); 7806 if (token != NULL) { 7807 error = ipf_getnextrule(softc, token, data); 7808 WRITE_ENTER(&softc->ipf_tokens); 7809 ipf_token_deref(softc, token); 7810 RWLOCK_EXIT(&softc->ipf_tokens); 7811 } else { 7812 error = ipf_inobj(softc, data, &obj, &it, IPFOBJ_IPFITER); 7813 if (error != 0) 7814 return (error); 7815 it.iri_rule = NULL; 7816 error = ipf_outobj(softc, data, &it, IPFOBJ_IPFITER); 7817 } 7818 7819 return (error); 7820} 7821 7822 7823/* ------------------------------------------------------------------------ */ 7824/* Function: ipf_geniter */ 7825/* Returns: int - 0 = success, else error */ 7826/* Parameters: softc(I) - pointer to soft context main structure */ 7827/* token(I) - pointer to ipftoken_t structure */ 7828/* itp(I) - pointer to iterator data */ 7829/* */ 7830/* Decide which iterator function to call using information passed through */ 7831/* the ipfgeniter_t structure at itp. */ 7832/* ------------------------------------------------------------------------ */ 7833static int 7834ipf_geniter(ipf_main_softc_t *softc, ipftoken_t *token, ipfgeniter_t *itp) 7835{ 7836 int error; 7837 7838 switch (itp->igi_type) 7839 { 7840 case IPFGENITER_FRAG : 7841 error = ipf_frag_pkt_next(softc, token, itp); 7842 break; 7843 default : 7844 IPFERROR(92); 7845 error = EINVAL; 7846 break; 7847 } 7848 7849 return (error); 7850} 7851 7852 7853/* ------------------------------------------------------------------------ */ 7854/* Function: ipf_genericiter */ 7855/* Returns: int - 0 = success, else error */ 7856/* Parameters: softc(I)- pointer to soft context main structure */ 7857/* data(I) - the token type to match */ 7858/* uid(I) - uid owning the token */ 7859/* ptr(I) - context pointer for the token */ 7860/* */ 7861/* Handle the SIOCGENITER ioctl for the ipfilter device. The primary role */ 7862/* ------------------------------------------------------------------------ */ 7863int 7864ipf_genericiter(ipf_main_softc_t *softc, void *data, int uid, void *ctx) 7865{ 7866 ipftoken_t *token; 7867 ipfgeniter_t iter; 7868 int error; 7869 7870 error = ipf_inobj(softc, data, NULL, &iter, IPFOBJ_GENITER); 7871 if (error != 0) 7872 return (error); 7873 7874 token = ipf_token_find(softc, iter.igi_type, uid, ctx); 7875 if (token != NULL) { 7876 token->ipt_subtype = iter.igi_type; 7877 error = ipf_geniter(softc, token, &iter); 7878 WRITE_ENTER(&softc->ipf_tokens); 7879 ipf_token_deref(softc, token); 7880 RWLOCK_EXIT(&softc->ipf_tokens); 7881 } else { 7882 IPFERROR(93); 7883 error = 0; 7884 } 7885 7886 return (error); 7887} 7888 7889 7890/* ------------------------------------------------------------------------ */ 7891/* Function: ipf_ipf_ioctl */ 7892/* Returns: int - 0 = success, else error */ 7893/* Parameters: softc(I)- pointer to soft context main structure */ 7894/* data(I) - the token type to match */ 7895/* cmd(I) - the ioctl command number */ 7896/* mode(I) - mode flags for the ioctl */ 7897/* uid(I) - uid owning the token */ 7898/* ptr(I) - context pointer for the token */ 7899/* */ 7900/* This function handles all of the ioctl command that are actually issued */ 7901/* to the /dev/ipl device. */ 7902/* ------------------------------------------------------------------------ */ 7903int 7904ipf_ipf_ioctl(ipf_main_softc_t *softc, caddr_t data, ioctlcmd_t cmd, int mode, 7905 int uid, void *ctx) 7906{ 7907 friostat_t fio; 7908 int error, tmp; 7909 ipfobj_t obj; 7910 SPL_INT(s); 7911 7912 switch (cmd) 7913 { 7914 case SIOCFRENB : 7915 if (!(mode & FWRITE)) { 7916 IPFERROR(94); 7917 error = EPERM; 7918 } else { 7919 error = BCOPYIN(data, &tmp, sizeof(tmp)); 7920 if (error != 0) { 7921 IPFERROR(95); 7922 error = EFAULT; 7923 break; 7924 } 7925 7926 WRITE_ENTER(&softc->ipf_global); 7927 if (tmp) { 7928 if (softc->ipf_running > 0) 7929 error = 0; 7930 else 7931 error = ipfattach(softc); 7932 if (error == 0) 7933 softc->ipf_running = 1; 7934 else 7935 (void) ipfdetach(softc); 7936 } else { 7937 if (softc->ipf_running == 1) 7938 error = ipfdetach(softc); 7939 else 7940 error = 0; 7941 if (error == 0) 7942 softc->ipf_running = -1; 7943 } 7944 RWLOCK_EXIT(&softc->ipf_global); 7945 } 7946 break; 7947 7948 case SIOCIPFSET : 7949 if (!(mode & FWRITE)) { 7950 IPFERROR(96); 7951 error = EPERM; 7952 break; 7953 } 7954 /* FALLTHRU */ 7955 case SIOCIPFGETNEXT : 7956 case SIOCIPFGET : 7957 error = ipf_ipftune(softc, cmd, (void *)data); 7958 break; 7959 7960 case SIOCSETFF : 7961 if (!(mode & FWRITE)) { 7962 IPFERROR(97); 7963 error = EPERM; 7964 } else { 7965 error = BCOPYIN(data, &softc->ipf_flags, 7966 sizeof(softc->ipf_flags)); 7967 if (error != 0) { 7968 IPFERROR(98); 7969 error = EFAULT; 7970 } 7971 } 7972 break; 7973 7974 case SIOCGETFF : 7975 error = BCOPYOUT(&softc->ipf_flags, data, 7976 sizeof(softc->ipf_flags)); 7977 if (error != 0) { 7978 IPFERROR(99); 7979 error = EFAULT; 7980 } 7981 break; 7982 7983 case SIOCFUNCL : 7984 error = ipf_resolvefunc(softc, (void *)data); 7985 break; 7986 7987 case SIOCINAFR : 7988 case SIOCRMAFR : 7989 case SIOCADAFR : 7990 case SIOCZRLST : 7991 if (!(mode & FWRITE)) { 7992 IPFERROR(100); 7993 error = EPERM; 7994 } else { 7995 error = frrequest(softc, IPL_LOGIPF, cmd, (caddr_t)data, 7996 softc->ipf_active, 1); 7997 } 7998 break; 7999 8000 case SIOCINIFR : 8001 case SIOCRMIFR : 8002 case SIOCADIFR : 8003 if (!(mode & FWRITE)) { 8004 IPFERROR(101); 8005 error = EPERM; 8006 } else { 8007 error = frrequest(softc, IPL_LOGIPF, cmd, (caddr_t)data, 8008 1 - softc->ipf_active, 1); 8009 } 8010 break; 8011 8012 case SIOCSWAPA : 8013 if (!(mode & FWRITE)) { 8014 IPFERROR(102); 8015 error = EPERM; 8016 } else { 8017 WRITE_ENTER(&softc->ipf_mutex); 8018 error = BCOPYOUT(&softc->ipf_active, data, 8019 sizeof(softc->ipf_active)); 8020 if (error != 0) { 8021 IPFERROR(103); 8022 error = EFAULT; 8023 } else { 8024 softc->ipf_active = 1 - softc->ipf_active; 8025 } 8026 RWLOCK_EXIT(&softc->ipf_mutex); 8027 } 8028 break; 8029 8030 case SIOCGETFS : 8031 error = ipf_inobj(softc, (void *)data, &obj, &fio, 8032 IPFOBJ_IPFSTAT); 8033 if (error != 0) 8034 break; 8035 ipf_getstat(softc, &fio, obj.ipfo_rev); 8036 error = ipf_outobj(softc, (void *)data, &fio, IPFOBJ_IPFSTAT); 8037 break; 8038 8039 case SIOCFRZST : 8040 if (!(mode & FWRITE)) { 8041 IPFERROR(104); 8042 error = EPERM; 8043 } else 8044 error = ipf_zerostats(softc, (caddr_t)data); 8045 break; 8046 8047 case SIOCIPFFL : 8048 if (!(mode & FWRITE)) { 8049 IPFERROR(105); 8050 error = EPERM; 8051 } else { 8052 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8053 if (!error) { 8054 tmp = ipf_flush(softc, IPL_LOGIPF, tmp); 8055 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8056 if (error != 0) { 8057 IPFERROR(106); 8058 error = EFAULT; 8059 } 8060 } else { 8061 IPFERROR(107); 8062 error = EFAULT; 8063 } 8064 } 8065 break; 8066 8067#ifdef USE_INET6 8068 case SIOCIPFL6 : 8069 if (!(mode & FWRITE)) { 8070 IPFERROR(108); 8071 error = EPERM; 8072 } else { 8073 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8074 if (!error) { 8075 tmp = ipf_flush(softc, IPL_LOGIPF, tmp); 8076 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8077 if (error != 0) { 8078 IPFERROR(109); 8079 error = EFAULT; 8080 } 8081 } else { 8082 IPFERROR(110); 8083 error = EFAULT; 8084 } 8085 } 8086 break; 8087#endif 8088 8089 case SIOCSTLCK : 8090 if (!(mode & FWRITE)) { 8091 IPFERROR(122); 8092 error = EPERM; 8093 } else { 8094 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8095 if (error == 0) { 8096 ipf_state_setlock(softc->ipf_state_soft, tmp); 8097 ipf_nat_setlock(softc->ipf_nat_soft, tmp); 8098 ipf_frag_setlock(softc->ipf_frag_soft, tmp); 8099 ipf_auth_setlock(softc->ipf_auth_soft, tmp); 8100 } else { 8101 IPFERROR(111); 8102 error = EFAULT; 8103 } 8104 } 8105 break; 8106 8107#ifdef IPFILTER_LOG 8108 case SIOCIPFFB : 8109 if (!(mode & FWRITE)) { 8110 IPFERROR(112); 8111 error = EPERM; 8112 } else { 8113 tmp = ipf_log_clear(softc, IPL_LOGIPF); 8114 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8115 if (error) { 8116 IPFERROR(113); 8117 error = EFAULT; 8118 } 8119 } 8120 break; 8121#endif /* IPFILTER_LOG */ 8122 8123 case SIOCFRSYN : 8124 if (!(mode & FWRITE)) { 8125 IPFERROR(114); 8126 error = EPERM; 8127 } else { 8128 WRITE_ENTER(&softc->ipf_global); 8129#if (SOLARIS && defined(_KERNEL)) && !defined(INSTANCES) 8130 error = ipfsync(); 8131#else 8132 ipf_sync(softc, NULL); 8133 error = 0; 8134#endif 8135 RWLOCK_EXIT(&softc->ipf_global); 8136 8137 } 8138 break; 8139 8140 case SIOCGFRST : 8141 error = ipf_outobj(softc, (void *)data, 8142 ipf_frag_stats(softc->ipf_frag_soft), 8143 IPFOBJ_FRAGSTAT); 8144 break; 8145 8146#ifdef IPFILTER_LOG 8147 case FIONREAD : 8148 tmp = ipf_log_bytesused(softc, IPL_LOGIPF); 8149 error = BCOPYOUT(&tmp, data, sizeof(tmp)); 8150 break; 8151#endif 8152 8153 case SIOCIPFITER : 8154 SPL_SCHED(s); 8155 error = ipf_frruleiter(softc, data, uid, ctx); 8156 SPL_X(s); 8157 break; 8158 8159 case SIOCGENITER : 8160 SPL_SCHED(s); 8161 error = ipf_genericiter(softc, data, uid, ctx); 8162 SPL_X(s); 8163 break; 8164 8165 case SIOCIPFDELTOK : 8166 error = BCOPYIN(data, &tmp, sizeof(tmp)); 8167 if (error == 0) { 8168 SPL_SCHED(s); 8169 error = ipf_token_del(softc, tmp, uid, ctx); 8170 SPL_X(s); 8171 } 8172 break; 8173 8174 default : 8175 IPFERROR(115); 8176 error = EINVAL; 8177 break; 8178 } 8179 8180 return (error); 8181} 8182 8183 8184/* ------------------------------------------------------------------------ */ 8185/* Function: ipf_decaps */ 8186/* Returns: int - -1 == decapsulation failed, else bit mask of */ 8187/* flags indicating packet filtering decision. */ 8188/* Parameters: fin(I) - pointer to packet information */ 8189/* pass(I) - IP protocol version to match */ 8190/* l5proto(I) - layer 5 protocol to decode UDP data as. */ 8191/* */ 8192/* This function is called for packets that are wrapt up in other packets, */ 8193/* for example, an IP packet that is the entire data segment for another IP */ 8194/* packet. If the basic constraints for this are satisfied, change the */ 8195/* buffer to point to the start of the inner packet and start processing */ 8196/* rules belonging to the head group this rule specifies. */ 8197/* ------------------------------------------------------------------------ */ 8198u_32_t 8199ipf_decaps(fr_info_t *fin, u_32_t pass, int l5proto) 8200{ 8201 fr_info_t fin2, *fino = NULL; 8202 int elen, hlen, nh; 8203 grehdr_t gre; 8204 ip_t *ip; 8205 mb_t *m; 8206 8207 if ((fin->fin_flx & FI_COALESCE) == 0) 8208 if (ipf_coalesce(fin) == -1) 8209 goto cantdecaps; 8210 8211 m = fin->fin_m; 8212 hlen = fin->fin_hlen; 8213 8214 switch (fin->fin_p) 8215 { 8216 case IPPROTO_UDP : 8217 /* 8218 * In this case, the specific protocol being decapsulated 8219 * inside UDP frames comes from the rule. 8220 */ 8221 nh = fin->fin_fr->fr_icode; 8222 break; 8223 8224 case IPPROTO_GRE : /* 47 */ 8225 bcopy(fin->fin_dp, (char *)&gre, sizeof(gre)); 8226 hlen += sizeof(grehdr_t); 8227 if (gre.gr_R|gre.gr_s) 8228 goto cantdecaps; 8229 if (gre.gr_C) 8230 hlen += 4; 8231 if (gre.gr_K) 8232 hlen += 4; 8233 if (gre.gr_S) 8234 hlen += 4; 8235 8236 nh = IPPROTO_IP; 8237 8238 /* 8239 * If the routing options flag is set, validate that it is 8240 * there and bounce over it. 8241 */ 8242#if 0 8243 /* This is really heavy weight and lots of room for error, */ 8244 /* so for now, put it off and get the simple stuff right. */ 8245 if (gre.gr_R) { 8246 u_char off, len, *s; 8247 u_short af; 8248 int end; 8249 8250 end = 0; 8251 s = fin->fin_dp; 8252 s += hlen; 8253 aplen = fin->fin_plen - hlen; 8254 while (aplen > 3) { 8255 af = (s[0] << 8) | s[1]; 8256 off = s[2]; 8257 len = s[3]; 8258 aplen -= 4; 8259 s += 4; 8260 if (af == 0 && len == 0) { 8261 end = 1; 8262 break; 8263 } 8264 if (aplen < len) 8265 break; 8266 s += len; 8267 aplen -= len; 8268 } 8269 if (end != 1) 8270 goto cantdecaps; 8271 hlen = s - (u_char *)fin->fin_dp; 8272 } 8273#endif 8274 break; 8275 8276#ifdef IPPROTO_IPIP 8277 case IPPROTO_IPIP : /* 4 */ 8278#endif 8279 nh = IPPROTO_IP; 8280 break; 8281 8282 default : /* Includes ESP, AH is special for IPv4 */ 8283 goto cantdecaps; 8284 } 8285 8286 switch (nh) 8287 { 8288 case IPPROTO_IP : 8289 case IPPROTO_IPV6 : 8290 break; 8291 default : 8292 goto cantdecaps; 8293 } 8294 8295 bcopy((char *)fin, (char *)&fin2, sizeof(fin2)); 8296 fino = fin; 8297 fin = &fin2; 8298 elen = hlen; 8299#if SOLARIS && defined(_KERNEL) 8300 m->b_rptr += elen; 8301#else 8302 m->m_data += elen; 8303 m->m_len -= elen; 8304#endif 8305 fin->fin_plen -= elen; 8306 8307 ip = (ip_t *)((char *)fin->fin_ip + elen); 8308 8309 /* 8310 * Make sure we have at least enough data for the network layer 8311 * header. 8312 */ 8313 if (IP_V(ip) == 4) 8314 hlen = IP_HL(ip) << 2; 8315#ifdef USE_INET6 8316 else if (IP_V(ip) == 6) 8317 hlen = sizeof(ip6_t); 8318#endif 8319 else 8320 goto cantdecaps2; 8321 8322 if (fin->fin_plen < hlen) 8323 goto cantdecaps2; 8324 8325 fin->fin_dp = (char *)ip + hlen; 8326 8327 if (IP_V(ip) == 4) { 8328 /* 8329 * Perform IPv4 header checksum validation. 8330 */ 8331 if (ipf_cksum((u_short *)ip, hlen)) 8332 goto cantdecaps2; 8333 } 8334 8335 if (ipf_makefrip(hlen, ip, fin) == -1) { 8336cantdecaps2: 8337 if (m != NULL) { 8338#if SOLARIS && defined(_KERNEL) 8339 m->b_rptr -= elen; 8340#else 8341 m->m_data -= elen; 8342 m->m_len += elen; 8343#endif 8344 } 8345cantdecaps: 8346 DT1(frb_decapfrip, fr_info_t *, fin); 8347 pass &= ~FR_CMDMASK; 8348 pass |= FR_BLOCK|FR_QUICK; 8349 fin->fin_reason = FRB_DECAPFRIP; 8350 return (-1); 8351 } 8352 8353 pass = ipf_scanlist(fin, pass); 8354 8355 /* 8356 * Copy the packet filter "result" fields out of the fr_info_t struct 8357 * that is local to the decapsulation processing and back into the 8358 * one we were called with. 8359 */ 8360 fino->fin_flx = fin->fin_flx; 8361 fino->fin_rev = fin->fin_rev; 8362 fino->fin_icode = fin->fin_icode; 8363 fino->fin_rule = fin->fin_rule; 8364 (void) strncpy(fino->fin_group, fin->fin_group, FR_GROUPLEN); 8365 fino->fin_fr = fin->fin_fr; 8366 fino->fin_error = fin->fin_error; 8367 fino->fin_mp = fin->fin_mp; 8368 fino->fin_m = fin->fin_m; 8369 m = fin->fin_m; 8370 if (m != NULL) { 8371#if SOLARIS && defined(_KERNEL) 8372 m->b_rptr -= elen; 8373#else 8374 m->m_data -= elen; 8375 m->m_len += elen; 8376#endif 8377 } 8378 return (pass); 8379} 8380 8381 8382/* ------------------------------------------------------------------------ */ 8383/* Function: ipf_matcharray_load */ 8384/* Returns: int - 0 = success, else error */ 8385/* Parameters: softc(I) - pointer to soft context main structure */ 8386/* data(I) - pointer to ioctl data */ 8387/* objp(I) - ipfobj_t structure to load data into */ 8388/* arrayptr(I) - pointer to location to store array pointer */ 8389/* */ 8390/* This function loads in a mathing array through the ipfobj_t struct that */ 8391/* describes it. Sanity checking and array size limitations are enforced */ 8392/* in this function to prevent userspace from trying to load in something */ 8393/* that is insanely big. Once the size of the array is known, the memory */ 8394/* required is malloc'd and returned through changing *arrayptr. The */ 8395/* contents of the array are verified before returning. Only in the event */ 8396/* of a successful call is the caller required to free up the malloc area. */ 8397/* ------------------------------------------------------------------------ */ 8398int 8399ipf_matcharray_load(ipf_main_softc_t *softc, caddr_t data, ipfobj_t *objp, 8400 int **arrayptr) 8401{ 8402 int arraysize, *array, error; 8403 8404 *arrayptr = NULL; 8405 8406 error = BCOPYIN(data, objp, sizeof(*objp)); 8407 if (error != 0) { 8408 IPFERROR(116); 8409 return (EFAULT); 8410 } 8411 8412 if (objp->ipfo_type != IPFOBJ_IPFEXPR) { 8413 IPFERROR(117); 8414 return (EINVAL); 8415 } 8416 8417 if (((objp->ipfo_size & 3) != 0) || (objp->ipfo_size == 0) || 8418 (objp->ipfo_size > 1024)) { 8419 IPFERROR(118); 8420 return (EINVAL); 8421 } 8422 8423 arraysize = objp->ipfo_size * sizeof(*array); 8424 KMALLOCS(array, int *, arraysize); 8425 if (array == NULL) { 8426 IPFERROR(119); 8427 return (ENOMEM); 8428 } 8429 8430 error = COPYIN(objp->ipfo_ptr, array, arraysize); 8431 if (error != 0) { 8432 KFREES(array, arraysize); 8433 IPFERROR(120); 8434 return (EFAULT); 8435 } 8436 8437 if (ipf_matcharray_verify(array, arraysize) != 0) { 8438 KFREES(array, arraysize); 8439 IPFERROR(121); 8440 return (EINVAL); 8441 } 8442 8443 *arrayptr = array; 8444 return (0); 8445} 8446 8447 8448/* ------------------------------------------------------------------------ */ 8449/* Function: ipf_matcharray_verify */ 8450/* Returns: Nil */ 8451/* Parameters: array(I) - pointer to matching array */ 8452/* arraysize(I) - number of elements in the array */ 8453/* */ 8454/* Verify the contents of a matching array by stepping through each element */ 8455/* in it. The actual commands in the array are not verified for */ 8456/* correctness, only that all of the sizes are correctly within limits. */ 8457/* ------------------------------------------------------------------------ */ 8458int 8459ipf_matcharray_verify(int *array, int arraysize) 8460{ 8461 int i, nelem, maxidx; 8462 ipfexp_t *e; 8463 8464 nelem = arraysize / sizeof(*array); 8465 8466 /* 8467 * Currently, it makes no sense to have an array less than 6 8468 * elements long - the initial size at the from, a single operation 8469 * (minimum 4 in length) and a trailer, for a total of 6. 8470 */ 8471 if ((array[0] < 6) || (arraysize < 24) || (arraysize > 4096)) { 8472 return (-1); 8473 } 8474 8475 /* 8476 * Verify the size of data pointed to by array with how long 8477 * the array claims to be itself. 8478 */ 8479 if (array[0] * sizeof(*array) != arraysize) { 8480 return (-1); 8481 } 8482 8483 maxidx = nelem - 1; 8484 /* 8485 * The last opcode in this array should be an IPF_EXP_END. 8486 */ 8487 if (array[maxidx] != IPF_EXP_END) { 8488 return (-1); 8489 } 8490 8491 for (i = 1; i < maxidx; ) { 8492 e = (ipfexp_t *)(array + i); 8493 8494 /* 8495 * The length of the bits to check must be at least 1 8496 * (or else there is nothing to comapre with!) and it 8497 * cannot exceed the length of the data present. 8498 */ 8499 if ((e->ipfe_size < 1 ) || 8500 (e->ipfe_size + i > maxidx)) { 8501 return (-1); 8502 } 8503 i += e->ipfe_size; 8504 } 8505 return (0); 8506} 8507 8508 8509/* ------------------------------------------------------------------------ */ 8510/* Function: ipf_fr_matcharray */ 8511/* Returns: int - 0 = match failed, else positive match */ 8512/* Parameters: fin(I) - pointer to packet information */ 8513/* array(I) - pointer to matching array */ 8514/* */ 8515/* This function is used to apply a matching array against a packet and */ 8516/* return an indication of whether or not the packet successfully matches */ 8517/* all of the commands in it. */ 8518/* ------------------------------------------------------------------------ */ 8519static int 8520ipf_fr_matcharray(fr_info_t *fin, int *array) 8521{ 8522 int i, n, *x, rv, p; 8523 ipfexp_t *e; 8524 8525 rv = 0; 8526 n = array[0]; 8527 x = array + 1; 8528 8529 for (; n > 0; x += 3 + x[3], rv = 0) { 8530 e = (ipfexp_t *)x; 8531 if (e->ipfe_cmd == IPF_EXP_END) 8532 break; 8533 n -= e->ipfe_size; 8534 8535 /* 8536 * The upper 16 bits currently store the protocol value. 8537 * This is currently used with TCP and UDP port compares and 8538 * allows "tcp.port = 80" without requiring an explicit 8539 " "ip.pr = tcp" first. 8540 */ 8541 p = e->ipfe_cmd >> 16; 8542 if ((p != 0) && (p != fin->fin_p)) 8543 break; 8544 8545 switch (e->ipfe_cmd) 8546 { 8547 case IPF_EXP_IP_PR : 8548 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8549 rv |= (fin->fin_p == e->ipfe_arg0[i]); 8550 } 8551 break; 8552 8553 case IPF_EXP_IP_SRCADDR : 8554 if (fin->fin_v != 4) 8555 break; 8556 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8557 rv |= ((fin->fin_saddr & 8558 e->ipfe_arg0[i * 2 + 1]) == 8559 e->ipfe_arg0[i * 2]); 8560 } 8561 break; 8562 8563 case IPF_EXP_IP_DSTADDR : 8564 if (fin->fin_v != 4) 8565 break; 8566 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8567 rv |= ((fin->fin_daddr & 8568 e->ipfe_arg0[i * 2 + 1]) == 8569 e->ipfe_arg0[i * 2]); 8570 } 8571 break; 8572 8573 case IPF_EXP_IP_ADDR : 8574 if (fin->fin_v != 4) 8575 break; 8576 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8577 rv |= ((fin->fin_saddr & 8578 e->ipfe_arg0[i * 2 + 1]) == 8579 e->ipfe_arg0[i * 2]) || 8580 ((fin->fin_daddr & 8581 e->ipfe_arg0[i * 2 + 1]) == 8582 e->ipfe_arg0[i * 2]); 8583 } 8584 break; 8585 8586#ifdef USE_INET6 8587 case IPF_EXP_IP6_SRCADDR : 8588 if (fin->fin_v != 6) 8589 break; 8590 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8591 rv |= IP6_MASKEQ(&fin->fin_src6, 8592 &e->ipfe_arg0[i * 8 + 4], 8593 &e->ipfe_arg0[i * 8]); 8594 } 8595 break; 8596 8597 case IPF_EXP_IP6_DSTADDR : 8598 if (fin->fin_v != 6) 8599 break; 8600 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8601 rv |= IP6_MASKEQ(&fin->fin_dst6, 8602 &e->ipfe_arg0[i * 8 + 4], 8603 &e->ipfe_arg0[i * 8]); 8604 } 8605 break; 8606 8607 case IPF_EXP_IP6_ADDR : 8608 if (fin->fin_v != 6) 8609 break; 8610 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8611 rv |= IP6_MASKEQ(&fin->fin_src6, 8612 &e->ipfe_arg0[i * 8 + 4], 8613 &e->ipfe_arg0[i * 8]) || 8614 IP6_MASKEQ(&fin->fin_dst6, 8615 &e->ipfe_arg0[i * 8 + 4], 8616 &e->ipfe_arg0[i * 8]); 8617 } 8618 break; 8619#endif 8620 8621 case IPF_EXP_UDP_PORT : 8622 case IPF_EXP_TCP_PORT : 8623 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8624 rv |= (fin->fin_sport == e->ipfe_arg0[i]) || 8625 (fin->fin_dport == e->ipfe_arg0[i]); 8626 } 8627 break; 8628 8629 case IPF_EXP_UDP_SPORT : 8630 case IPF_EXP_TCP_SPORT : 8631 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8632 rv |= (fin->fin_sport == e->ipfe_arg0[i]); 8633 } 8634 break; 8635 8636 case IPF_EXP_UDP_DPORT : 8637 case IPF_EXP_TCP_DPORT : 8638 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8639 rv |= (fin->fin_dport == e->ipfe_arg0[i]); 8640 } 8641 break; 8642 8643 case IPF_EXP_TCP_FLAGS : 8644 for (i = 0; !rv && i < e->ipfe_narg; i++) { 8645 rv |= ((fin->fin_tcpf & 8646 e->ipfe_arg0[i * 2 + 1]) == 8647 e->ipfe_arg0[i * 2]); 8648 } 8649 break; 8650 } 8651 rv ^= e->ipfe_not; 8652 8653 if (rv == 0) 8654 break; 8655 } 8656 8657 return (rv); 8658} 8659 8660 8661/* ------------------------------------------------------------------------ */ 8662/* Function: ipf_queueflush */ 8663/* Returns: int - number of entries flushed (0 = none) */ 8664/* Parameters: softc(I) - pointer to soft context main structure */ 8665/* deletefn(I) - function to call to delete entry */ 8666/* ipfqs(I) - top of the list of ipf internal queues */ 8667/* userqs(I) - top of the list of user defined timeouts */ 8668/* */ 8669/* This fucntion gets called when the state/NAT hash tables fill up and we */ 8670/* need to try a bit harder to free up some space. The algorithm used here */ 8671/* split into two parts but both halves have the same goal: to reduce the */ 8672/* number of connections considered to be "active" to the low watermark. */ 8673/* There are two steps in doing this: */ 8674/* 1) Remove any TCP connections that are already considered to be "closed" */ 8675/* but have not yet been removed from the state table. The two states */ 8676/* TCPS_TIME_WAIT and TCPS_CLOSED are considered to be the perfect */ 8677/* candidates for this style of removal. If freeing up entries in */ 8678/* CLOSED or both CLOSED and TIME_WAIT brings us to the low watermark, */ 8679/* we do not go on to step 2. */ 8680/* */ 8681/* 2) Look for the oldest entries on each timeout queue and free them if */ 8682/* they are within the given window we are considering. Where the */ 8683/* window starts and the steps taken to increase its size depend upon */ 8684/* how long ipf has been running (ipf_ticks.) Anything modified in the */ 8685/* last 30 seconds is not touched. */ 8686/* touched */ 8687/* die ipf_ticks 30*1.5 1800*1.5 | 43200*1.5 */ 8688/* | | | | | | */ 8689/* future <--+----------+--------+-----------+-----+-----+-----------> past */ 8690/* now \_int=30s_/ \_int=1hr_/ \_int=12hr */ 8691/* */ 8692/* Points to note: */ 8693/* - tqe_die is the time, in the future, when entries die. */ 8694/* - tqe_die - ipf_ticks is how long left the connection has to live in ipf */ 8695/* ticks. */ 8696/* - tqe_touched is when the entry was last used by NAT/state */ 8697/* - the closer tqe_touched is to ipf_ticks, the further tqe_die will be */ 8698/* ipf_ticks any given timeout queue and vice versa. */ 8699/* - both tqe_die and tqe_touched increase over time */ 8700/* - timeout queues are sorted with the highest value of tqe_die at the */ 8701/* bottom and therefore the smallest values of each are at the top */ 8702/* - the pointer passed in as ipfqs should point to an array of timeout */ 8703/* queues representing each of the TCP states */ 8704/* */ 8705/* We start by setting up a maximum range to scan for things to move of */ 8706/* iend (newest) to istart (oldest) in chunks of "interval". If nothing is */ 8707/* found in that range, "interval" is adjusted (so long as it isn't 30) and */ 8708/* we start again with a new value for "iend" and "istart". This is */ 8709/* continued until we either finish the scan of 30 second intervals or the */ 8710/* low water mark is reached. */ 8711/* ------------------------------------------------------------------------ */ 8712int 8713ipf_queueflush(ipf_main_softc_t *softc, ipftq_delete_fn_t deletefn, 8714 ipftq_t *ipfqs, ipftq_t *userqs, u_int *activep, int size, int low) 8715{ 8716 u_long interval, istart, iend; 8717 ipftq_t *ifq, *ifqnext; 8718 ipftqent_t *tqe, *tqn; 8719 int removed = 0; 8720 8721 for (tqn = ipfqs[IPF_TCPS_CLOSED].ifq_head; ((tqe = tqn) != NULL); ) { 8722 tqn = tqe->tqe_next; 8723 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8724 removed++; 8725 } 8726 if ((*activep * 100 / size) > low) { 8727 for (tqn = ipfqs[IPF_TCPS_TIME_WAIT].ifq_head; 8728 ((tqe = tqn) != NULL); ) { 8729 tqn = tqe->tqe_next; 8730 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8731 removed++; 8732 } 8733 } 8734 8735 if ((*activep * 100 / size) <= low) { 8736 return (removed); 8737 } 8738 8739 /* 8740 * NOTE: Use of "* 15 / 10" is required here because if "* 1.5" is 8741 * used then the operations are upgraded to floating point 8742 * and kernels don't like floating point... 8743 */ 8744 if (softc->ipf_ticks > IPF_TTLVAL(43200 * 15 / 10)) { 8745 istart = IPF_TTLVAL(86400 * 4); 8746 interval = IPF_TTLVAL(43200); 8747 } else if (softc->ipf_ticks > IPF_TTLVAL(1800 * 15 / 10)) { 8748 istart = IPF_TTLVAL(43200); 8749 interval = IPF_TTLVAL(1800); 8750 } else if (softc->ipf_ticks > IPF_TTLVAL(30 * 15 / 10)) { 8751 istart = IPF_TTLVAL(1800); 8752 interval = IPF_TTLVAL(30); 8753 } else { 8754 return (0); 8755 } 8756 if (istart > softc->ipf_ticks) { 8757 if (softc->ipf_ticks - interval < interval) 8758 istart = interval; 8759 else 8760 istart = (softc->ipf_ticks / interval) * interval; 8761 } 8762 8763 iend = softc->ipf_ticks - interval; 8764 8765 while ((*activep * 100 / size) > low) { 8766 u_long try; 8767 8768 try = softc->ipf_ticks - istart; 8769 8770 for (ifq = ipfqs; ifq != NULL; ifq = ifq->ifq_next) { 8771 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { 8772 if (try < tqe->tqe_touched) 8773 break; 8774 tqn = tqe->tqe_next; 8775 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8776 removed++; 8777 } 8778 } 8779 8780 for (ifq = userqs; ifq != NULL; ifq = ifqnext) { 8781 ifqnext = ifq->ifq_next; 8782 8783 for (tqn = ifq->ifq_head; ((tqe = tqn) != NULL); ) { 8784 if (try < tqe->tqe_touched) 8785 break; 8786 tqn = tqe->tqe_next; 8787 if ((*deletefn)(softc, tqe->tqe_parent) == 0) 8788 removed++; 8789 } 8790 } 8791 8792 if (try >= iend) { 8793 if (interval == IPF_TTLVAL(43200)) { 8794 interval = IPF_TTLVAL(1800); 8795 } else if (interval == IPF_TTLVAL(1800)) { 8796 interval = IPF_TTLVAL(30); 8797 } else { 8798 break; 8799 } 8800 if (interval >= softc->ipf_ticks) 8801 break; 8802 8803 iend = softc->ipf_ticks - interval; 8804 } 8805 istart -= interval; 8806 } 8807 8808 return (removed); 8809} 8810 8811 8812/* ------------------------------------------------------------------------ */ 8813/* Function: ipf_deliverlocal */ 8814/* Returns: int - 1 = local address, 0 = non-local address */ 8815/* Parameters: softc(I) - pointer to soft context main structure */ 8816/* ipversion(I) - IP protocol version (4 or 6) */ 8817/* ifp(I) - network interface pointer */ 8818/* ipaddr(I) - IPv4/6 destination address */ 8819/* */ 8820/* This fucntion is used to determine in the address "ipaddr" belongs to */ 8821/* the network interface represented by ifp. */ 8822/* ------------------------------------------------------------------------ */ 8823int 8824ipf_deliverlocal(ipf_main_softc_t *softc, int ipversion, void *ifp, 8825 i6addr_t *ipaddr) 8826{ 8827 i6addr_t addr; 8828 int islocal = 0; 8829 8830 if (ipversion == 4) { 8831 if (ipf_ifpaddr(softc, 4, FRI_NORMAL, ifp, &addr, NULL) == 0) { 8832 if (addr.in4.s_addr == ipaddr->in4.s_addr) 8833 islocal = 1; 8834 } 8835 8836#ifdef USE_INET6 8837 } else if (ipversion == 6) { 8838 if (ipf_ifpaddr(softc, 6, FRI_NORMAL, ifp, &addr, NULL) == 0) { 8839 if (IP6_EQ(&addr, ipaddr)) 8840 islocal = 1; 8841 } 8842#endif 8843 } 8844 8845 return (islocal); 8846} 8847 8848 8849/* ------------------------------------------------------------------------ */ 8850/* Function: ipf_settimeout */ 8851/* Returns: int - 0 = success, -1 = failure */ 8852/* Parameters: softc(I) - pointer to soft context main structure */ 8853/* t(I) - pointer to tuneable array entry */ 8854/* p(I) - pointer to values passed in to apply */ 8855/* */ 8856/* This function is called to set the timeout values for each distinct */ 8857/* queue timeout that is available. When called, it calls into both the */ 8858/* state and NAT code, telling them to update their timeout queues. */ 8859/* ------------------------------------------------------------------------ */ 8860static int 8861ipf_settimeout(struct ipf_main_softc_s *softc, ipftuneable_t *t, 8862 ipftuneval_t *p) 8863{ 8864 8865 /* 8866 * ipf_interror should be set by the functions called here, not 8867 * by this function - it's just a middle man. 8868 */ 8869 if (ipf_state_settimeout(softc, t, p) == -1) 8870 return (-1); 8871 if (ipf_nat_settimeout(softc, t, p) == -1) 8872 return (-1); 8873 return (0); 8874} 8875 8876 8877/* ------------------------------------------------------------------------ */ 8878/* Function: ipf_apply_timeout */ 8879/* Returns: int - 0 = success, -1 = failure */ 8880/* Parameters: head(I) - pointer to tuneable array entry */ 8881/* seconds(I) - pointer to values passed in to apply */ 8882/* */ 8883/* This function applies a timeout of "seconds" to the timeout queue that */ 8884/* is pointed to by "head". All entries on this list have an expiration */ 8885/* set to be the current tick value of ipf plus the ttl. Given that this */ 8886/* function should only be called when the delta is non-zero, the task is */ 8887/* to walk the entire list and apply the change. The sort order will not */ 8888/* change. The only catch is that this is O(n) across the list, so if the */ 8889/* queue has lots of entries (10s of thousands or 100s of thousands), it */ 8890/* could take a relatively long time to work through them all. */ 8891/* ------------------------------------------------------------------------ */ 8892void 8893ipf_apply_timeout(ipftq_t *head, u_int seconds) 8894{ 8895 u_int oldtimeout, newtimeout; 8896 ipftqent_t *tqe; 8897 int delta; 8898 8899 MUTEX_ENTER(&head->ifq_lock); 8900 oldtimeout = head->ifq_ttl; 8901 newtimeout = IPF_TTLVAL(seconds); 8902 delta = oldtimeout - newtimeout; 8903 8904 head->ifq_ttl = newtimeout; 8905 8906 for (tqe = head->ifq_head; tqe != NULL; tqe = tqe->tqe_next) { 8907 tqe->tqe_die += delta; 8908 } 8909 MUTEX_EXIT(&head->ifq_lock); 8910} 8911 8912 8913/* ------------------------------------------------------------------------ */ 8914/* Function: ipf_settimeout_tcp */ 8915/* Returns: int - 0 = successfully applied, -1 = failed */ 8916/* Parameters: t(I) - pointer to tuneable to change */ 8917/* p(I) - pointer to new timeout information */ 8918/* tab(I) - pointer to table of TCP queues */ 8919/* */ 8920/* This function applies the new timeout (p) to the TCP tunable (t) and */ 8921/* updates all of the entries on the relevant timeout queue by calling */ 8922/* ipf_apply_timeout(). */ 8923/* ------------------------------------------------------------------------ */ 8924int 8925ipf_settimeout_tcp(ipftuneable_t *t, ipftuneval_t *p, ipftq_t *tab) 8926{ 8927 if (!strcmp(t->ipft_name, "tcp_idle_timeout") || 8928 !strcmp(t->ipft_name, "tcp_established")) { 8929 ipf_apply_timeout(&tab[IPF_TCPS_ESTABLISHED], p->ipftu_int); 8930 } else if (!strcmp(t->ipft_name, "tcp_close_wait")) { 8931 ipf_apply_timeout(&tab[IPF_TCPS_CLOSE_WAIT], p->ipftu_int); 8932 } else if (!strcmp(t->ipft_name, "tcp_last_ack")) { 8933 ipf_apply_timeout(&tab[IPF_TCPS_LAST_ACK], p->ipftu_int); 8934 } else if (!strcmp(t->ipft_name, "tcp_timeout")) { 8935 ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int); 8936 ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int); 8937 ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int); 8938 } else if (!strcmp(t->ipft_name, "tcp_listen")) { 8939 ipf_apply_timeout(&tab[IPF_TCPS_LISTEN], p->ipftu_int); 8940 } else if (!strcmp(t->ipft_name, "tcp_half_established")) { 8941 ipf_apply_timeout(&tab[IPF_TCPS_HALF_ESTAB], p->ipftu_int); 8942 } else if (!strcmp(t->ipft_name, "tcp_closing")) { 8943 ipf_apply_timeout(&tab[IPF_TCPS_CLOSING], p->ipftu_int); 8944 } else if (!strcmp(t->ipft_name, "tcp_syn_received")) { 8945 ipf_apply_timeout(&tab[IPF_TCPS_SYN_RECEIVED], p->ipftu_int); 8946 } else if (!strcmp(t->ipft_name, "tcp_syn_sent")) { 8947 ipf_apply_timeout(&tab[IPF_TCPS_SYN_SENT], p->ipftu_int); 8948 } else if (!strcmp(t->ipft_name, "tcp_closed")) { 8949 ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int); 8950 } else if (!strcmp(t->ipft_name, "tcp_half_closed")) { 8951 ipf_apply_timeout(&tab[IPF_TCPS_CLOSED], p->ipftu_int); 8952 } else if (!strcmp(t->ipft_name, "tcp_time_wait")) { 8953 ipf_apply_timeout(&tab[IPF_TCPS_TIME_WAIT], p->ipftu_int); 8954 } else { 8955 /* 8956 * ipf_interror isn't set here because it should be set 8957 * by whatever called this function. 8958 */ 8959 return (-1); 8960 } 8961 return (0); 8962} 8963 8964 8965/* ------------------------------------------------------------------------ */ 8966/* Function: ipf_main_soft_create */ 8967/* Returns: NULL = failure, else success */ 8968/* Parameters: arg(I) - pointer to soft context structure if already allocd */ 8969/* */ 8970/* Create the foundation soft context structure. In circumstances where it */ 8971/* is not required to dynamically allocate the context, a pointer can be */ 8972/* passed in (rather than NULL) to a structure to be initialised. */ 8973/* The main thing of interest is that a number of locks are initialised */ 8974/* here instead of in the where might be expected - in the relevant create */ 8975/* function elsewhere. This is done because the current locking design has */ 8976/* some areas where these locks are used outside of their module. */ 8977/* Possibly the most important exercise that is done here is setting of all */ 8978/* the timeout values, allowing them to be changed before init(). */ 8979/* ------------------------------------------------------------------------ */ 8980void * 8981ipf_main_soft_create(void *arg) 8982{ 8983 ipf_main_softc_t *softc; 8984 8985 if (arg == NULL) { 8986 KMALLOC(softc, ipf_main_softc_t *); 8987 if (softc == NULL) 8988 return (NULL); 8989 } else { 8990 softc = arg; 8991 } 8992 8993 bzero((char *)softc, sizeof(*softc)); 8994 8995 /* 8996 * This serves as a flag as to whether or not the softc should be 8997 * free'd when _destroy is called. 8998 */ 8999 softc->ipf_dynamic_softc = (arg == NULL) ? 1 : 0; 9000 9001 softc->ipf_tuners = ipf_tune_array_copy(softc, 9002 sizeof(ipf_main_tuneables), 9003 ipf_main_tuneables); 9004 if (softc->ipf_tuners == NULL) { 9005 ipf_main_soft_destroy(softc); 9006 return (NULL); 9007 } 9008 9009 MUTEX_INIT(&softc->ipf_rw, "ipf rw mutex"); 9010 MUTEX_INIT(&softc->ipf_timeoutlock, "ipf timeout lock"); 9011 RWLOCK_INIT(&softc->ipf_global, "ipf filter load/unload mutex"); 9012 RWLOCK_INIT(&softc->ipf_mutex, "ipf filter rwlock"); 9013 RWLOCK_INIT(&softc->ipf_tokens, "ipf token rwlock"); 9014 RWLOCK_INIT(&softc->ipf_state, "ipf state rwlock"); 9015 RWLOCK_INIT(&softc->ipf_nat, "ipf IP NAT rwlock"); 9016 RWLOCK_INIT(&softc->ipf_poolrw, "ipf pool rwlock"); 9017 RWLOCK_INIT(&softc->ipf_frag, "ipf frag rwlock"); 9018 9019 softc->ipf_token_head = NULL; 9020 softc->ipf_token_tail = &softc->ipf_token_head; 9021 9022 softc->ipf_tcpidletimeout = FIVE_DAYS; 9023 softc->ipf_tcpclosewait = IPF_TTLVAL(2 * TCP_MSL); 9024 softc->ipf_tcplastack = IPF_TTLVAL(30); 9025 softc->ipf_tcptimewait = IPF_TTLVAL(2 * TCP_MSL); 9026 softc->ipf_tcptimeout = IPF_TTLVAL(2 * TCP_MSL); 9027 softc->ipf_tcpsynsent = IPF_TTLVAL(2 * TCP_MSL); 9028 softc->ipf_tcpsynrecv = IPF_TTLVAL(2 * TCP_MSL); 9029 softc->ipf_tcpclosed = IPF_TTLVAL(30); 9030 softc->ipf_tcphalfclosed = IPF_TTLVAL(2 * 3600); 9031 softc->ipf_udptimeout = IPF_TTLVAL(120); 9032 softc->ipf_udpacktimeout = IPF_TTLVAL(12); 9033 softc->ipf_icmptimeout = IPF_TTLVAL(60); 9034 softc->ipf_icmpacktimeout = IPF_TTLVAL(6); 9035 softc->ipf_iptimeout = IPF_TTLVAL(60); 9036 9037#if defined(IPFILTER_DEFAULT_BLOCK) 9038 softc->ipf_pass = FR_BLOCK|FR_NOMATCH; 9039#else 9040 softc->ipf_pass = (IPF_DEFAULT_PASS)|FR_NOMATCH; 9041#endif 9042 softc->ipf_minttl = 4; 9043 softc->ipf_icmpminfragmtu = 68; 9044 softc->ipf_flags = IPF_LOGGING; 9045 9046#ifdef LARGE_NAT 9047 softc->ipf_large_nat = 1; 9048#endif 9049 ipf_fbsd_kenv_get(softc); 9050 9051 return (softc); 9052} 9053 9054/* ------------------------------------------------------------------------ */ 9055/* Function: ipf_main_soft_init */ 9056/* Returns: 0 = success, -1 = failure */ 9057/* Parameters: softc(I) - pointer to soft context main structure */ 9058/* */ 9059/* A null-op function that exists as a placeholder so that the flow in */ 9060/* other functions is obvious. */ 9061/* ------------------------------------------------------------------------ */ 9062/*ARGSUSED*/ 9063int 9064ipf_main_soft_init(ipf_main_softc_t *softc) 9065{ 9066 return (0); 9067} 9068 9069 9070/* ------------------------------------------------------------------------ */ 9071/* Function: ipf_main_soft_destroy */ 9072/* Returns: void */ 9073/* Parameters: softc(I) - pointer to soft context main structure */ 9074/* */ 9075/* Undo everything that we did in ipf_main_soft_create. */ 9076/* */ 9077/* The most important check that needs to be made here is whether or not */ 9078/* the structure was allocated by ipf_main_soft_create() by checking what */ 9079/* value is stored in ipf_dynamic_main. */ 9080/* ------------------------------------------------------------------------ */ 9081/*ARGSUSED*/ 9082void 9083ipf_main_soft_destroy(ipf_main_softc_t *softc) 9084{ 9085 9086 RW_DESTROY(&softc->ipf_frag); 9087 RW_DESTROY(&softc->ipf_poolrw); 9088 RW_DESTROY(&softc->ipf_nat); 9089 RW_DESTROY(&softc->ipf_state); 9090 RW_DESTROY(&softc->ipf_tokens); 9091 RW_DESTROY(&softc->ipf_mutex); 9092 RW_DESTROY(&softc->ipf_global); 9093 MUTEX_DESTROY(&softc->ipf_timeoutlock); 9094 MUTEX_DESTROY(&softc->ipf_rw); 9095 9096 if (softc->ipf_tuners != NULL) { 9097 KFREES(softc->ipf_tuners, sizeof(ipf_main_tuneables)); 9098 } 9099 if (softc->ipf_dynamic_softc == 1) { 9100 KFREE(softc); 9101 } 9102} 9103 9104 9105/* ------------------------------------------------------------------------ */ 9106/* Function: ipf_main_soft_fini */ 9107/* Returns: 0 = success, -1 = failure */ 9108/* Parameters: softc(I) - pointer to soft context main structure */ 9109/* */ 9110/* Clean out the rules which have been added since _init was last called, */ 9111/* the only dynamic part of the mainline. */ 9112/* ------------------------------------------------------------------------ */ 9113int 9114ipf_main_soft_fini(ipf_main_softc_t *softc) 9115{ 9116 (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE|FR_INACTIVE); 9117 (void) ipf_flush(softc, IPL_LOGIPF, FR_INQUE|FR_OUTQUE); 9118 (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE|FR_INACTIVE); 9119 (void) ipf_flush(softc, IPL_LOGCOUNT, FR_INQUE|FR_OUTQUE); 9120 9121 return (0); 9122} 9123 9124 9125/* ------------------------------------------------------------------------ */ 9126/* Function: ipf_main_load */ 9127/* Returns: 0 = success, -1 = failure */ 9128/* Parameters: none */ 9129/* */ 9130/* Handle global initialisation that needs to be done for the base part of */ 9131/* IPFilter. At present this just amounts to initialising some ICMP lookup */ 9132/* arrays that get used by the state/NAT code. */ 9133/* ------------------------------------------------------------------------ */ 9134int 9135ipf_main_load(void) 9136{ 9137 int i; 9138 9139 /* fill icmp reply type table */ 9140 for (i = 0; i <= ICMP_MAXTYPE; i++) 9141 icmpreplytype4[i] = -1; 9142 icmpreplytype4[ICMP_ECHO] = ICMP_ECHOREPLY; 9143 icmpreplytype4[ICMP_TSTAMP] = ICMP_TSTAMPREPLY; 9144 icmpreplytype4[ICMP_IREQ] = ICMP_IREQREPLY; 9145 icmpreplytype4[ICMP_MASKREQ] = ICMP_MASKREPLY; 9146 9147#ifdef USE_INET6 9148 /* fill icmp reply type table */ 9149 for (i = 0; i <= ICMP6_MAXTYPE; i++) 9150 icmpreplytype6[i] = -1; 9151 icmpreplytype6[ICMP6_ECHO_REQUEST] = ICMP6_ECHO_REPLY; 9152 icmpreplytype6[ICMP6_MEMBERSHIP_QUERY] = ICMP6_MEMBERSHIP_REPORT; 9153 icmpreplytype6[ICMP6_NI_QUERY] = ICMP6_NI_REPLY; 9154 icmpreplytype6[ND_ROUTER_SOLICIT] = ND_ROUTER_ADVERT; 9155 icmpreplytype6[ND_NEIGHBOR_SOLICIT] = ND_NEIGHBOR_ADVERT; 9156#endif 9157 9158 return (0); 9159} 9160 9161 9162/* ------------------------------------------------------------------------ */ 9163/* Function: ipf_main_unload */ 9164/* Returns: 0 = success, -1 = failure */ 9165/* Parameters: none */ 9166/* */ 9167/* A null-op function that exists as a placeholder so that the flow in */ 9168/* other functions is obvious. */ 9169/* ------------------------------------------------------------------------ */ 9170int 9171ipf_main_unload(void) 9172{ 9173 return (0); 9174} 9175 9176 9177/* ------------------------------------------------------------------------ */ 9178/* Function: ipf_load_all */ 9179/* Returns: 0 = success, -1 = failure */ 9180/* Parameters: none */ 9181/* */ 9182/* Work through all of the subsystems inside IPFilter and call the load */ 9183/* function for each in an order that won't lead to a crash :) */ 9184/* ------------------------------------------------------------------------ */ 9185int 9186ipf_load_all(void) 9187{ 9188 if (ipf_main_load() == -1) 9189 return (-1); 9190 9191 if (ipf_state_main_load() == -1) 9192 return (-1); 9193 9194 if (ipf_nat_main_load() == -1) 9195 return (-1); 9196 9197 if (ipf_frag_main_load() == -1) 9198 return (-1); 9199 9200 if (ipf_auth_main_load() == -1) 9201 return (-1); 9202 9203 if (ipf_proxy_main_load() == -1) 9204 return (-1); 9205 9206 return (0); 9207} 9208 9209 9210/* ------------------------------------------------------------------------ */ 9211/* Function: ipf_unload_all */ 9212/* Returns: 0 = success, -1 = failure */ 9213/* Parameters: none */ 9214/* */ 9215/* Work through all of the subsystems inside IPFilter and call the unload */ 9216/* function for each in an order that won't lead to a crash :) */ 9217/* ------------------------------------------------------------------------ */ 9218int 9219ipf_unload_all(void) 9220{ 9221 if (ipf_proxy_main_unload() == -1) 9222 return (-1); 9223 9224 if (ipf_auth_main_unload() == -1) 9225 return (-1); 9226 9227 if (ipf_frag_main_unload() == -1) 9228 return (-1); 9229 9230 if (ipf_nat_main_unload() == -1) 9231 return (-1); 9232 9233 if (ipf_state_main_unload() == -1) 9234 return (-1); 9235 9236 if (ipf_main_unload() == -1) 9237 return (-1); 9238 9239 return (0); 9240} 9241 9242 9243/* ------------------------------------------------------------------------ */ 9244/* Function: ipf_create_all */ 9245/* Returns: NULL = failure, else success */ 9246/* Parameters: arg(I) - pointer to soft context main structure */ 9247/* */ 9248/* Work through all of the subsystems inside IPFilter and call the create */ 9249/* function for each in an order that won't lead to a crash :) */ 9250/* ------------------------------------------------------------------------ */ 9251ipf_main_softc_t * 9252ipf_create_all(void *arg) 9253{ 9254 ipf_main_softc_t *softc; 9255 9256 softc = ipf_main_soft_create(arg); 9257 if (softc == NULL) 9258 return (NULL); 9259 9260#ifdef IPFILTER_LOG 9261 softc->ipf_log_soft = ipf_log_soft_create(softc); 9262 if (softc->ipf_log_soft == NULL) { 9263 ipf_destroy_all(softc); 9264 return (NULL); 9265 } 9266#endif 9267 9268 softc->ipf_lookup_soft = ipf_lookup_soft_create(softc); 9269 if (softc->ipf_lookup_soft == NULL) { 9270 ipf_destroy_all(softc); 9271 return (NULL); 9272 } 9273 9274 softc->ipf_sync_soft = ipf_sync_soft_create(softc); 9275 if (softc->ipf_sync_soft == NULL) { 9276 ipf_destroy_all(softc); 9277 return (NULL); 9278 } 9279 9280 softc->ipf_state_soft = ipf_state_soft_create(softc); 9281 if (softc->ipf_state_soft == NULL) { 9282 ipf_destroy_all(softc); 9283 return (NULL); 9284 } 9285 9286 softc->ipf_nat_soft = ipf_nat_soft_create(softc); 9287 if (softc->ipf_nat_soft == NULL) { 9288 ipf_destroy_all(softc); 9289 return (NULL); 9290 } 9291 9292 softc->ipf_frag_soft = ipf_frag_soft_create(softc); 9293 if (softc->ipf_frag_soft == NULL) { 9294 ipf_destroy_all(softc); 9295 return (NULL); 9296 } 9297 9298 softc->ipf_auth_soft = ipf_auth_soft_create(softc); 9299 if (softc->ipf_auth_soft == NULL) { 9300 ipf_destroy_all(softc); 9301 return (NULL); 9302 } 9303 9304 softc->ipf_proxy_soft = ipf_proxy_soft_create(softc); 9305 if (softc->ipf_proxy_soft == NULL) { 9306 ipf_destroy_all(softc); 9307 return (NULL); 9308 } 9309 9310 return (softc); 9311} 9312 9313 9314/* ------------------------------------------------------------------------ */ 9315/* Function: ipf_destroy_all */ 9316/* Returns: void */ 9317/* Parameters: softc(I) - pointer to soft context main structure */ 9318/* */ 9319/* Work through all of the subsystems inside IPFilter and call the destroy */ 9320/* function for each in an order that won't lead to a crash :) */ 9321/* */ 9322/* Every one of these functions is expected to succeed, so there is no */ 9323/* checking of return values. */ 9324/* ------------------------------------------------------------------------ */ 9325void 9326ipf_destroy_all(ipf_main_softc_t *softc) 9327{ 9328 9329 if (softc->ipf_state_soft != NULL) { 9330 ipf_state_soft_destroy(softc, softc->ipf_state_soft); 9331 softc->ipf_state_soft = NULL; 9332 } 9333 9334 if (softc->ipf_nat_soft != NULL) { 9335 ipf_nat_soft_destroy(softc, softc->ipf_nat_soft); 9336 softc->ipf_nat_soft = NULL; 9337 } 9338 9339 if (softc->ipf_frag_soft != NULL) { 9340 ipf_frag_soft_destroy(softc, softc->ipf_frag_soft); 9341 softc->ipf_frag_soft = NULL; 9342 } 9343 9344 if (softc->ipf_auth_soft != NULL) { 9345 ipf_auth_soft_destroy(softc, softc->ipf_auth_soft); 9346 softc->ipf_auth_soft = NULL; 9347 } 9348 9349 if (softc->ipf_proxy_soft != NULL) { 9350 ipf_proxy_soft_destroy(softc, softc->ipf_proxy_soft); 9351 softc->ipf_proxy_soft = NULL; 9352 } 9353 9354 if (softc->ipf_sync_soft != NULL) { 9355 ipf_sync_soft_destroy(softc, softc->ipf_sync_soft); 9356 softc->ipf_sync_soft = NULL; 9357 } 9358 9359 if (softc->ipf_lookup_soft != NULL) { 9360 ipf_lookup_soft_destroy(softc, softc->ipf_lookup_soft); 9361 softc->ipf_lookup_soft = NULL; 9362 } 9363 9364#ifdef IPFILTER_LOG 9365 if (softc->ipf_log_soft != NULL) { 9366 ipf_log_soft_destroy(softc, softc->ipf_log_soft); 9367 softc->ipf_log_soft = NULL; 9368 } 9369#endif 9370 9371 ipf_main_soft_destroy(softc); 9372} 9373 9374 9375/* ------------------------------------------------------------------------ */ 9376/* Function: ipf_init_all */ 9377/* Returns: 0 = success, -1 = failure */ 9378/* Parameters: softc(I) - pointer to soft context main structure */ 9379/* */ 9380/* Work through all of the subsystems inside IPFilter and call the init */ 9381/* function for each in an order that won't lead to a crash :) */ 9382/* ------------------------------------------------------------------------ */ 9383int 9384ipf_init_all(ipf_main_softc_t *softc) 9385{ 9386 9387 if (ipf_main_soft_init(softc) == -1) 9388 return (-1); 9389 9390#ifdef IPFILTER_LOG 9391 if (ipf_log_soft_init(softc, softc->ipf_log_soft) == -1) 9392 return (-1); 9393#endif 9394 9395 if (ipf_lookup_soft_init(softc, softc->ipf_lookup_soft) == -1) 9396 return (-1); 9397 9398 if (ipf_sync_soft_init(softc, softc->ipf_sync_soft) == -1) 9399 return (-1); 9400 9401 if (ipf_state_soft_init(softc, softc->ipf_state_soft) == -1) 9402 return (-1); 9403 9404 if (ipf_nat_soft_init(softc, softc->ipf_nat_soft) == -1) 9405 return (-1); 9406 9407 if (ipf_frag_soft_init(softc, softc->ipf_frag_soft) == -1) 9408 return (-1); 9409 9410 if (ipf_auth_soft_init(softc, softc->ipf_auth_soft) == -1) 9411 return (-1); 9412 9413 if (ipf_proxy_soft_init(softc, softc->ipf_proxy_soft) == -1) 9414 return (-1); 9415 9416 return (0); 9417} 9418 9419 9420/* ------------------------------------------------------------------------ */ 9421/* Function: ipf_fini_all */ 9422/* Returns: 0 = success, -1 = failure */ 9423/* Parameters: softc(I) - pointer to soft context main structure */ 9424/* */ 9425/* Work through all of the subsystems inside IPFilter and call the fini */ 9426/* function for each in an order that won't lead to a crash :) */ 9427/* ------------------------------------------------------------------------ */ 9428int 9429ipf_fini_all(ipf_main_softc_t *softc) 9430{ 9431 9432 ipf_token_flush(softc); 9433 9434 if (ipf_proxy_soft_fini(softc, softc->ipf_proxy_soft) == -1) 9435 return (-1); 9436 9437 if (ipf_auth_soft_fini(softc, softc->ipf_auth_soft) == -1) 9438 return (-1); 9439 9440 if (ipf_frag_soft_fini(softc, softc->ipf_frag_soft) == -1) 9441 return (-1); 9442 9443 if (ipf_nat_soft_fini(softc, softc->ipf_nat_soft) == -1) 9444 return (-1); 9445 9446 if (ipf_state_soft_fini(softc, softc->ipf_state_soft) == -1) 9447 return (-1); 9448 9449 if (ipf_sync_soft_fini(softc, softc->ipf_sync_soft) == -1) 9450 return (-1); 9451 9452 if (ipf_lookup_soft_fini(softc, softc->ipf_lookup_soft) == -1) 9453 return (-1); 9454 9455#ifdef IPFILTER_LOG 9456 if (ipf_log_soft_fini(softc, softc->ipf_log_soft) == -1) 9457 return (-1); 9458#endif 9459 9460 if (ipf_main_soft_fini(softc) == -1) 9461 return (-1); 9462 9463 return (0); 9464} 9465 9466 9467/* ------------------------------------------------------------------------ */ 9468/* Function: ipf_rule_expire */ 9469/* Returns: Nil */ 9470/* Parameters: softc(I) - pointer to soft context main structure */ 9471/* */ 9472/* At present this function exists just to support temporary addition of */ 9473/* firewall rules. Both inactive and active lists are scanned for items to */ 9474/* purge, as by rights, the expiration is computed as soon as the rule is */ 9475/* loaded in. */ 9476/* ------------------------------------------------------------------------ */ 9477void 9478ipf_rule_expire(ipf_main_softc_t *softc) 9479{ 9480 frentry_t *fr; 9481 9482 if ((softc->ipf_rule_explist[0] == NULL) && 9483 (softc->ipf_rule_explist[1] == NULL)) 9484 return; 9485 9486 WRITE_ENTER(&softc->ipf_mutex); 9487 9488 while ((fr = softc->ipf_rule_explist[0]) != NULL) { 9489 /* 9490 * Because the list is kept sorted on insertion, the fist 9491 * one that dies in the future means no more work to do. 9492 */ 9493 if (fr->fr_die > softc->ipf_ticks) 9494 break; 9495 ipf_rule_delete(softc, fr, IPL_LOGIPF, 0); 9496 } 9497 9498 while ((fr = softc->ipf_rule_explist[1]) != NULL) { 9499 /* 9500 * Because the list is kept sorted on insertion, the fist 9501 * one that dies in the future means no more work to do. 9502 */ 9503 if (fr->fr_die > softc->ipf_ticks) 9504 break; 9505 ipf_rule_delete(softc, fr, IPL_LOGIPF, 1); 9506 } 9507 9508 RWLOCK_EXIT(&softc->ipf_mutex); 9509} 9510 9511 9512static int ipf_ht_node_cmp(struct host_node_s *, struct host_node_s *); 9513static void ipf_ht_node_make_key(host_track_t *, host_node_t *, int, 9514 i6addr_t *); 9515 9516host_node_t RBI_ZERO(ipf_rb); 9517RBI_CODE(ipf_rb, host_node_t, hn_entry, ipf_ht_node_cmp) 9518 9519 9520/* ------------------------------------------------------------------------ */ 9521/* Function: ipf_ht_node_cmp */ 9522/* Returns: int - 0 == nodes are the same, .. */ 9523/* Parameters: k1(I) - pointer to first key to compare */ 9524/* k2(I) - pointer to second key to compare */ 9525/* */ 9526/* The "key" for the node is a combination of two fields: the address */ 9527/* family and the address itself. */ 9528/* */ 9529/* Because we're not actually interpreting the address data, it isn't */ 9530/* necessary to convert them to/from network/host byte order. The mask is */ 9531/* just used to remove bits that aren't significant - it doesn't matter */ 9532/* where they are, as long as they're always in the same place. */ 9533/* */ 9534/* As with IP6_EQ, comparing IPv6 addresses starts at the bottom because */ 9535/* this is where individual ones will differ the most - but not true for */ 9536/* for /48's, etc. */ 9537/* ------------------------------------------------------------------------ */ 9538static int 9539ipf_ht_node_cmp(struct host_node_s *k1, struct host_node_s *k2) 9540{ 9541 int i; 9542 9543 i = (k2->hn_addr.adf_family - k1->hn_addr.adf_family); 9544 if (i != 0) 9545 return (i); 9546 9547 if (k1->hn_addr.adf_family == AF_INET) 9548 return (k2->hn_addr.adf_addr.in4.s_addr - 9549 k1->hn_addr.adf_addr.in4.s_addr); 9550 9551 i = k2->hn_addr.adf_addr.i6[3] - k1->hn_addr.adf_addr.i6[3]; 9552 if (i != 0) 9553 return (i); 9554 i = k2->hn_addr.adf_addr.i6[2] - k1->hn_addr.adf_addr.i6[2]; 9555 if (i != 0) 9556 return (i); 9557 i = k2->hn_addr.adf_addr.i6[1] - k1->hn_addr.adf_addr.i6[1]; 9558 if (i != 0) 9559 return (i); 9560 i = k2->hn_addr.adf_addr.i6[0] - k1->hn_addr.adf_addr.i6[0]; 9561 return (i); 9562} 9563 9564 9565/* ------------------------------------------------------------------------ */ 9566/* Function: ipf_ht_node_make_key */ 9567/* Returns: Nil */ 9568/* parameters: htp(I) - pointer to address tracking structure */ 9569/* key(I) - where to store masked address for lookup */ 9570/* family(I) - protocol family of address */ 9571/* addr(I) - pointer to network address */ 9572/* */ 9573/* Using the "netmask" (number of bits) stored parent host tracking struct, */ 9574/* copy the address passed in into the key structure whilst masking out the */ 9575/* bits that we don't want. */ 9576/* */ 9577/* Because the parser will set ht_netmask to 128 if there is no protocol */ 9578/* specified (the parser doesn't know if it should be a v4 or v6 rule), we */ 9579/* have to be wary of that and not allow 32-128 to happen. */ 9580/* ------------------------------------------------------------------------ */ 9581static void 9582ipf_ht_node_make_key(host_track_t *htp, host_node_t *key, int family, 9583 i6addr_t *addr) 9584{ 9585 key->hn_addr.adf_family = family; 9586 if (family == AF_INET) { 9587 u_32_t mask; 9588 int bits; 9589 9590 key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in4); 9591 bits = htp->ht_netmask; 9592 if (bits >= 32) { 9593 mask = 0xffffffff; 9594 } else { 9595 mask = htonl(0xffffffff << (32 - bits)); 9596 } 9597 key->hn_addr.adf_addr.in4.s_addr = addr->in4.s_addr & mask; 9598#ifdef USE_INET6 9599 } else { 9600 int bits = htp->ht_netmask; 9601 9602 key->hn_addr.adf_len = sizeof(key->hn_addr.adf_addr.in6); 9603 if (bits > 96) { 9604 key->hn_addr.adf_addr.i6[3] = addr->i6[3] & 9605 htonl(0xffffffff << (128 - bits)); 9606 key->hn_addr.adf_addr.i6[2] = addr->i6[2]; 9607 key->hn_addr.adf_addr.i6[1] = addr->i6[2]; 9608 key->hn_addr.adf_addr.i6[0] = addr->i6[2]; 9609 } else if (bits > 64) { 9610 key->hn_addr.adf_addr.i6[3] = 0; 9611 key->hn_addr.adf_addr.i6[2] = addr->i6[2] & 9612 htonl(0xffffffff << (96 - bits)); 9613 key->hn_addr.adf_addr.i6[1] = addr->i6[1]; 9614 key->hn_addr.adf_addr.i6[0] = addr->i6[0]; 9615 } else if (bits > 32) { 9616 key->hn_addr.adf_addr.i6[3] = 0; 9617 key->hn_addr.adf_addr.i6[2] = 0; 9618 key->hn_addr.adf_addr.i6[1] = addr->i6[1] & 9619 htonl(0xffffffff << (64 - bits)); 9620 key->hn_addr.adf_addr.i6[0] = addr->i6[0]; 9621 } else { 9622 key->hn_addr.adf_addr.i6[3] = 0; 9623 key->hn_addr.adf_addr.i6[2] = 0; 9624 key->hn_addr.adf_addr.i6[1] = 0; 9625 key->hn_addr.adf_addr.i6[0] = addr->i6[0] & 9626 htonl(0xffffffff << (32 - bits)); 9627 } 9628#endif 9629 } 9630} 9631 9632 9633/* ------------------------------------------------------------------------ */ 9634/* Function: ipf_ht_node_add */ 9635/* Returns: int - 0 == success, -1 == failure */ 9636/* Parameters: softc(I) - pointer to soft context main structure */ 9637/* htp(I) - pointer to address tracking structure */ 9638/* family(I) - protocol family of address */ 9639/* addr(I) - pointer to network address */ 9640/* */ 9641/* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS */ 9642/* ipf_ht_node_del FROM RUNNING CONCURRENTLY ON THE SAME htp. */ 9643/* */ 9644/* After preparing the key with the address information to find, look in */ 9645/* the red-black tree to see if the address is known. A successful call to */ 9646/* this function can mean one of two things: a new node was added to the */ 9647/* tree or a matching node exists and we're able to bump up its activity. */ 9648/* ------------------------------------------------------------------------ */ 9649int 9650ipf_ht_node_add(ipf_main_softc_t *softc, host_track_t *htp, int family, 9651 i6addr_t *addr) 9652{ 9653 host_node_t *h; 9654 host_node_t k; 9655 9656 ipf_ht_node_make_key(htp, &k, family, addr); 9657 9658 h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k); 9659 if (h == NULL) { 9660 if (htp->ht_cur_nodes >= htp->ht_max_nodes) 9661 return (-1); 9662 KMALLOC(h, host_node_t *); 9663 if (h == NULL) { 9664 DT(ipf_rb_no_mem); 9665 LBUMP(ipf_rb_no_mem); 9666 return (-1); 9667 } 9668 9669 /* 9670 * If there was a macro to initialise the RB node then that 9671 * would get used here, but there isn't... 9672 */ 9673 bzero((char *)h, sizeof(*h)); 9674 h->hn_addr = k.hn_addr; 9675 h->hn_addr.adf_family = k.hn_addr.adf_family; 9676 RBI_INSERT(ipf_rb, &htp->ht_root, h); 9677 htp->ht_cur_nodes++; 9678 } else { 9679 if ((htp->ht_max_per_node != 0) && 9680 (h->hn_active >= htp->ht_max_per_node)) { 9681 DT(ipf_rb_node_max); 9682 LBUMP(ipf_rb_node_max); 9683 return (-1); 9684 } 9685 } 9686 9687 h->hn_active++; 9688 9689 return (0); 9690} 9691 9692 9693/* ------------------------------------------------------------------------ */ 9694/* Function: ipf_ht_node_del */ 9695/* Returns: int - 0 == success, -1 == failure */ 9696/* parameters: htp(I) - pointer to address tracking structure */ 9697/* family(I) - protocol family of address */ 9698/* addr(I) - pointer to network address */ 9699/* */ 9700/* NOTE: THIS FUNCTION MUST BE CALLED WITH AN EXCLUSIVE LOCK THAT PREVENTS */ 9701/* ipf_ht_node_add FROM RUNNING CONCURRENTLY ON THE SAME htp. */ 9702/* */ 9703/* Try and find the address passed in amongst the leavese on this tree to */ 9704/* be friend. If found then drop the active account for that node drops by */ 9705/* one. If that count reaches 0, it is time to free it all up. */ 9706/* ------------------------------------------------------------------------ */ 9707int 9708ipf_ht_node_del(host_track_t *htp, int family, i6addr_t *addr) 9709{ 9710 host_node_t *h; 9711 host_node_t k; 9712 9713 ipf_ht_node_make_key(htp, &k, family, addr); 9714 9715 h = RBI_SEARCH(ipf_rb, &htp->ht_root, &k); 9716 if (h == NULL) { 9717 return (-1); 9718 } else { 9719 h->hn_active--; 9720 if (h->hn_active == 0) { 9721 (void) RBI_DELETE(ipf_rb, &htp->ht_root, h); 9722 htp->ht_cur_nodes--; 9723 KFREE(h); 9724 } 9725 } 9726 9727 return (0); 9728} 9729 9730 9731/* ------------------------------------------------------------------------ */ 9732/* Function: ipf_rb_ht_init */ 9733/* Returns: Nil */ 9734/* Parameters: head(I) - pointer to host tracking structure */ 9735/* */ 9736/* Initialise the host tracking structure to be ready for use above. */ 9737/* ------------------------------------------------------------------------ */ 9738void 9739ipf_rb_ht_init(host_track_t *head) 9740{ 9741 RBI_INIT(ipf_rb, &head->ht_root); 9742} 9743 9744 9745/* ------------------------------------------------------------------------ */ 9746/* Function: ipf_rb_ht_freenode */ 9747/* Returns: Nil */ 9748/* Parameters: head(I) - pointer to host tracking structure */ 9749/* arg(I) - additional argument from walk caller */ 9750/* */ 9751/* Free an actual host_node_t structure. */ 9752/* ------------------------------------------------------------------------ */ 9753void 9754ipf_rb_ht_freenode(host_node_t *node, void *arg) 9755{ 9756 KFREE(node); 9757} 9758 9759 9760/* ------------------------------------------------------------------------ */ 9761/* Function: ipf_rb_ht_flush */ 9762/* Returns: Nil */ 9763/* Parameters: head(I) - pointer to host tracking structure */ 9764/* */ 9765/* Remove all of the nodes in the tree tracking hosts by calling a walker */ 9766/* and free'ing each one. */ 9767/* ------------------------------------------------------------------------ */ 9768void 9769ipf_rb_ht_flush(host_track_t *head) 9770{ 9771 RBI_WALK(ipf_rb, &head->ht_root, ipf_rb_ht_freenode, NULL); 9772} 9773 9774 9775/* ------------------------------------------------------------------------ */ 9776/* Function: ipf_slowtimer */ 9777/* Returns: Nil */ 9778/* Parameters: ptr(I) - pointer to main ipf soft context structure */ 9779/* */ 9780/* Slowly expire held state for fragments. Timeouts are set * in */ 9781/* expectation of this being called twice per second. */ 9782/* ------------------------------------------------------------------------ */ 9783void 9784ipf_slowtimer(ipf_main_softc_t *softc) 9785{ 9786 9787 ipf_token_expire(softc); 9788 ipf_frag_expire(softc); 9789 ipf_state_expire(softc); 9790 ipf_nat_expire(softc); 9791 ipf_auth_expire(softc); 9792 ipf_lookup_expire(softc); 9793 ipf_rule_expire(softc); 9794 ipf_sync_expire(softc); 9795 softc->ipf_ticks++; 9796} 9797 9798 9799/* ------------------------------------------------------------------------ */ 9800/* Function: ipf_inet_mask_add */ 9801/* Returns: Nil */ 9802/* Parameters: bits(I) - pointer to nat context information */ 9803/* mtab(I) - pointer to mask hash table structure */ 9804/* */ 9805/* When called, bits represents the mask of a new NAT rule that has just */ 9806/* been added. This function inserts a bitmask into the array of masks to */ 9807/* search when searching for a matching NAT rule for a packet. */ 9808/* Prevention of duplicate masks is achieved by checking the use count for */ 9809/* a given netmask. */ 9810/* ------------------------------------------------------------------------ */ 9811void 9812ipf_inet_mask_add(int bits, ipf_v4_masktab_t *mtab) 9813{ 9814 u_32_t mask; 9815 int i, j; 9816 9817 mtab->imt4_masks[bits]++; 9818 if (mtab->imt4_masks[bits] > 1) 9819 return; 9820 9821 if (bits == 0) 9822 mask = 0; 9823 else 9824 mask = 0xffffffff << (32 - bits); 9825 9826 for (i = 0; i < 33; i++) { 9827 if (ntohl(mtab->imt4_active[i]) < mask) { 9828 for (j = 32; j > i; j--) 9829 mtab->imt4_active[j] = mtab->imt4_active[j - 1]; 9830 mtab->imt4_active[i] = htonl(mask); 9831 break; 9832 } 9833 } 9834 mtab->imt4_max++; 9835} 9836 9837 9838/* ------------------------------------------------------------------------ */ 9839/* Function: ipf_inet_mask_del */ 9840/* Returns: Nil */ 9841/* Parameters: bits(I) - number of bits set in the netmask */ 9842/* mtab(I) - pointer to mask hash table structure */ 9843/* */ 9844/* Remove the 32bit bitmask represented by "bits" from the collection of */ 9845/* netmasks stored inside of mtab. */ 9846/* ------------------------------------------------------------------------ */ 9847void 9848ipf_inet_mask_del(int bits, ipf_v4_masktab_t *mtab) 9849{ 9850 u_32_t mask; 9851 int i, j; 9852 9853 mtab->imt4_masks[bits]--; 9854 if (mtab->imt4_masks[bits] > 0) 9855 return; 9856 9857 mask = htonl(0xffffffff << (32 - bits)); 9858 for (i = 0; i < 33; i++) { 9859 if (mtab->imt4_active[i] == mask) { 9860 for (j = i + 1; j < 33; j++) 9861 mtab->imt4_active[j - 1] = mtab->imt4_active[j]; 9862 break; 9863 } 9864 } 9865 mtab->imt4_max--; 9866 ASSERT(mtab->imt4_max >= 0); 9867} 9868 9869 9870#ifdef USE_INET6 9871/* ------------------------------------------------------------------------ */ 9872/* Function: ipf_inet6_mask_add */ 9873/* Returns: Nil */ 9874/* Parameters: bits(I) - number of bits set in mask */ 9875/* mask(I) - pointer to mask to add */ 9876/* mtab(I) - pointer to mask hash table structure */ 9877/* */ 9878/* When called, bitcount represents the mask of a IPv6 NAT map rule that */ 9879/* has just been added. This function inserts a bitmask into the array of */ 9880/* masks to search when searching for a matching NAT rule for a packet. */ 9881/* Prevention of duplicate masks is achieved by checking the use count for */ 9882/* a given netmask. */ 9883/* ------------------------------------------------------------------------ */ 9884void 9885ipf_inet6_mask_add(int bits, i6addr_t *mask, ipf_v6_masktab_t *mtab) 9886{ 9887 i6addr_t zero; 9888 int i, j; 9889 9890 mtab->imt6_masks[bits]++; 9891 if (mtab->imt6_masks[bits] > 1) 9892 return; 9893 9894 if (bits == 0) { 9895 mask = &zero; 9896 zero.i6[0] = 0; 9897 zero.i6[1] = 0; 9898 zero.i6[2] = 0; 9899 zero.i6[3] = 0; 9900 } 9901 9902 for (i = 0; i < 129; i++) { 9903 if (IP6_LT(&mtab->imt6_active[i], mask)) { 9904 for (j = 128; j > i; j--) 9905 mtab->imt6_active[j] = mtab->imt6_active[j - 1]; 9906 mtab->imt6_active[i] = *mask; 9907 break; 9908 } 9909 } 9910 mtab->imt6_max++; 9911} 9912 9913 9914/* ------------------------------------------------------------------------ */ 9915/* Function: ipf_inet6_mask_del */ 9916/* Returns: Nil */ 9917/* Parameters: bits(I) - number of bits set in mask */ 9918/* mask(I) - pointer to mask to remove */ 9919/* mtab(I) - pointer to mask hash table structure */ 9920/* */ 9921/* Remove the 128bit bitmask represented by "bits" from the collection of */ 9922/* netmasks stored inside of mtab. */ 9923/* ------------------------------------------------------------------------ */ 9924void 9925ipf_inet6_mask_del(int bits, i6addr_t *mask, ipf_v6_masktab_t *mtab) 9926{ 9927 i6addr_t zero; 9928 int i, j; 9929 9930 mtab->imt6_masks[bits]--; 9931 if (mtab->imt6_masks[bits] > 0) 9932 return; 9933 9934 if (bits == 0) 9935 mask = &zero; 9936 zero.i6[0] = 0; 9937 zero.i6[1] = 0; 9938 zero.i6[2] = 0; 9939 zero.i6[3] = 0; 9940 9941 for (i = 0; i < 129; i++) { 9942 if (IP6_EQ(&mtab->imt6_active[i], mask)) { 9943 for (j = i + 1; j < 129; j++) { 9944 mtab->imt6_active[j - 1] = mtab->imt6_active[j]; 9945 if (IP6_EQ(&mtab->imt6_active[j - 1], &zero)) 9946 break; 9947 } 9948 break; 9949 } 9950 } 9951 mtab->imt6_max--; 9952 ASSERT(mtab->imt6_max >= 0); 9953} 9954#endif 9955