ip_fw_sockopt.c revision 200601
1/*- 2 * Copyright (c) 2002 Luigi Rizzo, Universita` di Pisa 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26#include <sys/cdefs.h> 27__FBSDID("$FreeBSD: head/sys/netinet/ipfw/ip_fw_sockopt.c 200601 2009-12-16 10:48:40Z luigi $"); 28 29#define DEB(x) 30#define DDB(x) x 31 32/* 33 * Sockopt support for ipfw. The routines here implement 34 * the upper half of the ipfw code. 35 */ 36 37#if !defined(KLD_MODULE) 38#include "opt_ipfw.h" 39#include "opt_ipdivert.h" 40#include "opt_ipdn.h" 41#include "opt_inet.h" 42#ifndef INET 43#error IPFIREWALL requires INET. 44#endif /* INET */ 45#endif 46#include "opt_inet6.h" 47#include "opt_ipsec.h" 48 49#include <sys/param.h> 50#include <sys/systm.h> 51#include <sys/malloc.h> 52#include <sys/kernel.h> 53#include <sys/lock.h> 54#include <sys/priv.h> 55#include <sys/proc.h> 56#include <sys/rwlock.h> 57#include <sys/socket.h> 58#include <sys/socketvar.h> 59#include <sys/sysctl.h> 60#include <sys/syslog.h> 61#include <net/if.h> 62#include <net/route.h> 63#include <net/vnet.h> 64 65#include <netinet/in.h> 66#include <netinet/ip_fw.h> 67#include <netinet/ipfw/ip_fw_private.h> 68#include <netinet/ip_divert.h> 69 70#include <netgraph/ng_ipfw.h> 71 72#ifdef MAC 73#include <security/mac/mac_framework.h> 74#endif 75 76MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's"); 77 78/* 79 * static variables followed by global ones 80 */ 81 82static VNET_DEFINE(u_int32_t, static_count); /* # of static rules */ 83static VNET_DEFINE(u_int32_t, static_len); /* bytes of static rules */ 84#define V_static_count VNET(static_count) 85#define V_static_len VNET(static_len) 86 87#ifdef SYSCTL_NODE 88SYSCTL_DECL(_net_inet_ip_fw); 89SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, autoinc_step, 90 CTLFLAG_RW, &VNET_NAME(autoinc_step), 0, 91 "Rule number auto-increment step"); 92SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, static_count, 93 CTLFLAG_RD, &VNET_NAME(static_count), 0, 94 "Number of static rules"); 95 96#endif /* SYSCTL_NODE */ 97 98/* 99 * When a rule is added/deleted, clear the next_rule pointers in all rules. 100 * These will be reconstructed on the fly as packets are matched. 101 */ 102static void 103flush_rule_ptrs(struct ip_fw_chain *chain) 104{ 105 struct ip_fw *rule; 106 107 IPFW_WLOCK_ASSERT(chain); 108 109 chain->id++; 110 111 for (rule = chain->rules; rule; rule = rule->next) 112 rule->next_rule = NULL; 113} 114 115/* 116 * Add a new rule to the list. Copy the rule into a malloc'ed area, then 117 * possibly create a rule number and add the rule to the list. 118 * Update the rule_number in the input struct so the caller knows it as well. 119 */ 120int 121ipfw_add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule) 122{ 123 struct ip_fw *rule, *f, *prev; 124 int l = RULESIZE(input_rule); 125 126 if (chain->rules == NULL && input_rule->rulenum != IPFW_DEFAULT_RULE) 127 return (EINVAL); 128 129 rule = malloc(l, M_IPFW, M_NOWAIT | M_ZERO); 130 if (rule == NULL) 131 return (ENOSPC); 132 133 bcopy(input_rule, rule, l); 134 135 rule->next = NULL; 136 rule->next_rule = NULL; 137 138 rule->pcnt = 0; 139 rule->bcnt = 0; 140 rule->timestamp = 0; 141 142 IPFW_WLOCK(chain); 143 144 if (chain->rules == NULL) { /* default rule */ 145 chain->rules = rule; 146 rule->id = ++chain->id; 147 goto done; 148 } 149 150 /* 151 * If rulenum is 0, find highest numbered rule before the 152 * default rule, and add autoinc_step 153 */ 154 if (V_autoinc_step < 1) 155 V_autoinc_step = 1; 156 else if (V_autoinc_step > 1000) 157 V_autoinc_step = 1000; 158 if (rule->rulenum == 0) { 159 /* 160 * locate the highest numbered rule before default 161 */ 162 for (f = chain->rules; f; f = f->next) { 163 if (f->rulenum == IPFW_DEFAULT_RULE) 164 break; 165 rule->rulenum = f->rulenum; 166 } 167 if (rule->rulenum < IPFW_DEFAULT_RULE - V_autoinc_step) 168 rule->rulenum += V_autoinc_step; 169 input_rule->rulenum = rule->rulenum; 170 } 171 172 /* 173 * Now insert the new rule in the right place in the sorted list. 174 */ 175 for (prev = NULL, f = chain->rules; f; prev = f, f = f->next) { 176 if (f->rulenum > rule->rulenum) { /* found the location */ 177 if (prev) { 178 rule->next = f; 179 prev->next = rule; 180 } else { /* head insert */ 181 rule->next = chain->rules; 182 chain->rules = rule; 183 } 184 break; 185 } 186 } 187 flush_rule_ptrs(chain); 188 /* chain->id incremented inside flush_rule_ptrs() */ 189 rule->id = chain->id; 190done: 191 V_static_count++; 192 V_static_len += l; 193 IPFW_WUNLOCK(chain); 194 DEB(printf("ipfw: installed rule %d, static count now %d\n", 195 rule->rulenum, V_static_count);) 196 return (0); 197} 198 199/** 200 * Remove a static rule (including derived * dynamic rules) 201 * and place it on the ``reap list'' for later reclamation. 202 * The caller is in charge of clearing rule pointers to avoid 203 * dangling pointers. 204 * @return a pointer to the next entry. 205 * Arguments are not checked, so they better be correct. 206 */ 207static struct ip_fw * 208remove_rule(struct ip_fw_chain *chain, struct ip_fw *rule, 209 struct ip_fw *prev) 210{ 211 struct ip_fw *n; 212 int l = RULESIZE(rule); 213 214 IPFW_WLOCK_ASSERT(chain); 215 216 n = rule->next; 217 ipfw_remove_dyn_children(rule); 218 if (prev == NULL) 219 chain->rules = n; 220 else 221 prev->next = n; 222 V_static_count--; 223 V_static_len -= l; 224 225 rule->next = chain->reap; 226 chain->reap = rule; 227 228 return n; 229} 230 231/* 232 * Reclaim storage associated with a list of rules. This is 233 * typically the list created using remove_rule. 234 * A NULL pointer on input is handled correctly. 235 */ 236void 237ipfw_reap_rules(struct ip_fw *head) 238{ 239 struct ip_fw *rule; 240 241 while ((rule = head) != NULL) { 242 head = head->next; 243 free(rule, M_IPFW); 244 } 245} 246 247/* 248 * Remove all rules from a chain (except rules in set RESVD_SET 249 * unless kill_default = 1). The caller is responsible for 250 * reclaiming storage for the rules left in chain->reap. 251 */ 252void 253ipfw_free_chain(struct ip_fw_chain *chain, int kill_default) 254{ 255 struct ip_fw *prev, *rule; 256 257 IPFW_WLOCK_ASSERT(chain); 258 259 chain->reap = NULL; 260 flush_rule_ptrs(chain); /* more efficient to do outside the loop */ 261 for (prev = NULL, rule = chain->rules; rule ; ) 262 if (kill_default || rule->set != RESVD_SET) 263 rule = remove_rule(chain, rule, prev); 264 else { 265 prev = rule; 266 rule = rule->next; 267 } 268} 269 270/** 271 * Remove all rules with given number, and also do set manipulation. 272 * Assumes chain != NULL && *chain != NULL. 273 * 274 * The argument is an u_int32_t. The low 16 bit are the rule or set number, 275 * the next 8 bits are the new set, the top 8 bits are the command: 276 * 277 * 0 delete rules with given number 278 * 1 delete rules with given set number 279 * 2 move rules with given number to new set 280 * 3 move rules with given set number to new set 281 * 4 swap sets with given numbers 282 * 5 delete rules with given number and with given set number 283 */ 284static int 285del_entry(struct ip_fw_chain *chain, u_int32_t arg) 286{ 287 struct ip_fw *prev = NULL, *rule; 288 u_int16_t rulenum; /* rule or old_set */ 289 u_int8_t cmd, new_set; 290 291 rulenum = arg & 0xffff; 292 cmd = (arg >> 24) & 0xff; 293 new_set = (arg >> 16) & 0xff; 294 295 if (cmd > 5 || new_set > RESVD_SET) 296 return EINVAL; 297 if (cmd == 0 || cmd == 2 || cmd == 5) { 298 if (rulenum >= IPFW_DEFAULT_RULE) 299 return EINVAL; 300 } else { 301 if (rulenum > RESVD_SET) /* old_set */ 302 return EINVAL; 303 } 304 305 IPFW_WLOCK(chain); 306 rule = chain->rules; /* common starting point */ 307 chain->reap = NULL; /* prepare for deletions */ 308 switch (cmd) { 309 case 0: /* delete rules with given number */ 310 /* 311 * locate first rule to delete 312 */ 313 for (; rule->rulenum < rulenum; prev = rule, rule = rule->next) 314 ; 315 if (rule->rulenum != rulenum) { 316 IPFW_WUNLOCK(chain); 317 return EINVAL; 318 } 319 320 /* 321 * flush pointers outside the loop, then delete all matching 322 * rules. prev remains the same throughout the cycle. 323 */ 324 flush_rule_ptrs(chain); 325 while (rule->rulenum == rulenum) 326 rule = remove_rule(chain, rule, prev); 327 break; 328 329 case 1: /* delete all rules with given set number */ 330 flush_rule_ptrs(chain); 331 while (rule->rulenum < IPFW_DEFAULT_RULE) { 332 if (rule->set == rulenum) 333 rule = remove_rule(chain, rule, prev); 334 else { 335 prev = rule; 336 rule = rule->next; 337 } 338 } 339 break; 340 341 case 2: /* move rules with given number to new set */ 342 for (; rule->rulenum < IPFW_DEFAULT_RULE; rule = rule->next) 343 if (rule->rulenum == rulenum) 344 rule->set = new_set; 345 break; 346 347 case 3: /* move rules with given set number to new set */ 348 for (; rule->rulenum < IPFW_DEFAULT_RULE; rule = rule->next) 349 if (rule->set == rulenum) 350 rule->set = new_set; 351 break; 352 353 case 4: /* swap two sets */ 354 for (; rule->rulenum < IPFW_DEFAULT_RULE; rule = rule->next) 355 if (rule->set == rulenum) 356 rule->set = new_set; 357 else if (rule->set == new_set) 358 rule->set = rulenum; 359 break; 360 361 case 5: /* delete rules with given number and with given set number. 362 * rulenum - given rule number; 363 * new_set - given set number. 364 */ 365 for (; rule->rulenum < rulenum; prev = rule, rule = rule->next) 366 ; 367 if (rule->rulenum != rulenum) { 368 IPFW_WUNLOCK(chain); 369 return (EINVAL); 370 } 371 flush_rule_ptrs(chain); 372 while (rule->rulenum == rulenum) { 373 if (rule->set == new_set) 374 rule = remove_rule(chain, rule, prev); 375 else { 376 prev = rule; 377 rule = rule->next; 378 } 379 } 380 } 381 /* 382 * Look for rules to reclaim. We grab the list before 383 * releasing the lock then reclaim them w/o the lock to 384 * avoid a LOR with dummynet. 385 */ 386 rule = chain->reap; 387 IPFW_WUNLOCK(chain); 388 ipfw_reap_rules(rule); 389 return 0; 390} 391 392/* 393 * Clear counters for a specific rule. 394 * The enclosing "table" is assumed locked. 395 */ 396static void 397clear_counters(struct ip_fw *rule, int log_only) 398{ 399 ipfw_insn_log *l = (ipfw_insn_log *)ACTION_PTR(rule); 400 401 if (log_only == 0) { 402 rule->bcnt = rule->pcnt = 0; 403 rule->timestamp = 0; 404 } 405 if (l->o.opcode == O_LOG) 406 l->log_left = l->max_log; 407} 408 409/** 410 * Reset some or all counters on firewall rules. 411 * The argument `arg' is an u_int32_t. The low 16 bit are the rule number, 412 * the next 8 bits are the set number, the top 8 bits are the command: 413 * 0 work with rules from all set's; 414 * 1 work with rules only from specified set. 415 * Specified rule number is zero if we want to clear all entries. 416 * log_only is 1 if we only want to reset logs, zero otherwise. 417 */ 418static int 419zero_entry(struct ip_fw_chain *chain, u_int32_t arg, int log_only) 420{ 421 struct ip_fw *rule; 422 char *msg; 423 424 uint16_t rulenum = arg & 0xffff; 425 uint8_t set = (arg >> 16) & 0xff; 426 uint8_t cmd = (arg >> 24) & 0xff; 427 428 if (cmd > 1) 429 return (EINVAL); 430 if (cmd == 1 && set > RESVD_SET) 431 return (EINVAL); 432 433 IPFW_WLOCK(chain); 434 if (rulenum == 0) { 435 V_norule_counter = 0; 436 for (rule = chain->rules; rule; rule = rule->next) { 437 /* Skip rules from another set. */ 438 if (cmd == 1 && rule->set != set) 439 continue; 440 clear_counters(rule, log_only); 441 } 442 msg = log_only ? "All logging counts reset" : 443 "Accounting cleared"; 444 } else { 445 int cleared = 0; 446 /* 447 * We can have multiple rules with the same number, so we 448 * need to clear them all. 449 */ 450 for (rule = chain->rules; rule; rule = rule->next) 451 if (rule->rulenum == rulenum) { 452 while (rule && rule->rulenum == rulenum) { 453 if (cmd == 0 || rule->set == set) 454 clear_counters(rule, log_only); 455 rule = rule->next; 456 } 457 cleared = 1; 458 break; 459 } 460 if (!cleared) { /* we did not find any matching rules */ 461 IPFW_WUNLOCK(chain); 462 return (EINVAL); 463 } 464 msg = log_only ? "logging count reset" : "cleared"; 465 } 466 IPFW_WUNLOCK(chain); 467 468 if (V_fw_verbose) { 469 int lev = LOG_SECURITY | LOG_NOTICE; 470 471 if (rulenum) 472 log(lev, "ipfw: Entry %d %s.\n", rulenum, msg); 473 else 474 log(lev, "ipfw: %s.\n", msg); 475 } 476 return (0); 477} 478 479/* 480 * Check validity of the structure before insert. 481 * Rules are simple, so this mostly need to check rule sizes. 482 */ 483static int 484check_ipfw_struct(struct ip_fw *rule, int size) 485{ 486 int l, cmdlen = 0; 487 int have_action=0; 488 ipfw_insn *cmd; 489 490 if (size < sizeof(*rule)) { 491 printf("ipfw: rule too short\n"); 492 return (EINVAL); 493 } 494 /* first, check for valid size */ 495 l = RULESIZE(rule); 496 if (l != size) { 497 printf("ipfw: size mismatch (have %d want %d)\n", size, l); 498 return (EINVAL); 499 } 500 if (rule->act_ofs >= rule->cmd_len) { 501 printf("ipfw: bogus action offset (%u > %u)\n", 502 rule->act_ofs, rule->cmd_len - 1); 503 return (EINVAL); 504 } 505 /* 506 * Now go for the individual checks. Very simple ones, basically only 507 * instruction sizes. 508 */ 509 for (l = rule->cmd_len, cmd = rule->cmd ; 510 l > 0 ; l -= cmdlen, cmd += cmdlen) { 511 cmdlen = F_LEN(cmd); 512 if (cmdlen > l) { 513 printf("ipfw: opcode %d size truncated\n", 514 cmd->opcode); 515 return EINVAL; 516 } 517 DEB(printf("ipfw: opcode %d\n", cmd->opcode);) 518 switch (cmd->opcode) { 519 case O_PROBE_STATE: 520 case O_KEEP_STATE: 521 case O_PROTO: 522 case O_IP_SRC_ME: 523 case O_IP_DST_ME: 524 case O_LAYER2: 525 case O_IN: 526 case O_FRAG: 527 case O_DIVERTED: 528 case O_IPOPT: 529 case O_IPTOS: 530 case O_IPPRECEDENCE: 531 case O_IPVER: 532 case O_TCPWIN: 533 case O_TCPFLAGS: 534 case O_TCPOPTS: 535 case O_ESTAB: 536 case O_VERREVPATH: 537 case O_VERSRCREACH: 538 case O_ANTISPOOF: 539 case O_IPSEC: 540#ifdef INET6 541 case O_IP6_SRC_ME: 542 case O_IP6_DST_ME: 543 case O_EXT_HDR: 544 case O_IP6: 545#endif 546 case O_IP4: 547 case O_TAG: 548 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 549 goto bad_size; 550 break; 551 552 case O_FIB: 553 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 554 goto bad_size; 555 if (cmd->arg1 >= rt_numfibs) { 556 printf("ipfw: invalid fib number %d\n", 557 cmd->arg1); 558 return EINVAL; 559 } 560 break; 561 562 case O_SETFIB: 563 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 564 goto bad_size; 565 if (cmd->arg1 >= rt_numfibs) { 566 printf("ipfw: invalid fib number %d\n", 567 cmd->arg1); 568 return EINVAL; 569 } 570 goto check_action; 571 572 case O_UID: 573 case O_GID: 574 case O_JAIL: 575 case O_IP_SRC: 576 case O_IP_DST: 577 case O_TCPSEQ: 578 case O_TCPACK: 579 case O_PROB: 580 case O_ICMPTYPE: 581 if (cmdlen != F_INSN_SIZE(ipfw_insn_u32)) 582 goto bad_size; 583 break; 584 585 case O_LIMIT: 586 if (cmdlen != F_INSN_SIZE(ipfw_insn_limit)) 587 goto bad_size; 588 break; 589 590 case O_LOG: 591 if (cmdlen != F_INSN_SIZE(ipfw_insn_log)) 592 goto bad_size; 593 594 ((ipfw_insn_log *)cmd)->log_left = 595 ((ipfw_insn_log *)cmd)->max_log; 596 597 break; 598 599 case O_IP_SRC_MASK: 600 case O_IP_DST_MASK: 601 /* only odd command lengths */ 602 if ( !(cmdlen & 1) || cmdlen > 31) 603 goto bad_size; 604 break; 605 606 case O_IP_SRC_SET: 607 case O_IP_DST_SET: 608 if (cmd->arg1 == 0 || cmd->arg1 > 256) { 609 printf("ipfw: invalid set size %d\n", 610 cmd->arg1); 611 return EINVAL; 612 } 613 if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 614 (cmd->arg1+31)/32 ) 615 goto bad_size; 616 break; 617 618 case O_IP_SRC_LOOKUP: 619 case O_IP_DST_LOOKUP: 620 if (cmd->arg1 >= IPFW_TABLES_MAX) { 621 printf("ipfw: invalid table number %d\n", 622 cmd->arg1); 623 return (EINVAL); 624 } 625 if (cmdlen != F_INSN_SIZE(ipfw_insn) && 626 cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1 && 627 cmdlen != F_INSN_SIZE(ipfw_insn_u32)) 628 goto bad_size; 629 break; 630 631 case O_MACADDR2: 632 if (cmdlen != F_INSN_SIZE(ipfw_insn_mac)) 633 goto bad_size; 634 break; 635 636 case O_NOP: 637 case O_IPID: 638 case O_IPTTL: 639 case O_IPLEN: 640 case O_TCPDATALEN: 641 case O_TAGGED: 642 if (cmdlen < 1 || cmdlen > 31) 643 goto bad_size; 644 break; 645 646 case O_MAC_TYPE: 647 case O_IP_SRCPORT: 648 case O_IP_DSTPORT: /* XXX artificial limit, 30 port pairs */ 649 if (cmdlen < 2 || cmdlen > 31) 650 goto bad_size; 651 break; 652 653 case O_RECV: 654 case O_XMIT: 655 case O_VIA: 656 if (cmdlen != F_INSN_SIZE(ipfw_insn_if)) 657 goto bad_size; 658 break; 659 660 case O_ALTQ: 661 if (cmdlen != F_INSN_SIZE(ipfw_insn_altq)) 662 goto bad_size; 663 break; 664 665 case O_PIPE: 666 case O_QUEUE: 667 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 668 goto bad_size; 669 goto check_action; 670 671 case O_FORWARD_IP: 672#ifdef IPFIREWALL_FORWARD 673 if (cmdlen != F_INSN_SIZE(ipfw_insn_sa)) 674 goto bad_size; 675 goto check_action; 676#else 677 return EINVAL; 678#endif 679 680 case O_DIVERT: 681 case O_TEE: 682 if (ip_divert_ptr == NULL) 683 return EINVAL; 684 else 685 goto check_size; 686 case O_NETGRAPH: 687 case O_NGTEE: 688 if (!NG_IPFW_LOADED) 689 return EINVAL; 690 else 691 goto check_size; 692 case O_NAT: 693 if (!IPFW_NAT_LOADED) 694 return EINVAL; 695 if (cmdlen != F_INSN_SIZE(ipfw_insn_nat)) 696 goto bad_size; 697 goto check_action; 698 case O_FORWARD_MAC: /* XXX not implemented yet */ 699 case O_CHECK_STATE: 700 case O_COUNT: 701 case O_ACCEPT: 702 case O_DENY: 703 case O_REJECT: 704#ifdef INET6 705 case O_UNREACH6: 706#endif 707 case O_SKIPTO: 708 case O_REASS: 709check_size: 710 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 711 goto bad_size; 712check_action: 713 if (have_action) { 714 printf("ipfw: opcode %d, multiple actions" 715 " not allowed\n", 716 cmd->opcode); 717 return EINVAL; 718 } 719 have_action = 1; 720 if (l != cmdlen) { 721 printf("ipfw: opcode %d, action must be" 722 " last opcode\n", 723 cmd->opcode); 724 return EINVAL; 725 } 726 break; 727#ifdef INET6 728 case O_IP6_SRC: 729 case O_IP6_DST: 730 if (cmdlen != F_INSN_SIZE(struct in6_addr) + 731 F_INSN_SIZE(ipfw_insn)) 732 goto bad_size; 733 break; 734 735 case O_FLOW6ID: 736 if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 737 ((ipfw_insn_u32 *)cmd)->o.arg1) 738 goto bad_size; 739 break; 740 741 case O_IP6_SRC_MASK: 742 case O_IP6_DST_MASK: 743 if ( !(cmdlen & 1) || cmdlen > 127) 744 goto bad_size; 745 break; 746 case O_ICMP6TYPE: 747 if( cmdlen != F_INSN_SIZE( ipfw_insn_icmp6 ) ) 748 goto bad_size; 749 break; 750#endif 751 752 default: 753 switch (cmd->opcode) { 754#ifndef INET6 755 case O_IP6_SRC_ME: 756 case O_IP6_DST_ME: 757 case O_EXT_HDR: 758 case O_IP6: 759 case O_UNREACH6: 760 case O_IP6_SRC: 761 case O_IP6_DST: 762 case O_FLOW6ID: 763 case O_IP6_SRC_MASK: 764 case O_IP6_DST_MASK: 765 case O_ICMP6TYPE: 766 printf("ipfw: no IPv6 support in kernel\n"); 767 return EPROTONOSUPPORT; 768#endif 769 default: 770 printf("ipfw: opcode %d, unknown opcode\n", 771 cmd->opcode); 772 return EINVAL; 773 } 774 } 775 } 776 if (have_action == 0) { 777 printf("ipfw: missing action\n"); 778 return EINVAL; 779 } 780 return 0; 781 782bad_size: 783 printf("ipfw: opcode %d size %d wrong\n", 784 cmd->opcode, cmdlen); 785 return EINVAL; 786} 787 788/* 789 * Copy the static and dynamic rules to the supplied buffer 790 * and return the amount of space actually used. 791 */ 792static size_t 793ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space) 794{ 795 char *bp = buf; 796 char *ep = bp + space; 797 struct ip_fw *rule; 798 int i; 799 time_t boot_seconds; 800 801 boot_seconds = boottime.tv_sec; 802 /* XXX this can take a long time and locking will block packet flow */ 803 IPFW_RLOCK(chain); 804 for (rule = chain->rules; rule ; rule = rule->next) { 805 /* 806 * Verify the entry fits in the buffer in case the 807 * rules changed between calculating buffer space and 808 * now. This would be better done using a generation 809 * number but should suffice for now. 810 */ 811 i = RULESIZE(rule); 812 if (bp + i <= ep) { 813 bcopy(rule, bp, i); 814 /* 815 * XXX HACK. Store the disable mask in the "next" 816 * pointer in a wild attempt to keep the ABI the same. 817 * Why do we do this on EVERY rule? 818 */ 819 bcopy(&V_set_disable, 820 &(((struct ip_fw *)bp)->next_rule), 821 sizeof(V_set_disable)); 822 if (((struct ip_fw *)bp)->timestamp) 823 ((struct ip_fw *)bp)->timestamp += boot_seconds; 824 bp += i; 825 } 826 } 827 IPFW_RUNLOCK(chain); 828 ipfw_get_dynamic(&bp, ep); /* protected by the dynamic lock */ 829 return (bp - (char *)buf); 830} 831 832 833/** 834 * {set|get}sockopt parser. 835 */ 836int 837ipfw_ctl(struct sockopt *sopt) 838{ 839#define RULE_MAXSIZE (256*sizeof(u_int32_t)) 840 int error; 841 size_t size; 842 struct ip_fw *buf, *rule; 843 u_int32_t rulenum[2]; 844 845 error = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW); 846 if (error) 847 return (error); 848 849 /* 850 * Disallow modifications in really-really secure mode, but still allow 851 * the logging counters to be reset. 852 */ 853 if (sopt->sopt_name == IP_FW_ADD || 854 (sopt->sopt_dir == SOPT_SET && sopt->sopt_name != IP_FW_RESETLOG)) { 855 error = securelevel_ge(sopt->sopt_td->td_ucred, 3); 856 if (error) 857 return (error); 858 } 859 860 error = 0; 861 862 switch (sopt->sopt_name) { 863 case IP_FW_GET: 864 /* 865 * pass up a copy of the current rules. Static rules 866 * come first (the last of which has number IPFW_DEFAULT_RULE), 867 * followed by a possibly empty list of dynamic rule. 868 * The last dynamic rule has NULL in the "next" field. 869 * 870 * Note that the calculated size is used to bound the 871 * amount of data returned to the user. The rule set may 872 * change between calculating the size and returning the 873 * data in which case we'll just return what fits. 874 */ 875 size = V_static_len; /* size of static rules */ 876 size += ipfw_dyn_len(); 877 878 if (size >= sopt->sopt_valsize) 879 break; 880 /* 881 * XXX todo: if the user passes a short length just to know 882 * how much room is needed, do not bother filling up the 883 * buffer, just jump to the sooptcopyout. 884 */ 885 buf = malloc(size, M_TEMP, M_WAITOK); 886 error = sooptcopyout(sopt, buf, 887 ipfw_getrules(&V_layer3_chain, buf, size)); 888 free(buf, M_TEMP); 889 break; 890 891 case IP_FW_FLUSH: 892 /* 893 * Normally we cannot release the lock on each iteration. 894 * We could do it here only because we start from the head all 895 * the times so there is no risk of missing some entries. 896 * On the other hand, the risk is that we end up with 897 * a very inconsistent ruleset, so better keep the lock 898 * around the whole cycle. 899 * 900 * XXX this code can be improved by resetting the head of 901 * the list to point to the default rule, and then freeing 902 * the old list without the need for a lock. 903 */ 904 905 IPFW_WLOCK(&V_layer3_chain); 906 ipfw_free_chain(&V_layer3_chain, 0 /* keep default rule */); 907 rule = V_layer3_chain.reap; 908 IPFW_WUNLOCK(&V_layer3_chain); 909 ipfw_reap_rules(rule); 910 break; 911 912 case IP_FW_ADD: 913 rule = malloc(RULE_MAXSIZE, M_TEMP, M_WAITOK); 914 error = sooptcopyin(sopt, rule, RULE_MAXSIZE, 915 sizeof(struct ip_fw) ); 916 if (error == 0) 917 error = check_ipfw_struct(rule, sopt->sopt_valsize); 918 if (error == 0) { 919 error = ipfw_add_rule(&V_layer3_chain, rule); 920 size = RULESIZE(rule); 921 if (!error && sopt->sopt_dir == SOPT_GET) 922 error = sooptcopyout(sopt, rule, size); 923 } 924 free(rule, M_TEMP); 925 break; 926 927 case IP_FW_DEL: 928 /* 929 * IP_FW_DEL is used for deleting single rules or sets, 930 * and (ab)used to atomically manipulate sets. Argument size 931 * is used to distinguish between the two: 932 * sizeof(u_int32_t) 933 * delete single rule or set of rules, 934 * or reassign rules (or sets) to a different set. 935 * 2*sizeof(u_int32_t) 936 * atomic disable/enable sets. 937 * first u_int32_t contains sets to be disabled, 938 * second u_int32_t contains sets to be enabled. 939 */ 940 error = sooptcopyin(sopt, rulenum, 941 2*sizeof(u_int32_t), sizeof(u_int32_t)); 942 if (error) 943 break; 944 size = sopt->sopt_valsize; 945 if (size == sizeof(u_int32_t)) /* delete or reassign */ 946 error = del_entry(&V_layer3_chain, rulenum[0]); 947 else if (size == 2*sizeof(u_int32_t)) /* set enable/disable */ 948 V_set_disable = 949 (V_set_disable | rulenum[0]) & ~rulenum[1] & 950 ~(1<<RESVD_SET); /* set RESVD_SET always enabled */ 951 else 952 error = EINVAL; 953 break; 954 955 case IP_FW_ZERO: 956 case IP_FW_RESETLOG: /* argument is an u_int_32, the rule number */ 957 rulenum[0] = 0; 958 if (sopt->sopt_val != 0) { 959 error = sooptcopyin(sopt, rulenum, 960 sizeof(u_int32_t), sizeof(u_int32_t)); 961 if (error) 962 break; 963 } 964 error = zero_entry(&V_layer3_chain, rulenum[0], 965 sopt->sopt_name == IP_FW_RESETLOG); 966 break; 967 968 case IP_FW_TABLE_ADD: 969 { 970 ipfw_table_entry ent; 971 972 error = sooptcopyin(sopt, &ent, 973 sizeof(ent), sizeof(ent)); 974 if (error) 975 break; 976 error = ipfw_add_table_entry(&V_layer3_chain, ent.tbl, 977 ent.addr, ent.masklen, ent.value); 978 } 979 break; 980 981 case IP_FW_TABLE_DEL: 982 { 983 ipfw_table_entry ent; 984 985 error = sooptcopyin(sopt, &ent, 986 sizeof(ent), sizeof(ent)); 987 if (error) 988 break; 989 error = ipfw_del_table_entry(&V_layer3_chain, ent.tbl, 990 ent.addr, ent.masklen); 991 } 992 break; 993 994 case IP_FW_TABLE_FLUSH: 995 { 996 u_int16_t tbl; 997 998 error = sooptcopyin(sopt, &tbl, 999 sizeof(tbl), sizeof(tbl)); 1000 if (error) 1001 break; 1002 IPFW_WLOCK(&V_layer3_chain); 1003 error = ipfw_flush_table(&V_layer3_chain, tbl); 1004 IPFW_WUNLOCK(&V_layer3_chain); 1005 } 1006 break; 1007 1008 case IP_FW_TABLE_GETSIZE: 1009 { 1010 u_int32_t tbl, cnt; 1011 1012 if ((error = sooptcopyin(sopt, &tbl, sizeof(tbl), 1013 sizeof(tbl)))) 1014 break; 1015 IPFW_RLOCK(&V_layer3_chain); 1016 error = ipfw_count_table(&V_layer3_chain, tbl, &cnt); 1017 IPFW_RUNLOCK(&V_layer3_chain); 1018 if (error) 1019 break; 1020 error = sooptcopyout(sopt, &cnt, sizeof(cnt)); 1021 } 1022 break; 1023 1024 case IP_FW_TABLE_LIST: 1025 { 1026 ipfw_table *tbl; 1027 1028 if (sopt->sopt_valsize < sizeof(*tbl)) { 1029 error = EINVAL; 1030 break; 1031 } 1032 size = sopt->sopt_valsize; 1033 tbl = malloc(size, M_TEMP, M_WAITOK); 1034 error = sooptcopyin(sopt, tbl, size, sizeof(*tbl)); 1035 if (error) { 1036 free(tbl, M_TEMP); 1037 break; 1038 } 1039 tbl->size = (size - sizeof(*tbl)) / 1040 sizeof(ipfw_table_entry); 1041 IPFW_RLOCK(&V_layer3_chain); 1042 error = ipfw_dump_table(&V_layer3_chain, tbl); 1043 IPFW_RUNLOCK(&V_layer3_chain); 1044 if (error) { 1045 free(tbl, M_TEMP); 1046 break; 1047 } 1048 error = sooptcopyout(sopt, tbl, size); 1049 free(tbl, M_TEMP); 1050 } 1051 break; 1052 1053 case IP_FW_NAT_CFG: 1054 if (IPFW_NAT_LOADED) 1055 error = ipfw_nat_cfg_ptr(sopt); 1056 else { 1057 printf("IP_FW_NAT_CFG: %s\n", 1058 "ipfw_nat not present, please load it"); 1059 error = EINVAL; 1060 } 1061 break; 1062 1063 case IP_FW_NAT_DEL: 1064 if (IPFW_NAT_LOADED) 1065 error = ipfw_nat_del_ptr(sopt); 1066 else { 1067 printf("IP_FW_NAT_DEL: %s\n", 1068 "ipfw_nat not present, please load it"); 1069 error = EINVAL; 1070 } 1071 break; 1072 1073 case IP_FW_NAT_GET_CONFIG: 1074 if (IPFW_NAT_LOADED) 1075 error = ipfw_nat_get_cfg_ptr(sopt); 1076 else { 1077 printf("IP_FW_NAT_GET_CFG: %s\n", 1078 "ipfw_nat not present, please load it"); 1079 error = EINVAL; 1080 } 1081 break; 1082 1083 case IP_FW_NAT_GET_LOG: 1084 if (IPFW_NAT_LOADED) 1085 error = ipfw_nat_get_log_ptr(sopt); 1086 else { 1087 printf("IP_FW_NAT_GET_LOG: %s\n", 1088 "ipfw_nat not present, please load it"); 1089 error = EINVAL; 1090 } 1091 break; 1092 1093 default: 1094 printf("ipfw: ipfw_ctl invalid option %d\n", sopt->sopt_name); 1095 error = EINVAL; 1096 } 1097 1098 return (error); 1099#undef RULE_MAXSIZE 1100} 1101/* end of file */ 1102