Deleted Added
full compact
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 ---