Module Name: src Committed By: rmind Date: Mon Sep 30 00:37:12 UTC 2019
Modified Files: src/lib/libnpf: libnpf.3 npf.c npf.h src/sys/net/npf: npf_ctl.c src/usr.sbin/npf/npfctl: npf.conf.5 npf_build.c npf_parse.y npf_scan.l npfctl.c npfctl.h src/usr.sbin/npf/npftest: npftest.conf Log Message: libnpf/npfctl: support dynamic NAT rulesets using a name prefix. To generate a diff of this commit: cvs rdiff -u -r1.10 -r1.11 src/lib/libnpf/libnpf.3 cvs rdiff -u -r1.47 -r1.48 src/lib/libnpf/npf.c cvs rdiff -u -r1.37 -r1.38 src/lib/libnpf/npf.h cvs rdiff -u -r1.58 -r1.59 src/sys/net/npf/npf_ctl.c cvs rdiff -u -r1.88 -r1.89 src/usr.sbin/npf/npfctl/npf.conf.5 cvs rdiff -u -r1.52 -r1.53 src/usr.sbin/npf/npfctl/npf_build.c cvs rdiff -u -r1.49 -r1.50 src/usr.sbin/npf/npfctl/npf_parse.y cvs rdiff -u -r1.29 -r1.30 src/usr.sbin/npf/npfctl/npf_scan.l cvs rdiff -u -r1.62 -r1.63 src/usr.sbin/npf/npfctl/npfctl.c cvs rdiff -u -r1.50 -r1.51 src/usr.sbin/npf/npfctl/npfctl.h cvs rdiff -u -r1.7 -r1.8 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.10 src/lib/libnpf/libnpf.3:1.11 --- src/lib/libnpf/libnpf.3:1.10 Wed Aug 21 21:45:47 2019 +++ src/lib/libnpf/libnpf.3 Mon Sep 30 00:37:11 2019 @@ -1,4 +1,4 @@ -.\" $NetBSD: libnpf.3,v 1.10 2019/08/21 21:45:47 rmind Exp $ +.\" $NetBSD: libnpf.3,v 1.11 2019/09/30 00:37:11 rmind 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.47 src/lib/libnpf/npf.c:1.48 --- src/lib/libnpf/npf.c:1.47 Wed Aug 21 21:45:47 2019 +++ src/lib/libnpf/npf.c Mon Sep 30 00:37:11 2019 @@ -28,7 +28,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.47 2019/08/21 21:45:47 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.48 2019/09/30 00:37:11 rmind 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.37 src/lib/libnpf/npf.h:1.38 --- src/lib/libnpf/npf.h:1.37 Wed Aug 21 21:45:47 2019 +++ src/lib/libnpf/npf.h Mon Sep 30 00:37:11 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_ctl.c diff -u src/sys/net/npf/npf_ctl.c:1.58 src/sys/net/npf/npf_ctl.c:1.59 --- src/sys/net/npf/npf_ctl.c:1.58 Sun Aug 25 17:38:25 2019 +++ src/sys/net/npf/npf_ctl.c Mon Sep 30 00:37:11 2019 @@ -36,7 +36,7 @@ #ifdef _KERNEL #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.58 2019/08/25 17:38:25 rmind Exp $"); +__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.59 2019/09/30 00:37:11 rmind 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/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.89 --- 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 Mon Sep 30 00:37:11 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.89 2019/09/30 00:37:11 rmind 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 ] Index: src/usr.sbin/npf/npfctl/npf_build.c diff -u src/usr.sbin/npf/npfctl/npf_build.c:1.52 src/usr.sbin/npf/npfctl/npf_build.c:1.53 --- src/usr.sbin/npf/npfctl/npf_build.c:1.52 Sun Sep 29 18:51:08 2019 +++ src/usr.sbin/npf/npfctl/npf_build.c Mon Sep 30 00:37:11 2019 @@ -32,7 +32,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: npf_build.c,v 1.52 2019/09/29 18:51:08 rmind Exp $"); +__RCSID("$NetBSD: npf_build.c,v 1.53 2019/09/30 00:37:11 rmind Exp $"); #include <sys/types.h> #define __FAVOR_BSD @@ -537,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); @@ -866,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; } } @@ -959,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) { @@ -969,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.50 --- 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 Mon Sep 30 00:37:11 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.30 --- 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 Mon Sep 30 00:37:11 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.c diff -u src/usr.sbin/npf/npfctl/npfctl.c:1.62 src/usr.sbin/npf/npfctl/npfctl.c:1.63 --- src/usr.sbin/npf/npfctl/npfctl.c:1.62 Sun Sep 29 16:58:35 2019 +++ src/usr.sbin/npf/npfctl/npfctl.c Mon Sep 30 00:37:11 2019 @@ -28,7 +28,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: npfctl.c,v 1.62 2019/09/29 16:58:35 rmind Exp $"); +__RCSID("$NetBSD: npfctl.c,v 1.63 2019/09/30 00:37:11 rmind Exp $"); #include <sys/stat.h> #include <sys/types.h> @@ -54,8 +54,6 @@ __RCSID("$NetBSD: npfctl.c,v 1.62 2019/0 #include "npfctl.h" -extern void npf_yyparse_string(const char *); - enum { NPFCTL_START, NPFCTL_STOP, @@ -282,11 +280,9 @@ npfctl_print_addrmask(int alen, const ch static int npfctl_table_type(const char *typename) { - int i; - static const struct tbltype_s { - const char *name; - u_int type; + const char * name; + unsigned type; } tbltypes[] = { { "ipset", NPF_TABLE_IPSET }, { "lpm", NPF_TABLE_LPM }, @@ -294,12 +290,11 @@ npfctl_table_type(const char *typename) { NULL, 0 } }; - for (i = 0; tbltypes[i].name != NULL; i++) { + for (unsigned i = 0; tbltypes[i].name != NULL; i++) { if (strcmp(typename, tbltypes[i].name) == 0) { return tbltypes[i].type; } } - return 0; } @@ -484,7 +479,7 @@ again: } 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; @@ -493,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"); } @@ -528,6 +523,14 @@ npfctl_generate_key(nl_rule_t *rl, void free(meta); } +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) { @@ -548,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; @@ -566,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; Index: src/usr.sbin/npf/npfctl/npfctl.h diff -u src/usr.sbin/npf/npfctl/npfctl.h:1.50 src/usr.sbin/npf/npfctl/npfctl.h:1.51 --- src/usr.sbin/npf/npfctl/npfctl.h:1.50 Sun Sep 29 16:58:35 2019 +++ src/usr.sbin/npf/npfctl/npfctl.h Mon Sep 30 00:37:11 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,7 +115,7 @@ 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 *, @@ -136,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. 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.8 --- src/usr.sbin/npf/npftest/npftest.conf:1.7 Tue Jul 23 00:52:02 2019 +++ src/usr.sbin/npf/npftest/npftest.conf Mon Sep 30 00:37:11 2019 @@ -1,4 +1,4 @@ -# $NetBSD: npftest.conf,v 1.7 2019/07/23 00:52:02 rmind Exp $ +# $NetBSD: npftest.conf,v 1.8 2019/09/30 00:37:11 rmind 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