diff --git a/sys/netinet/ipfw/ip_fw2.c b/sys/netinet/ipfw/ip_fw2.c index b1e8480460b2..82c5381574b0 100644 --- a/sys/netinet/ipfw/ip_fw2.c +++ b/sys/netinet/ipfw/ip_fw2.c @@ -152,6 +152,8 @@ struct table_entry { static VNET_DEFINE(int, autoinc_step); #define V_autoinc_step VNET(autoinc_step) +static VNET_DEFINE(int, fw_deny_unknown_exthdrs); +#define V_fw_deny_unknown_exthdrs VNET(fw_deny_unknown_exthdrs) extern int ipfw_chg_hook(SYSCTL_HANDLER_ARGS); @@ -161,24 +163,38 @@ SYSCTL_VNET_PROC(_net_inet_ip_fw, OID_AUTO, enable, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_enable), 0, ipfw_chg_hook, "I", "Enable ipfw"); SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, autoinc_step, - CTLFLAG_RW, &VNET_NAME(autoinc_step), 0, "Rule number auto-increment step"); + CTLFLAG_RW, &VNET_NAME(autoinc_step), 0, + "Rule number auto-increment step"); SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, one_pass, CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_one_pass), 0, "Only do a single pass through ipfw when using dummynet(4)"); SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, verbose, - CTLFLAG_RW | CTLFLAG_SECURE3, - &VNET_NAME(fw_verbose), 0, "Log matches to ipfw rules"); + CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw_verbose), 0, + "Log matches to ipfw rules"); SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, verbose_limit, CTLFLAG_RW, &VNET_NAME(verbose_limit), 0, "Set upper limit of matches of ipfw rules logged"); SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, default_rule, CTLFLAG_RD, - NULL, IPFW_DEFAULT_RULE, "The default/max possible rule number."); + NULL, IPFW_DEFAULT_RULE, + "The default/max possible rule number."); SYSCTL_UINT(_net_inet_ip_fw, OID_AUTO, tables_max, CTLFLAG_RD, - NULL, IPFW_TABLES_MAX, "The maximum number of tables."); + NULL, IPFW_TABLES_MAX, + "The maximum number of tables."); SYSCTL_INT(_net_inet_ip_fw, OID_AUTO, default_to_accept, CTLFLAG_RDTUN, - &default_to_accept, 0, "Make the default rule accept all packets."); + &default_to_accept, 0, + "Make the default rule accept all packets."); TUNABLE_INT("net.inet.ip.fw.default_to_accept", &default_to_accept); -#endif /* SYSCTL_NODE */ +#ifdef INET6 +SYSCTL_DECL(_net_inet6_ip6); +SYSCTL_NODE(_net_inet6_ip6, OID_AUTO, fw, CTLFLAG_RW, 0, "Firewall"); +SYSCTL_VNET_PROC(_net_inet6_ip6_fw, OID_AUTO, enable, + CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3, &VNET_NAME(fw6_enable), 0, + ipfw_chg_hook, "I", "Enable ipfw+6"); +SYSCTL_VNET_INT(_net_inet6_ip6_fw, OID_AUTO, deny_unknown_exthdrs, + CTLFLAG_RW | CTLFLAG_SECURE, &VNET_NAME(fw_deny_unknown_exthdrs), 0, + "Deny packets with unknown IPv6 Extension Headers"); +#endif +#endif /* * Description of dynamic rules. @@ -277,16 +293,20 @@ static VNET_DEFINE(u_int32_t, dyn_max); /* max # of dynamic rules */ #ifdef SYSCTL_NODE SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, dyn_buckets, - CTLFLAG_RW, &VNET_NAME(dyn_buckets), 0, "Number of dyn. buckets"); + CTLFLAG_RW, &VNET_NAME(dyn_buckets), 0, + "Number of dyn. buckets"); SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, curr_dyn_buckets, CTLFLAG_RD, &VNET_NAME(curr_dyn_buckets), 0, "Current Number of dyn. buckets"); SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, dyn_count, - CTLFLAG_RD, &VNET_NAME(dyn_count), 0, "Number of dyn. rules"); + CTLFLAG_RD, &VNET_NAME(dyn_count), 0, + "Number of dyn. rules"); SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, dyn_max, - CTLFLAG_RW, &VNET_NAME(dyn_max), 0, "Max number of dyn. rules"); + CTLFLAG_RW, &VNET_NAME(dyn_max), 0, + "Max number of dyn. rules"); SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, static_count, - CTLFLAG_RD, &VNET_NAME(static_count), 0, "Number of static rules"); + CTLFLAG_RD, &VNET_NAME(static_count), 0, + "Number of static rules"); SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, dyn_ack_lifetime, CTLFLAG_RW, &VNET_NAME(dyn_ack_lifetime), 0, "Lifetime of dyn. rules for acks"); @@ -310,21 +330,6 @@ SYSCTL_VNET_INT(_net_inet_ip_fw, OID_AUTO, dyn_keepalive, "Enable keepalives for dyn. rules"); #endif /* SYSCTL_NODE */ -#ifdef INET6 -/* - * IPv6 specific variables - */ -#ifdef SYSCTL_NODE -SYSCTL_DECL(_net_inet6_ip6); -#endif /* SYSCTL_NODE */ - -static struct sysctl_ctx_list ip6_fw_sysctl_ctx; -static struct sysctl_oid *ip6_fw_sysctl_tree; -#endif /* INET6 */ - -static VNET_DEFINE(int, fw_deny_unknown_exthdrs); -#define V_fw_deny_unknown_exthdrs VNET(fw_deny_unknown_exthdrs) - /* * L3HDR maps an ipv4 pointer into a layer3 header pointer of type T * Other macros just cast void * into the appropriate type @@ -4511,17 +4516,22 @@ ipfw_ctl(struct sockopt *sopt) #undef RULE_MAXSIZE } + /* * This procedure is only used to handle keepalives. It is invoked * every dyn_keepalive_period */ static void -ipfw_tick(void * __unused unused) +ipfw_tick(void * vnetx) { struct mbuf *m0, *m, *mnext, **mtailp; int i; ipfw_dyn_rule *q; +#ifdef VIMAGE + struct vnet *vp = vnetx; +#endif + CURVNET_SET(vp); if (V_dyn_keepalive == 0 || V_ipfw_dyn_v == NULL || V_dyn_count == 0) goto done; @@ -4566,80 +4576,29 @@ ipfw_tick(void * __unused unused) } done: callout_reset(&V_ipfw_timeout, V_dyn_keepalive_period * hz, - ipfw_tick, NULL); + ipfw_tick, vnetx); + CURVNET_RESTORE(); } + + +/**************** + * Stuff that must be initialised only on boot or module load + */ int ipfw_init(void) { - struct ip_fw default_rule; - int error; + int error = 0; - V_autoinc_step = 100; /* bounded to 1..1000 in add_rule() */ - - V_ipfw_dyn_v = NULL; - V_dyn_buckets = 256; /* must be power of 2 */ - V_curr_dyn_buckets = 256; /* must be power of 2 */ - - V_dyn_ack_lifetime = 300; - V_dyn_syn_lifetime = 20; - V_dyn_fin_lifetime = 1; - V_dyn_rst_lifetime = 1; - V_dyn_udp_lifetime = 10; - V_dyn_short_lifetime = 5; - - V_dyn_keepalive_interval = 20; - V_dyn_keepalive_period = 5; - V_dyn_keepalive = 1; /* do send keepalives */ - - V_dyn_max = 4096; /* max # of dynamic rules */ - - V_fw_deny_unknown_exthdrs = 1; - -#ifdef INET6 - /* Setup IPv6 fw sysctl tree. */ - sysctl_ctx_init(&ip6_fw_sysctl_ctx); - ip6_fw_sysctl_tree = SYSCTL_ADD_NODE(&ip6_fw_sysctl_ctx, - SYSCTL_STATIC_CHILDREN(_net_inet6_ip6), OID_AUTO, "fw", - CTLFLAG_RW | CTLFLAG_SECURE, 0, "Firewall"); - SYSCTL_ADD_PROC(&ip6_fw_sysctl_ctx, SYSCTL_CHILDREN(ip6_fw_sysctl_tree), - OID_AUTO, "enable", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_SECURE3, - &V_fw6_enable, 0, ipfw_chg_hook, "I", "Enable ipfw+6"); - SYSCTL_ADD_INT(&ip6_fw_sysctl_ctx, SYSCTL_CHILDREN(ip6_fw_sysctl_tree), - OID_AUTO, "deny_unknown_exthdrs", CTLFLAG_RW | CTLFLAG_SECURE, - &V_fw_deny_unknown_exthdrs, 0, - "Deny packets with unknown IPv6 Extension Headers"); -#endif - - V_layer3_chain.rules = NULL; - IPFW_LOCK_INIT(&V_layer3_chain); ipfw_dyn_rule_zone = uma_zcreate("IPFW dynamic rule", sizeof(ipfw_dyn_rule), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0); + IPFW_DYN_LOCK_INIT(); - callout_init(&V_ipfw_timeout, CALLOUT_MPSAFE); - - bzero(&default_rule, sizeof default_rule); - - default_rule.act_ofs = 0; - default_rule.rulenum = IPFW_DEFAULT_RULE; - default_rule.cmd_len = 1; - default_rule.set = RESVD_SET; - - default_rule.cmd[0].len = 1; - default_rule.cmd[0].opcode = default_to_accept ? O_ACCEPT : O_DENY; - - error = add_rule(&V_layer3_chain, &default_rule); - if (error != 0) { - printf("ipfw2: error %u initializing default rule " - "(support disabled)\n", error); - IPFW_DYN_LOCK_DESTROY(); - IPFW_LOCK_DESTROY(&V_layer3_chain); - uma_zdestroy(ipfw_dyn_rule_zone); - return (error); - } - - ip_fw_default_rule = V_layer3_chain.rules; + /* + * Only print out this stuff the first time around, + * when called from the sysinit code. + */ printf("ipfw2 " #ifdef INET6 "(+ipv6) " @@ -4662,15 +4621,13 @@ ipfw_init(void) #else "loadable", #endif + default_to_accept ? "accept" : "deny"); - default_rule.cmd[0].opcode == O_ACCEPT ? "accept" : "deny"); - -#ifdef IPFIREWALL_VERBOSE - V_fw_verbose = 1; -#endif -#ifdef IPFIREWALL_VERBOSE_LIMIT - V_verbose_limit = IPFIREWALL_VERBOSE_LIMIT; -#endif + /* + * Note: V_xxx variables can be accessed here but the iattach() + * may not have been called yet for the VIMGE case. + * Tuneables will have been processed. + */ if (V_fw_verbose == 0) printf("disabled\n"); else if (V_verbose_limit == 0) @@ -4679,44 +4636,141 @@ ipfw_init(void) printf("limited to %d packets/entry by default\n", V_verbose_limit); - error = init_tables(&V_layer3_chain); - if (error) { - IPFW_DYN_LOCK_DESTROY(); - IPFW_LOCK_DESTROY(&V_layer3_chain); - uma_zdestroy(ipfw_dyn_rule_zone); - return (error); - } + /* + * Other things that are only done the first time. + * (now that we a re cuaranteed of success). + */ ip_fw_ctl_ptr = ipfw_ctl; ip_fw_chk_ptr = ipfw_chk; - callout_reset(&V_ipfw_timeout, hz, ipfw_tick, NULL); + return (error); +} + +/**************** + * Stuff that must be initialised for every instance + * (including the forst of course). + */ +static int +vnet_ipfw_init(const void *unused) +{ + int error; + struct ip_fw default_rule; + + /* First set up some values that are compile time options */ +#ifdef IPFIREWALL_VERBOSE + V_fw_verbose = 1; +#endif +#ifdef IPFIREWALL_VERBOSE_LIMIT + V_verbose_limit = IPFIREWALL_VERBOSE_LIMIT; +#endif + + error = init_tables(&V_layer3_chain); + if (error) { + panic("init_tables"); /* XXX Marko fix this ! */ + } +#ifdef IPFIREWALL_NAT LIST_INIT(&V_layer3_chain.nat); +#endif + + V_autoinc_step = 100; /* bounded to 1..1000 in add_rule() */ + + V_ipfw_dyn_v = NULL; + V_dyn_buckets = 256; /* must be power of 2 */ + V_curr_dyn_buckets = 256; /* must be power of 2 */ + + V_dyn_ack_lifetime = 300; + V_dyn_syn_lifetime = 20; + V_dyn_fin_lifetime = 1; + V_dyn_rst_lifetime = 1; + V_dyn_udp_lifetime = 10; + V_dyn_short_lifetime = 5; + + V_dyn_keepalive_interval = 20; + V_dyn_keepalive_period = 5; + V_dyn_keepalive = 1; /* do send keepalives */ + + V_dyn_max = 4096; /* max # of dynamic rules */ + + V_fw_deny_unknown_exthdrs = 1; + + V_layer3_chain.rules = NULL; + IPFW_LOCK_INIT(&V_layer3_chain); + callout_init(&V_ipfw_timeout, CALLOUT_MPSAFE); + + bzero(&default_rule, sizeof default_rule); + default_rule.act_ofs = 0; + default_rule.rulenum = IPFW_DEFAULT_RULE; + default_rule.cmd_len = 1; + default_rule.set = RESVD_SET; + default_rule.cmd[0].len = 1; + default_rule.cmd[0].opcode = default_to_accept ? O_ACCEPT : O_DENY; + error = add_rule(&V_layer3_chain, &default_rule); + + if (error != 0) { + printf("ipfw2: error %u initializing default rule " + "(support disabled)\n", error); + IPFW_LOCK_DESTROY(&V_layer3_chain); + printf("leaving ipfw_iattach (1) with error %d\n", error); + return (error); + } + + ip_fw_default_rule = V_layer3_chain.rules; + + if (error) { + IPFW_LOCK_DESTROY(&V_layer3_chain); + printf("leaving ipfw_iattach (2) with error %d\n", error); + return (error); + } +#ifdef VIMAGE /* want a better way to do this */ + callout_reset(&V_ipfw_timeout, hz, ipfw_tick, curvnet); +#else + callout_reset(&V_ipfw_timeout, hz, ipfw_tick, NULL); +#endif + + /* First set up some values that are compile time options */ return (0); } +/********************** + * Called for the removal of the last instance only on module unload. + */ void ipfw_destroy(void) { - struct ip_fw *reap; - ip_fw_chk_ptr = NULL; ip_fw_ctl_ptr = NULL; + uma_zdestroy(ipfw_dyn_rule_zone); + IPFW_DYN_LOCK_DESTROY(); + printf("IP firewall unloaded\n"); +} + +/*********************** + * Called for the removal of each instance. + */ +static int +vnet_ipfw_uninit(const void *unused) +{ + struct ip_fw *reap; + callout_drain(&V_ipfw_timeout); IPFW_WLOCK(&V_layer3_chain); flush_tables(&V_layer3_chain); + V_layer3_chain.reap = NULL; free_chain(&V_layer3_chain, 1 /* kill default rule */); reap = V_layer3_chain.reap; + V_layer3_chain.reap = NULL; IPFW_WUNLOCK(&V_layer3_chain); - reap_rules(reap); - IPFW_DYN_LOCK_DESTROY(); - uma_zdestroy(ipfw_dyn_rule_zone); + if (reap != NULL) + reap_rules(reap); + IPFW_LOCK_DESTROY(&V_layer3_chain); if (V_ipfw_dyn_v != NULL) free(V_ipfw_dyn_v, M_IPFW); - IPFW_LOCK_DESTROY(&V_layer3_chain); - -#ifdef INET6 - /* Free IPv6 fw sysctl tree. */ - sysctl_ctx_free(&ip6_fw_sysctl_ctx); -#endif - - printf("IP firewall unloaded\n"); + return 0; } + +VNET_SYSINIT(vnet_ipfw_init, SI_SUB_KTHREAD_INIT, SI_ORDER_ANY, + vnet_ipfw_init, NULL); + +VNET_SYSUNINIT(vnet_ipfw_uninit, SI_SUB_KTHREAD_INIT, SI_ORDER_ANY, + vnet_ipfw_uninit, NULL); + +