ip_fw2.c (200580) | ip_fw2.c (200590) |
---|---|
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. --- 10 unchanged lines hidden (view full) --- 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> | 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. --- 10 unchanged lines hidden (view full) --- 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_fw2.c 200580 2009-12-15 16:15:14Z luigi $"); | 27__FBSDID("$FreeBSD: head/sys/netinet/ipfw/ip_fw2.c 200590 2009-12-15 21:24:12Z luigi $"); |
28 29#define DEB(x) 30#define DDB(x) x 31 32/* 33 * Implement IP packet firewall (new version) 34 */ 35 --- 24 unchanged lines hidden (view full) --- 60#include <sys/rwlock.h> 61#include <sys/socket.h> 62#include <sys/socketvar.h> 63#include <sys/sysctl.h> 64#include <sys/syslog.h> 65#include <sys/ucred.h> 66#include <net/ethernet.h> /* for ETHERTYPE_IP */ 67#include <net/if.h> | 28 29#define DEB(x) 30#define DDB(x) x 31 32/* 33 * Implement IP packet firewall (new version) 34 */ 35 --- 24 unchanged lines hidden (view full) --- 60#include <sys/rwlock.h> 61#include <sys/socket.h> 62#include <sys/socketvar.h> 63#include <sys/sysctl.h> 64#include <sys/syslog.h> 65#include <sys/ucred.h> 66#include <net/ethernet.h> /* for ETHERTYPE_IP */ 67#include <net/if.h> |
68#include <net/radix.h> | |
69#include <net/route.h> 70#include <net/pf_mtag.h> 71#include <net/vnet.h> 72 73#include <netinet/in.h> 74#include <netinet/in_var.h> 75#include <netinet/in_pcb.h> 76#include <netinet/ip.h> --- 30 unchanged lines hidden (view full) --- 107/* 108 * set_disable contains one bit per set value (0..31). 109 * If the bit is set, all rules with the corresponding set 110 * are disabled. Set RESVD_SET(31) is reserved for the default rule 111 * and rules that are not deleted by the flush command, 112 * and CANNOT be disabled. 113 * Rules in set RESVD_SET can only be deleted explicitly. 114 */ | 68#include <net/route.h> 69#include <net/pf_mtag.h> 70#include <net/vnet.h> 71 72#include <netinet/in.h> 73#include <netinet/in_var.h> 74#include <netinet/in_pcb.h> 75#include <netinet/ip.h> --- 30 unchanged lines hidden (view full) --- 106/* 107 * set_disable contains one bit per set value (0..31). 108 * If the bit is set, all rules with the corresponding set 109 * are disabled. Set RESVD_SET(31) is reserved for the default rule 110 * and rules that are not deleted by the flush command, 111 * and CANNOT be disabled. 112 * Rules in set RESVD_SET can only be deleted explicitly. 113 */ |
115static VNET_DEFINE(u_int32_t, set_disable); | 114VNET_DEFINE(u_int32_t, set_disable); |
116VNET_DEFINE(int, fw_verbose); 117 118#define V_set_disable VNET(set_disable) 119#define V_verbose_limit VNET(verbose_limit) 120 121#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT 122static int default_to_accept = 1; 123#else 124static int default_to_accept; 125#endif 126 127struct ip_fw *ip_fw_default_rule; 128 129/* 130 * list of rules for layer 3 131 */ 132VNET_DEFINE(struct ip_fw_chain, layer3_chain); 133 134MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's"); | 115VNET_DEFINE(int, fw_verbose); 116 117#define V_set_disable VNET(set_disable) 118#define V_verbose_limit VNET(verbose_limit) 119 120#ifdef IPFIREWALL_DEFAULT_TO_ACCEPT 121static int default_to_accept = 1; 122#else 123static int default_to_accept; 124#endif 125 126struct ip_fw *ip_fw_default_rule; 127 128/* 129 * list of rules for layer 3 130 */ 131VNET_DEFINE(struct ip_fw_chain, layer3_chain); 132 133MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's"); |
135MALLOC_DEFINE(M_IPFW_TBL, "ipfw_tbl", "IpFw tables"); 136#define IPFW_NAT_LOADED (ipfw_nat_ptr != NULL) | |
137ipfw_nat_t *ipfw_nat_ptr = NULL; 138struct cfg_nat *(*lookup_nat_ptr)(struct nat_list *, int); 139ipfw_nat_cfg_t *ipfw_nat_cfg_ptr; 140ipfw_nat_cfg_t *ipfw_nat_del_ptr; 141ipfw_nat_cfg_t *ipfw_nat_get_cfg_ptr; 142ipfw_nat_cfg_t *ipfw_nat_get_log_ptr; 143 144struct table_entry { 145 struct radix_node rn[2]; 146 struct sockaddr_in addr, mask; 147 u_int32_t value; 148}; 149 150static VNET_DEFINE(int, autoinc_step); 151#define V_autoinc_step VNET(autoinc_step) 152static VNET_DEFINE(int, fw_deny_unknown_exthdrs); 153#define V_fw_deny_unknown_exthdrs VNET(fw_deny_unknown_exthdrs) 154 | 134ipfw_nat_t *ipfw_nat_ptr = NULL; 135struct cfg_nat *(*lookup_nat_ptr)(struct nat_list *, int); 136ipfw_nat_cfg_t *ipfw_nat_cfg_ptr; 137ipfw_nat_cfg_t *ipfw_nat_del_ptr; 138ipfw_nat_cfg_t *ipfw_nat_get_cfg_ptr; 139ipfw_nat_cfg_t *ipfw_nat_get_log_ptr; 140 141struct table_entry { 142 struct radix_node rn[2]; 143 struct sockaddr_in addr, mask; 144 u_int32_t value; 145}; 146 147static VNET_DEFINE(int, autoinc_step); 148#define V_autoinc_step VNET(autoinc_step) 149static VNET_DEFINE(int, fw_deny_unknown_exthdrs); 150#define V_fw_deny_unknown_exthdrs VNET(fw_deny_unknown_exthdrs) 151 |
155static VNET_DEFINE(u_int32_t, static_count); /* # of static rules */ 156static VNET_DEFINE(u_int32_t, static_len); /* bytes of static rules */ 157#define V_static_count VNET(static_count) 158#define V_static_len VNET(static_len) | |
159extern int ipfw_chg_hook(SYSCTL_HANDLER_ARGS); 160 161#ifdef SYSCTL_NODE 162SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall"); 163SYSCTL_VNET_PROC(_net_inet_ip_fw, OID_AUTO, enable, 164 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_enable), 0, 165 ipfw_chg_hook, "I", "Enable ipfw"); 166SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, autoinc_step, --- 25 unchanged lines hidden (view full) --- 192SYSCTL_VNET_PROC(_net_inet6_ip6_fw, OID_AUTO, enable, 193 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw6_enable), 0, 194 ipfw_chg_hook, "I", "Enable ipfw+6"); 195SYSCTL_VNET_INT(_net_inet6_ip6_fw, OID_AUTO, deny_unknown_exthdrs, 196 CTLFLAG_RW | CTLFLAG_SECURE, &VNET_NAME(fw_deny_unknown_exthdrs), 0, 197 "Deny packets with unknown IPv6 Extension Headers"); 198#endif /* INET6 */ 199 | 152extern int ipfw_chg_hook(SYSCTL_HANDLER_ARGS); 153 154#ifdef SYSCTL_NODE 155SYSCTL_NODE(_net_inet_ip, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall"); 156SYSCTL_VNET_PROC(_net_inet_ip_fw, OID_AUTO, enable, 157 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_enable), 0, 158 ipfw_chg_hook, "I", "Enable ipfw"); 159SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, autoinc_step, --- 25 unchanged lines hidden (view full) --- 185SYSCTL_VNET_PROC(_net_inet6_ip6_fw, OID_AUTO, enable, 186 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw6_enable), 0, 187 ipfw_chg_hook, "I", "Enable ipfw+6"); 188SYSCTL_VNET_INT(_net_inet6_ip6_fw, OID_AUTO, deny_unknown_exthdrs, 189 CTLFLAG_RW | CTLFLAG_SECURE, &VNET_NAME(fw_deny_unknown_exthdrs), 0, 190 "Deny packets with unknown IPv6 Extension Headers"); 191#endif /* INET6 */ 192 |
200SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, static_count, 201 CTLFLAG_RD, &VNET_NAME(static_count), 0, 202 "Number of static rules"); | |
203#endif /* SYSCTL_NODE */ 204 205 206/* 207 * L3HDR maps an ipv4 pointer into a layer3 header pointer of type T 208 * Other macros just cast void * into the appropriate type 209 */ 210#define L3HDR(T, ip) ((T *)((u_int32_t *)(ip) + (ip)->ip_hl)) --- 477 unchanged lines hidden (view full) --- 688 } 689 if (rule == NULL) /* failure or not a skipto */ 690 rule = me->next; 691 me->next_rule = rule; 692 return rule; 693} 694 695static int | 193#endif /* SYSCTL_NODE */ 194 195 196/* 197 * L3HDR maps an ipv4 pointer into a layer3 header pointer of type T 198 * Other macros just cast void * into the appropriate type 199 */ 200#define L3HDR(T, ip) ((T *)((u_int32_t *)(ip) + (ip)->ip_hl)) --- 477 unchanged lines hidden (view full) --- 678 } 679 if (rule == NULL) /* failure or not a skipto */ 680 rule = me->next; 681 me->next_rule = rule; 682 return rule; 683} 684 685static int |
696add_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, 697 uint8_t mlen, uint32_t value) 698{ 699 struct radix_node_head *rnh; 700 struct table_entry *ent; 701 struct radix_node *rn; 702 703 if (tbl >= IPFW_TABLES_MAX) 704 return (EINVAL); 705 rnh = ch->tables[tbl]; 706 ent = malloc(sizeof(*ent), M_IPFW_TBL, M_NOWAIT | M_ZERO); 707 if (ent == NULL) 708 return (ENOMEM); 709 ent->value = value; 710 ent->addr.sin_len = ent->mask.sin_len = 8; 711 ent->mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 712 ent->addr.sin_addr.s_addr = addr & ent->mask.sin_addr.s_addr; 713 IPFW_WLOCK(ch); 714 rn = rnh->rnh_addaddr(&ent->addr, &ent->mask, rnh, (void *)ent); 715 if (rn == NULL) { 716 IPFW_WUNLOCK(ch); 717 free(ent, M_IPFW_TBL); 718 return (EEXIST); 719 } 720 IPFW_WUNLOCK(ch); 721 return (0); 722} 723 724static int 725del_table_entry(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, 726 uint8_t mlen) 727{ 728 struct radix_node_head *rnh; 729 struct table_entry *ent; 730 struct sockaddr_in sa, mask; 731 732 if (tbl >= IPFW_TABLES_MAX) 733 return (EINVAL); 734 rnh = ch->tables[tbl]; 735 sa.sin_len = mask.sin_len = 8; 736 mask.sin_addr.s_addr = htonl(mlen ? ~((1 << (32 - mlen)) - 1) : 0); 737 sa.sin_addr.s_addr = addr & mask.sin_addr.s_addr; 738 IPFW_WLOCK(ch); 739 ent = (struct table_entry *)rnh->rnh_deladdr(&sa, &mask, rnh); 740 if (ent == NULL) { 741 IPFW_WUNLOCK(ch); 742 return (ESRCH); 743 } 744 IPFW_WUNLOCK(ch); 745 free(ent, M_IPFW_TBL); 746 return (0); 747} 748 749static int 750flush_table_entry(struct radix_node *rn, void *arg) 751{ 752 struct radix_node_head * const rnh = arg; 753 struct table_entry *ent; 754 755 ent = (struct table_entry *) 756 rnh->rnh_deladdr(rn->rn_key, rn->rn_mask, rnh); 757 if (ent != NULL) 758 free(ent, M_IPFW_TBL); 759 return (0); 760} 761 762static int 763flush_table(struct ip_fw_chain *ch, uint16_t tbl) 764{ 765 struct radix_node_head *rnh; 766 767 IPFW_WLOCK_ASSERT(ch); 768 769 if (tbl >= IPFW_TABLES_MAX) 770 return (EINVAL); 771 rnh = ch->tables[tbl]; 772 KASSERT(rnh != NULL, ("NULL IPFW table")); 773 rnh->rnh_walktree(rnh, flush_table_entry, rnh); 774 return (0); 775} 776 777static void 778flush_tables(struct ip_fw_chain *ch) 779{ 780 uint16_t tbl; 781 782 IPFW_WLOCK_ASSERT(ch); 783 784 for (tbl = 0; tbl < IPFW_TABLES_MAX; tbl++) 785 flush_table(ch, tbl); 786} 787 788static int 789init_tables(struct ip_fw_chain *ch) 790{ 791 int i; 792 uint16_t j; 793 794 for (i = 0; i < IPFW_TABLES_MAX; i++) { 795 if (!rn_inithead((void **)&ch->tables[i], 32)) { 796 for (j = 0; j < i; j++) { 797 (void) flush_table(ch, j); 798 } 799 return (ENOMEM); 800 } 801 } 802 return (0); 803} 804 805static int 806lookup_table(struct ip_fw_chain *ch, uint16_t tbl, in_addr_t addr, 807 uint32_t *val) 808{ 809 struct radix_node_head *rnh; 810 struct table_entry *ent; 811 struct sockaddr_in sa; 812 813 if (tbl >= IPFW_TABLES_MAX) 814 return (0); 815 rnh = ch->tables[tbl]; 816 sa.sin_len = 8; 817 sa.sin_addr.s_addr = addr; 818 ent = (struct table_entry *)(rnh->rnh_lookup(&sa, NULL, rnh)); 819 if (ent != NULL) { 820 *val = ent->value; 821 return (1); 822 } 823 return (0); 824} 825 826static int 827count_table_entry(struct radix_node *rn, void *arg) 828{ 829 u_int32_t * const cnt = arg; 830 831 (*cnt)++; 832 return (0); 833} 834 835static int 836count_table(struct ip_fw_chain *ch, uint32_t tbl, uint32_t *cnt) 837{ 838 struct radix_node_head *rnh; 839 840 if (tbl >= IPFW_TABLES_MAX) 841 return (EINVAL); 842 rnh = ch->tables[tbl]; 843 *cnt = 0; 844 rnh->rnh_walktree(rnh, count_table_entry, cnt); 845 return (0); 846} 847 848static int 849dump_table_entry(struct radix_node *rn, void *arg) 850{ 851 struct table_entry * const n = (struct table_entry *)rn; 852 ipfw_table * const tbl = arg; 853 ipfw_table_entry *ent; 854 855 if (tbl->cnt == tbl->size) 856 return (1); 857 ent = &tbl->ent[tbl->cnt]; 858 ent->tbl = tbl->tbl; 859 if (in_nullhost(n->mask.sin_addr)) 860 ent->masklen = 0; 861 else 862 ent->masklen = 33 - ffs(ntohl(n->mask.sin_addr.s_addr)); 863 ent->addr = n->addr.sin_addr.s_addr; 864 ent->value = n->value; 865 tbl->cnt++; 866 return (0); 867} 868 869static int 870dump_table(struct ip_fw_chain *ch, ipfw_table *tbl) 871{ 872 struct radix_node_head *rnh; 873 874 if (tbl->tbl >= IPFW_TABLES_MAX) 875 return (EINVAL); 876 rnh = ch->tables[tbl->tbl]; 877 tbl->cnt = 0; 878 rnh->rnh_walktree(rnh, dump_table_entry, tbl); 879 return (0); 880} 881 882static int | |
883check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif, 884 struct in_addr dst_ip, u_int16_t dst_port, struct in_addr src_ip, 885 u_int16_t src_port, struct ucred **uc, int *ugid_lookupp, 886 struct inpcb *inp) 887{ 888 struct inpcbinfo *pi; 889 int wildcard; 890 struct inpcb *pcb; --- 740 unchanged lines hidden (view full) --- 1631 &ucred_lookup, args->inp); 1632 if (v == 4 /* O_UID */) 1633 a = ucred_cache->cr_uid; 1634 else if (v == 5 /* O_JAIL */) 1635 a = ucred_cache->cr_prison->pr_id; 1636 } else 1637 break; 1638 } | 686check_uidgid(ipfw_insn_u32 *insn, int proto, struct ifnet *oif, 687 struct in_addr dst_ip, u_int16_t dst_port, struct in_addr src_ip, 688 u_int16_t src_port, struct ucred **uc, int *ugid_lookupp, 689 struct inpcb *inp) 690{ 691 struct inpcbinfo *pi; 692 int wildcard; 693 struct inpcb *pcb; --- 740 unchanged lines hidden (view full) --- 1434 &ucred_lookup, args->inp); 1435 if (v == 4 /* O_UID */) 1436 a = ucred_cache->cr_uid; 1437 else if (v == 5 /* O_JAIL */) 1438 a = ucred_cache->cr_prison->pr_id; 1439 } else 1440 break; 1441 } |
1639 match = lookup_table(chain, cmd->arg1, a, | 1442 match = ipfw_lookup_table(chain, cmd->arg1, a, |
1640 &v); 1641 if (!match) 1642 break; 1643 if (cmdlen == F_INSN_SIZE(ipfw_insn_u32)) 1644 match = 1645 ((ipfw_insn_u32 *)cmd)->d[0] == v; 1646 else 1647 tablearg = v; --- 795 unchanged lines hidden (view full) --- 2443 return (retval); 2444 2445pullup_failed: 2446 if (V_fw_verbose) 2447 printf("ipfw: pullup failed\n"); 2448 return (IP_FW_DENY); 2449} 2450 | 1443 &v); 1444 if (!match) 1445 break; 1446 if (cmdlen == F_INSN_SIZE(ipfw_insn_u32)) 1447 match = 1448 ((ipfw_insn_u32 *)cmd)->d[0] == v; 1449 else 1450 tablearg = v; --- 795 unchanged lines hidden (view full) --- 2246 return (retval); 2247 2248pullup_failed: 2249 if (V_fw_verbose) 2250 printf("ipfw: pullup failed\n"); 2251 return (IP_FW_DENY); 2252} 2253 |
2451/* 2452 * When a rule is added/deleted, clear the next_rule pointers in all rules. 2453 * These will be reconstructed on the fly as packets are matched. 2454 */ 2455static void 2456flush_rule_ptrs(struct ip_fw_chain *chain) 2457{ 2458 struct ip_fw *rule; 2459 2460 IPFW_WLOCK_ASSERT(chain); 2461 2462 chain->id++; 2463 2464 for (rule = chain->rules; rule; rule = rule->next) 2465 rule->next_rule = NULL; 2466} 2467 2468/* 2469 * Add a new rule to the list. Copy the rule into a malloc'ed area, then 2470 * possibly create a rule number and add the rule to the list. 2471 * Update the rule_number in the input struct so the caller knows it as well. 2472 */ 2473static int 2474add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule) 2475{ 2476 struct ip_fw *rule, *f, *prev; 2477 int l = RULESIZE(input_rule); 2478 2479 if (chain->rules == NULL && input_rule->rulenum != IPFW_DEFAULT_RULE) 2480 return (EINVAL); 2481 2482 rule = malloc(l, M_IPFW, M_NOWAIT | M_ZERO); 2483 if (rule == NULL) 2484 return (ENOSPC); 2485 2486 bcopy(input_rule, rule, l); 2487 2488 rule->next = NULL; 2489 rule->next_rule = NULL; 2490 2491 rule->pcnt = 0; 2492 rule->bcnt = 0; 2493 rule->timestamp = 0; 2494 2495 IPFW_WLOCK(chain); 2496 2497 if (chain->rules == NULL) { /* default rule */ 2498 chain->rules = rule; 2499 rule->id = ++chain->id; 2500 goto done; 2501 } 2502 2503 /* 2504 * If rulenum is 0, find highest numbered rule before the 2505 * default rule, and add autoinc_step 2506 */ 2507 if (V_autoinc_step < 1) 2508 V_autoinc_step = 1; 2509 else if (V_autoinc_step > 1000) 2510 V_autoinc_step = 1000; 2511 if (rule->rulenum == 0) { 2512 /* 2513 * locate the highest numbered rule before default 2514 */ 2515 for (f = chain->rules; f; f = f->next) { 2516 if (f->rulenum == IPFW_DEFAULT_RULE) 2517 break; 2518 rule->rulenum = f->rulenum; 2519 } 2520 if (rule->rulenum < IPFW_DEFAULT_RULE - V_autoinc_step) 2521 rule->rulenum += V_autoinc_step; 2522 input_rule->rulenum = rule->rulenum; 2523 } 2524 2525 /* 2526 * Now insert the new rule in the right place in the sorted list. 2527 */ 2528 for (prev = NULL, f = chain->rules; f; prev = f, f = f->next) { 2529 if (f->rulenum > rule->rulenum) { /* found the location */ 2530 if (prev) { 2531 rule->next = f; 2532 prev->next = rule; 2533 } else { /* head insert */ 2534 rule->next = chain->rules; 2535 chain->rules = rule; 2536 } 2537 break; 2538 } 2539 } 2540 flush_rule_ptrs(chain); 2541 /* chain->id incremented inside flush_rule_ptrs() */ 2542 rule->id = chain->id; 2543done: 2544 V_static_count++; 2545 V_static_len += l; 2546 IPFW_WUNLOCK(chain); 2547 DEB(printf("ipfw: installed rule %d, static count now %d\n", 2548 rule->rulenum, V_static_count);) 2549 return (0); 2550} 2551 2552/** 2553 * Remove a static rule (including derived * dynamic rules) 2554 * and place it on the ``reap list'' for later reclamation. 2555 * The caller is in charge of clearing rule pointers to avoid 2556 * dangling pointers. 2557 * @return a pointer to the next entry. 2558 * Arguments are not checked, so they better be correct. 2559 */ 2560static struct ip_fw * 2561remove_rule(struct ip_fw_chain *chain, struct ip_fw *rule, 2562 struct ip_fw *prev) 2563{ 2564 struct ip_fw *n; 2565 int l = RULESIZE(rule); 2566 2567 IPFW_WLOCK_ASSERT(chain); 2568 2569 n = rule->next; 2570 remove_dyn_children(rule); 2571 if (prev == NULL) 2572 chain->rules = n; 2573 else 2574 prev->next = n; 2575 V_static_count--; 2576 V_static_len -= l; 2577 2578 rule->next = chain->reap; 2579 chain->reap = rule; 2580 2581 return n; 2582} 2583 2584/* 2585 * Reclaim storage associated with a list of rules. This is 2586 * typically the list created using remove_rule. 2587 * A NULL pointer on input is handled correctly. 2588 */ 2589static void 2590reap_rules(struct ip_fw *head) 2591{ 2592 struct ip_fw *rule; 2593 2594 while ((rule = head) != NULL) { 2595 head = head->next; 2596 free(rule, M_IPFW); 2597 } 2598} 2599 2600/* 2601 * Remove all rules from a chain (except rules in set RESVD_SET 2602 * unless kill_default = 1). The caller is responsible for 2603 * reclaiming storage for the rules left in chain->reap. 2604 */ 2605static void 2606free_chain(struct ip_fw_chain *chain, int kill_default) 2607{ 2608 struct ip_fw *prev, *rule; 2609 2610 IPFW_WLOCK_ASSERT(chain); 2611 2612 chain->reap = NULL; 2613 flush_rule_ptrs(chain); /* more efficient to do outside the loop */ 2614 for (prev = NULL, rule = chain->rules; rule ; ) 2615 if (kill_default || rule->set != RESVD_SET) 2616 rule = remove_rule(chain, rule, prev); 2617 else { 2618 prev = rule; 2619 rule = rule->next; 2620 } 2621} 2622 2623/** 2624 * Remove all rules with given number, and also do set manipulation. 2625 * Assumes chain != NULL && *chain != NULL. 2626 * 2627 * The argument is an u_int32_t. The low 16 bit are the rule or set number, 2628 * the next 8 bits are the new set, the top 8 bits are the command: 2629 * 2630 * 0 delete rules with given number 2631 * 1 delete rules with given set number 2632 * 2 move rules with given number to new set 2633 * 3 move rules with given set number to new set 2634 * 4 swap sets with given numbers 2635 * 5 delete rules with given number and with given set number 2636 */ 2637static int 2638del_entry(struct ip_fw_chain *chain, u_int32_t arg) 2639{ 2640 struct ip_fw *prev = NULL, *rule; 2641 u_int16_t rulenum; /* rule or old_set */ 2642 u_int8_t cmd, new_set; 2643 2644 rulenum = arg & 0xffff; 2645 cmd = (arg >> 24) & 0xff; 2646 new_set = (arg >> 16) & 0xff; 2647 2648 if (cmd > 5 || new_set > RESVD_SET) 2649 return EINVAL; 2650 if (cmd == 0 || cmd == 2 || cmd == 5) { 2651 if (rulenum >= IPFW_DEFAULT_RULE) 2652 return EINVAL; 2653 } else { 2654 if (rulenum > RESVD_SET) /* old_set */ 2655 return EINVAL; 2656 } 2657 2658 IPFW_WLOCK(chain); 2659 rule = chain->rules; /* common starting point */ 2660 chain->reap = NULL; /* prepare for deletions */ 2661 switch (cmd) { 2662 case 0: /* delete rules with given number */ 2663 /* 2664 * locate first rule to delete 2665 */ 2666 for (; rule->rulenum < rulenum; prev = rule, rule = rule->next) 2667 ; 2668 if (rule->rulenum != rulenum) { 2669 IPFW_WUNLOCK(chain); 2670 return EINVAL; 2671 } 2672 2673 /* 2674 * flush pointers outside the loop, then delete all matching 2675 * rules. prev remains the same throughout the cycle. 2676 */ 2677 flush_rule_ptrs(chain); 2678 while (rule->rulenum == rulenum) 2679 rule = remove_rule(chain, rule, prev); 2680 break; 2681 2682 case 1: /* delete all rules with given set number */ 2683 flush_rule_ptrs(chain); 2684 while (rule->rulenum < IPFW_DEFAULT_RULE) { 2685 if (rule->set == rulenum) 2686 rule = remove_rule(chain, rule, prev); 2687 else { 2688 prev = rule; 2689 rule = rule->next; 2690 } 2691 } 2692 break; 2693 2694 case 2: /* move rules with given number to new set */ 2695 for (; rule->rulenum < IPFW_DEFAULT_RULE; rule = rule->next) 2696 if (rule->rulenum == rulenum) 2697 rule->set = new_set; 2698 break; 2699 2700 case 3: /* move rules with given set number to new set */ 2701 for (; rule->rulenum < IPFW_DEFAULT_RULE; rule = rule->next) 2702 if (rule->set == rulenum) 2703 rule->set = new_set; 2704 break; 2705 2706 case 4: /* swap two sets */ 2707 for (; rule->rulenum < IPFW_DEFAULT_RULE; rule = rule->next) 2708 if (rule->set == rulenum) 2709 rule->set = new_set; 2710 else if (rule->set == new_set) 2711 rule->set = rulenum; 2712 break; 2713 2714 case 5: /* delete rules with given number and with given set number. 2715 * rulenum - given rule number; 2716 * new_set - given set number. 2717 */ 2718 for (; rule->rulenum < rulenum; prev = rule, rule = rule->next) 2719 ; 2720 if (rule->rulenum != rulenum) { 2721 IPFW_WUNLOCK(chain); 2722 return (EINVAL); 2723 } 2724 flush_rule_ptrs(chain); 2725 while (rule->rulenum == rulenum) { 2726 if (rule->set == new_set) 2727 rule = remove_rule(chain, rule, prev); 2728 else { 2729 prev = rule; 2730 rule = rule->next; 2731 } 2732 } 2733 } 2734 /* 2735 * Look for rules to reclaim. We grab the list before 2736 * releasing the lock then reclaim them w/o the lock to 2737 * avoid a LOR with dummynet. 2738 */ 2739 rule = chain->reap; 2740 IPFW_WUNLOCK(chain); 2741 reap_rules(rule); 2742 return 0; 2743} 2744 2745/* 2746 * Clear counters for a specific rule. 2747 * The enclosing "table" is assumed locked. 2748 */ 2749static void 2750clear_counters(struct ip_fw *rule, int log_only) 2751{ 2752 ipfw_insn_log *l = (ipfw_insn_log *)ACTION_PTR(rule); 2753 2754 if (log_only == 0) { 2755 rule->bcnt = rule->pcnt = 0; 2756 rule->timestamp = 0; 2757 } 2758 if (l->o.opcode == O_LOG) 2759 l->log_left = l->max_log; 2760} 2761 2762/** 2763 * Reset some or all counters on firewall rules. 2764 * The argument `arg' is an u_int32_t. The low 16 bit are the rule number, 2765 * the next 8 bits are the set number, the top 8 bits are the command: 2766 * 0 work with rules from all set's; 2767 * 1 work with rules only from specified set. 2768 * Specified rule number is zero if we want to clear all entries. 2769 * log_only is 1 if we only want to reset logs, zero otherwise. 2770 */ 2771static int 2772zero_entry(struct ip_fw_chain *chain, u_int32_t arg, int log_only) 2773{ 2774 struct ip_fw *rule; 2775 char *msg; 2776 2777 uint16_t rulenum = arg & 0xffff; 2778 uint8_t set = (arg >> 16) & 0xff; 2779 uint8_t cmd = (arg >> 24) & 0xff; 2780 2781 if (cmd > 1) 2782 return (EINVAL); 2783 if (cmd == 1 && set > RESVD_SET) 2784 return (EINVAL); 2785 2786 IPFW_WLOCK(chain); 2787 if (rulenum == 0) { 2788 V_norule_counter = 0; 2789 for (rule = chain->rules; rule; rule = rule->next) { 2790 /* Skip rules from another set. */ 2791 if (cmd == 1 && rule->set != set) 2792 continue; 2793 clear_counters(rule, log_only); 2794 } 2795 msg = log_only ? "All logging counts reset" : 2796 "Accounting cleared"; 2797 } else { 2798 int cleared = 0; 2799 /* 2800 * We can have multiple rules with the same number, so we 2801 * need to clear them all. 2802 */ 2803 for (rule = chain->rules; rule; rule = rule->next) 2804 if (rule->rulenum == rulenum) { 2805 while (rule && rule->rulenum == rulenum) { 2806 if (cmd == 0 || rule->set == set) 2807 clear_counters(rule, log_only); 2808 rule = rule->next; 2809 } 2810 cleared = 1; 2811 break; 2812 } 2813 if (!cleared) { /* we did not find any matching rules */ 2814 IPFW_WUNLOCK(chain); 2815 return (EINVAL); 2816 } 2817 msg = log_only ? "logging count reset" : "cleared"; 2818 } 2819 IPFW_WUNLOCK(chain); 2820 2821 if (V_fw_verbose) { 2822 int lev = LOG_SECURITY | LOG_NOTICE; 2823 2824 if (rulenum) 2825 log(lev, "ipfw: Entry %d %s.\n", rulenum, msg); 2826 else 2827 log(lev, "ipfw: %s.\n", msg); 2828 } 2829 return (0); 2830} 2831 2832/* 2833 * Check validity of the structure before insert. 2834 * Fortunately rules are simple, so this mostly need to check rule sizes. 2835 */ 2836static int 2837check_ipfw_struct(struct ip_fw *rule, int size) 2838{ 2839 int l, cmdlen = 0; 2840 int have_action=0; 2841 ipfw_insn *cmd; 2842 2843 if (size < sizeof(*rule)) { 2844 printf("ipfw: rule too short\n"); 2845 return (EINVAL); 2846 } 2847 /* first, check for valid size */ 2848 l = RULESIZE(rule); 2849 if (l != size) { 2850 printf("ipfw: size mismatch (have %d want %d)\n", size, l); 2851 return (EINVAL); 2852 } 2853 if (rule->act_ofs >= rule->cmd_len) { 2854 printf("ipfw: bogus action offset (%u > %u)\n", 2855 rule->act_ofs, rule->cmd_len - 1); 2856 return (EINVAL); 2857 } 2858 /* 2859 * Now go for the individual checks. Very simple ones, basically only 2860 * instruction sizes. 2861 */ 2862 for (l = rule->cmd_len, cmd = rule->cmd ; 2863 l > 0 ; l -= cmdlen, cmd += cmdlen) { 2864 cmdlen = F_LEN(cmd); 2865 if (cmdlen > l) { 2866 printf("ipfw: opcode %d size truncated\n", 2867 cmd->opcode); 2868 return EINVAL; 2869 } 2870 DEB(printf("ipfw: opcode %d\n", cmd->opcode);) 2871 switch (cmd->opcode) { 2872 case O_PROBE_STATE: 2873 case O_KEEP_STATE: 2874 case O_PROTO: 2875 case O_IP_SRC_ME: 2876 case O_IP_DST_ME: 2877 case O_LAYER2: 2878 case O_IN: 2879 case O_FRAG: 2880 case O_DIVERTED: 2881 case O_IPOPT: 2882 case O_IPTOS: 2883 case O_IPPRECEDENCE: 2884 case O_IPVER: 2885 case O_TCPWIN: 2886 case O_TCPFLAGS: 2887 case O_TCPOPTS: 2888 case O_ESTAB: 2889 case O_VERREVPATH: 2890 case O_VERSRCREACH: 2891 case O_ANTISPOOF: 2892 case O_IPSEC: 2893#ifdef INET6 2894 case O_IP6_SRC_ME: 2895 case O_IP6_DST_ME: 2896 case O_EXT_HDR: 2897 case O_IP6: 2898#endif 2899 case O_IP4: 2900 case O_TAG: 2901 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 2902 goto bad_size; 2903 break; 2904 2905 case O_FIB: 2906 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 2907 goto bad_size; 2908 if (cmd->arg1 >= rt_numfibs) { 2909 printf("ipfw: invalid fib number %d\n", 2910 cmd->arg1); 2911 return EINVAL; 2912 } 2913 break; 2914 2915 case O_SETFIB: 2916 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 2917 goto bad_size; 2918 if (cmd->arg1 >= rt_numfibs) { 2919 printf("ipfw: invalid fib number %d\n", 2920 cmd->arg1); 2921 return EINVAL; 2922 } 2923 goto check_action; 2924 2925 case O_UID: 2926 case O_GID: 2927 case O_JAIL: 2928 case O_IP_SRC: 2929 case O_IP_DST: 2930 case O_TCPSEQ: 2931 case O_TCPACK: 2932 case O_PROB: 2933 case O_ICMPTYPE: 2934 if (cmdlen != F_INSN_SIZE(ipfw_insn_u32)) 2935 goto bad_size; 2936 break; 2937 2938 case O_LIMIT: 2939 if (cmdlen != F_INSN_SIZE(ipfw_insn_limit)) 2940 goto bad_size; 2941 break; 2942 2943 case O_LOG: 2944 if (cmdlen != F_INSN_SIZE(ipfw_insn_log)) 2945 goto bad_size; 2946 2947 ((ipfw_insn_log *)cmd)->log_left = 2948 ((ipfw_insn_log *)cmd)->max_log; 2949 2950 break; 2951 2952 case O_IP_SRC_MASK: 2953 case O_IP_DST_MASK: 2954 /* only odd command lengths */ 2955 if ( !(cmdlen & 1) || cmdlen > 31) 2956 goto bad_size; 2957 break; 2958 2959 case O_IP_SRC_SET: 2960 case O_IP_DST_SET: 2961 if (cmd->arg1 == 0 || cmd->arg1 > 256) { 2962 printf("ipfw: invalid set size %d\n", 2963 cmd->arg1); 2964 return EINVAL; 2965 } 2966 if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 2967 (cmd->arg1+31)/32 ) 2968 goto bad_size; 2969 break; 2970 2971 case O_IP_SRC_LOOKUP: 2972 case O_IP_DST_LOOKUP: 2973 if (cmd->arg1 >= IPFW_TABLES_MAX) { 2974 printf("ipfw: invalid table number %d\n", 2975 cmd->arg1); 2976 return (EINVAL); 2977 } 2978 if (cmdlen != F_INSN_SIZE(ipfw_insn) && 2979 cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1 && 2980 cmdlen != F_INSN_SIZE(ipfw_insn_u32)) 2981 goto bad_size; 2982 break; 2983 2984 case O_MACADDR2: 2985 if (cmdlen != F_INSN_SIZE(ipfw_insn_mac)) 2986 goto bad_size; 2987 break; 2988 2989 case O_NOP: 2990 case O_IPID: 2991 case O_IPTTL: 2992 case O_IPLEN: 2993 case O_TCPDATALEN: 2994 case O_TAGGED: 2995 if (cmdlen < 1 || cmdlen > 31) 2996 goto bad_size; 2997 break; 2998 2999 case O_MAC_TYPE: 3000 case O_IP_SRCPORT: 3001 case O_IP_DSTPORT: /* XXX artificial limit, 30 port pairs */ 3002 if (cmdlen < 2 || cmdlen > 31) 3003 goto bad_size; 3004 break; 3005 3006 case O_RECV: 3007 case O_XMIT: 3008 case O_VIA: 3009 if (cmdlen != F_INSN_SIZE(ipfw_insn_if)) 3010 goto bad_size; 3011 break; 3012 3013 case O_ALTQ: 3014 if (cmdlen != F_INSN_SIZE(ipfw_insn_altq)) 3015 goto bad_size; 3016 break; 3017 3018 case O_PIPE: 3019 case O_QUEUE: 3020 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 3021 goto bad_size; 3022 goto check_action; 3023 3024 case O_FORWARD_IP: 3025#ifdef IPFIREWALL_FORWARD 3026 if (cmdlen != F_INSN_SIZE(ipfw_insn_sa)) 3027 goto bad_size; 3028 goto check_action; 3029#else 3030 return EINVAL; 3031#endif 3032 3033 case O_DIVERT: 3034 case O_TEE: 3035 if (ip_divert_ptr == NULL) 3036 return EINVAL; 3037 else 3038 goto check_size; 3039 case O_NETGRAPH: 3040 case O_NGTEE: 3041 if (!NG_IPFW_LOADED) 3042 return EINVAL; 3043 else 3044 goto check_size; 3045 case O_NAT: 3046 if (!IPFW_NAT_LOADED) 3047 return EINVAL; 3048 if (cmdlen != F_INSN_SIZE(ipfw_insn_nat)) 3049 goto bad_size; 3050 goto check_action; 3051 case O_FORWARD_MAC: /* XXX not implemented yet */ 3052 case O_CHECK_STATE: 3053 case O_COUNT: 3054 case O_ACCEPT: 3055 case O_DENY: 3056 case O_REJECT: 3057#ifdef INET6 3058 case O_UNREACH6: 3059#endif 3060 case O_SKIPTO: 3061 case O_REASS: 3062check_size: 3063 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 3064 goto bad_size; 3065check_action: 3066 if (have_action) { 3067 printf("ipfw: opcode %d, multiple actions" 3068 " not allowed\n", 3069 cmd->opcode); 3070 return EINVAL; 3071 } 3072 have_action = 1; 3073 if (l != cmdlen) { 3074 printf("ipfw: opcode %d, action must be" 3075 " last opcode\n", 3076 cmd->opcode); 3077 return EINVAL; 3078 } 3079 break; 3080#ifdef INET6 3081 case O_IP6_SRC: 3082 case O_IP6_DST: 3083 if (cmdlen != F_INSN_SIZE(struct in6_addr) + 3084 F_INSN_SIZE(ipfw_insn)) 3085 goto bad_size; 3086 break; 3087 3088 case O_FLOW6ID: 3089 if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 3090 ((ipfw_insn_u32 *)cmd)->o.arg1) 3091 goto bad_size; 3092 break; 3093 3094 case O_IP6_SRC_MASK: 3095 case O_IP6_DST_MASK: 3096 if ( !(cmdlen & 1) || cmdlen > 127) 3097 goto bad_size; 3098 break; 3099 case O_ICMP6TYPE: 3100 if( cmdlen != F_INSN_SIZE( ipfw_insn_icmp6 ) ) 3101 goto bad_size; 3102 break; 3103#endif 3104 3105 default: 3106 switch (cmd->opcode) { 3107#ifndef INET6 3108 case O_IP6_SRC_ME: 3109 case O_IP6_DST_ME: 3110 case O_EXT_HDR: 3111 case O_IP6: 3112 case O_UNREACH6: 3113 case O_IP6_SRC: 3114 case O_IP6_DST: 3115 case O_FLOW6ID: 3116 case O_IP6_SRC_MASK: 3117 case O_IP6_DST_MASK: 3118 case O_ICMP6TYPE: 3119 printf("ipfw: no IPv6 support in kernel\n"); 3120 return EPROTONOSUPPORT; 3121#endif 3122 default: 3123 printf("ipfw: opcode %d, unknown opcode\n", 3124 cmd->opcode); 3125 return EINVAL; 3126 } 3127 } 3128 } 3129 if (have_action == 0) { 3130 printf("ipfw: missing action\n"); 3131 return EINVAL; 3132 } 3133 return 0; 3134 3135bad_size: 3136 printf("ipfw: opcode %d size %d wrong\n", 3137 cmd->opcode, cmdlen); 3138 return EINVAL; 3139} 3140 3141/* 3142 * Copy the static and dynamic rules to the supplied buffer 3143 * and return the amount of space actually used. 3144 */ 3145static size_t 3146ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space) 3147{ 3148 char *bp = buf; 3149 char *ep = bp + space; 3150 struct ip_fw *rule; 3151 int i; 3152 time_t boot_seconds; 3153 3154 boot_seconds = boottime.tv_sec; 3155 /* XXX this can take a long time and locking will block packet flow */ 3156 IPFW_RLOCK(chain); 3157 for (rule = chain->rules; rule ; rule = rule->next) { 3158 /* 3159 * Verify the entry fits in the buffer in case the 3160 * rules changed between calculating buffer space and 3161 * now. This would be better done using a generation 3162 * number but should suffice for now. 3163 */ 3164 i = RULESIZE(rule); 3165 if (bp + i <= ep) { 3166 bcopy(rule, bp, i); 3167 /* 3168 * XXX HACK. Store the disable mask in the "next" 3169 * pointer in a wild attempt to keep the ABI the same. 3170 * Why do we do this on EVERY rule? 3171 */ 3172 bcopy(&V_set_disable, 3173 &(((struct ip_fw *)bp)->next_rule), 3174 sizeof(V_set_disable)); 3175 if (((struct ip_fw *)bp)->timestamp) 3176 ((struct ip_fw *)bp)->timestamp += boot_seconds; 3177 bp += i; 3178 } 3179 } 3180 IPFW_RUNLOCK(chain); 3181 ipfw_get_dynamic(&bp, ep); 3182 return (bp - (char *)buf); 3183} 3184 3185 3186/** 3187 * {set|get}sockopt parser. 3188 */ 3189static int 3190ipfw_ctl(struct sockopt *sopt) 3191{ 3192#define RULE_MAXSIZE (256*sizeof(u_int32_t)) 3193 int error; 3194 size_t size; 3195 struct ip_fw *buf, *rule; 3196 u_int32_t rulenum[2]; 3197 3198 error = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW); 3199 if (error) 3200 return (error); 3201 3202 /* 3203 * Disallow modifications in really-really secure mode, but still allow 3204 * the logging counters to be reset. 3205 */ 3206 if (sopt->sopt_name == IP_FW_ADD || 3207 (sopt->sopt_dir == SOPT_SET && sopt->sopt_name != IP_FW_RESETLOG)) { 3208 error = securelevel_ge(sopt->sopt_td->td_ucred, 3); 3209 if (error) 3210 return (error); 3211 } 3212 3213 error = 0; 3214 3215 switch (sopt->sopt_name) { 3216 case IP_FW_GET: 3217 /* 3218 * pass up a copy of the current rules. Static rules 3219 * come first (the last of which has number IPFW_DEFAULT_RULE), 3220 * followed by a possibly empty list of dynamic rule. 3221 * The last dynamic rule has NULL in the "next" field. 3222 * 3223 * Note that the calculated size is used to bound the 3224 * amount of data returned to the user. The rule set may 3225 * change between calculating the size and returning the 3226 * data in which case we'll just return what fits. 3227 */ 3228 size = V_static_len; /* size of static rules */ 3229 size += ipfw_dyn_len(); 3230 3231 if (size >= sopt->sopt_valsize) 3232 break; 3233 /* 3234 * XXX todo: if the user passes a short length just to know 3235 * how much room is needed, do not bother filling up the 3236 * buffer, just jump to the sooptcopyout. 3237 */ 3238 buf = malloc(size, M_TEMP, M_WAITOK); 3239 error = sooptcopyout(sopt, buf, 3240 ipfw_getrules(&V_layer3_chain, buf, size)); 3241 free(buf, M_TEMP); 3242 break; 3243 3244 case IP_FW_FLUSH: 3245 /* 3246 * Normally we cannot release the lock on each iteration. 3247 * We could do it here only because we start from the head all 3248 * the times so there is no risk of missing some entries. 3249 * On the other hand, the risk is that we end up with 3250 * a very inconsistent ruleset, so better keep the lock 3251 * around the whole cycle. 3252 * 3253 * XXX this code can be improved by resetting the head of 3254 * the list to point to the default rule, and then freeing 3255 * the old list without the need for a lock. 3256 */ 3257 3258 IPFW_WLOCK(&V_layer3_chain); 3259 free_chain(&V_layer3_chain, 0 /* keep default rule */); 3260 rule = V_layer3_chain.reap; 3261 IPFW_WUNLOCK(&V_layer3_chain); 3262 reap_rules(rule); 3263 break; 3264 3265 case IP_FW_ADD: 3266 rule = malloc(RULE_MAXSIZE, M_TEMP, M_WAITOK); 3267 error = sooptcopyin(sopt, rule, RULE_MAXSIZE, 3268 sizeof(struct ip_fw) ); 3269 if (error == 0) 3270 error = check_ipfw_struct(rule, sopt->sopt_valsize); 3271 if (error == 0) { 3272 error = add_rule(&V_layer3_chain, rule); 3273 size = RULESIZE(rule); 3274 if (!error && sopt->sopt_dir == SOPT_GET) 3275 error = sooptcopyout(sopt, rule, size); 3276 } 3277 free(rule, M_TEMP); 3278 break; 3279 3280 case IP_FW_DEL: 3281 /* 3282 * IP_FW_DEL is used for deleting single rules or sets, 3283 * and (ab)used to atomically manipulate sets. Argument size 3284 * is used to distinguish between the two: 3285 * sizeof(u_int32_t) 3286 * delete single rule or set of rules, 3287 * or reassign rules (or sets) to a different set. 3288 * 2*sizeof(u_int32_t) 3289 * atomic disable/enable sets. 3290 * first u_int32_t contains sets to be disabled, 3291 * second u_int32_t contains sets to be enabled. 3292 */ 3293 error = sooptcopyin(sopt, rulenum, 3294 2*sizeof(u_int32_t), sizeof(u_int32_t)); 3295 if (error) 3296 break; 3297 size = sopt->sopt_valsize; 3298 if (size == sizeof(u_int32_t)) /* delete or reassign */ 3299 error = del_entry(&V_layer3_chain, rulenum[0]); 3300 else if (size == 2*sizeof(u_int32_t)) /* set enable/disable */ 3301 V_set_disable = 3302 (V_set_disable | rulenum[0]) & ~rulenum[1] & 3303 ~(1<<RESVD_SET); /* set RESVD_SET always enabled */ 3304 else 3305 error = EINVAL; 3306 break; 3307 3308 case IP_FW_ZERO: 3309 case IP_FW_RESETLOG: /* argument is an u_int_32, the rule number */ 3310 rulenum[0] = 0; 3311 if (sopt->sopt_val != 0) { 3312 error = sooptcopyin(sopt, rulenum, 3313 sizeof(u_int32_t), sizeof(u_int32_t)); 3314 if (error) 3315 break; 3316 } 3317 error = zero_entry(&V_layer3_chain, rulenum[0], 3318 sopt->sopt_name == IP_FW_RESETLOG); 3319 break; 3320 3321 case IP_FW_TABLE_ADD: 3322 { 3323 ipfw_table_entry ent; 3324 3325 error = sooptcopyin(sopt, &ent, 3326 sizeof(ent), sizeof(ent)); 3327 if (error) 3328 break; 3329 error = add_table_entry(&V_layer3_chain, ent.tbl, 3330 ent.addr, ent.masklen, ent.value); 3331 } 3332 break; 3333 3334 case IP_FW_TABLE_DEL: 3335 { 3336 ipfw_table_entry ent; 3337 3338 error = sooptcopyin(sopt, &ent, 3339 sizeof(ent), sizeof(ent)); 3340 if (error) 3341 break; 3342 error = del_table_entry(&V_layer3_chain, ent.tbl, 3343 ent.addr, ent.masklen); 3344 } 3345 break; 3346 3347 case IP_FW_TABLE_FLUSH: 3348 { 3349 u_int16_t tbl; 3350 3351 error = sooptcopyin(sopt, &tbl, 3352 sizeof(tbl), sizeof(tbl)); 3353 if (error) 3354 break; 3355 IPFW_WLOCK(&V_layer3_chain); 3356 error = flush_table(&V_layer3_chain, tbl); 3357 IPFW_WUNLOCK(&V_layer3_chain); 3358 } 3359 break; 3360 3361 case IP_FW_TABLE_GETSIZE: 3362 { 3363 u_int32_t tbl, cnt; 3364 3365 if ((error = sooptcopyin(sopt, &tbl, sizeof(tbl), 3366 sizeof(tbl)))) 3367 break; 3368 IPFW_RLOCK(&V_layer3_chain); 3369 error = count_table(&V_layer3_chain, tbl, &cnt); 3370 IPFW_RUNLOCK(&V_layer3_chain); 3371 if (error) 3372 break; 3373 error = sooptcopyout(sopt, &cnt, sizeof(cnt)); 3374 } 3375 break; 3376 3377 case IP_FW_TABLE_LIST: 3378 { 3379 ipfw_table *tbl; 3380 3381 if (sopt->sopt_valsize < sizeof(*tbl)) { 3382 error = EINVAL; 3383 break; 3384 } 3385 size = sopt->sopt_valsize; 3386 tbl = malloc(size, M_TEMP, M_WAITOK); 3387 error = sooptcopyin(sopt, tbl, size, sizeof(*tbl)); 3388 if (error) { 3389 free(tbl, M_TEMP); 3390 break; 3391 } 3392 tbl->size = (size - sizeof(*tbl)) / 3393 sizeof(ipfw_table_entry); 3394 IPFW_RLOCK(&V_layer3_chain); 3395 error = dump_table(&V_layer3_chain, tbl); 3396 IPFW_RUNLOCK(&V_layer3_chain); 3397 if (error) { 3398 free(tbl, M_TEMP); 3399 break; 3400 } 3401 error = sooptcopyout(sopt, tbl, size); 3402 free(tbl, M_TEMP); 3403 } 3404 break; 3405 3406 case IP_FW_NAT_CFG: 3407 if (IPFW_NAT_LOADED) 3408 error = ipfw_nat_cfg_ptr(sopt); 3409 else { 3410 printf("IP_FW_NAT_CFG: %s\n", 3411 "ipfw_nat not present, please load it"); 3412 error = EINVAL; 3413 } 3414 break; 3415 3416 case IP_FW_NAT_DEL: 3417 if (IPFW_NAT_LOADED) 3418 error = ipfw_nat_del_ptr(sopt); 3419 else { 3420 printf("IP_FW_NAT_DEL: %s\n", 3421 "ipfw_nat not present, please load it"); 3422 error = EINVAL; 3423 } 3424 break; 3425 3426 case IP_FW_NAT_GET_CONFIG: 3427 if (IPFW_NAT_LOADED) 3428 error = ipfw_nat_get_cfg_ptr(sopt); 3429 else { 3430 printf("IP_FW_NAT_GET_CFG: %s\n", 3431 "ipfw_nat not present, please load it"); 3432 error = EINVAL; 3433 } 3434 break; 3435 3436 case IP_FW_NAT_GET_LOG: 3437 if (IPFW_NAT_LOADED) 3438 error = ipfw_nat_get_log_ptr(sopt); 3439 else { 3440 printf("IP_FW_NAT_GET_LOG: %s\n", 3441 "ipfw_nat not present, please load it"); 3442 error = EINVAL; 3443 } 3444 break; 3445 3446 default: 3447 printf("ipfw: ipfw_ctl invalid option %d\n", sopt->sopt_name); 3448 error = EINVAL; 3449 } 3450 3451 return (error); 3452#undef RULE_MAXSIZE 3453} 3454 | |
3455/**************** 3456 * Stuff that must be initialised only on boot or module load 3457 */ 3458static int 3459ipfw_init(void) 3460{ 3461 int error = 0; 3462 --- 68 unchanged lines hidden (view full) --- 3531 /* First set up some values that are compile time options */ 3532#ifdef IPFIREWALL_VERBOSE 3533 V_fw_verbose = 1; 3534#endif 3535#ifdef IPFIREWALL_VERBOSE_LIMIT 3536 V_verbose_limit = IPFIREWALL_VERBOSE_LIMIT; 3537#endif 3538 | 2254/**************** 2255 * Stuff that must be initialised only on boot or module load 2256 */ 2257static int 2258ipfw_init(void) 2259{ 2260 int error = 0; 2261 --- 68 unchanged lines hidden (view full) --- 2330 /* First set up some values that are compile time options */ 2331#ifdef IPFIREWALL_VERBOSE 2332 V_fw_verbose = 1; 2333#endif 2334#ifdef IPFIREWALL_VERBOSE_LIMIT 2335 V_verbose_limit = IPFIREWALL_VERBOSE_LIMIT; 2336#endif 2337 |
3539 error = init_tables(&V_layer3_chain); | 2338 error = ipfw_init_tables(&V_layer3_chain); |
3540 if (error) { 3541 panic("init_tables"); /* XXX Marko fix this ! */ 3542 } 3543#ifdef IPFIREWALL_NAT 3544 LIST_INIT(&V_layer3_chain.nat); 3545#endif 3546 3547 V_autoinc_step = 100; /* bounded to 1..1000 in add_rule() */ --- 6 unchanged lines hidden (view full) --- 3554 3555 bzero(&default_rule, sizeof default_rule); 3556 default_rule.act_ofs = 0; 3557 default_rule.rulenum = IPFW_DEFAULT_RULE; 3558 default_rule.cmd_len = 1; 3559 default_rule.set = RESVD_SET; 3560 default_rule.cmd[0].len = 1; 3561 default_rule.cmd[0].opcode = default_to_accept ? O_ACCEPT : O_DENY; | 2339 if (error) { 2340 panic("init_tables"); /* XXX Marko fix this ! */ 2341 } 2342#ifdef IPFIREWALL_NAT 2343 LIST_INIT(&V_layer3_chain.nat); 2344#endif 2345 2346 V_autoinc_step = 100; /* bounded to 1..1000 in add_rule() */ --- 6 unchanged lines hidden (view full) --- 2353 2354 bzero(&default_rule, sizeof default_rule); 2355 default_rule.act_ofs = 0; 2356 default_rule.rulenum = IPFW_DEFAULT_RULE; 2357 default_rule.cmd_len = 1; 2358 default_rule.set = RESVD_SET; 2359 default_rule.cmd[0].len = 1; 2360 default_rule.cmd[0].opcode = default_to_accept ? O_ACCEPT : O_DENY; |
3562 error = add_rule(&V_layer3_chain, &default_rule); | 2361 error = ipfw_add_rule(&V_layer3_chain, &default_rule); |
3563 3564 if (error != 0) { 3565 printf("ipfw2: error %u initializing default rule " 3566 "(support disabled)\n", error); 3567 IPFW_LOCK_DESTROY(&V_layer3_chain); 3568 printf("leaving ipfw_iattach (1) with error %d\n", error); 3569 return (error); 3570 } --- 56 unchanged lines hidden (view full) --- 3627 V_ip_fw_ctl_ptr = NULL; 3628 3629 IPFW_WLOCK(&V_layer3_chain); 3630 /* We wait on the wlock here until the last user leaves */ 3631 IPFW_WUNLOCK(&V_layer3_chain); 3632 IPFW_WLOCK(&V_layer3_chain); 3633 3634 ipfw_dyn_uninit(0); /* run the callout_drain */ | 2362 2363 if (error != 0) { 2364 printf("ipfw2: error %u initializing default rule " 2365 "(support disabled)\n", error); 2366 IPFW_LOCK_DESTROY(&V_layer3_chain); 2367 printf("leaving ipfw_iattach (1) with error %d\n", error); 2368 return (error); 2369 } --- 56 unchanged lines hidden (view full) --- 2426 V_ip_fw_ctl_ptr = NULL; 2427 2428 IPFW_WLOCK(&V_layer3_chain); 2429 /* We wait on the wlock here until the last user leaves */ 2430 IPFW_WUNLOCK(&V_layer3_chain); 2431 IPFW_WLOCK(&V_layer3_chain); 2432 2433 ipfw_dyn_uninit(0); /* run the callout_drain */ |
3635 flush_tables(&V_layer3_chain); | 2434 ipfw_flush_tables(&V_layer3_chain); |
3636 V_layer3_chain.reap = NULL; | 2435 V_layer3_chain.reap = NULL; |
3637 free_chain(&V_layer3_chain, 1 /* kill default rule */); | 2436 ipfw_free_chain(&V_layer3_chain, 1 /* kill default rule */); |
3638 reap = V_layer3_chain.reap; 3639 V_layer3_chain.reap = NULL; 3640 IPFW_WUNLOCK(&V_layer3_chain); 3641 if (reap != NULL) | 2437 reap = V_layer3_chain.reap; 2438 V_layer3_chain.reap = NULL; 2439 IPFW_WUNLOCK(&V_layer3_chain); 2440 if (reap != NULL) |
3642 reap_rules(reap); | 2441 ipfw_reap_rules(reap); |
3643 IPFW_LOCK_DESTROY(&V_layer3_chain); 3644 ipfw_dyn_uninit(1); /* free the remaining parts */ 3645 return 0; 3646} 3647 3648/* 3649 * Module event handler. 3650 * In general we have the choice of handling most of these events by the --- 68 unchanged lines hidden --- | 2442 IPFW_LOCK_DESTROY(&V_layer3_chain); 2443 ipfw_dyn_uninit(1); /* free the remaining parts */ 2444 return 0; 2445} 2446 2447/* 2448 * Module event handler. 2449 * In general we have the choice of handling most of these events by the --- 68 unchanged lines hidden --- |