Module Name: src Committed By: rmind Date: Mon Jan 2 21:49:51 UTC 2017
Modified Files: src/sys/modules/npf: Makefile src/sys/net/npf: files.npf npf_ctl.c npf_impl.h npf_os.c npf_tableset.c npf_worker.c Added Files: src/sys/net/npf: npf_ifaddr.c Log Message: NPF: implement dynamic handling of interface addresses (the kernel part). To generate a diff of this commit: cvs rdiff -u -r1.20 -r1.21 src/sys/modules/npf/Makefile cvs rdiff -u -r1.19 -r1.20 src/sys/net/npf/files.npf cvs rdiff -u -r1.45 -r1.46 src/sys/net/npf/npf_ctl.c cvs rdiff -u -r0 -r1.1 src/sys/net/npf/npf_ifaddr.c cvs rdiff -u -r1.65 -r1.66 src/sys/net/npf/npf_impl.h cvs rdiff -u -r1.2 -r1.3 src/sys/net/npf/npf_os.c \ src/sys/net/npf/npf_worker.c cvs rdiff -u -r1.25 -r1.26 src/sys/net/npf/npf_tableset.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/modules/npf/Makefile diff -u src/sys/modules/npf/Makefile:1.20 src/sys/modules/npf/Makefile:1.21 --- src/sys/modules/npf/Makefile:1.20 Wed Dec 28 13:50:55 2016 +++ src/sys/modules/npf/Makefile Mon Jan 2 21:49:51 2017 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.20 2016/12/28 13:50:55 christos Exp $ +# $NetBSD: Makefile,v 1.21 2017/01/02 21:49:51 rmind Exp $ # # Public Domain. # @@ -13,7 +13,7 @@ SRCS= npf.c npf_alg.c npf_conf.c npf_ct SRCS+= npf_bpf.c npf_if.c npf_inet.c npf_mbuf.c npf_nat.c SRCS+= npf_ruleset.c npf_conn.c npf_conndb.c npf_rproc.c SRCS+= npf_state.c npf_state_tcp.c npf_tableset.c -SRCS+= lpm.c npf_sendpkt.c npf_worker.c npf_os.c +SRCS+= lpm.c npf_sendpkt.c npf_worker.c npf_ifaddr.c npf_os.c CPPFLAGS+= -DINET6 Index: src/sys/net/npf/files.npf diff -u src/sys/net/npf/files.npf:1.19 src/sys/net/npf/files.npf:1.20 --- src/sys/net/npf/files.npf:1.19 Mon Dec 26 23:05:06 2016 +++ src/sys/net/npf/files.npf Mon Jan 2 21:49:51 2017 @@ -1,4 +1,4 @@ -# $NetBSD: files.npf,v 1.19 2016/12/26 23:05:06 christos Exp $ +# $NetBSD: files.npf,v 1.20 2017/01/02 21:49:51 rmind Exp $ # # Public Domain. # @@ -11,7 +11,6 @@ defpseudo npf: ifnet # Core file net/npf/npf.c npf -file net/npf/npf_os.c npf file net/npf/npf_conf.c npf file net/npf/npf_ctl.c npf file net/npf/npf_handler.c npf @@ -31,6 +30,9 @@ file net/npf/npf_alg.c npf file net/npf/npf_sendpkt.c npf file net/npf/npf_worker.c npf +file net/npf/npf_os.c npf +file net/npf/npf_ifaddr.c npf + # LPM file net/npf/lpm.c npf Index: src/sys/net/npf/npf_ctl.c diff -u src/sys/net/npf/npf_ctl.c:1.45 src/sys/net/npf/npf_ctl.c:1.46 --- src/sys/net/npf/npf_ctl.c:1.45 Mon Dec 26 23:05:06 2016 +++ src/sys/net/npf/npf_ctl.c Mon Jan 2 21:49:51 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: npf_ctl.c,v 1.45 2016/12/26 23:05:06 christos Exp $ */ +/* $NetBSD: npf_ctl.c,v 1.46 2017/01/02 21:49:51 rmind Exp $ */ /*- * Copyright (c) 2009-2014 The NetBSD Foundation, Inc. @@ -38,7 +38,7 @@ #ifdef _KERNEL #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.45 2016/12/26 23:05:06 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.46 2017/01/02 21:49:51 rmind Exp $"); #include <sys/param.h> #include <sys/conf.h> @@ -108,7 +108,7 @@ npf_mk_table_entries(npf_table_t *t, pro } static int __noinline -npf_mk_tables(npf_tableset_t *tblset, prop_array_t tables, +npf_mk_tables(npf_t *npf, npf_tableset_t *tblset, prop_array_t tables, prop_dictionary_t errdict) { prop_object_iterator_t it; @@ -160,9 +160,6 @@ npf_mk_tables(npf_tableset_t *tblset, pr error = EINVAL; break; } - if (type == NPF_TABLE_HASH) { - size = 1024; /* XXX */ - } /* Create and insert the table. */ t = npf_table_create(name, (u_int)tid, type, blob, size); @@ -558,7 +555,7 @@ npfctl_load(npf_t *npf, u_long cmd, void goto fail; } tblset = npf_tableset_create(nitems); - error = npf_mk_tables(tblset, tables, errdict); + error = npf_mk_tables(npf, tblset, tables, errdict); if (error) { goto fail; } Index: src/sys/net/npf/npf_impl.h diff -u src/sys/net/npf/npf_impl.h:1.65 src/sys/net/npf/npf_impl.h:1.66 --- src/sys/net/npf/npf_impl.h:1.65 Wed Dec 28 21:55:04 2016 +++ src/sys/net/npf/npf_impl.h Mon Jan 2 21:49:51 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: npf_impl.h,v 1.65 2016/12/28 21:55:04 christos Exp $ */ +/* $NetBSD: npf_impl.h,v 1.66 2017/01/02 21:49:51 rmind Exp $ */ /*- * Copyright (c) 2009-2014 The NetBSD Foundation, Inc. @@ -247,6 +247,10 @@ void npf_ifmap_flush(npf_t *); u_int npf_ifmap_getid(npf_t *, const ifnet_t *); const char * npf_ifmap_getname(npf_t *, const u_int); +void npf_ifaddr_init(npf_t *); +void npf_ifaddr_sync(npf_t *, ifnet_t *); +void npf_ifaddr_flush(npf_t *, ifnet_t *); + /* Packet filter hooks. */ int npf_pfil_register(bool); void npf_pfil_unregister(bool); @@ -297,12 +301,14 @@ void npf_tableset_destroy(npf_tableset_ int npf_tableset_insert(npf_tableset_t *, npf_table_t *); npf_table_t * npf_tableset_getbyname(npf_tableset_t *, const char *); npf_table_t * npf_tableset_getbyid(npf_tableset_t *, u_int); +npf_table_t * npf_tableset_swap(npf_tableset_t *, npf_table_t *); void npf_tableset_reload(npf_t *, npf_tableset_t *, npf_tableset_t *); int npf_tableset_export(npf_t *, const npf_tableset_t *, prop_array_t); npf_table_t * npf_table_create(const char *, u_int, int, void *, size_t); void npf_table_destroy(npf_table_t *); +u_int npf_table_getid(npf_table_t *); int npf_table_check(npf_tableset_t *, const char *, u_int, int); int npf_table_insert(npf_table_t *, const int, const npf_addr_t *, const npf_netmask_t); Index: src/sys/net/npf/npf_os.c diff -u src/sys/net/npf/npf_os.c:1.2 src/sys/net/npf/npf_os.c:1.3 --- src/sys/net/npf/npf_os.c:1.2 Mon Dec 26 23:59:47 2016 +++ src/sys/net/npf/npf_os.c Mon Jan 2 21:49:51 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: npf_os.c,v 1.2 2016/12/26 23:59:47 rmind Exp $ */ +/* $NetBSD: npf_os.c,v 1.3 2017/01/02 21:49:51 rmind Exp $ */ /*- * Copyright (c) 2009-2016 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ #ifdef _KERNEL #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: npf_os.c,v 1.2 2016/12/26 23:59:47 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: npf_os.c,v 1.3 2017/01/02 21:49:51 rmind Exp $"); #ifdef _KERNEL_OPT #include "pf.h" @@ -150,6 +150,7 @@ npf_init(void) npf = npf_create(0, NULL, &kern_ifops); npf_setkernctx(npf); npf_pfil_register(true); + npf_ifaddr_init(npf); #ifdef _MODULE devmajor_t bmajor = NODEVMAJOR, cmajor = NODEVMAJOR; @@ -196,7 +197,6 @@ npfattach(int nunits) static int npf_dev_open(dev_t dev, int flag, int mode, lwp_t *l) { - /* Available only for super-user. */ if (kauth_authorize_network(l->l_cred, KAUTH_NETWORK_FIREWALL, KAUTH_REQ_NETWORK_FIREWALL_FW, NULL, NULL, NULL)) { @@ -354,13 +354,37 @@ npf_ifhook(void *arg, unsigned long cmd, switch (cmd) { case PFIL_IFNET_ATTACH: npf_ifmap_attach(npf, ifp); + npf_ifaddr_sync(npf, ifp); break; case PFIL_IFNET_DETACH: npf_ifmap_detach(npf, ifp); + npf_ifaddr_flush(npf, ifp); break; } } +static void +npf_ifaddrhook(void *arg, u_long cmd, void *arg2) +{ + npf_t *npf = npf_getkernctx(); + struct ifaddr *ifa = arg2; + + switch (cmd) { + case SIOCSIFADDR: + case SIOCAIFADDR: + case SIOCDIFADDR: +#ifdef INET6 + case SIOCSIFADDR_IN6: + case SIOCAIFADDR_IN6: + case SIOCDIFADDR_IN6: +#endif + break; + default: + return; + } + npf_ifaddr_sync(npf, ifa->ifa_ifp); +} + /* * npf_pfil_register: register pfil(9) hooks. */ @@ -380,7 +404,13 @@ npf_pfil_register(bool init) error = ENOENT; goto out; } - error = pfil_add_ihook(npf_ifhook, NULL, PFIL_IFNET, npf_ph_if); + + error = pfil_add_ihook(npf_ifhook, NULL, + PFIL_IFNET, npf_ph_if); + KASSERT(error == 0); + + error = pfil_add_ihook(npf_ifaddrhook, NULL, + PFIL_IFADDR, npf_ph_if); KASSERT(error == 0); } if (init) { @@ -432,7 +462,10 @@ npf_pfil_unregister(bool fini) KERNEL_LOCK(1, NULL); if (fini && npf_ph_if) { - (void)pfil_remove_ihook(npf_ifhook, NULL, PFIL_IFNET, npf_ph_if); + (void)pfil_remove_ihook(npf_ifhook, NULL, + PFIL_IFNET, npf_ph_if); + (void)pfil_remove_ihook(npf_ifaddrhook, NULL, + PFIL_IFADDR, npf_ph_if); } if (npf_ph_inet) { (void)pfil_remove_hook(npfkern_packet_handler, npf, Index: src/sys/net/npf/npf_worker.c diff -u src/sys/net/npf/npf_worker.c:1.2 src/sys/net/npf/npf_worker.c:1.3 --- src/sys/net/npf/npf_worker.c:1.2 Mon Dec 26 23:05:06 2016 +++ src/sys/net/npf/npf_worker.c Mon Jan 2 21:49:51 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: npf_worker.c,v 1.2 2016/12/26 23:05:06 christos Exp $ */ +/* $NetBSD: npf_worker.c,v 1.3 2017/01/02 21:49:51 rmind Exp $ */ /*- * Copyright (c) 2010-2015 The NetBSD Foundation, Inc. @@ -31,7 +31,7 @@ #ifdef _KERNEL #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: npf_worker.c,v 1.2 2016/12/26 23:05:06 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: npf_worker.c,v 1.3 2017/01/02 21:49:51 rmind Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -73,9 +73,8 @@ npf_worker_sysinit(unsigned nworkers) mutex_init(&wrk->worker_lock, MUTEX_DEFAULT, IPL_SOFTNET); cv_init(&wrk->worker_cv, "npfgccv"); - if (kthread_create(PRI_NONE, KTHREAD_MPSAFE | - KTHREAD_MUSTJOIN, NULL, npf_worker, wrk, &wrk->worker_lwp, - "npfgc-%u", i)) { + if (kthread_create(PRI_NONE, KTHREAD_MPSAFE | KTHREAD_MUSTJOIN, + NULL, npf_worker, wrk, &wrk->worker_lwp, "npfgc-%u", i)) { npf_worker_sysfini(); return ENOMEM; } Index: src/sys/net/npf/npf_tableset.c diff -u src/sys/net/npf/npf_tableset.c:1.25 src/sys/net/npf/npf_tableset.c:1.26 --- src/sys/net/npf/npf_tableset.c:1.25 Mon Dec 26 23:05:06 2016 +++ src/sys/net/npf/npf_tableset.c Mon Jan 2 21:49:51 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: npf_tableset.c,v 1.25 2016/12/26 23:05:06 christos Exp $ */ +/* $NetBSD: npf_tableset.c,v 1.26 2017/01/02 21:49:51 rmind Exp $ */ /*- * Copyright (c) 2009-2016 The NetBSD Foundation, Inc. @@ -42,7 +42,7 @@ #ifdef _KERNEL #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.25 2016/12/26 23:05:06 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: npf_tableset.c,v 1.26 2017/01/02 21:49:51 rmind Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -183,6 +183,21 @@ npf_tableset_insert(npf_tableset_t *ts, return error; } +npf_table_t * +npf_tableset_swap(npf_tableset_t *ts, npf_table_t *newt) +{ + const u_int tid = newt->t_id; + npf_table_t *oldt = ts->ts_map[tid]; + + KASSERT(tid < ts->ts_nitems); + KASSERT(oldt->t_id == newt->t_id); + + newt->t_refcnt = oldt->t_refcnt; + oldt->t_refcnt = 0; + + return atomic_swap_ptr(&ts->ts_map[tid], newt); +} + /* * npf_tableset_getbyname: look for a table in the set given the name. */ @@ -354,7 +369,8 @@ npf_table_create(const char *name, u_int LIST_INIT(&t->t_list); break; case NPF_TABLE_HASH: - t->t_hashl = hashinit(1024, HASH_LIST, true, &t->t_hashmask); + size = MIN(size, 128); + t->t_hashl = hashinit(size, HASH_LIST, true, &t->t_hashmask); if (t->t_hashl == NULL) { goto out; } @@ -409,6 +425,12 @@ npf_table_destroy(npf_table_t *t) kmem_free(t, sizeof(npf_table_t)); } +u_int +npf_table_getid(npf_table_t *t) +{ + return t->t_id; +} + /* * npf_table_check: validate the name, ID and type. */ Added files: Index: src/sys/net/npf/npf_ifaddr.c diff -u /dev/null src/sys/net/npf/npf_ifaddr.c:1.1 --- /dev/null Mon Jan 2 21:49:51 2017 +++ src/sys/net/npf/npf_ifaddr.c Mon Jan 2 21:49:51 2017 @@ -0,0 +1,179 @@ +/* $NetBSD: npf_ifaddr.c,v 1.1 2017/01/02 21:49:51 rmind Exp $ */ + +/*- + * Copyright (c) 2014 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Mindaugas Rasiukevicius. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * NPF network interface handling module. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: npf_ifaddr.c,v 1.1 2017/01/02 21:49:51 rmind Exp $"); + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/kmem.h> + +#include <net/if.h> +#include <netinet/in.h> +#include <netinet6/in6_var.h> + +#include "npf_impl.h" + +void +npf_ifaddr_init(npf_t *npf) +{ + ifnet_t *ifp; + + KERNEL_LOCK(1, NULL); + IFNET_LOCK(); + IFNET_WRITER_FOREACH(ifp) { + npf_ifaddr_sync(npf, ifp); + } + IFNET_UNLOCK(); + KERNEL_UNLOCK_ONE(NULL); +} + +static npf_table_t * +lookup_ifnet_table(npf_t *npf, ifnet_t *ifp) +{ + const npf_ifops_t *ifops = npf->ifops; + char tname[NPF_TABLE_MAXNAMELEN]; + npf_tableset_t *ts; + const char *ifname; + npf_table_t *t; + u_int tid; + + /* Get the interface name and prefix it. */ + ifname = ifops->getname(ifp); + snprintf(tname, sizeof(tname), ".ifnet-%s", ifname); + + KERNEL_LOCK(1, NULL); + npf_config_enter(npf); + ts = npf_config_tableset(npf); + + /* + * Check whether this interface is of any interest to us. + */ + t = npf_tableset_getbyname(ts, tname); + if (!t) { + goto out; + } + tid = npf_table_getid(t); + + /* Create a new NPF table for the interface. */ + t = npf_table_create(tname, tid, NPF_TABLE_HASH, NULL, 16); + if (!t) { + goto out; + } + return t; +out: + npf_config_exit(npf); + KERNEL_UNLOCK_ONE(NULL); + return NULL; +} + +static void +replace_ifnet_table(npf_t *npf, npf_table_t *newt) +{ + npf_tableset_t *ts = npf_config_tableset(npf); + npf_table_t *oldt; + + KERNEL_UNLOCK_ONE(NULL); + + /* + * Finally, swap the tables and issue a sync barrier. + */ + oldt = npf_tableset_swap(ts, newt); + npf_config_sync(npf); + npf_config_exit(npf); + + /* At this point, it is safe to destroy the old table. */ + npf_table_destroy(oldt); +} + +void +npf_ifaddr_sync(npf_t *npf, ifnet_t *ifp) +{ + npf_table_t *t; + struct ifaddr *ifa; + + /* + * First, check whether this interface is of any interest to us. + * + * => Acquires npf-config-lock and kernel-lock on success. + */ + t = lookup_ifnet_table(npf, ifp); + if (!t) + return; + + /* + * Populate the table with the interface addresses. + * Note: currently, this list is protected by the kernel-lock. + */ + IFADDR_FOREACH(ifa, ifp) { + struct sockaddr *sa = ifa->ifa_addr; + const void *p = NULL; + int alen = 0; + + if (sa->sa_family == AF_INET) { + const struct sockaddr_in *sin4 = satosin(sa); + alen = sizeof(struct in_addr); + p = &sin4->sin_addr; + } + if (sa->sa_family == AF_INET6) { + const struct sockaddr_in6 *sin6 = satosin6(sa); + alen = sizeof(struct in6_addr); + p = &sin6->sin6_addr; + } + if (alen) { + npf_addr_t addr; + memcpy(&addr, p, alen); + npf_table_insert(t, alen, &addr, NPF_NO_NETMASK); + } + } + + /* Publish the new table. */ + replace_ifnet_table(npf, t); +} + +void +npf_ifaddr_flush(npf_t *npf, ifnet_t *ifp) +{ + npf_table_t *t; + + /* + * Flush: just load an empty table. + */ + t = lookup_ifnet_table(npf, ifp); + if (!t) { + return; + } + replace_ifnet_table(npf, t); +}