diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/net/if_ethersubr.c | 6 | ||||
-rw-r--r-- | sys/net/pfil.c | 147 | ||||
-rw-r--r-- | sys/net/pfil.h | 7 | ||||
-rw-r--r-- | sys/netinet/ip_input.c | 3 | ||||
-rw-r--r-- | sys/netinet6/ip6_input.c | 4 | ||||
-rw-r--r-- | sys/netpfil/ipfw/ip_fw_pfil.c | 6 | ||||
-rw-r--r-- | sys/netpfil/pf/pf_ioctl.c | 10 |
7 files changed, 176 insertions, 7 deletions
diff --git a/sys/net/if_ethersubr.c b/sys/net/if_ethersubr.c index ea22d33..5e2499d 100644 --- a/sys/net/if_ethersubr.c +++ b/sys/net/if_ethersubr.c @@ -108,6 +108,8 @@ CTASSERT(sizeof (struct ether_addr) == ETHER_ADDR_LEN); VNET_DEFINE(struct pfil_head, link_pfil_hook); /* Packet filter hooks */ +SYSCTL_DECL(_net_link); + /* netgraph node hooks for ng_ether(4) */ void (*ng_ether_input_p)(struct ifnet *ifp, struct mbuf **mp); void (*ng_ether_input_orphan_p)(struct ifnet *ifp, struct mbuf *m); @@ -685,6 +687,9 @@ vnet_ether_init(__unused void *arg) if ((i = pfil_head_register(&V_link_pfil_hook)) != 0) printf("%s: WARNING: unable to register pfil link hook, " "error %d\n", __func__, i); + else + pfil_head_export_sysctl(&V_link_pfil_hook, + SYSCTL_STATIC_CHILDREN(_net_link)); } VNET_SYSINIT(vnet_ether_init, SI_SUB_PROTO_IF, SI_ORDER_ANY, vnet_ether_init, NULL); @@ -972,7 +977,6 @@ ether_reassign(struct ifnet *ifp, struct vnet *new_vnet, char *unused __unused) } #endif -SYSCTL_DECL(_net_link); SYSCTL_NODE(_net_link, IFT_ETHER, ether, CTLFLAG_RW, 0, "Ethernet"); #if 0 diff --git a/sys/net/pfil.c b/sys/net/pfil.c index 44373ee..5d5d346 100644 --- a/sys/net/pfil.c +++ b/sys/net/pfil.c @@ -34,6 +34,7 @@ #include <sys/errno.h> #include <sys/lock.h> #include <sys/malloc.h> +#include <sys/sbuf.h> #include <sys/rmlock.h> #include <sys/socket.h> #include <sys/socketvar.h> @@ -78,7 +79,7 @@ pfil_run_hooks(struct pfil_head *ph, struct mbuf **mp, struct ifnet *ifp, KASSERT(ph->ph_nhooks >= 0, ("Pfil hook count dropped < 0")); for (pfh = pfil_chain_get(dir, ph); pfh != NULL; pfh = TAILQ_NEXT(pfh, pfil_chain)) { - if (pfh->pfil_func != NULL) { + if (!(pfh->pfil_flags & PFIL_DISABLED) && pfh->pfil_func != NULL) { rv = (*pfh->pfil_func)(pfh->pfil_arg, &m, ifp, dir, inp); if (rv != 0 || m == NULL) @@ -211,6 +212,140 @@ pfil_head_unregister(struct pfil_head *ph) return (0); } +static int +pfil_sysctl_handler(SYSCTL_HANDLER_ARGS) +{ + struct rm_priotracker rmpt; + struct pfil_head *ph; + struct packet_filter_hook *pfh, *pfhtmp; + struct sbuf *sb; + pfil_chain_t npfl, *pfl; + char *new_order, *elm, *parse; + int i = 0, err = 0, hintlen, reqlen; + + hintlen = 0; + + ph = (struct pfil_head *)arg1; + if (ph == NULL || !PFIL_HOOKED(ph)) { + err = SYSCTL_OUT(req, "", 2); + return (err); + } + + if (arg2 == PFIL_IN) + pfl = &ph->ph_in; + else + pfl = &ph->ph_out; + + if (TAILQ_EMPTY(pfl)) { + err = SYSCTL_OUT(req, "", 2); + return (err); + } + + /* + * NOTE: This is needed to avoid witness(4) warnings. + */ + PFIL_RLOCK(ph, &rmpt); + TAILQ_FOREACH(pfh, pfl, pfil_chain) { + if (pfh->pfil_name != NULL) + hintlen = strlen(pfh->pfil_name); + else + hintlen += 2; + } + PFIL_RUNLOCK(ph, &rmpt); + + sb = sbuf_new(NULL, NULL, hintlen + 1, SBUF_AUTOEXTEND); + if (sb == NULL) + return (EINVAL); + + PFIL_RLOCK(ph, &rmpt); + TAILQ_FOREACH(pfh, pfl, pfil_chain) { + if (i > 0) + sbuf_printf(sb, ", "); + if (pfh->pfil_name != NULL) + sbuf_printf(sb, "%s%s", pfh->pfil_name, + pfh->pfil_flags & PFIL_DISABLED ? "*" : ""); + else + sbuf_printf(sb, "%s%s", "NA", + pfh->pfil_flags & PFIL_DISABLED ? "*" : ""); + i++; + } + PFIL_RUNLOCK(ph, &rmpt); + + sbuf_finish(sb); + + /* hint for sensible write buffer sizes */ + hintlen = sbuf_len(sb) + i * 2; + err = SYSCTL_OUT(req, sbuf_data(sb), sbuf_len(sb) + 1); + sbuf_delete(sb); + + if (err || !req->newptr) + return (err); + + if ((reqlen = req->newlen - req->newidx) > hintlen) + return (E2BIG); + new_order = malloc(reqlen + 1, M_TEMP, M_WAITOK|M_ZERO); + + err = SYSCTL_IN(req, new_order, reqlen); + if (err) + goto error; + new_order[reqlen] = '\0'; /* Just in case */ + parse = new_order; + + TAILQ_INIT(&npfl); + PFIL_WLOCK(ph); + while ((elm = strsep(&parse, " \t,")) != NULL) { + if (*elm == '\0') + continue; + TAILQ_FOREACH_SAFE(pfh, pfl, pfil_chain, pfhtmp) { + if (pfh->pfil_name != NULL) { + if (!strcmp(pfh->pfil_name, elm)) { + TAILQ_REMOVE(pfl, pfh, pfil_chain); + TAILQ_INSERT_TAIL(&npfl, pfh, pfil_chain); + pfh->pfil_flags &= ~PFIL_DISABLED; + break; + } + } else { + if (!strcmp(elm, "NA")) { + TAILQ_REMOVE(pfl, pfh, pfil_chain); + TAILQ_INSERT_TAIL(&npfl, pfh, pfil_chain); + pfh->pfil_flags &= ~PFIL_DISABLED; + break; + } + } + } + } + + TAILQ_FOREACH_SAFE(pfh, pfl, pfil_chain, pfhtmp) { + pfh->pfil_flags |= PFIL_DISABLED; + TAILQ_REMOVE(pfl, pfh, pfil_chain); + TAILQ_INSERT_TAIL(&npfl, pfh, pfil_chain); + } + + TAILQ_CONCAT(pfl, &npfl, pfil_chain); + +error: + PFIL_WUNLOCK(ph); + free(new_order, M_TEMP); + return (err); +} + +void +pfil_head_export_sysctl(struct pfil_head *ph, struct sysctl_oid_list *parent) +{ + struct sysctl_oid *root; + + root = SYSCTL_ADD_NODE(&ph->ph_clist, parent, OID_AUTO, "pfil", + CTLFLAG_RW, 0, "pfil(9) management"); + SYSCTL_ADD_PROC((void *)&ph->ph_clist, SYSCTL_CHILDREN(root), OID_AUTO, + "inbound", CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_SECURE3, + (void *)ph, PFIL_IN, pfil_sysctl_handler, "A", + "Inbound filter hooks"); + SYSCTL_ADD_PROC((void *)&ph->ph_clist, SYSCTL_CHILDREN(root), OID_AUTO, + "outbound", CTLTYPE_STRING|CTLFLAG_RW|CTLFLAG_SECURE3, + (void *)ph, PFIL_OUT, pfil_sysctl_handler, "A", + "Outbound filter hooks"); +} + /* * pfil_head_get() returns the pfil_head for a given key/dlt. */ @@ -238,6 +373,12 @@ pfil_head_get(int type, u_long val) int pfil_add_hook(pfil_func_t func, void *arg, int flags, struct pfil_head *ph) { + return (pfil_add_named_hook(func, arg, NULL, flags, ph)); +} + +int +pfil_add_named_hook(pfil_func_t func, void *arg, char *name, int flags, struct pfil_head *ph) +{ struct packet_filter_hook *pfh1 = NULL; struct packet_filter_hook *pfh2 = NULL; int err; @@ -262,6 +403,8 @@ pfil_add_hook(pfil_func_t func, void *arg, int flags, struct pfil_head *ph) if (flags & PFIL_IN) { pfh1->pfil_func = func; pfh1->pfil_arg = arg; + pfh1->pfil_name = name; + pfh1->pfil_flags &= ~PFIL_DISABLED; err = pfil_chain_add(&ph->ph_in, pfh1, flags & ~PFIL_OUT); if (err) goto locked_error; @@ -270,6 +413,8 @@ pfil_add_hook(pfil_func_t func, void *arg, int flags, struct pfil_head *ph) if (flags & PFIL_OUT) { pfh2->pfil_func = func; pfh2->pfil_arg = arg; + pfh2->pfil_name = name; + pfh2->pfil_flags &= ~PFIL_DISABLED; err = pfil_chain_add(&ph->ph_out, pfh2, flags & ~PFIL_IN); if (err) { if (flags & PFIL_IN) diff --git a/sys/net/pfil.h b/sys/net/pfil.h index c9a1b65..ff260ce 100644 --- a/sys/net/pfil.h +++ b/sys/net/pfil.h @@ -38,6 +38,7 @@ #include <sys/_mutex.h> #include <sys/lock.h> #include <sys/rmlock.h> +#include <sys/sysctl.h> struct mbuf; struct ifnet; @@ -55,11 +56,14 @@ struct packet_filter_hook { TAILQ_ENTRY(packet_filter_hook) pfil_chain; pfil_func_t pfil_func; void *pfil_arg; + int pfil_flags; + char *pfil_name; }; #define PFIL_IN 0x00000001 #define PFIL_OUT 0x00000002 #define PFIL_WAITOK 0x00000004 +#define PFIL_DISABLED 0x00000008 #define PFIL_ALL (PFIL_IN|PFIL_OUT) typedef TAILQ_HEAD(pfil_chain, packet_filter_hook) pfil_chain_t; @@ -85,6 +89,7 @@ struct pfil_head { struct rmlock ph_lock; /* Private lock storage */ int flags; #endif + struct sysctl_ctx_list ph_clist; union { u_long phu_val; void *phu_ptr; @@ -96,7 +101,9 @@ struct pfil_head { /* Public functions for pfil hook management by packet filters. */ struct pfil_head *pfil_head_get(int, u_long); +void pfil_head_export_sysctl(struct pfil_head *, struct sysctl_oid_list *); int pfil_add_hook(pfil_func_t, void *, int, struct pfil_head *); +int pfil_add_named_hook(pfil_func_t, void *, char *, int, struct pfil_head *); int pfil_remove_hook(pfil_func_t, void *, int, struct pfil_head *); #define PFIL_HOOKED(p) ((p)->ph_nhooks > 0) diff --git a/sys/netinet/ip_input.c b/sys/netinet/ip_input.c index 2dc080f..77e6a48 100644 --- a/sys/netinet/ip_input.c +++ b/sys/netinet/ip_input.c @@ -297,6 +297,9 @@ ip_init(void) if ((i = pfil_head_register(&V_inet_pfil_hook)) != 0) printf("%s: WARNING: unable to register pfil hook, " "error %d\n", __func__, i); + else + pfil_head_export_sysctl(&V_inet_pfil_hook, + SYSCTL_STATIC_CHILDREN(_net_inet_ip)); /* Skip initialization of globals for non-default instances. */ if (!IS_DEFAULT_VNET(curvnet)) diff --git a/sys/netinet6/ip6_input.c b/sys/netinet6/ip6_input.c index b8a75c6..b6602d3 100644 --- a/sys/netinet6/ip6_input.c +++ b/sys/netinet6/ip6_input.c @@ -136,6 +136,7 @@ static struct netisr_handler ip6_nh = { VNET_DECLARE(struct callout, in6_tmpaddrtimer_ch); #define V_in6_tmpaddrtimer_ch VNET(in6_tmpaddrtimer_ch) +SYSCTL_DECL(_net_inet6_ip6); VNET_DEFINE(struct pfil_head, inet6_pfil_hook); VNET_PCPUSTAT_DEFINE(struct ip6stat, ip6stat); @@ -182,6 +183,9 @@ ip6_init(void) if ((i = pfil_head_register(&V_inet6_pfil_hook)) != 0) printf("%s: WARNING: unable to register pfil hook, " "error %d\n", __func__, i); + else + pfil_head_export_sysctl(&V_inet6_pfil_hook, + SYSCTL_STATIC_CHILDREN(_net_inet6_ip6)); scope6_init(); addrsel_policy_init(); diff --git a/sys/netpfil/ipfw/ip_fw_pfil.c b/sys/netpfil/ipfw/ip_fw_pfil.c index 2bcd1dd..d1202ff 100644 --- a/sys/netpfil/ipfw/ip_fw_pfil.c +++ b/sys/netpfil/ipfw/ip_fw_pfil.c @@ -499,7 +499,11 @@ ipfw_hook(int onoff, int pf) hook_func = (pf == AF_LINK) ? ipfw_check_frame : ipfw_check_packet; - (void) (onoff ? pfil_add_hook : pfil_remove_hook) + if (onoff) + (void) pfil_add_named_hook + (hook_func, NULL, "ipfw", PFIL_IN | PFIL_OUT | PFIL_WAITOK, pfh); + else + (void) pfil_remove_hook (hook_func, NULL, PFIL_IN | PFIL_OUT | PFIL_WAITOK, pfh); return 0; diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c index 23b9efc..16da924 100644 --- a/sys/netpfil/pf/pf_ioctl.c +++ b/sys/netpfil/pf/pf_ioctl.c @@ -3688,8 +3688,8 @@ hook_pf(void) pfh_inet = pfil_head_get(PFIL_TYPE_AF, AF_INET); if (pfh_inet == NULL) return (ESRCH); /* XXX */ - pfil_add_hook(pf_check_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet); - pfil_add_hook(pf_check_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet); + pfil_add_named_hook(pf_check_in, NULL, "pf", PFIL_IN | PFIL_WAITOK, pfh_inet); + pfil_add_named_hook(pf_check_out, NULL, "pf", PFIL_OUT | PFIL_WAITOK, pfh_inet); #endif #ifdef INET6 pfh_inet6 = pfil_head_get(PFIL_TYPE_AF, AF_INET6); @@ -3702,8 +3702,10 @@ hook_pf(void) #endif return (ESRCH); /* XXX */ } - pfil_add_hook(pf_check6_in, NULL, PFIL_IN | PFIL_WAITOK, pfh_inet6); - pfil_add_hook(pf_check6_out, NULL, PFIL_OUT | PFIL_WAITOK, pfh_inet6); + pfil_add_named_hook(pf_check6_in, NULL, "pf", PFIL_IN | PFIL_WAITOK, + pfh_inet6); + pfil_add_named_hook(pf_check6_out, NULL, "pf", PFIL_OUT | PFIL_WAITOK, + pfh_inet6); #endif V_pf_pfil_hooked = 1; |