Module Name: src Committed By: snj Date: Sat Mar 21 17:49:03 UTC 2015
Modified Files: src/sys/net/npf [netbsd-7]: npf_ctl.c npf_ruleset.c src/usr.sbin/npf/npfctl [netbsd-7]: npf_build.c npf_show.c Log Message: Pull up following revision(s) (requested by rmind in ticket #630): sys/net/npf/npf_ctl.c: revision 1.41 sys/net/npf/npf_ruleset.c: revision 1.42 usr.sbin/npf/npfctl/npf_build.c: revision 1.39 usr.sbin/npf/npfctl/npf_show.c: revision 1.18 NPF: replace the TAILQ of the dynamic rules with a linked list and fix the inheriting of the active dynamic rules during the reload; also, fix a bug in the insert path by putting a memory barrier in the right place. -- npfctl: - Fix the filter criteria when to/from is omitted but port used. - Print more user-friendly error if an NPF table has a duplicate entry. To generate a diff of this commit: cvs rdiff -u -r1.38.2.1 -r1.38.2.2 src/sys/net/npf/npf_ctl.c cvs rdiff -u -r1.37.2.3 -r1.37.2.4 src/sys/net/npf/npf_ruleset.c cvs rdiff -u -r1.38 -r1.38.2.1 src/usr.sbin/npf/npfctl/npf_build.c cvs rdiff -u -r1.15.2.1 -r1.15.2.2 src/usr.sbin/npf/npfctl/npf_show.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/net/npf/npf_ctl.c diff -u src/sys/net/npf/npf_ctl.c:1.38.2.1 src/sys/net/npf/npf_ctl.c:1.38.2.2 --- src/sys/net/npf/npf_ctl.c:1.38.2.1 Fri Aug 29 11:14:14 2014 +++ src/sys/net/npf/npf_ctl.c Sat Mar 21 17:49:03 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: npf_ctl.c,v 1.38.2.1 2014/08/29 11:14:14 martin Exp $ */ +/* $NetBSD: npf_ctl.c,v 1.38.2.2 2015/03/21 17:49:03 snj Exp $ */ /*- * Copyright (c) 2009-2014 The NetBSD Foundation, Inc. @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.38.2.1 2014/08/29 11:14:14 martin Exp $"); +__KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.38.2.2 2015/03/21 17:49:03 snj Exp $"); #include <sys/param.h> #include <sys/conf.h> @@ -778,6 +778,9 @@ npfctl_rule(u_long cmd, void *data) } case NPF_CMD_RULE_LIST: { retdict = npf_ruleset_list(rlset, ruleset_name); + if (!retdict) { + error = ESRCH; + } break; } case NPF_CMD_RULE_FLUSH: { @@ -797,6 +800,7 @@ npfctl_rule(u_long cmd, void *data) npf_config_exit(); if (rl) { + KASSERT(error); npf_rule_free(rl); } out: Index: src/sys/net/npf/npf_ruleset.c diff -u src/sys/net/npf/npf_ruleset.c:1.37.2.3 src/sys/net/npf/npf_ruleset.c:1.37.2.4 --- src/sys/net/npf/npf_ruleset.c:1.37.2.3 Wed Feb 4 07:13:04 2015 +++ src/sys/net/npf/npf_ruleset.c Sat Mar 21 17:49:03 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: npf_ruleset.c,v 1.37.2.3 2015/02/04 07:13:04 snj Exp $ */ +/* $NetBSD: npf_ruleset.c,v 1.37.2.4 2015/03/21 17:49:03 snj Exp $ */ /*- * Copyright (c) 2009-2015 The NetBSD Foundation, Inc. @@ -34,7 +34,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.37.2.3 2015/02/04 07:13:04 snj Exp $"); +__KERNEL_RCSID(0, "$NetBSD: npf_ruleset.c,v 1.37.2.4 2015/03/21 17:49:03 snj Exp $"); #include <sys/param.h> #include <sys/types.h> @@ -89,21 +89,24 @@ struct npf_rule { npf_natpolicy_t * r_natp; npf_rproc_t * r_rproc; - /* Rule priority: (highest) 1, 2 ... n (lowest). */ - pri_t r_priority; - - /* - * Dynamic group: subset queue and a dynamic group list entry. - * Dynamic rule: entry and the parent rule (the group). - */ union { - TAILQ_HEAD(npf_ruleq, npf_rule) r_subset; - TAILQ_ENTRY(npf_rule) r_entry; - } /* C11 */; - union { - LIST_ENTRY(npf_rule) r_dentry; - npf_rule_t * r_parent; - } /* C11 */; + /* + * Dynamic group: rule subset and a group list entry. + */ + struct { + npf_rule_t * r_subset; + LIST_ENTRY(npf_rule) r_dentry; + }; + + /* + * Dynamic rule: priority, parent group and next rule. + */ + struct { + int r_priority; + npf_rule_t * r_parent; + npf_rule_t * r_next; + }; + }; /* Rule ID, name and the optional key. */ uint64_t r_id; @@ -147,19 +150,6 @@ npf_ruleset_create(size_t slots) return rlset; } -static void -npf_ruleset_unlink(npf_ruleset_t *rlset, npf_rule_t *rl) -{ - if (NPF_DYNAMIC_GROUP_P(rl->r_attr)) { - LIST_REMOVE(rl, r_dentry); - } - if (NPF_DYNAMIC_RULE_P(rl->r_attr)) { - npf_rule_t *rg = rl->r_parent; - TAILQ_REMOVE(&rg->r_subset, rl, r_entry); - } - LIST_REMOVE(rl, r_aentry); -} - void npf_ruleset_destroy(npf_ruleset_t *rlset) { @@ -167,7 +157,19 @@ npf_ruleset_destroy(npf_ruleset_t *rlset npf_rule_t *rl; while ((rl = LIST_FIRST(&rlset->rs_all)) != NULL) { - npf_ruleset_unlink(rlset, rl); + if (NPF_DYNAMIC_GROUP_P(rl->r_attr)) { + /* + * Note: r_subset may point to the rules which + * were inherited by a new ruleset. + */ + rl->r_subset = NULL; + LIST_REMOVE(rl, r_dentry); + } + if (NPF_DYNAMIC_RULE_P(rl->r_attr)) { + /* Not removing from r_subset, see above. */ + KASSERT(rl->r_parent != NULL); + } + LIST_REMOVE(rl, r_aentry); npf_rule_free(rl); } KASSERT(LIST_EMPTY(&rlset->rs_dynamic)); @@ -222,16 +224,16 @@ npf_ruleset_lookup(npf_ruleset_t *rlset, int npf_ruleset_add(npf_ruleset_t *rlset, const char *rname, npf_rule_t *rl) { - npf_rule_t *rg, *it; - pri_t priocmd; + npf_rule_t *rg, *it, *target; + int priocmd; + if (!NPF_DYNAMIC_RULE_P(rl->r_attr)) { + return EINVAL; + } rg = npf_ruleset_lookup(rlset, rname); if (rg == NULL) { return ESRCH; } - if (!NPF_DYNAMIC_RULE_P(rl->r_attr)) { - return EINVAL; - } /* Dynamic rule - assign a unique ID and save the parent. */ rl->r_id = ++rlset->rs_idcnt; @@ -245,29 +247,32 @@ npf_ruleset_add(npf_ruleset_t *rlset, co rl->r_priority = 0; } + /* + * WARNING: once rg->subset or target->r_next of an *active* + * rule is set, then our rule becomes globally visible and active. + * Must issue a load fence to ensure rl->r_next visibility first. + */ switch (priocmd) { - case NPF_PRI_FIRST: - TAILQ_FOREACH(it, &rg->r_subset, r_entry) { - if (rl->r_priority <= it->r_priority) - break; - } - if (it) { - TAILQ_INSERT_BEFORE(it, rl, r_entry); - } else { - TAILQ_INSERT_HEAD(&rg->r_subset, rl, r_entry); - } - break; case NPF_PRI_LAST: default: - TAILQ_FOREACH(it, &rg->r_subset, r_entry) { - if (rl->r_priority < it->r_priority) - break; - } - if (it) { - TAILQ_INSERT_BEFORE(it, rl, r_entry); - } else { - TAILQ_INSERT_TAIL(&rg->r_subset, rl, r_entry); + target = NULL; + it = rg->r_subset; + while (it && it->r_priority <= rl->r_priority) { + target = it; + it = it->r_next; + } + if (target) { + rl->r_next = target->r_next; + membar_producer(); + target->r_next = rl; + break; } + /* FALLTHROUGH */ + + case NPF_PRI_FIRST: + rl->r_next = rg->r_subset; + membar_producer(); + rg->r_subset = rl; break; } @@ -276,26 +281,41 @@ npf_ruleset_add(npf_ruleset_t *rlset, co return 0; } +static void +npf_ruleset_unlink(npf_rule_t *rl, npf_rule_t *prev) +{ + KASSERT(NPF_DYNAMIC_RULE_P(rl->r_attr)); + if (prev) { + prev->r_next = rl->r_next; + } else { + npf_rule_t *rg = rl->r_parent; + rg->r_subset = rl->r_next; + } + LIST_REMOVE(rl, r_aentry); +} + /* * npf_ruleset_remove: remove the dynamic rule given the rule ID. */ int npf_ruleset_remove(npf_ruleset_t *rlset, const char *rname, uint64_t id) { - npf_rule_t *rg, *rl; + npf_rule_t *rg, *prev = NULL; if ((rg = npf_ruleset_lookup(rlset, rname)) == NULL) { return ESRCH; } - TAILQ_FOREACH(rl, &rg->r_subset, r_entry) { + for (npf_rule_t *rl = rg->r_subset; rl; rl = rl->r_next) { KASSERT(rl->r_parent == rg); + KASSERT(NPF_DYNAMIC_RULE_P(rl->r_attr)); /* Compare ID. On match, remove and return. */ if (rl->r_id == id) { - npf_ruleset_unlink(rlset, rl); + npf_ruleset_unlink(rl, prev); LIST_INSERT_HEAD(&rlset->rs_gc, rl, r_aentry); return 0; } + prev = rl; } return ENOENT; } @@ -307,7 +327,7 @@ int npf_ruleset_remkey(npf_ruleset_t *rlset, const char *rname, const void *key, size_t len) { - npf_rule_t *rg, *rl; + npf_rule_t *rg, *rlast = NULL, *prev = NULL, *lastprev = NULL; KASSERT(len && len <= NPF_RULE_MAXKEYLEN); @@ -315,18 +335,22 @@ npf_ruleset_remkey(npf_ruleset_t *rlset, return ESRCH; } - /* Find the last in the list. */ - TAILQ_FOREACH_REVERSE(rl, &rg->r_subset, npf_ruleq, r_entry) { + /* Compare the key and find the last in the list. */ + for (npf_rule_t *rl = rg->r_subset; rl; rl = rl->r_next) { KASSERT(rl->r_parent == rg); - - /* Compare the key. On match, remove and return. */ + KASSERT(NPF_DYNAMIC_RULE_P(rl->r_attr)); if (memcmp(rl->r_key, key, len) == 0) { - npf_ruleset_unlink(rlset, rl); - LIST_INSERT_HEAD(&rlset->rs_gc, rl, r_aentry); - return 0; + lastprev = prev; + rlast = rl; } + prev = rl; } - return ENOENT; + if (!rlast) { + return ENOENT; + } + npf_ruleset_unlink(rlast, lastprev); + LIST_INSERT_HEAD(&rlset->rs_gc, rlast, r_aentry); + return 0; } /* @@ -337,7 +361,7 @@ npf_ruleset_list(npf_ruleset_t *rlset, c { prop_dictionary_t rgdict; prop_array_t rules; - npf_rule_t *rg, *rl; + npf_rule_t *rg; KASSERT(npf_config_locked_p()); @@ -352,12 +376,13 @@ npf_ruleset_list(npf_ruleset_t *rlset, c return NULL; } - TAILQ_FOREACH(rl, &rg->r_subset, r_entry) { + for (npf_rule_t *rl = rg->r_subset; rl; rl = rl->r_next) { prop_dictionary_t rldict; - rldict = prop_dictionary_create(); KASSERT(rl->r_parent == rg); + KASSERT(NPF_DYNAMIC_RULE_P(rl->r_attr)); + rldict = prop_dictionary_create(); if (npf_rule_export(rlset, rl, rldict)) { prop_object_release(rldict); prop_object_release(rules); @@ -387,10 +412,17 @@ npf_ruleset_flush(npf_ruleset_t *rlset, if ((rg = npf_ruleset_lookup(rlset, rname)) == NULL) { return ESRCH; } - while ((rl = TAILQ_FIRST(&rg->r_subset)) != NULL) { + + rl = atomic_swap_ptr(&rg->r_subset, NULL); + membar_producer(); + + while (rl) { + KASSERT(NPF_DYNAMIC_RULE_P(rl->r_attr)); KASSERT(rl->r_parent == rg); - npf_ruleset_unlink(rlset, rl); + + LIST_REMOVE(rl, r_aentry); LIST_INSERT_HEAD(&rlset->rs_gc, rl, r_aentry); + rl = rl->r_next; } return 0; } @@ -460,27 +492,33 @@ npf_ruleset_reload(npf_ruleset_t *newset * Scan the dynamic rules and share (migrate) if needed. */ LIST_FOREACH(rg, &newset->rs_dynamic, r_dentry) { - npf_rule_t *actrg; + npf_rule_t *active_rgroup; /* Look for a dynamic ruleset group with such name. */ - actrg = npf_ruleset_lookup(oldset, rg->r_name); - if (actrg == NULL) { + active_rgroup = npf_ruleset_lookup(oldset, rg->r_name); + if (active_rgroup == NULL) { continue; } /* - * Copy the list-head structure. This is necessary because - * the rules are still active and therefore accessible for - * inspection via the old ruleset. + * ATOMICITY: Copy the head pointer of the linked-list, + * but do not remove the rules from the active r_subset. + * This is necessary because the rules are still active + * and therefore are accessible for inspection via the + * old ruleset. */ - memcpy(&rg->r_subset, &actrg->r_subset, sizeof(rg->r_subset)); - TAILQ_FOREACH(rl, &rg->r_subset, r_entry) { - /* - * We can safely migrate to the new all-rule list - * and re-set the parent rule, though. - */ + rg->r_subset = active_rgroup->r_subset; + + /* + * We can safely migrate to the new all-rule list and + * reset the parent rule, though. + */ + for (rl = rg->r_subset; rl; rl = rl->r_next) { + KASSERT(NPF_DYNAMIC_RULE_P(rl->r_attr)); LIST_REMOVE(rl, r_aentry); LIST_INSERT_HEAD(&newset->rs_all, rl, r_aentry); + + KASSERT(rl->r_parent == active_rgroup); rl->r_parent = rg; } } @@ -614,7 +652,6 @@ npf_rule_alloc(prop_dictionary_t rldict) /* Allocate a rule structure. */ rl = kmem_zalloc(sizeof(npf_rule_t), KM_SLEEP); - TAILQ_INIT(&rl->r_subset); rl->r_natp = NULL; /* Name (optional) */ @@ -626,9 +663,17 @@ npf_rule_alloc(prop_dictionary_t rldict) /* Attributes, priority and interface ID (optional). */ prop_dictionary_get_uint32(rldict, "attr", &rl->r_attr); - prop_dictionary_get_int32(rldict, "prio", &rl->r_priority); rl->r_attr &= ~NPF_RULE_PRIVMASK; + if (NPF_DYNAMIC_RULE_P(rl->r_attr)) { + /* Priority of the dynamic rule. */ + prop_dictionary_get_int32(rldict, "prio", &rl->r_priority); + } else { + /* The skip-to index. No need to validate it. */ + prop_dictionary_get_uint32(rldict, "skip-to", &rl->r_skip_to); + } + + /* Interface name; register and get the npf-if-id. */ if (prop_dictionary_get_cstring_nocopy(rldict, "ifname", &rname)) { if ((rl->r_ifid = npf_ifmap_register(rname)) == 0) { kmem_free(rl, sizeof(npf_rule_t)); @@ -638,9 +683,6 @@ npf_rule_alloc(prop_dictionary_t rldict) rl->r_ifid = 0; } - /* Get the skip-to index. No need to validate it. */ - prop_dictionary_get_uint32(rldict, "skip-to", &rl->r_skip_to); - /* Key (optional). */ prop_object_t obj = prop_dictionary_get(rldict, "key"); const void *key = prop_data_data_nocopy(obj); @@ -829,15 +871,16 @@ npf_rule_inspect(const npf_rule_t *rl, b * npf_rule_reinspect: re-inspect the dynamic rule by iterating its list. * This is only for the dynamic rules. Subrules cannot have nested rules. */ -static npf_rule_t * -npf_rule_reinspect(const npf_rule_t *drl, bpf_args_t *bc_args, +static inline npf_rule_t * +npf_rule_reinspect(const npf_rule_t *rg, bpf_args_t *bc_args, const int di_mask, const u_int ifid) { npf_rule_t *final_rl = NULL, *rl; - KASSERT(NPF_DYNAMIC_GROUP_P(drl->r_attr)); + KASSERT(NPF_DYNAMIC_GROUP_P(rg->r_attr)); - TAILQ_FOREACH(rl, &drl->r_subset, r_entry) { + for (rl = rg->r_subset; rl; rl = rl->r_next) { + KASSERT(!final_rl || rl->r_priority >= final_rl->r_priority); if (!npf_rule_inspect(rl, bc_args, di_mask, ifid)) { continue; } @@ -882,7 +925,6 @@ npf_ruleset_inspect(npf_cache_t *npc, co const uint32_t attr = rl->r_attr; KASSERT(!nbuf_flag_p(nbuf, NBUF_DATAREF_RESET)); - KASSERT(!final_rl || rl->r_priority >= final_rl->r_priority); KASSERT(n < skip_to); /* Group is a barrier: return a matching if found any. */ @@ -948,7 +990,7 @@ npf_ruleset_dump(const char *name) LIST_FOREACH(rg, &rlset->rs_dynamic, r_dentry) { printf("ruleset '%s':\n", rg->r_name); - TAILQ_FOREACH(rl, &rg->r_subset, r_entry) { + for (rl = rg->r_subset; rl; rl = rl->r_next) { printf("\tid %"PRIu64", key: ", rl->r_id); for (u_int i = 0; i < NPF_RULE_MAXKEYLEN; i++) printf("%x", rl->r_key[i]); Index: src/usr.sbin/npf/npfctl/npf_build.c diff -u src/usr.sbin/npf/npfctl/npf_build.c:1.38 src/usr.sbin/npf/npfctl/npf_build.c:1.38.2.1 --- src/usr.sbin/npf/npfctl/npf_build.c:1.38 Sat May 31 22:41:37 2014 +++ src/usr.sbin/npf/npfctl/npf_build.c Sat Mar 21 17:49:03 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: npf_build.c,v 1.38 2014/05/31 22:41:37 rmind Exp $ */ +/* $NetBSD: npf_build.c,v 1.38.2.1 2015/03/21 17:49:03 snj Exp $ */ /*- * Copyright (c) 2011-2014 The NetBSD Foundation, Inc. @@ -34,7 +34,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: npf_build.c,v 1.38 2014/05/31 22:41:37 rmind Exp $"); +__RCSID("$NetBSD: npf_build.c,v 1.38.2.1 2015/03/21 17:49:03 snj Exp $"); #include <sys/types.h> #include <sys/mman.h> @@ -91,6 +91,10 @@ npfctl_config_send(int fd, const char *o } npf_rule_insert(npf_conf, NULL, defgroup); error = npf_config_submit(npf_conf, fd); + if (error == EEXIST) { /* XXX */ + errx(EXIT_FAILURE, "(re)load failed: " + "some table has a duplicate entry?"); + } if (error) { nl_error_t ne; _npf_config_error(npf_conf, &ne); Index: src/usr.sbin/npf/npfctl/npf_show.c diff -u src/usr.sbin/npf/npfctl/npf_show.c:1.15.2.1 src/usr.sbin/npf/npfctl/npf_show.c:1.15.2.2 --- src/usr.sbin/npf/npfctl/npf_show.c:1.15.2.1 Wed Feb 4 07:13:04 2015 +++ src/usr.sbin/npf/npfctl/npf_show.c Sat Mar 21 17:49:03 2015 @@ -1,4 +1,4 @@ -/* $NetBSD: npf_show.c,v 1.15.2.1 2015/02/04 07:13:04 snj Exp $ */ +/* $NetBSD: npf_show.c,v 1.15.2.2 2015/03/21 17:49:03 snj Exp $ */ /*- * Copyright (c) 2013 The NetBSD Foundation, Inc. @@ -36,7 +36,7 @@ */ #include <sys/cdefs.h> -__RCSID("$NetBSD: npf_show.c,v 1.15.2.1 2015/02/04 07:13:04 snj Exp $"); +__RCSID("$NetBSD: npf_show.c,v 1.15.2.2 2015/03/21 17:49:03 snj Exp $"); #include <sys/socket.h> #include <netinet/in.h> @@ -53,13 +53,22 @@ __RCSID("$NetBSD: npf_show.c,v 1.15.2.1 #include "npfctl.h" +#define SEEN_SRC 0x01 +#define SEEN_DST 0x02 + typedef struct { nl_config_t * conf; FILE * fp; long fpos; + u_int flags; + uint32_t curmark; } npf_conf_info_t; -static npf_conf_info_t stdout_ctx = { .fp = stdout, .fpos = 0 }; +static npf_conf_info_t stdout_ctx = { + .fp = stdout, + .fpos = 0, + .flags = 0 +}; static void print_indent(npf_conf_info_t *, u_int); static void print_linesep(npf_conf_info_t *); @@ -201,12 +210,18 @@ static char * print_portrange(npf_conf_info_t *ctx, const uint32_t *words) { u_int fport = words[0], tport = words[1]; + const char *any_str = ""; char *p; + if (ctx->curmark == BM_SRC_PORTS && (ctx->flags & SEEN_SRC) == 0) + any_str = "to any "; + if (ctx->curmark == BM_DST_PORTS && (ctx->flags & SEEN_DST) == 0) + any_str = "from any "; + if (fport != tport) { - easprintf(&p, "%u:%u", fport, tport); + easprintf(&p, "%s%u:%u", any_str, fport, tport); } else { - easprintf(&p, "%u", fport); + easprintf(&p, "%s%u", any_str, fport); } return p; } @@ -244,22 +259,23 @@ static const struct mark_keyword_mapent u_int mark; const char * token; const char * sep; + u_int set_flags; char * (*printfn)(npf_conf_info_t *, const uint32_t *); u_int fwords; } mark_keyword_map[] = { - { BM_IPVER, "family %s", NULL, print_family, 1 }, - { BM_PROTO, "proto %s", ", ", print_proto, 1 }, - { BM_TCPFL, "flags %s", NULL, print_tcpflags, 2 }, - { BM_ICMP_TYPE, "icmp-type %s", NULL, print_number, 1 }, - { BM_ICMP_CODE, "code %s", NULL, print_number, 1 }, - - { BM_SRC_CIDR, "from %s", ", ", print_address, 6 }, - { BM_SRC_TABLE, "from <%s>", NULL, print_table, 1 }, - { BM_SRC_PORTS, "port %s", ", ", print_portrange,2 }, - - { BM_DST_CIDR, "to %s", ", ", print_address, 6 }, - { BM_DST_TABLE, "to <%s>", NULL, print_table, 1 }, - { BM_DST_PORTS, "port %s", ", ", print_portrange,2 }, + { BM_IPVER, "family %s", NULL, 0, print_family, 1 }, + { BM_PROTO, "proto %s", ", ", 0, print_proto, 1 }, + { BM_TCPFL, "flags %s", NULL, 0, print_tcpflags, 2 }, + { BM_ICMP_TYPE, "icmp-type %s", NULL, 0, print_number, 1 }, + { BM_ICMP_CODE, "code %s", NULL, 0, print_number, 1 }, + + { BM_SRC_CIDR, "from %s", ", ", SEEN_SRC, print_address, 6 }, + { BM_SRC_TABLE, "from <%s>", NULL, SEEN_SRC, print_table, 1 }, + { BM_SRC_PORTS, "port %s", ", ", 0, print_portrange,2 }, + + { BM_DST_CIDR, "to %s", ", ", SEEN_DST, print_address, 6 }, + { BM_DST_TABLE, "to <%s>", NULL, SEEN_DST, print_table, 1 }, + { BM_DST_PORTS, "port %s", ", ", 0, print_portrange,2 }, }; static const char * __attribute__((format_arg(2))) @@ -285,6 +301,10 @@ scan_marks(npf_conf_info_t *ctx, const s errx(EXIT_FAILURE, "byte-code marking inconsistency"); } if (m == mk->mark) { + /* Set the current mark and the flags. */ + ctx->flags |= mk->set_flags; + ctx->curmark = m; + /* Value is processed by the print function. */ assert(mk->fwords == nwords); vals[nvals++] = mk->printfn(ctx, marks);