From 2ae7ec29fdc503579c8cc2b62714e3057c800ce2 Mon Sep 17 00:00:00 2001 From: Julian Elischer Date: Sun, 7 Feb 2010 09:00:22 +0000 Subject: [PATCH] MFC of 197952 and 198075 Virtualize the pfil hooks so that different jails may chose different packet filters. ALso allows ipfw to be enabled on on ejail and disabled on another. In 8.0 it's a global setting. and Unbreak the VIMAGE build with IPSEC, broken with r197952 by virtualizing the pfil hooks. For consistency add the V_ to virtualize the pfil hooks in here as well. --- sys/net/if_bridge.c | 41 +++++++------- sys/net/if_enc.c | 8 +-- sys/net/if_ethersubr.c | 6 +- sys/net/pfil.c | 53 ++++++++++++++++-- sys/netgraph/ng_bridge.c | 2 +- sys/netinet/ip_fastfwd.c | 9 +-- sys/netinet/ip_input.c | 20 +++---- sys/netinet/ip_output.c | 4 +- sys/netinet/ip_var.h | 12 +++- sys/netinet/ipfw/ip_fw2.c | 102 ++++++++++++++++++---------------- sys/netinet/ipfw/ip_fw_pfil.c | 36 ++++++++---- sys/netinet/raw_ip.c | 12 ++-- sys/netinet6/ip6_forward.c | 4 +- sys/netinet6/ip6_input.c | 21 +++---- sys/netinet6/ip6_output.c | 4 +- sys/netinet6/ip6_var.h | 3 +- 16 files changed, 203 insertions(+), 134 deletions(-) diff --git a/sys/net/if_bridge.c b/sys/net/if_bridge.c index d3a55fd15afc..8e0e6e1e6a52 100644 --- a/sys/net/if_bridge.c +++ b/sys/net/if_bridge.c @@ -109,6 +109,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include /* for struct arpcom */ #include @@ -1800,9 +1801,9 @@ bridge_dummynet(struct mbuf *m, struct ifnet *ifp) return; } - if (PFIL_HOOKED(&inet_pfil_hook) + if (PFIL_HOOKED(&V_inet_pfil_hook) #ifdef INET6 - || PFIL_HOOKED(&inet6_pfil_hook) + || PFIL_HOOKED(&V_inet6_pfil_hook) #endif ) { if (bridge_pfil(&m, sc->sc_ifp, ifp, PFIL_OUT) != 0) @@ -2062,9 +2063,9 @@ bridge_forward(struct bridge_softc *sc, struct bridge_iflist *sbif, ETHER_BPF_MTAP(ifp, m); /* run the packet filter */ - if (PFIL_HOOKED(&inet_pfil_hook) + if (PFIL_HOOKED(&V_inet_pfil_hook) #ifdef INET6 - || PFIL_HOOKED(&inet6_pfil_hook) + || PFIL_HOOKED(&V_inet6_pfil_hook) #endif ) { BRIDGE_UNLOCK(sc); @@ -2102,9 +2103,9 @@ bridge_forward(struct bridge_softc *sc, struct bridge_iflist *sbif, BRIDGE_UNLOCK(sc); - if (PFIL_HOOKED(&inet_pfil_hook) + if (PFIL_HOOKED(&V_inet_pfil_hook) #ifdef INET6 - || PFIL_HOOKED(&inet6_pfil_hook) + || PFIL_HOOKED(&V_inet6_pfil_hook) #endif ) { if (bridge_pfil(&m, ifp, dst_if, PFIL_OUT) != 0) @@ -2243,7 +2244,7 @@ bridge_input(struct ifnet *ifp, struct mbuf *m) #ifdef INET6 # define OR_PFIL_HOOKED_INET6 \ - || PFIL_HOOKED(&inet6_pfil_hook) + || PFIL_HOOKED(&V_inet6_pfil_hook) #else # define OR_PFIL_HOOKED_INET6 #endif @@ -2260,7 +2261,7 @@ bridge_input(struct ifnet *ifp, struct mbuf *m) iface->if_ipackets++; \ /* Filter on the physical interface. */ \ if (pfil_local_phys && \ - (PFIL_HOOKED(&inet_pfil_hook) \ + (PFIL_HOOKED(&V_inet_pfil_hook) \ OR_PFIL_HOOKED_INET6)) { \ if (bridge_pfil(&m, NULL, ifp, \ PFIL_IN) != 0 || m == NULL) { \ @@ -2349,9 +2350,9 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if, } /* Filter on the bridge interface before broadcasting */ - if (runfilt && (PFIL_HOOKED(&inet_pfil_hook) + if (runfilt && (PFIL_HOOKED(&V_inet_pfil_hook) #ifdef INET6 - || PFIL_HOOKED(&inet6_pfil_hook) + || PFIL_HOOKED(&V_inet6_pfil_hook) #endif )) { if (bridge_pfil(&m, sc->sc_ifp, NULL, PFIL_OUT) != 0) @@ -2396,9 +2397,9 @@ bridge_broadcast(struct bridge_softc *sc, struct ifnet *src_if, * pointer so we do not redundantly filter on the bridge for * each interface we broadcast on. */ - if (runfilt && (PFIL_HOOKED(&inet_pfil_hook) + if (runfilt && (PFIL_HOOKED(&V_inet_pfil_hook) #ifdef INET6 - || PFIL_HOOKED(&inet6_pfil_hook) + || PFIL_HOOKED(&V_inet6_pfil_hook) #endif )) { if (used == 0) { @@ -3037,7 +3038,7 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir) goto bad; } - if (ip_fw_chk_ptr && pfil_ipfw != 0 && dir == PFIL_OUT && ifp != NULL) { + if (V_ip_fw_chk_ptr && pfil_ipfw != 0 && dir == PFIL_OUT && ifp != NULL) { struct dn_pkt_tag *dn_tag; error = -1; @@ -3057,7 +3058,7 @@ bridge_pfil(struct mbuf **mp, struct ifnet *bifp, struct ifnet *ifp, int dir) args.next_hop = NULL; args.eh = &eh2; args.inp = NULL; /* used by ipfw uid/gid/jail rules */ - i = ip_fw_chk_ptr(&args); + i = V_ip_fw_chk_ptr(&args); *mp = args.m; if (*mp == NULL) @@ -3109,21 +3110,21 @@ ipfwpass: * in_if -> bridge_if -> out_if */ if (pfil_bridge && dir == PFIL_OUT && bifp != NULL) - error = pfil_run_hooks(&inet_pfil_hook, mp, bifp, + error = pfil_run_hooks(&V_inet_pfil_hook, mp, bifp, dir, NULL); if (*mp == NULL || error != 0) /* filter may consume */ break; if (pfil_member && ifp != NULL) - error = pfil_run_hooks(&inet_pfil_hook, mp, ifp, + error = pfil_run_hooks(&V_inet_pfil_hook, mp, ifp, dir, NULL); if (*mp == NULL || error != 0) /* filter may consume */ break; if (pfil_bridge && dir == PFIL_IN && bifp != NULL) - error = pfil_run_hooks(&inet_pfil_hook, mp, bifp, + error = pfil_run_hooks(&V_inet_pfil_hook, mp, bifp, dir, NULL); if (*mp == NULL || error != 0) /* filter may consume */ @@ -3163,21 +3164,21 @@ ipfwpass: #ifdef INET6 case ETHERTYPE_IPV6: if (pfil_bridge && dir == PFIL_OUT && bifp != NULL) - error = pfil_run_hooks(&inet6_pfil_hook, mp, bifp, + error = pfil_run_hooks(&V_inet6_pfil_hook, mp, bifp, dir, NULL); if (*mp == NULL || error != 0) /* filter may consume */ break; if (pfil_member && ifp != NULL) - error = pfil_run_hooks(&inet6_pfil_hook, mp, ifp, + error = pfil_run_hooks(&V_inet6_pfil_hook, mp, ifp, dir, NULL); if (*mp == NULL || error != 0) /* filter may consume */ break; if (pfil_bridge && dir == PFIL_IN && bifp != NULL) - error = pfil_run_hooks(&inet6_pfil_hook, mp, bifp, + error = pfil_run_hooks(&V_inet6_pfil_hook, mp, bifp, dir, NULL); break; #endif diff --git a/sys/net/if_enc.c b/sys/net/if_enc.c index a49c5dc5b236..b1fc0383a461 100644 --- a/sys/net/if_enc.c +++ b/sys/net/if_enc.c @@ -243,9 +243,9 @@ ipsec_filter(struct mbuf **mp, int dir, int flags) } /* Skip pfil(9) if no filters are loaded */ - if (!(PFIL_HOOKED(&inet_pfil_hook) + if (!(PFIL_HOOKED(&V_inet_pfil_hook) #ifdef INET6 - || PFIL_HOOKED(&inet6_pfil_hook) + || PFIL_HOOKED(&V_inet6_pfil_hook) #endif )) { return (0); @@ -271,7 +271,7 @@ ipsec_filter(struct mbuf **mp, int dir, int flags) ip->ip_len = ntohs(ip->ip_len); ip->ip_off = ntohs(ip->ip_off); - error = pfil_run_hooks(&inet_pfil_hook, mp, + error = pfil_run_hooks(&V_inet_pfil_hook, mp, encif, dir, NULL); if (*mp == NULL || error != 0) @@ -285,7 +285,7 @@ ipsec_filter(struct mbuf **mp, int dir, int flags) #ifdef INET6 case 6: - error = pfil_run_hooks(&inet6_pfil_hook, mp, + error = pfil_run_hooks(&V_inet6_pfil_hook, mp, encif, dir, NULL); break; #endif diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index bac204449230..5dff9bce55dc 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -434,7 +434,7 @@ ether_output_frame(struct ifnet *ifp, struct mbuf *m) { #if defined(INET) || defined(INET6) - if (ip_fw_chk_ptr && V_ether_ipfw != 0) { + if (V_ip_fw_chk_ptr && V_ether_ipfw != 0) { if (ether_ipfw_chk(&m, ifp, 0) == 0) { if (m) { m_freem(m); @@ -502,7 +502,7 @@ ether_ipfw_chk(struct mbuf **m0, struct ifnet *dst, int shared) args.next_hop = NULL; /* we do not support forward yet */ args.eh = &save_eh; /* MAC header for bridged/MAC packets */ args.inp = NULL; /* used by ipfw uid/gid/jail rules */ - i = ip_fw_chk_ptr(&args); + i = V_ip_fw_chk_ptr(&args); m = args.m; if (m != NULL) { /* @@ -775,7 +775,7 @@ ether_demux(struct ifnet *ifp, struct mbuf *m) * Allow dummynet and/or ipfw to claim the frame. * Do not do this for PROMISC frames in case we are re-entered. */ - if (ip_fw_chk_ptr && V_ether_ipfw != 0 && !(m->m_flags & M_PROMISC)) { + if (V_ip_fw_chk_ptr && V_ether_ipfw != 0 && !(m->m_flags & M_PROMISC)) { if (ether_ipfw_chk(&m, NULL, 0) == 0) { if (m) m_freem(m); /* dropped; free mbuf chain */ diff --git a/sys/net/pfil.c b/sys/net/pfil.c index 0ae889a6f278..df0e30fe571b 100644 --- a/sys/net/pfil.c +++ b/sys/net/pfil.c @@ -58,8 +58,9 @@ static int pfil_list_remove(pfil_list_t *, int (*)(void *, struct mbuf **, struct ifnet *, int, struct inpcb *), void *); -LIST_HEAD(, pfil_head) pfil_head_list = - LIST_HEAD_INITIALIZER(&pfil_head_list); +LIST_HEAD(pfilheadhead, pfil_head); +VNET_DEFINE(struct pfilheadhead, pfil_head_list); +#define V_pfil_head_list VNET(pfil_head_list) /* * pfil_run_hooks() runs the specified packet filter hooks. @@ -99,7 +100,7 @@ pfil_head_register(struct pfil_head *ph) struct pfil_head *lph; PFIL_LIST_LOCK(); - LIST_FOREACH(lph, &pfil_head_list, ph_list) { + LIST_FOREACH(lph, &V_pfil_head_list, ph_list) { if (ph->ph_type == lph->ph_type && ph->ph_un.phu_val == lph->ph_un.phu_val) { PFIL_LIST_UNLOCK(); @@ -110,7 +111,7 @@ pfil_head_register(struct pfil_head *ph) ph->ph_nhooks = 0; TAILQ_INIT(&ph->ph_in); TAILQ_INIT(&ph->ph_out); - LIST_INSERT_HEAD(&pfil_head_list, ph, ph_list); + LIST_INSERT_HEAD(&V_pfil_head_list, ph, ph_list); PFIL_LIST_UNLOCK(); return (0); } @@ -145,7 +146,7 @@ pfil_head_get(int type, u_long val) struct pfil_head *ph; PFIL_LIST_LOCK(); - LIST_FOREACH(ph, &pfil_head_list, ph_list) + LIST_FOREACH(ph, &V_pfil_head_list, ph_list) if (ph->ph_type == type && ph->ph_un.phu_val == val) break; PFIL_LIST_UNLOCK(); @@ -284,3 +285,45 @@ pfil_list_remove(pfil_list_t *list, } return (ENOENT); } + +/**************** + * Stuff that must be initialized for every instance + * (including the first of course). + */ +static int +vnet_pfil_init(const void *unused) +{ + LIST_INIT(&V_pfil_head_list); + return (0); +} + +/*********************** + * Called for the removal of each instance. + */ +static int +vnet_pfil_uninit(const void *unused) +{ + /* XXX should panic if list is not empty */ + return 0; +} + +/* Define startup order. */ +#define PFIL_SYSINIT_ORDER SI_SUB_PROTO_BEGIN +#define PFIL_MODEVENT_ORDER (SI_ORDER_FIRST) /* On boot slot in here. */ +#define PFIL_VNET_ORDER (PFIL_MODEVENT_ORDER + 2) /* Later still. */ + +/* + * Starting up. + * VNET_SYSINIT is called for each existing vnet and each new vnet. + */ +VNET_SYSINIT(vnet_pfil_init, PFIL_SYSINIT_ORDER, PFIL_VNET_ORDER, + vnet_pfil_init, NULL); + +/* + * Closing up shop. These are done in REVERSE ORDER, + * Not called on reboot. + * VNET_SYSUNINIT is called for each exiting vnet as it exits. + */ +VNET_SYSUNINIT(vnet_pfil_uninit, PFIL_SYSINIT_ORDER, PFIL_VNET_ORDER, + vnet_pfil_uninit, NULL); + diff --git a/sys/netgraph/ng_bridge.c b/sys/netgraph/ng_bridge.c index e42b5a547f03..c6f41836cca5 100644 --- a/sys/netgraph/ng_bridge.c +++ b/sys/netgraph/ng_bridge.c @@ -634,7 +634,7 @@ ng_bridge_rcvdata(hook_p hook, item_p item) /* Run packet through ipfw processing, if enabled */ #if 0 - if (priv->conf.ipfw[linkNum] && V_fw_enable && ip_fw_chk_ptr != NULL) { + if (priv->conf.ipfw[linkNum] && V_fw_enable && V_ip_fw_chk_ptr != NULL) { /* XXX not implemented yet */ } #endif diff --git a/sys/netinet/ip_fastfwd.c b/sys/netinet/ip_fastfwd.c index f53f787ed875..31565d1ad857 100644 --- a/sys/netinet/ip_fastfwd.c +++ b/sys/netinet/ip_fastfwd.c @@ -351,10 +351,11 @@ ip_fastforward(struct mbuf *m) /* * Run through list of ipfilter hooks for input packets */ - if (!PFIL_HOOKED(&inet_pfil_hook)) + if (!PFIL_HOOKED(&V_inet_pfil_hook)) goto passin; - if (pfil_run_hooks(&inet_pfil_hook, &m, m->m_pkthdr.rcvif, PFIL_IN, NULL) || + if (pfil_run_hooks( + &V_inet_pfil_hook, &m, m->m_pkthdr.rcvif, PFIL_IN, NULL) || m == NULL) goto drop; @@ -438,10 +439,10 @@ passin: /* * Run through list of hooks for output packets. */ - if (!PFIL_HOOKED(&inet_pfil_hook)) + if (!PFIL_HOOKED(&V_inet_pfil_hook)) goto passout; - if (pfil_run_hooks(&inet_pfil_hook, &m, ifp, PFIL_OUT, NULL) || m == NULL) { + if (pfil_run_hooks(&V_inet_pfil_hook, &m, ifp, PFIL_OUT, NULL) || m == NULL) { goto drop; } diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index d6915d7bf956..8ffa01ab8a23 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -170,7 +170,7 @@ SYSCTL_VNET_INT(_net_inet_ip, OID_AUTO, check_interface, CTLFLAG_RW, &VNET_NAME(ip_checkinterface), 0, "Verify packet arrives on correct interface"); -struct pfil_head inet_pfil_hook; /* Packet filter hooks */ +VNET_DEFINE(struct pfil_head, inet_pfil_hook); /* Packet filter hooks */ static struct netisr_handler ip_nh = { .nh_name = "ip", @@ -318,6 +318,13 @@ ip_init(void) NULL, UMA_ALIGN_PTR, 0); maxnipq_update(); + /* Initialize packet filter hooks. */ + V_inet_pfil_hook.ph_type = PFIL_TYPE_AF; + V_inet_pfil_hook.ph_af = AF_INET; + if ((i = pfil_head_register(&V_inet_pfil_hook)) != 0) + printf("%s: WARNING: unable to register pfil hook, " + "error %d\n", __func__, i); + #ifdef FLOWTABLE TUNABLE_INT_FETCH("net.inet.ip.output_flowtable_size", &V_ip_output_flowtable_size); @@ -348,13 +355,6 @@ ip_init(void) ip_protox[pr->pr_protocol] = pr - inetsw; } - /* Initialize packet filter hooks. */ - inet_pfil_hook.ph_type = PFIL_TYPE_AF; - inet_pfil_hook.ph_af = AF_INET; - if ((i = pfil_head_register(&inet_pfil_hook)) != 0) - printf("%s: WARNING: unable to register pfil hook, " - "error %d\n", __func__, i); - /* Start ipport_tick. */ callout_init(&ipport_tick_callout, CALLOUT_MPSAFE); callout_reset(&ipport_tick_callout, 1, ipport_tick, NULL); @@ -510,11 +510,11 @@ tooshort: */ /* Jump over all PFIL processing if hooks are not active. */ - if (!PFIL_HOOKED(&inet_pfil_hook)) + if (!PFIL_HOOKED(&V_inet_pfil_hook)) goto passin; odst = ip->ip_dst; - if (pfil_run_hooks(&inet_pfil_hook, &m, ifp, PFIL_IN, NULL) != 0) + if (pfil_run_hooks(&V_inet_pfil_hook, &m, ifp, PFIL_IN, NULL) != 0) return; if (m == NULL) /* consumed by filter */ return; diff --git a/sys/netinet/ip_output.c b/sys/netinet/ip_output.c index e222cdaaa1fc..b5be6fd1e1fe 100644 --- a/sys/netinet/ip_output.c +++ b/sys/netinet/ip_output.c @@ -489,12 +489,12 @@ sendit: #endif /* IPSEC */ /* Jump over all PFIL processing if hooks are not active. */ - if (!PFIL_HOOKED(&inet_pfil_hook)) + if (!PFIL_HOOKED(&V_inet_pfil_hook)) goto passout; /* Run through list of hooks for output packets. */ odst.s_addr = ip->ip_dst.s_addr; - error = pfil_run_hooks(&inet_pfil_hook, &m, ifp, PFIL_OUT, inp); + error = pfil_run_hooks(&V_inet_pfil_hook, &m, ifp, PFIL_OUT, inp); if (error != 0 || m == NULL) goto done; diff --git a/sys/netinet/ip_var.h b/sys/netinet/ip_var.h index 448ba3d79784..a1d2166ac3ac 100644 --- a/sys/netinet/ip_var.h +++ b/sys/netinet/ip_var.h @@ -244,14 +244,20 @@ extern int (*ip_rsvp_vif)(struct socket *, struct sockopt *); extern void (*ip_rsvp_force_done)(struct socket *); extern void (*rsvp_input_p)(struct mbuf *m, int off); -extern struct pfil_head inet_pfil_hook; /* packet filter hooks */ +VNET_DECLARE(struct pfil_head, inet_pfil_hook); /* packet filter hooks */ +#define V_inet_pfil_hook VNET(inet_pfil_hook) void in_delayed_cksum(struct mbuf *m); /* ipfw and dummynet hooks. Most are declared in raw_ip.c */ struct ip_fw_args; -extern int (*ip_fw_chk_ptr)(struct ip_fw_args *args); -extern int (*ip_fw_ctl_ptr)(struct sockopt *); +typedef int (*ip_fw_chk_ptr_t)(struct ip_fw_args *args); +typedef int (*ip_fw_ctl_ptr_t)(struct sockopt *); +VNET_DECLARE(ip_fw_chk_ptr_t, ip_fw_chk_ptr); +VNET_DECLARE(ip_fw_ctl_ptr_t, ip_fw_ctl_ptr); +#define V_ip_fw_chk_ptr VNET(ip_fw_chk_ptr) +#define V_ip_fw_ctl_ptr VNET(ip_fw_ctl_ptr) + extern int (*ip_dn_ctl_ptr)(struct sockopt *); extern int (*ip_dn_io_ptr)(struct mbuf **m, int dir, struct ip_fw_args *fwa); extern void (*ip_dn_ruledel_ptr)(void *); /* in ip_fw2.c */ diff --git a/sys/netinet/ipfw/ip_fw2.c b/sys/netinet/ipfw/ip_fw2.c index 4c08bc5d17b0..1ccbf2bcb788 100644 --- a/sys/netinet/ipfw/ip_fw2.c +++ b/sys/netinet/ipfw/ip_fw2.c @@ -2581,6 +2581,10 @@ do { \ } IPFW_RLOCK(chain); + if (! V_ipfw_vnet_ready) { /* shutting down, leave NOW. */ + IPFW_RUNLOCK(chain); + return (IP_FW_PASS); /* accept */ + } mtag = m_tag_find(m, PACKET_TAG_DIVERT, NULL); if (args->rule) { /* @@ -4760,29 +4764,21 @@ ipfw_init(void) printf("limited to %d packets/entry by default\n", V_verbose_limit); - /* - * Hook us up to pfil. - * Eventually pfil will be per vnet. - */ - if ((error = ipfw_hook()) != 0) { - printf("ipfw_hook() error\n"); - return (error); - } -#ifdef INET6 - if ((error = ipfw6_hook()) != 0) { - printf("ipfw6_hook() error\n"); - return (error); - } -#endif - /* - * 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; return (error); } +/********************** + * Called for the removal of the last instance only on module unload. + */ +static void +ipfw_destroy(void) +{ + + uma_zdestroy(ipfw_dyn_rule_zone); + IPFW_DYN_LOCK_DESTROY(); + printf("IP firewall unloaded\n"); +} + /**************** * Stuff that must be initialized for every instance * (including the first of course). @@ -4866,21 +4862,32 @@ vnet_ipfw_init(const void *unused) /* First set up some values that are compile time options */ V_ipfw_vnet_ready = 1; /* Open for business */ + + /* Hook up the raw inputs */ + V_ip_fw_ctl_ptr = ipfw_ctl; + V_ip_fw_chk_ptr = ipfw_chk; + + /* + * Hook us up to pfil. + */ + if (V_fw_enable) { + if ((error = ipfw_hook()) != 0) { + printf("ipfw_hook() error\n"); + return (error); + } + } +#ifdef INET6 + if (V_fw6_enable) { + if ((error = ipfw6_hook()) != 0) { + printf("ipfw6_hook() error\n"); + /* XXX should we unhook everything else? */ + return (error); + } + } +#endif return (0); } -/********************** - * Called for the removal of the last instance only on module unload. - */ -static void -ipfw_destroy(void) -{ - - uma_zdestroy(ipfw_dyn_rule_zone); - IPFW_DYN_LOCK_DESTROY(); - printf("IP firewall unloaded\n"); -} - /*********************** * Called for the removal of each instance. */ @@ -4890,9 +4897,18 @@ vnet_ipfw_uninit(const void *unused) struct ip_fw *reap; V_ipfw_vnet_ready = 0; /* tell new callers to go away */ - callout_drain(&V_ipfw_timeout); - /* We wait on the wlock here until the last user leaves */ + ipfw_unhook(); +#ifdef INET6 + ipfw6_unhook(); +#endif + /* layer2 and other entrypoints still come in this way. */ + V_ip_fw_chk_ptr = NULL; + V_ip_fw_ctl_ptr = NULL; IPFW_WLOCK(&V_layer3_chain); + /* We wait on the wlock here until the last user leaves */ + IPFW_WUNLOCK(&V_layer3_chain); + IPFW_WLOCK(&V_layer3_chain); + callout_drain(&V_ipfw_timeout); flush_tables(&V_layer3_chain); V_layer3_chain.reap = NULL; free_chain(&V_layer3_chain, 1 /* kill default rule */); @@ -4926,21 +4942,10 @@ ipfw_modevent(module_t mod, int type, void *unused) /* Called once at module load or * system boot if compiled in. */ break; - case MOD_UNLOAD: - break; case MOD_QUIESCE: - /* Yes, the unhooks can return errors, we can safely ignore - * them. Eventually these will be done per jail as they - * shut down. We will wait on each vnet's l3 lock as existing - * callers go away. - */ - ipfw_unhook(); -#ifdef INET6 - ipfw6_unhook(); -#endif - /* layer2 and other entrypoints still come in this way. */ - ip_fw_chk_ptr = NULL; - ip_fw_ctl_ptr = NULL; + /* Called before unload. May veto unloading. */ + break; + case MOD_UNLOAD: /* Called during unload. */ break; case MOD_SHUTDOWN: @@ -4989,4 +4994,3 @@ SYSUNINIT(ipfw_destroy, IPFW_SI_SUB_FIREWALL, IPFW_MODULE_ORDER, VNET_SYSUNINIT(vnet_ipfw_uninit, IPFW_SI_SUB_FIREWALL, IPFW_VNET_ORDER, vnet_ipfw_uninit, NULL); - diff --git a/sys/netinet/ipfw/ip_fw_pfil.c b/sys/netinet/ipfw/ip_fw_pfil.c index ffffb594546b..db7308407a83 100644 --- a/sys/netinet/ipfw/ip_fw_pfil.c +++ b/sys/netinet/ipfw/ip_fw_pfil.c @@ -515,42 +515,54 @@ ipfw6_unhook(void) int ipfw_chg_hook(SYSCTL_HANDLER_ARGS) { - int enable = *(int *)arg1; + int enable; + int oldenable; int error; -#ifdef VIMAGE /* Since enabling is global, only let base do it. */ - if (! IS_DEFAULT_VNET(curvnet)) - return (EPERM); + if (arg1 == &VNET_NAME(fw_enable)) { + enable = V_fw_enable; + } +#ifdef INET6 + else if (arg1 == &VNET_NAME(fw6_enable)) { + enable = V_fw6_enable; + } #endif + else + return (EINVAL); + + oldenable = enable; + error = sysctl_handle_int(oidp, &enable, 0, req); + if (error) return (error); enable = (enable) ? 1 : 0; - if (enable == *(int *)arg1) + if (enable == oldenable) return (0); - if (arg1 == &V_fw_enable) { + if (arg1 == &VNET_NAME(fw_enable)) { if (enable) error = ipfw_hook(); else error = ipfw_unhook(); + if (error) + return (error); + V_fw_enable = enable; } #ifdef INET6 - if (arg1 == &V_fw6_enable) { + else if (arg1 == &VNET_NAME(fw6_enable)) { if (enable) error = ipfw6_hook(); else error = ipfw6_unhook(); + if (error) + return (error); + V_fw6_enable = enable; } #endif - if (error) - return (error); - - *(int *)arg1 = enable; - return (0); } diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c index aba1f5f4a115..3573472bf258 100644 --- a/sys/netinet/raw_ip.c +++ b/sys/netinet/raw_ip.c @@ -84,9 +84,9 @@ VNET_DEFINE(struct inpcbinfo, ripcbinfo); * The data hooks are not used here but it is convenient * to keep them all in one place. */ -int (*ip_fw_ctl_ptr)(struct sockopt *) = NULL; +VNET_DEFINE(ip_fw_chk_ptr_t, ip_fw_chk_ptr) = NULL; +VNET_DEFINE(ip_fw_ctl_ptr_t, ip_fw_ctl_ptr) = NULL; int (*ip_dn_ctl_ptr)(struct sockopt *) = NULL; -int (*ip_fw_chk_ptr)(struct ip_fw_args *args) = NULL; int (*ip_dn_io_ptr)(struct mbuf **m, int dir, struct ip_fw_args *fwa) = NULL; /* @@ -542,8 +542,8 @@ rip_ctloutput(struct socket *so, struct sockopt *sopt) case IP_FW_TABLE_LIST: case IP_FW_NAT_GET_CONFIG: case IP_FW_NAT_GET_LOG: - if (ip_fw_ctl_ptr != NULL) - error = ip_fw_ctl_ptr(sopt); + if (V_ip_fw_ctl_ptr != NULL) + error = V_ip_fw_ctl_ptr(sopt); else error = ENOPROTOOPT; break; @@ -605,8 +605,8 @@ rip_ctloutput(struct socket *so, struct sockopt *sopt) case IP_FW_TABLE_FLUSH: case IP_FW_NAT_CFG: case IP_FW_NAT_DEL: - if (ip_fw_ctl_ptr != NULL) - error = ip_fw_ctl_ptr(sopt); + if (V_ip_fw_ctl_ptr != NULL) + error = V_ip_fw_ctl_ptr(sopt); else error = ENOPROTOOPT; break; diff --git a/sys/netinet6/ip6_forward.c b/sys/netinet6/ip6_forward.c index 7ba4977d919c..cff29e19be52 100644 --- a/sys/netinet6/ip6_forward.c +++ b/sys/netinet6/ip6_forward.c @@ -551,11 +551,11 @@ skip_routing: in6_clearscope(&ip6->ip6_dst); /* Jump over all PFIL processing if hooks are not active. */ - if (!PFIL_HOOKED(&inet6_pfil_hook)) + if (!PFIL_HOOKED(&V_inet6_pfil_hook)) goto pass; /* Run through list of hooks for output packets. */ - error = pfil_run_hooks(&inet6_pfil_hook, &m, rt->rt_ifp, PFIL_OUT, NULL); + error = pfil_run_hooks(&V_inet6_pfil_hook, &m, rt->rt_ifp, PFIL_OUT, NULL); if (error != 0) goto senderr; if (m == NULL) diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index 4958d748a899..5bc38bdc9aa9 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -152,7 +152,7 @@ VNET_DECLARE(int, udp6_recvspace); struct rwlock in6_ifaddr_lock; RW_SYSINIT(in6_ifaddr_lock, &in6_ifaddr_lock, "in6_ifaddr_lock"); -struct pfil_head inet6_pfil_hook; +VNET_DEFINE (struct pfil_head, inet6_pfil_hook); static void ip6_init2(void *); static struct ip6aux *ip6_setdstifaddr(struct mbuf *, struct in6_ifaddr *); @@ -247,6 +247,13 @@ ip6_init(void) V_ip6_desync_factor = arc4random() % MAX_TEMP_DESYNC_FACTOR; + /* Initialize packet filter hooks. */ + V_inet6_pfil_hook.ph_type = PFIL_TYPE_AF; + V_inet6_pfil_hook.ph_af = AF_INET6; + if ((i = pfil_head_register(&V_inet6_pfil_hook)) != 0) + printf("%s: WARNING: unable to register pfil hook, " + "error %d\n", __func__, i); + /* Skip global initialization stuff for non-default instances. */ if (!IS_DEFAULT_VNET(curvnet)) return; @@ -275,13 +282,6 @@ ip6_init(void) ip6_protox[pr->pr_protocol] = pr - inet6sw; } - /* Initialize packet filter hooks. */ - inet6_pfil_hook.ph_type = PFIL_TYPE_AF; - inet6_pfil_hook.ph_af = AF_INET6; - if ((i = pfil_head_register(&inet6_pfil_hook)) != 0) - printf("%s: WARNING: unable to register pfil hook, " - "error %d\n", __func__, i); - netisr_register(&ip6_nh); } @@ -515,10 +515,11 @@ ip6_input(struct mbuf *m) odst = ip6->ip6_dst; /* Jump over all PFIL processing if hooks are not active. */ - if (!PFIL_HOOKED(&inet6_pfil_hook)) + if (!PFIL_HOOKED(&V_inet6_pfil_hook)) goto passin; - if (pfil_run_hooks(&inet6_pfil_hook, &m, m->m_pkthdr.rcvif, PFIL_IN, NULL)) + if (pfil_run_hooks(&V_inet6_pfil_hook, &m, + m->m_pkthdr.rcvif, PFIL_IN, NULL)) return; if (m == NULL) /* consumed by filter */ return; diff --git a/sys/netinet6/ip6_output.c b/sys/netinet6/ip6_output.c index 98875640e7a5..c2ec49aa3509 100644 --- a/sys/netinet6/ip6_output.c +++ b/sys/netinet6/ip6_output.c @@ -805,12 +805,12 @@ again: } /* Jump over all PFIL processing if hooks are not active. */ - if (!PFIL_HOOKED(&inet6_pfil_hook)) + if (!PFIL_HOOKED(&V_inet6_pfil_hook)) goto passout; odst = ip6->ip6_dst; /* Run through list of hooks for output packets. */ - error = pfil_run_hooks(&inet6_pfil_hook, &m, ifp, PFIL_OUT, inp); + error = pfil_run_hooks(&V_inet6_pfil_hook, &m, ifp, PFIL_OUT, inp); if (error != 0 || m == NULL) goto done; ip6 = mtod(m, struct ip6_hdr *); diff --git a/sys/netinet6/ip6_var.h b/sys/netinet6/ip6_var.h index e8fe3ec04a4a..a0a0f3a18d8f 100644 --- a/sys/netinet6/ip6_var.h +++ b/sys/netinet6/ip6_var.h @@ -358,7 +358,8 @@ VNET_DECLARE(int, ip6_use_defzone); /* Whether to use the default scope #endif #define V_ip6_use_defzone VNET(ip6_use_defzone) -extern struct pfil_head inet6_pfil_hook; /* packet filter hooks */ +VNET_DECLARE (struct pfil_head, inet6_pfil_hook); /* packet filter hooks */ +#define V_inet6_pfil_hook VNET(inet6_pfil_hook) extern struct pr_usrreqs rip6_usrreqs; struct sockopt;