Module Name: src
Committed By: martin
Date: Fri Oct 4 08:06:35 UTC 2019
Modified Files:
src/lib/libnpf [netbsd-9]: libnpf.3 npf.c npf.h
src/sys/net/npf [netbsd-9]: npf_conn.c npf_ctl.c npf_if.c npf_impl.h
npf_ruleset.c
src/usr.sbin/npf/npfctl [netbsd-9]: npf.conf.5 npf_build.c npf_parse.y
npf_scan.l npfctl.8 npfctl.c npfctl.h
src/usr.sbin/npf/npftest [netbsd-9]: npftest.conf
Log Message:
Pull up following revision(s) (requested by rmind in ticket #282):
usr.sbin/npf/npfctl/npf_build.c: revision 1.53
lib/libnpf/npf.c: revision 1.48
usr.sbin/npf/npfctl/npfctl.h: revision 1.50
sys/net/npf/npf_impl.h: revision 1.80
usr.sbin/npf/npfctl/npfctl.h: revision 1.51
sys/net/npf/npf_ruleset.c: revision 1.49
usr.sbin/npf/npfctl/npf.conf.5: revision 1.90
sys/net/npf/npf_ctl.c: revision 1.59
lib/libnpf/libnpf.3: revision 1.11
usr.sbin/npf/npfctl/npf_parse.y: revision 1.50
usr.sbin/npf/npftest/npftest.conf: revision 1.8
usr.sbin/npf/npfctl/npfctl.c: revision 1.62
usr.sbin/npf/npfctl/npfctl.c: revision 1.63
usr.sbin/npf/npfctl/npf_scan.l: revision 1.30
usr.sbin/npf/npfctl/npfctl.8: revision 1.22
lib/libnpf/npf.h: revision 1.38
usr.sbin/npf/npfctl/npfctl.8: revision 1.23
usr.sbin/npf/npfctl/npfctl.8: revision 1.24
sys/net/npf/npf_if.c: revision 1.11
sys/net/npf/npf_if.c: revision 1.12
usr.sbin/npf/npfctl/npf.conf.5: revision 1.89
sys/net/npf/npf_conn.c: revision 1.30
usr.sbin/npf/npfctl/npf_build.c: revision 1.52
npfctl: implement table replace subcommand.
Contributed by Timshel Knoll-Miller.
NPF ifmap: rework and fix a few small bugs.
npfctl: implement table replace subcommand.
Contributed by Timshel Knoll-Miller.
(missed a file in previous commit; cvs is so helpful..)
libnpf/npfctl: support dynamic NAT rulesets using a name prefix.
Use -width Pa for FILES.
Fix pasto in table replace -t type
Use -width Pa for FILES.
npf_ifmap_copylogname: be more defensive.
To generate a diff of this commit:
cvs rdiff -u -r1.9.2.1 -r1.9.2.2 src/lib/libnpf/libnpf.3
cvs rdiff -u -r1.46.2.1 -r1.46.2.2 src/lib/libnpf/npf.c
cvs rdiff -u -r1.36.2.1 -r1.36.2.2 src/lib/libnpf/npf.h
cvs rdiff -u -r1.27.2.1 -r1.27.2.2 src/sys/net/npf/npf_conn.c
cvs rdiff -u -r1.54.2.3 -r1.54.2.4 src/sys/net/npf/npf_ctl.c
cvs rdiff -u -r1.9.4.1 -r1.9.4.2 src/sys/net/npf/npf_if.c
cvs rdiff -u -r1.75.2.3 -r1.75.2.4 src/sys/net/npf/npf_impl.h
cvs rdiff -u -r1.48 -r1.48.2.1 src/sys/net/npf/npf_ruleset.c
cvs rdiff -u -r1.88 -r1.88.2.1 src/usr.sbin/npf/npfctl/npf.conf.5
cvs rdiff -u -r1.50.2.1 -r1.50.2.2 src/usr.sbin/npf/npfctl/npf_build.c
cvs rdiff -u -r1.49 -r1.49.2.1 src/usr.sbin/npf/npfctl/npf_parse.y
cvs rdiff -u -r1.29 -r1.29.2.1 src/usr.sbin/npf/npfctl/npf_scan.l
cvs rdiff -u -r1.21 -r1.21.2.1 src/usr.sbin/npf/npfctl/npfctl.8
cvs rdiff -u -r1.60.2.1 -r1.60.2.2 src/usr.sbin/npf/npfctl/npfctl.c
cvs rdiff -u -r1.48.2.1 -r1.48.2.2 src/usr.sbin/npf/npfctl/npfctl.h
cvs rdiff -u -r1.7 -r1.7.2.1 src/usr.sbin/npf/npftest/npftest.conf
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
Modified files:
Index: src/lib/libnpf/libnpf.3
diff -u src/lib/libnpf/libnpf.3:1.9.2.1 src/lib/libnpf/libnpf.3:1.9.2.2
--- src/lib/libnpf/libnpf.3:1.9.2.1 Sun Sep 1 13:13:13 2019
+++ src/lib/libnpf/libnpf.3 Fri Oct 4 08:06:35 2019
@@ -1,4 +1,4 @@
-.\" $NetBSD: libnpf.3,v 1.9.2.1 2019/09/01 13:13:13 martin Exp $
+.\" $NetBSD: libnpf.3,v 1.9.2.2 2019/10/04 08:06:35 martin Exp $
.\"
.\" Copyright (c) 2011-2019 The NetBSD Foundation, Inc.
.\" All rights reserved.
@@ -27,7 +27,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd August 21, 2019
+.Dd August 25, 2019
.Dt LIBNPF 3
.Os
.Sh NAME
@@ -108,6 +108,15 @@
.Fn npf_table_replace "int fd" "nl_table_t *tl" "npf_error_t *errinfo"
.Ft void
.Fn npf_table_destroy "nl_table_t *tl"
+.\" ---
+.Ft int
+.Fn npf_ruleset_add "int fd" "const char *name" "nl_rule_t *rl" "uint64_t *id"
+.Ft int
+.Fn npf_ruleset_remove "int fd" "const char *name" "uint64_t id"
+.Ft int
+.Fn npf_ruleset_remkey "int fd" "const char *name" "const void *key" "size_t len"
+.Ft int
+.Fn npf_ruleset_flush "int fd" "const char *name"
.\" -----
.Sh DESCRIPTION
The
@@ -352,7 +361,9 @@ Additionally,
may be specified to indicate the translation network;
otherwise, it should be set to
.Dv NPF_NO_NETMASK .
-In such case, a custom algorithm may need to be specified using the
+.Pp
+In order to use the translation network, a custom algorithm may need to
+be specified using the
.Fn npf_nat_setalgo
function.
.\" ---
@@ -368,6 +379,9 @@ Currently, the following algorithms are
Hash of the source and destination addresses.
.It Dv NPF_ALGO_RR
Round-robin for the translation addresses.
+.It Dv NPF_ALGO_NETMAP
+Network-to-network map as described below, but with state tracking.
+It is used when it is necessary to translate the ports.
.El
.Pp
The following are support with static NAT:
@@ -450,6 +464,39 @@ specified by
Destroy the specified table.
.El
.\" -----
+.Ss Ruleset interface
+.Bl -tag -width 4n
+.It Fn npf_ruleset_add "fd" "name" "rl" "id"
+Add a given rule, specified by
+.Fa rl ,
+into the dynamic ruleset named
+.Fa name .
+On success, return 0 and a unique rule ID in the
+.Fa id
+parameter.
+.It Fn npf_ruleset_remove "fd" "name" "id"
+Remove a rule from the dynamic ruleset, specified by
+.Fa name .
+The rule is specified by its unique ID in the
+.Fa id
+parameter.
+.It Fn npf_ruleset_remkey "fd" "name" "key" "len"
+Remove a rule from the dynamic ruleset, specified by
+.Fa name .
+The rule is specified by its key, in the
+.Fa key
+and
+.Fa len
+parameters.
+The key for the rule must have been set during its construction, using the
+.Fn npf_rule_setkey
+routine.
+.It Fn npf_ruleset_flush "fd" "name"
+Clear the dynamic ruleset, specified by
+.Fa name ,
+by removing all its rules.
+.El
+.\" -----
.Sh SEE ALSO
.Xr bpf 4 ,
.Xr npf 7 ,
Index: src/lib/libnpf/npf.c
diff -u src/lib/libnpf/npf.c:1.46.2.1 src/lib/libnpf/npf.c:1.46.2.2
--- src/lib/libnpf/npf.c:1.46.2.1 Sun Sep 1 13:13:13 2019
+++ src/lib/libnpf/npf.c Fri Oct 4 08:06:35 2019
@@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.46.2.1 2019/09/01 13:13:13 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.46.2.2 2019/10/04 08:06:35 martin Exp $");
#include <sys/types.h>
#include <sys/mman.h>
@@ -401,14 +401,31 @@ npf_param_set(nl_config_t *ncf, const ch
* DYNAMIC RULESET INTERFACE.
*/
+static inline bool
+_npf_nat_ruleset_p(const char *name)
+{
+ return strncmp(name, NPF_RULESET_MAP_PREF,
+ sizeof(NPF_RULESET_MAP_PREF) - 1) == 0;
+}
+
int
npf_ruleset_add(int fd, const char *rname, nl_rule_t *rl, uint64_t *id)
{
+ const bool natset = _npf_nat_ruleset_p(rname);
nvlist_t *rule_dict = rl->rule_dict;
nvlist_t *ret_dict;
+ nvlist_add_number(rule_dict, "attr",
+ NPF_RULE_DYNAMIC | nvlist_take_number(rule_dict, "attr"));
+
+ if (natset && !dnvlist_get_bool(rule_dict, "nat-rule", false)) {
+ errno = EINVAL;
+ return errno;
+ }
nvlist_add_string(rule_dict, "ruleset-name", rname);
+ nvlist_add_bool(rule_dict, "nat-ruleset", natset);
nvlist_add_number(rule_dict, "command", NPF_CMD_RULE_ADD);
+
if (nvlist_xfer_ioctl(fd, IOC_NPF_RULE, rule_dict, &ret_dict) == -1) {
return errno;
}
@@ -419,11 +436,14 @@ npf_ruleset_add(int fd, const char *rnam
int
npf_ruleset_remove(int fd, const char *rname, uint64_t id)
{
+ const bool natset = _npf_nat_ruleset_p(rname);
nvlist_t *rule_dict = nvlist_create(0);
nvlist_add_string(rule_dict, "ruleset-name", rname);
+ nvlist_add_bool(rule_dict, "nat-ruleset", natset);
nvlist_add_number(rule_dict, "command", NPF_CMD_RULE_REMOVE);
nvlist_add_number(rule_dict, "id", id);
+
if (nvlist_send_ioctl(fd, IOC_NPF_RULE, rule_dict) == -1) {
return errno;
}
@@ -433,11 +453,14 @@ npf_ruleset_remove(int fd, const char *r
int
npf_ruleset_remkey(int fd, const char *rname, const void *key, size_t len)
{
+ const bool natset = _npf_nat_ruleset_p(rname);
nvlist_t *rule_dict = nvlist_create(0);
nvlist_add_string(rule_dict, "ruleset-name", rname);
+ nvlist_add_bool(rule_dict, "nat-ruleset", natset);
nvlist_add_number(rule_dict, "command", NPF_CMD_RULE_REMKEY);
nvlist_add_binary(rule_dict, "key", key, len);
+
if (nvlist_send_ioctl(fd, IOC_NPF_RULE, rule_dict) == -1) {
return errno;
}
@@ -447,10 +470,13 @@ npf_ruleset_remkey(int fd, const char *r
int
npf_ruleset_flush(int fd, const char *rname)
{
+ const bool natset = _npf_nat_ruleset_p(rname);
nvlist_t *rule_dict = nvlist_create(0);
nvlist_add_string(rule_dict, "ruleset-name", rname);
+ nvlist_add_bool(rule_dict, "nat-ruleset", natset);
nvlist_add_number(rule_dict, "command", NPF_CMD_RULE_FLUSH);
+
if (nvlist_send_ioctl(fd, IOC_NPF_RULE, rule_dict) == -1) {
return errno;
}
@@ -678,10 +704,12 @@ npf_rule_getcode(nl_rule_t *rl, int *typ
int
_npf_ruleset_list(int fd, const char *rname, nl_config_t *ncf)
{
+ const bool natset = _npf_nat_ruleset_p(rname);
nvlist_t *req, *ret;
req = nvlist_create(0);
nvlist_add_string(req, "ruleset-name", rname);
+ nvlist_add_bool(req, "nat-ruleset", natset);
nvlist_add_number(req, "command", NPF_CMD_RULE_LIST);
if (nvlist_xfer_ioctl(fd, IOC_NPF_RULE, req, &ret) == -1) {
Index: src/lib/libnpf/npf.h
diff -u src/lib/libnpf/npf.h:1.36.2.1 src/lib/libnpf/npf.h:1.36.2.2
--- src/lib/libnpf/npf.h:1.36.2.1 Sun Sep 1 13:13:13 2019
+++ src/lib/libnpf/npf.h Fri Oct 4 08:06:35 2019
@@ -56,6 +56,12 @@ typedef struct nl_ext nl_ext_t;
typedef signed long nl_iter_t;
/*
+ * Ruleset prefix(es).
+ */
+
+#define NPF_RULESET_MAP_PREF "map:"
+
+/*
* Extensions API types.
*/
typedef int (*npfext_initfunc_t)(void);
Index: src/sys/net/npf/npf_conn.c
diff -u src/sys/net/npf/npf_conn.c:1.27.2.1 src/sys/net/npf/npf_conn.c:1.27.2.2
--- src/sys/net/npf/npf_conn.c:1.27.2.1 Wed Aug 7 08:28:37 2019
+++ src/sys/net/npf/npf_conn.c Fri Oct 4 08:06:35 2019
@@ -107,7 +107,7 @@
#ifdef _KERNEL
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_conn.c,v 1.27.2.1 2019/08/07 08:28:37 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_conn.c,v 1.27.2.2 2019/10/04 08:06:35 martin Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -782,7 +782,8 @@ npf_conn_export(npf_t *npf, npf_conn_t *
nvlist_add_number(cdict, "flags", con->c_flags);
nvlist_add_number(cdict, "proto", con->c_proto);
if (con->c_ifid) {
- const char *ifname = npf_ifmap_getname(npf, con->c_ifid);
+ char ifname[IFNAMSIZ];
+ npf_ifmap_copyname(npf, con->c_ifid, ifname, sizeof(ifname));
nvlist_add_string(cdict, "ifname", ifname);
}
nvlist_add_binary(cdict, "state", &con->c_state, sizeof(npf_state_t));
Index: src/sys/net/npf/npf_ctl.c
diff -u src/sys/net/npf/npf_ctl.c:1.54.2.3 src/sys/net/npf/npf_ctl.c:1.54.2.4
--- src/sys/net/npf/npf_ctl.c:1.54.2.3 Sun Sep 1 13:21:39 2019
+++ src/sys/net/npf/npf_ctl.c Fri Oct 4 08:06:35 2019
@@ -36,7 +36,7 @@
#ifdef _KERNEL
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.54.2.3 2019/09/01 13:21:39 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.54.2.4 2019/10/04 08:06:35 martin Exp $");
#include <sys/param.h>
#include <sys/conf.h>
@@ -196,7 +196,7 @@ npf_mk_table(npf_t *npf, const nvlist_t
goto out;
}
- t = npf_table_create(name, (u_int)tid, type, blob, size);
+ t = npf_table_create(name, (unsigned)tid, type, blob, size);
if (t == NULL) {
NPF_ERR_DEBUG(errdict);
error = ENOMEM;
@@ -473,7 +473,7 @@ npf_mk_singlenat(npf_t *npf, const nvlis
KASSERT(rl != NULL);
*rlp = rl;
- /* If rule is named, it is a group with NAT policies. */
+ /* If this rule is named, then it is a group with NAT policies. */
if (dnvlist_get_string(nat, "name", NULL)) {
return 0;
}
@@ -816,7 +816,7 @@ npfctl_rule(npf_t *npf, u_long cmd, void
return error;
}
rcmd = dnvlist_get_number(npf_rule, "command", 0);
- natset = dnvlist_get_bool(npf_rule, "nat-rule", false);
+ natset = dnvlist_get_bool(npf_rule, "nat-ruleset", false);
ruleset_name = dnvlist_get_string(npf_rule, "ruleset-name", NULL);
if (!ruleset_name) {
error = EINVAL;
Index: src/sys/net/npf/npf_if.c
diff -u src/sys/net/npf/npf_if.c:1.9.4.1 src/sys/net/npf/npf_if.c:1.9.4.2
--- src/sys/net/npf/npf_if.c:1.9.4.1 Tue Aug 13 14:35:55 2019
+++ src/sys/net/npf/npf_if.c Fri Oct 4 08:06:35 2019
@@ -1,4 +1,5 @@
/*-
+ * Copyright (c) 2019 Mindaugas Rasiukevicius <rmind at noxt eu>
* Copyright (c) 2013 The NetBSD Foundation, Inc.
* All rights reserved.
*
@@ -28,23 +29,34 @@
*/
/*
- * NPF network interface handling module.
+ * NPF network interface handling.
*
- * NPF uses its own interface IDs (npf-if-id). When NPF configuration is
- * (re)loaded, each required interface name is registered and a matching
- * network interface gets an ID assigned. If an interface is not present,
- * it gets an ID on attach.
+ * NPF uses its own interface IDs (npf-if-id). These IDs start from 1.
+ * Zero is reserved to indicate "no interface" case or an interface of
+ * no interest (i.e. not registered).
*
- * IDs start from 1. Zero is reserved to indicate "no interface" case or
- * an interface of no interest (i.e. not registered).
+ * This module provides an interface to primarily handle the following:
*
- * The IDs are mapped synchronously based on interface events which are
- * monitored using pfil(9) hooks.
+ * - Bind a symbolic interface name to NPF interface ID.
+ * - Associate NPF interface ID when the network interface is attached.
+ *
+ * When NPF configuration is (re)loaded, each referenced network interface
+ * name is registered with a unique ID. If the network interface is already
+ * attached, then the ID is associated with it immediately; otherwise, IDs
+ * are associated/disassociated on interface events which are monitored
+ * using pfil(9) hooks.
+ *
+ * To avoid race conditions when an active NPF configuration is updated or
+ * interfaces are detached/attached, the interface names are never removed
+ * and therefore IDs are never re-assigned. The only point when interface
+ * names and IDs are cleared is when the configuration is flushed.
+ *
+ * A linear counter is used for IDs.
*/
#ifdef _KERNEL
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_if.c,v 1.9.4.1 2019/08/13 14:35:55 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_if.c,v 1.9.4.2 2019/10/04 08:06:35 martin Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -55,9 +67,13 @@ __KERNEL_RCSID(0, "$NetBSD: npf_if.c,v 1
#include "npf_impl.h"
typedef struct npf_ifmap {
- char n_ifname[IFNAMSIZ];
+ char ifname[IFNAMSIZ + 1];
} npf_ifmap_t;
+#define NPF_IFMAP_NOID (0U)
+#define NPF_IFMAP_SLOT2ID(npf, slot) ((npf)->ifmap_off + (slot) + 1)
+#define NPF_IFMAP_ID2SLOT(npf, id) ((id) - (npf)->ifmap_off - 1)
+
void
npf_ifmap_init(npf_t *npf, const npf_ifops_t *ifops)
{
@@ -66,8 +82,10 @@ npf_ifmap_init(npf_t *npf, const npf_ifo
KASSERT(ifops != NULL);
ifops->flush((void *)(uintptr_t)0);
+ mutex_init(&npf->ifmap_lock, MUTEX_DEFAULT, IPL_SOFTNET);
npf->ifmap = kmem_zalloc(nbytes, KM_SLEEP);
npf->ifmap_cnt = 0;
+ npf->ifmap_off = 0;
npf->ifops = ifops;
}
@@ -75,128 +93,151 @@ void
npf_ifmap_fini(npf_t *npf)
{
const size_t nbytes = sizeof(npf_ifmap_t) * NPF_MAX_IFMAP;
+ mutex_destroy(&npf->ifmap_lock);
kmem_free(npf->ifmap, nbytes);
}
-static u_int
-npf_ifmap_new(npf_t *npf)
-{
- KASSERT(npf_config_locked_p(npf));
-
- for (u_int i = 0; i < npf->ifmap_cnt; i++)
- if (npf->ifmap[i].n_ifname[0] == '\0')
- return i + 1;
-
- if (npf->ifmap_cnt == NPF_MAX_IFMAP) {
- printf("npf_ifmap_new: out of slots; bump NPF_MAX_IFMAP\n");
- return 0;
- }
- return ++npf->ifmap_cnt;
-}
-
-static u_int
+static unsigned
npf_ifmap_lookup(npf_t *npf, const char *ifname)
{
- KASSERT(npf_config_locked_p(npf));
+ KASSERT(mutex_owned(&npf->ifmap_lock));
- for (u_int i = 0; i < npf->ifmap_cnt; i++) {
- npf_ifmap_t *nim = &npf->ifmap[i];
+ for (unsigned i = 0; i < npf->ifmap_cnt; i++) {
+ npf_ifmap_t *ifmap = &npf->ifmap[i];
- if (nim->n_ifname[0] && strcmp(nim->n_ifname, ifname) == 0)
- return i + 1;
+ if (strcmp(ifmap->ifname, ifname) == 0) {
+ return NPF_IFMAP_SLOT2ID(npf, i);
+ }
}
- return 0;
+ return NPF_IFMAP_NOID;
}
-u_int
+/*
+ * npf_ifmap_register: register an interface name; return an assigned
+ * NPF network ID on success (non-zero).
+ *
+ * This routine is mostly called on NPF configuration (re)load for the
+ * interfaces names referenced by the rules.
+ */
+unsigned
npf_ifmap_register(npf_t *npf, const char *ifname)
{
- npf_ifmap_t *nim;
+ npf_ifmap_t *ifmap;
+ unsigned id, i;
ifnet_t *ifp;
- u_int i;
- npf_config_enter(npf);
- if ((i = npf_ifmap_lookup(npf, ifname)) != 0) {
+ mutex_enter(&npf->ifmap_lock);
+ if ((id = npf_ifmap_lookup(npf, ifname)) != NPF_IFMAP_NOID) {
goto out;
}
- if ((i = npf_ifmap_new(npf)) == 0) {
+ if (npf->ifmap_cnt == NPF_MAX_IFMAP) {
+ printf("npf_ifmap_new: out of slots; bump NPF_MAX_IFMAP\n");
+ id = NPF_IFMAP_NOID;
goto out;
}
- nim = &npf->ifmap[i - 1];
- strlcpy(nim->n_ifname, ifname, IFNAMSIZ);
+ KASSERT(npf->ifmap_cnt < NPF_MAX_IFMAP);
+
+ /* Allocate a new slot and convert and assign an ID. */
+ i = npf->ifmap_cnt++;
+ ifmap = &npf->ifmap[i];
+ strlcpy(ifmap->ifname, ifname, IFNAMSIZ);
+ id = NPF_IFMAP_SLOT2ID(npf, i);
if ((ifp = npf->ifops->lookup(ifname)) != NULL) {
- npf->ifops->setmeta(ifp, (void *)(uintptr_t)i);
+ npf->ifops->setmeta(ifp, (void *)(uintptr_t)id);
}
out:
- npf_config_exit(npf);
- return i;
+ mutex_exit(&npf->ifmap_lock);
+ return id;
}
void
npf_ifmap_flush(npf_t *npf)
{
- KASSERT(npf_config_locked_p(npf));
-
- for (u_int i = 0; i < npf->ifmap_cnt; i++) {
- npf->ifmap[i].n_ifname[0] = '\0';
+ mutex_enter(&npf->ifmap_lock);
+ npf->ifops->flush((void *)(uintptr_t)NPF_IFMAP_NOID);
+ for (unsigned i = 0; i < npf->ifmap_cnt; i++) {
+ npf->ifmap[i].ifname[0] = '\0';
}
npf->ifmap_cnt = 0;
- npf->ifops->flush((void *)(uintptr_t)0);
+
+ /*
+ * Reset the ID counter if reaching the overflow; this is not
+ * realistic, but we maintain correctness.
+ */
+ if (npf->ifmap_off < (UINT_MAX - NPF_MAX_IFMAP)) {
+ npf->ifmap_off += NPF_MAX_IFMAP;
+ } else {
+ npf->ifmap_off = 0;
+ }
+ mutex_exit(&npf->ifmap_lock);
}
-u_int
+/*
+ * npf_ifmap_getid: get the ID for the given network interface.
+ *
+ * => This routine is typically called from the packet handler when
+ * matching whether the packet is on particular network interface.
+ *
+ * => This routine is lock-free; if the NPF configuration is flushed
+ * while the packet is in-flight, the ID will not match because we
+ * keep the IDs linear.
+ */
+unsigned
npf_ifmap_getid(npf_t *npf, const ifnet_t *ifp)
{
- const u_int i = (uintptr_t)npf->ifops->getmeta(ifp);
- KASSERT(i <= npf->ifmap_cnt);
- return i;
+ const unsigned id = (uintptr_t)npf->ifops->getmeta(ifp);
+ return id;
}
/*
- * This function is toxic; it can return garbage since we don't
- * lock, but it is only used temporarily and only for logging.
+ * npf_ifmap_copylogname: this function is toxic; it can return garbage
+ * as we don't lock, but it is only used temporarily and only for logging.
*/
void
-npf_ifmap_copyname(npf_t *npf, u_int id, char *buf, size_t len)
+npf_ifmap_copylogname(npf_t *npf, unsigned id, char *buf, size_t len)
{
- if (id > 0 && id < npf->ifmap_cnt)
- strlcpy(buf, npf->ifmap[id - 1].n_ifname,
- MIN(len, sizeof(npf->ifmap[id - 1].n_ifname)));
- else
+ const unsigned i = NPF_IFMAP_ID2SLOT(npf, id);
+
+ membar_consumer();
+
+ if (id != NPF_IFMAP_NOID && i < NPF_MAX_IFMAP) {
+ /*
+ * Lock-free access is safe as there is an extra byte
+ * with a permanent NUL terminator at the end.
+ */
+ const npf_ifmap_t *ifmap = &npf->ifmap[i];
+ strlcpy(buf, ifmap->ifname, MIN(len, IFNAMSIZ));
+ } else {
strlcpy(buf, "???", len);
+ }
}
-const char *
-npf_ifmap_getname(npf_t *npf, const u_int id)
+void
+npf_ifmap_copyname(npf_t *npf, unsigned id, char *buf, size_t len)
{
- const char *ifname;
-
- KASSERT(npf_config_locked_p(npf));
- KASSERT(id > 0 && id <= npf->ifmap_cnt);
-
- ifname = npf->ifmap[id - 1].n_ifname;
- KASSERT(ifname[0] != '\0');
- return ifname;
+ mutex_enter(&npf->ifmap_lock);
+ npf_ifmap_copylogname(npf, id, buf, len);
+ mutex_exit(&npf->ifmap_lock);
}
__dso_public void
npfk_ifmap_attach(npf_t *npf, ifnet_t *ifp)
{
const npf_ifops_t *ifops = npf->ifops;
- u_int i;
+ unsigned id;
- npf_config_enter(npf);
- i = npf_ifmap_lookup(npf, ifops->getname(ifp));
- ifops->setmeta(ifp, (void *)(uintptr_t)i);
- npf_config_exit(npf);
+ mutex_enter(&npf->ifmap_lock);
+ id = npf_ifmap_lookup(npf, ifops->getname(ifp));
+ ifops->setmeta(ifp, (void *)(uintptr_t)id);
+ mutex_exit(&npf->ifmap_lock);
}
__dso_public void
npfk_ifmap_detach(npf_t *npf, ifnet_t *ifp)
{
/* Diagnostic. */
- npf_config_enter(npf);
- npf->ifops->setmeta(ifp, (void *)(uintptr_t)0);
- npf_config_exit(npf);
+ mutex_enter(&npf->ifmap_lock);
+ npf->ifops->setmeta(ifp, (void *)(uintptr_t)NPF_IFMAP_NOID);
+ mutex_exit(&npf->ifmap_lock);
}
Index: src/sys/net/npf/npf_impl.h
diff -u src/sys/net/npf/npf_impl.h:1.75.2.3 src/sys/net/npf/npf_impl.h:1.75.2.4
--- src/sys/net/npf/npf_impl.h:1.75.2.3 Sun Sep 1 13:21:39 2019
+++ src/sys/net/npf/npf_impl.h Fri Oct 4 08:06:35 2019
@@ -234,6 +234,8 @@ struct npf {
const npf_ifops_t * ifops;
struct npf_ifmap * ifmap;
unsigned ifmap_cnt;
+ unsigned ifmap_off;
+ kmutex_t ifmap_lock;
/* Associated worker thread. */
unsigned worker_id;
@@ -319,8 +321,8 @@ void npf_ifmap_fini(npf_t *);
u_int npf_ifmap_register(npf_t *, const char *);
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_ifmap_copyname(npf_t *, u_int, char *, size_t);
+void npf_ifmap_copylogname(npf_t *, unsigned, char *, size_t);
+void npf_ifmap_copyname(npf_t *, unsigned, char *, size_t);
void npf_ifaddr_sync(npf_t *, ifnet_t *);
void npf_ifaddr_flush(npf_t *, ifnet_t *);
Index: src/sys/net/npf/npf_ruleset.c
diff -u src/sys/net/npf/npf_ruleset.c:1.48 src/sys/net/npf/npf_ruleset.c:1.48.2.1
--- src/sys/net/npf/npf_ruleset.c:1.48 Tue Jul 23 00:52:01 2019
+++ src/sys/net/npf/npf_ruleset.c Fri Oct 4 08:06:35 2019
@@ -33,7 +33,7 @@
#ifdef _KERNEL
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.48 2019/07/23 00:52:01 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.48.2.1 2019/10/04 08:06:35 martin Exp $");
#include <sys/param.h>
#include <sys/types.h>
@@ -680,7 +680,8 @@ npf_rule_export(npf_t *npf, const npf_ru
nvlist_add_binary(rule, "code", rl->r_code, rl->r_clen);
}
if (rl->r_ifid) {
- const char *ifname = npf_ifmap_getname(npf, rl->r_ifid);
+ char ifname[IFNAMSIZ];
+ npf_ifmap_copyname(npf, rl->r_ifid, ifname, sizeof(ifname));
nvlist_add_string(rule, "ifname", ifname);
}
nvlist_add_number(rule, "id", rl->r_id);
Index: src/usr.sbin/npf/npfctl/npf.conf.5
diff -u src/usr.sbin/npf/npfctl/npf.conf.5:1.88 src/usr.sbin/npf/npfctl/npf.conf.5:1.88.2.1
--- src/usr.sbin/npf/npfctl/npf.conf.5:1.88 Tue Jul 23 14:20:22 2019
+++ src/usr.sbin/npf/npfctl/npf.conf.5 Fri Oct 4 08:06:34 2019
@@ -1,4 +1,4 @@
-.\" $NetBSD: npf.conf.5,v 1.88 2019/07/23 14:20:22 wiz Exp $
+.\" $NetBSD: npf.conf.5,v 1.88.2.1 2019/10/04 08:06:34 martin Exp $
.\"
.\" Copyright (c) 2009-2019 The NetBSD Foundation, Inc.
.\" All rights reserved.
@@ -27,7 +27,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd May 19, 2019
+.Dd August 25, 2019
.Dt NPF.CONF 5
.Os
.Sh NAME
@@ -356,6 +356,11 @@ redirecting the public port 9022 to the
.Pp
.Dl map $ext_if dynamic proto tcp 10.1.1.2 port 22 <- $ext_if port 9022
.Pp
+In the regular dynamic NAT case, it is also possible to disable port
+translation using the
+.Cm no-ports
+flag.
+.Pp
The translation address can also be dynamic, based on the interface.
The following would select the IPv4 address(es) currently assigned to the
interface:
@@ -528,13 +533,15 @@ table-def = "table" table-id "type" ( "i
# Mapping for address translation.
-map = "map" interface
+map = map-common | map-ruleset
+map-common = "map" interface
( "static" [ "algo" map-algo ] | "dynamic" )
[ map-flags ] [ proto ]
map-seg ( "->" | "<-" | "<->" ) map-seg
[ "pass" [ proto ] filt-opts ]
+map-ruleset = "map" "ruleset" group-opts
-map-algo = "npt66"
+map-algo = "ip-hash" | "round-robin" | "netmap" | "npt66"
map-flags = "no-ports"
map-seg = ( addr-mask | interface ) [ port-opts ]
@@ -582,7 +589,7 @@ addr-mask = addr [ "/" mask ]
.Ed
.\" -----
.Sh FILES
-.Bl -tag -width /usr/share/examples/npf -compact
+.Bl -tag -width Pa -compact
.It Pa /dev/npf
control device
.It Pa /etc/npf.conf
Index: src/usr.sbin/npf/npfctl/npf_build.c
diff -u src/usr.sbin/npf/npfctl/npf_build.c:1.50.2.1 src/usr.sbin/npf/npfctl/npf_build.c:1.50.2.2
--- src/usr.sbin/npf/npfctl/npf_build.c:1.50.2.1 Sun Aug 11 10:10:23 2019
+++ src/usr.sbin/npf/npfctl/npf_build.c Fri Oct 4 08:06:34 2019
@@ -32,7 +32,7 @@
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: npf_build.c,v 1.50.2.1 2019/08/11 10:10:23 martin Exp $");
+__RCSID("$NetBSD: npf_build.c,v 1.50.2.2 2019/10/04 08:06:34 martin Exp $");
#include <sys/types.h>
#define __FAVOR_BSD
@@ -151,25 +151,32 @@ npfctl_debug_addif(const char *ifname)
return 0;
}
-unsigned
-npfctl_table_getid(const char *name)
+nl_table_t *
+npfctl_table_getbyname(nl_config_t *ncf, const char *name)
{
- unsigned tid = (unsigned)-1;
nl_iter_t i = NPF_ITER_BEGIN;
nl_table_t *tl;
/* XXX dynamic ruleset */
- if (!npf_conf) {
- return (unsigned)-1;
+ if (!ncf) {
+ return NULL;
}
- while ((tl = npf_table_iterate(npf_conf, &i)) != NULL) {
+ while ((tl = npf_table_iterate(ncf, &i)) != NULL) {
const char *tname = npf_table_getname(tl);
if (strcmp(tname, name) == 0) {
- tid = npf_table_getid(tl);
break;
}
}
- return tid;
+ return tl;
+}
+
+unsigned
+npfctl_table_getid(const char *name)
+{
+ nl_table_t *tl;
+
+ tl = npfctl_table_getbyname(npf_conf, name);
+ return tl ? npf_table_getid(tl) : (unsigned)-1;
}
const char *
@@ -530,16 +537,32 @@ npfctl_build_rproc(const char *name, npf
npf_rproc_insert(npf_conf, rp);
}
+/*
+ * npfctl_build_maprset: create and insert a NAT ruleset.
+ */
void
npfctl_build_maprset(const char *name, int attr, const char *ifname)
{
const int attr_di = (NPF_RULE_IN | NPF_RULE_OUT);
nl_rule_t *rl;
+ bool natset;
+ int err;
+
+ /* Validate the prefix. */
+ err = npfctl_nat_ruleset_p(name, &natset);
+ if (!natset) {
+ yyerror("NAT ruleset names must be prefixed with `"
+ NPF_RULESET_MAP_PREF "`");
+ }
+ if (err) {
+ yyerror("NAT ruleset is missing a name (only prefix found)");
+ }
/* If no direction is not specified, then both. */
if ((attr & attr_di) == 0) {
attr |= attr_di;
}
+
/* Allow only "in/out" attributes. */
attr = NPF_RULE_GROUP | NPF_RULE_DYNAMIC | (attr & attr_di);
rl = npf_rule_create(name, attr, ifname);
@@ -859,13 +882,22 @@ npfctl_build_natseg(int sd, int type, un
}
}
- if (nt1) {
- npf_rule_setprio(nt1, NPF_PRI_LAST);
- npf_nat_insert(npf_conf, nt1);
- }
- if (nt2) {
- npf_rule_setprio(nt2, NPF_PRI_LAST);
- npf_nat_insert(npf_conf, nt2);
+ if (npf_conf) {
+ if (nt1) {
+ npf_rule_setprio(nt1, NPF_PRI_LAST);
+ npf_nat_insert(npf_conf, nt1);
+ }
+ if (nt2) {
+ npf_rule_setprio(nt2, NPF_PRI_LAST);
+ npf_nat_insert(npf_conf, nt2);
+ }
+ } else {
+ // XXX/TODO: need to refactor a bit to enable this..
+ if (nt1 && nt2) {
+ errx(EXIT_FAILURE, "bidirectional NAT is currently "
+ "not yet supported in the dynamic rules");
+ }
+ the_rule = nt1 ? nt1 : nt2;
}
}
@@ -873,15 +905,13 @@ npfctl_build_natseg(int sd, int type, un
* npfctl_fill_table: fill NPF table with entries from a specified file.
*/
static void
-npfctl_fill_table(nl_table_t *tl, u_int type, const char *fname)
+npfctl_fill_table(nl_table_t *tl, u_int type, const char *fname, FILE *fp)
{
char *buf = NULL;
int l = 0;
- FILE *fp;
size_t n;
- fp = fopen(fname, "r");
- if (fp == NULL) {
+ if (fp == NULL && (fp = fopen(fname, "r")) == NULL) {
err(EXIT_FAILURE, "open '%s'", fname);
}
while (l++, getline(&buf, &n, fp) != -1) {
@@ -908,6 +938,23 @@ npfctl_fill_table(nl_table_t *tl, u_int
}
/*
+ * npfctl_load_table: create an NPF table and fill with contents from a file.
+ */
+nl_table_t *
+npfctl_load_table(const char *tname, int tid, u_int type,
+ const char *fname, FILE *fp)
+{
+ nl_table_t *tl;
+
+ tl = npf_table_create(tname, tid, type);
+ if (tl && fname) {
+ npfctl_fill_table(tl, type, fname, fp);
+ }
+
+ return tl;
+}
+
+/*
* npfctl_build_table: create an NPF table, add to the configuration and,
* if required, fill with contents from a file.
*/
@@ -916,15 +963,13 @@ npfctl_build_table(const char *tname, u_
{
nl_table_t *tl;
- tl = npf_table_create(tname, npfctl_tid_counter++, type);
- assert(tl != NULL);
-
- if (fname) {
- npfctl_fill_table(tl, type, fname);
- } else if (type == NPF_TABLE_CONST) {
+ if (type == NPF_TABLE_CONST && !fname) {
yyerror("table type 'const' must be loaded from a file");
}
+ tl = npfctl_load_table(tname, npfctl_tid_counter++, type, fname, NULL);
+ assert(tl != NULL);
+
if (npf_table_insert(npf_conf, tl)) {
yyerror("table '%s' is already defined", tname);
}
@@ -939,9 +984,13 @@ npfctl_ifnet_table(const char *ifname)
{
char tname[NPF_TABLE_MAXNAMELEN];
nl_table_t *tl;
- u_int tid;
+ unsigned tid;
snprintf(tname, sizeof(tname), NPF_IFNET_TABLE_PREF "%s", ifname);
+ if (!npf_conf) {
+ errx(EXIT_FAILURE, "expression `ifaddrs(%s)` is currently "
+ "not yet supported in dynamic rules", ifname);
+ }
tid = npfctl_table_getid(tname);
if (tid == (unsigned)-1) {
@@ -949,7 +998,7 @@ npfctl_ifnet_table(const char *ifname)
tl = npf_table_create(tname, tid, NPF_TABLE_IFADDR);
(void)npf_table_insert(npf_conf, tl);
}
- return npfvar_create_element(NPFVAR_TABLE, &tid, sizeof(u_int));
+ return npfvar_create_element(NPFVAR_TABLE, &tid, sizeof(unsigned));
}
/*
Index: src/usr.sbin/npf/npfctl/npf_parse.y
diff -u src/usr.sbin/npf/npfctl/npf_parse.y:1.49 src/usr.sbin/npf/npfctl/npf_parse.y:1.49.2.1
--- src/usr.sbin/npf/npfctl/npf_parse.y:1.49 Tue Jul 23 00:52:02 2019
+++ src/usr.sbin/npf/npfctl/npf_parse.y Fri Oct 4 08:06:34 2019
@@ -42,11 +42,11 @@
#define YYSTACKSIZE 4096
-int yyparsetarget;
+int yystarttoken;
const char * yyfilename;
extern int yylineno, yycolumn;
-extern int yylex(void);
+extern int yylex(int);
void
yyerror(const char *fmt, ...)
@@ -78,14 +78,6 @@ yyerror(const char *fmt, ...)
exit(EXIT_FAILURE);
}
-#define CHECK_PARSER_FILE \
- if (yyparsetarget != NPFCTL_PARSE_FILE) \
- yyerror("rule must be in the group");
-
-#define CHECK_PARSER_STRING \
- if (yyparsetarget != NPFCTL_PARSE_STRING) \
- yyerror("invalid rule syntax");
-
%}
/*
@@ -94,6 +86,17 @@ yyerror(const char *fmt, ...)
%expect 0
%expect-rr 0
+/*
+ * Depending on the mode of operation, set a different start symbol.
+ * Workaround yacc limitation by passing the start token.
+ */
+%start input
+%token RULE_ENTRY_TOKEN MAP_ENTRY_TOKEN
+%lex-param { int yystarttoken }
+
+/*
+ * General tokens.
+ */
%token ALG
%token ALGO
%token ALL
@@ -209,8 +212,9 @@ yyerror(const char *fmt, ...)
%%
input
- : { CHECK_PARSER_FILE } lines
- | { CHECK_PARSER_STRING } rule
+ : lines
+ | RULE_ENTRY_TOKEN rule
+ | MAP_ENTRY_TOKEN map
;
lines
Index: src/usr.sbin/npf/npfctl/npf_scan.l
diff -u src/usr.sbin/npf/npfctl/npf_scan.l:1.29 src/usr.sbin/npf/npfctl/npf_scan.l:1.29.2.1
--- src/usr.sbin/npf/npfctl/npf_scan.l:1.29 Tue Jul 23 00:52:02 2019
+++ src/usr.sbin/npf/npfctl/npf_scan.l Fri Oct 4 08:06:34 2019
@@ -39,7 +39,7 @@ int yycolumn;
#define YY_USER_ACTION yycolumn += yyleng;
-extern int yyparsetarget;
+extern int yystarttoken;
extern int yylineno;
extern const char * yyfilename;
extern int yyparse(void);
@@ -54,7 +54,7 @@ npfctl_parse_file(const char *name)
if (fp == NULL) {
err(EXIT_FAILURE, "open '%s'", name);
}
- yyparsetarget = NPFCTL_PARSE_FILE;
+ yystarttoken = 0;
yyrestart(fp);
yylineno = 1;
yycolumn = 0;
@@ -64,11 +64,21 @@ npfctl_parse_file(const char *name)
}
void
-npfctl_parse_string(const char *str)
+npfctl_parse_string(const char *str, parse_entry_t entry)
{
YY_BUFFER_STATE bs;
- yyparsetarget = NPFCTL_PARSE_STRING;
+ switch (entry) {
+ case NPFCTL_PARSE_RULE:
+ yystarttoken = RULE_ENTRY_TOKEN;
+ break;
+ case NPFCTL_PARSE_MAP:
+ yystarttoken = MAP_ENTRY_TOKEN;
+ break;
+ default:
+ abort();
+ }
+
bs = yy_scan_string(str);
yyfilename = "stdin";
yyparse();
@@ -85,6 +95,15 @@ NUMBER [0-9]+
HEXDIG [0-9a-fA-F]+
%%
+%{
+ /* This is prepended to yylex(). */
+ if (yystarttoken) {
+ int token = yystarttoken;
+ yystarttoken = 0;
+ return token;
+ }
+%}
+
alg return ALG;
table return TABLE;
type return TYPE;
Index: src/usr.sbin/npf/npfctl/npfctl.8
diff -u src/usr.sbin/npf/npfctl/npfctl.8:1.21 src/usr.sbin/npf/npfctl/npfctl.8:1.21.2.1
--- src/usr.sbin/npf/npfctl/npfctl.8:1.21 Sat Jan 19 21:19:32 2019
+++ src/usr.sbin/npf/npfctl/npfctl.8 Fri Oct 4 08:06:34 2019
@@ -1,4 +1,4 @@
-.\" $NetBSD: npfctl.8,v 1.21 2019/01/19 21:19:32 rmind Exp $
+.\" $NetBSD: npfctl.8,v 1.21.2.1 2019/10/04 08:06:34 martin Exp $
.\"
.\" Copyright (c) 2009-2014 The NetBSD Foundation, Inc.
.\" All rights reserved.
@@ -27,7 +27,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd December 10, 2017
+.Dd August 26, 2019
.Dt NPFCTL 8
.Os
.Sh NAME
@@ -114,28 +114,50 @@ List all rules in the dynamic ruleset sp
Remove all rules from the dynamic ruleset specified by
.Ar name .
.\" ---
-.It Ic table Ar tid Ic add Aq Ar addr/mask
+.It Ic table Ar name Ic add Aq Ar addr/mask
In table
-.Ar tid ,
+.Ar name ,
add the IP address and optionally netmask, specified by
.Aq Ar addr/mask .
Only the tables of type "lpm" support masks.
-.It Ic table Ar tid Ic rem Aq Ar addr/mask
+.It Ic table Ar name Ic rem Aq Ar addr/mask
In table
-.Ar tid ,
+.Ar name ,
remove the IP address and optionally netmask, specified by
.Aq Ar addr/mask .
Only the tables of type "lpm" support masks.
-.It Ic table Ar tid Ic test Aq Ar addr
+.It Ic table Ar name Ic test Aq Ar addr
Query the table
-.Ar tid
+.Ar name
for a specific IP address, specified by
.Ar addr .
If no mask is specified, a single host is assumed.
-.It Ic table Ar tid Ic list
+.It Ic table Ar name Ic list
List all entries in the currently loaded table specified by
-.Ar tid .
+.Ar name .
This operation is expensive and should be used with caution.
+.It Ic table Ar name Ic replace Oo Fl n Ar newname Oc Oo Fl t Ar type Oc Aq Ar path
+Replace the existing table specified by
+.Ar name
+with a new table built from the file specified by
+.Ar path .
+Optionally, the new table will:
+.Bl -tag -width xxxxxxxxxx -compact -offset 3n
+.It Fl n Ar newname
+be named
+.Ar newname ,
+effectively renaming the table.
+If not specified, the name of the table being replaced will be used.
+.It Fl t Ar type
+be of type
+.Ar type ;
+currently supported types are
+.Cm ipset ,
+.Cm lpm ,
+or
+.Cm const .
+If not specified, the type of the table being replaced will be used.
+.El
.\" ---
.It Ic save
Save the active configuration and a snapshot of the current connections.
@@ -181,7 +203,7 @@ See
for details.
.\" -----
.Sh FILES
-.Bl -tag -width /etc/npf.conf -compact
+.Bl -tag -width Pa -compact
.It Pa /dev/npf
control device
.It Pa /etc/npf.conf
@@ -201,6 +223,13 @@ Addition and removal of entries in the t
# npfctl table "vip" add 10.0.0.1
# npfctl table "vip" rem 182.168.0.0/24
.Ed
+.Pp
+Replacing the existing table which has ID "svr"
+with a new const table populated from file "/tmp/npf_vps_new",
+and renamed to "vps":
+.Bd -literal -offset indent
+# npfctl table "svr" replace -n "vps" -t const "/tmp/npf_vps_new"
+.Ed
.\" -----
.Sh SEE ALSO
.Xr bpf 4 ,
Index: src/usr.sbin/npf/npfctl/npfctl.c
diff -u src/usr.sbin/npf/npfctl/npfctl.c:1.60.2.1 src/usr.sbin/npf/npfctl/npfctl.c:1.60.2.2
--- src/usr.sbin/npf/npfctl/npfctl.c:1.60.2.1 Sun Sep 1 13:13:14 2019
+++ src/usr.sbin/npf/npfctl/npfctl.c Fri Oct 4 08:06:34 2019
@@ -28,7 +28,7 @@
*/
#include <sys/cdefs.h>
-__RCSID("$NetBSD: npfctl.c,v 1.60.2.1 2019/09/01 13:13:14 martin Exp $");
+__RCSID("$NetBSD: npfctl.c,v 1.60.2.2 2019/10/04 08:06:34 martin Exp $");
#include <sys/stat.h>
#include <sys/types.h>
@@ -54,8 +54,6 @@ __RCSID("$NetBSD: npfctl.c,v 1.60.2.1 20
#include "npfctl.h"
-extern void npf_yyparse_string(const char *);
-
enum {
NPFCTL_START,
NPFCTL_STOP,
@@ -142,10 +140,14 @@ usage(void)
"\t%s rule \"rule-name\" { list | flush }\n",
progname);
fprintf(stderr,
- "\t%s table <tid> { add | rem | test } <address/mask>\n",
+ "\t%s table \"table-name\" { add | rem | test } <address/mask>\n",
+ progname);
+ fprintf(stderr,
+ "\t%s table \"table-name\" { list | flush }\n",
progname);
fprintf(stderr,
- "\t%s table <tid> { list | flush }\n",
+ "\t%s table \"table-name\" replace [-n \"name\"]"
+ " [-t <type>] <table-file>\n",
progname);
fprintf(stderr,
"\t%s save | load\n",
@@ -275,7 +277,98 @@ npfctl_print_addrmask(int alen, const ch
return buf;
}
-__dead static void
+static int
+npfctl_table_type(const char *typename)
+{
+ static const struct tbltype_s {
+ const char * name;
+ unsigned type;
+ } tbltypes[] = {
+ { "ipset", NPF_TABLE_IPSET },
+ { "lpm", NPF_TABLE_LPM },
+ { "const", NPF_TABLE_CONST },
+ { NULL, 0 }
+ };
+
+ for (unsigned i = 0; tbltypes[i].name != NULL; i++) {
+ if (strcmp(typename, tbltypes[i].name) == 0) {
+ return tbltypes[i].type;
+ }
+ }
+ return 0;
+}
+
+static void
+npfctl_table_replace(int fd, int argc, char **argv)
+{
+ const char *name, *newname, *path, *typename = NULL;
+ int c, tid = -1;
+ FILE *fp;
+ nl_config_t *ncf;
+ nl_table_t *t;
+ u_int type = 0;
+
+ name = newname = argv[0];
+ optind = 2;
+ while ((c = getopt(argc, argv, "n:t:")) != -1) {
+ switch (c) {
+ case 't':
+ typename = optarg;
+ break;
+ case 'n':
+ newname = optarg;
+ break;
+ default:
+ fprintf(stderr,
+ "Usage: %s table \"table-name\" replace "
+ "[-n \"name\"] [-t <type>] <table-file>\n",
+ getprogname());
+ exit(EXIT_FAILURE);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (typename && (type = npfctl_table_type(typename)) == 0) {
+ errx(EXIT_FAILURE, "unsupported table type '%s'", typename);
+ }
+
+ if (argc != 1) {
+ usage();
+ }
+
+ path = argv[0];
+ if (strcmp(path, "-") == 0) {
+ path = "stdin";
+ fp = stdin;
+ } else if ((fp = fopen(path, "r")) == NULL) {
+ err(EXIT_FAILURE, "open '%s'", path);
+ }
+
+ /* Get existing config to lookup ID of existing table */
+ if ((ncf = npf_config_retrieve(fd)) == NULL) {
+ err(EXIT_FAILURE, "npf_config_retrieve()");
+ }
+ if ((t = npfctl_table_getbyname(ncf, name)) == NULL) {
+ errx(EXIT_FAILURE,
+ "table '%s' not found in the active configuration", name);
+ }
+ tid = npf_table_getid(t);
+ if (!type) {
+ type = npf_table_gettype(t);
+ }
+ npf_config_destroy(ncf);
+
+ if ((t = npfctl_load_table(newname, tid, type, path, fp)) == NULL) {
+ err(EXIT_FAILURE, "table load failed");
+ }
+
+ if (npf_table_replace(fd, t, NULL)) {
+ err(EXIT_FAILURE, "npf_table_replace(<%s>)", name);
+ }
+}
+
+static void
npfctl_table(int fd, int argc, char **argv)
{
static const struct tblops_s {
@@ -383,11 +476,10 @@ again:
nct.nct_cmd == NPF_CMD_TABLE_LOOKUP ?
"match" : "success");
}
- exit(EXIT_SUCCESS);
}
static nl_rule_t *
-npfctl_parse_rule(int argc, char **argv)
+npfctl_parse_rule(int argc, char **argv, parse_entry_t entry)
{
char rule_string[1024];
nl_rule_t *rl;
@@ -396,7 +488,7 @@ npfctl_parse_rule(int argc, char **argv)
if (!join(rule_string, sizeof(rule_string), argc, argv, " ")) {
errx(EXIT_FAILURE, "command too long");
}
- npfctl_parse_string(rule_string);
+ npfctl_parse_string(rule_string, entry);
if ((rl = npfctl_rule_ref()) == NULL) {
errx(EXIT_FAILURE, "could not parse the rule");
}
@@ -431,7 +523,15 @@ npfctl_generate_key(nl_rule_t *rl, void
free(meta);
}
-__dead static void
+int
+npfctl_nat_ruleset_p(const char *name, bool *natset)
+{
+ const size_t preflen = sizeof(NPF_RULESET_MAP_PREF) - 1;
+ *natset = strncmp(name, NPF_RULESET_MAP_PREF, preflen) == 0;
+ return (*natset && strlen(name) <= preflen) ? -1 : 0;
+}
+
+static void
npfctl_rule(int fd, int argc, char **argv)
{
static const struct ruleops_s {
@@ -451,11 +551,12 @@ npfctl_rule(int fd, int argc, char **arg
const char *ruleset_name = argv[0];
const char *cmd = argv[1];
int error, action = 0;
+ bool extra_arg, natset;
+ parse_entry_t entry;
uint64_t rule_id;
- bool extra_arg;
nl_rule_t *rl;
- for (int n = 0; ruleops[n].cmd != NULL; n++) {
+ for (unsigned n = 0; ruleops[n].cmd != NULL; n++) {
if (strcmp(cmd, ruleops[n].cmd) == 0) {
action = ruleops[n].action;
extra_arg = ruleops[n].extra_arg;
@@ -469,15 +570,22 @@ npfctl_rule(int fd, int argc, char **arg
usage();
}
+ if (npfctl_nat_ruleset_p(ruleset_name, &natset) != 0) {
+ errx(EXIT_FAILURE,
+ "invalid NAT ruleset name (note: the name must be "
+ "prefixed with `" NPF_RULESET_MAP_PREF "`)");
+ }
+ entry = natset ? NPFCTL_PARSE_MAP : NPFCTL_PARSE_RULE;
+
switch (action) {
case NPF_CMD_RULE_ADD:
- rl = npfctl_parse_rule(argc, argv);
+ rl = npfctl_parse_rule(argc, argv, entry);
npfctl_generate_key(rl, key);
npf_rule_setkey(rl, key, sizeof(key));
error = npf_ruleset_add(fd, ruleset_name, rl, &rule_id);
break;
case NPF_CMD_RULE_REMKEY:
- rl = npfctl_parse_rule(argc, argv);
+ rl = npfctl_parse_rule(argc, argv, entry);
npfctl_generate_key(rl, key);
error = npf_ruleset_remkey(fd, ruleset_name, key, sizeof(key));
break;
@@ -509,7 +617,6 @@ npfctl_rule(int fd, int argc, char **arg
if (action == NPF_CMD_RULE_ADD) {
printf("OK %" PRIx64 "\n", rule_id);
}
- exit(EXIT_SUCCESS);
}
static bool bpfjit = true;
@@ -754,7 +861,11 @@ npfctl(int action, int argc, char **argv
usage();
}
argv += 2;
- npfctl_table(fd, argc, argv);
+ if (strcmp(argv[1], "replace") == 0) {
+ npfctl_table_replace(fd, argc, argv);
+ } else {
+ npfctl_table(fd, argc, argv);
+ }
break;
case NPFCTL_RULE:
if ((argc -= 2) < 2) {
Index: src/usr.sbin/npf/npfctl/npfctl.h
diff -u src/usr.sbin/npf/npfctl/npfctl.h:1.48.2.1 src/usr.sbin/npf/npfctl/npfctl.h:1.48.2.2
--- src/usr.sbin/npf/npfctl/npfctl.h:1.48.2.1 Sun Aug 11 10:10:23 2019
+++ src/usr.sbin/npf/npfctl/npfctl.h Fri Oct 4 08:06:34 2019
@@ -102,7 +102,11 @@ typedef struct proc_param {
const char * pp_value;
} proc_param_t;
-enum { NPFCTL_PARSE_FILE, NPFCTL_PARSE_STRING };
+typedef enum {
+ NPFCTL_PARSE_DEFAULT,
+ NPFCTL_PARSE_RULE,
+ NPFCTL_PARSE_MAP
+} parse_entry_t;
#define NPF_IFNET_TABLE_PREF ".ifnet-"
#define NPF_IFNET_TABLE_PREFLEN (sizeof(NPF_IFNET_TABLE_PREF) - 1)
@@ -111,12 +115,13 @@ bool join(char *, size_t, int, char **,
void yyerror(const char *, ...) __printflike(1, 2) __dead;
void npfctl_bpfjit(bool);
void npfctl_parse_file(const char *);
-void npfctl_parse_string(const char *);
+void npfctl_parse_string(const char *, parse_entry_t);
void npfctl_print_error(const npf_error_t *);
char * npfctl_print_addrmask(int, const char *, const npf_addr_t *,
npf_netmask_t);
void npfctl_note_interface(const char *);
+nl_table_t * npfctl_table_getbyname(nl_config_t *, const char *);
unsigned npfctl_table_getid(const char *);
const char * npfctl_table_getname(nl_config_t *, unsigned, bool *);
int npfctl_protono(const char *);
@@ -135,6 +140,7 @@ npfvar_t * npfctl_parse_fam_addr_mask(co
bool npfctl_parse_cidr(char *, fam_addr_mask_t *, int *);
uint16_t npfctl_npt66_calcadj(npf_netmask_t, const npf_addr_t *,
const npf_addr_t *);
+int npfctl_nat_ruleset_p(const char *, bool *);
/*
* NPF extension loading.
@@ -196,8 +202,11 @@ void npfctl_show_init(void);
int npfctl_ruleset_show(int, const char *);
nl_rule_t * npfctl_rule_ref(void);
+nl_table_t * npfctl_table_ref(void);
bool npfctl_debug_addif(const char *);
+nl_table_t * npfctl_load_table(const char *, int, u_int, const char *, FILE *);
+
void npfctl_build_alg(const char *);
void npfctl_build_rproc(const char *, npfvar_t *);
void npfctl_build_group(const char *, int, const char *, bool);
Index: src/usr.sbin/npf/npftest/npftest.conf
diff -u src/usr.sbin/npf/npftest/npftest.conf:1.7 src/usr.sbin/npf/npftest/npftest.conf:1.7.2.1
--- src/usr.sbin/npf/npftest/npftest.conf:1.7 Tue Jul 23 00:52:02 2019
+++ src/usr.sbin/npf/npftest/npftest.conf Fri Oct 4 08:06:35 2019
@@ -1,4 +1,4 @@
-# $NetBSD: npftest.conf,v 1.7 2019/07/23 00:52:02 rmind Exp $
+# $NetBSD: npftest.conf,v 1.7.2.1 2019/10/04 08:06:35 martin Exp $
$ext_if = "npftest0"
$int_if = "npftest1"
@@ -32,7 +32,7 @@ $net_b = 10.255.0.0/16
map $ext_if static algo npt66 $net6_inner <-> $net6_outer
map $ext_if static algo netmap $net_a <-> $net_b
-map ruleset "dynamic-nat" on $ext_if
+map ruleset "map:some-daemon" on $ext_if
group "ext" on $ext_if {
pass out final from $local_ip3