Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 7 May 2021 15:25:40 GMT
From:      Kristof Provost <kp@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: 5b16c4b6e824 - stable/12 - pf: Implement nvlist variant of DIOCGETRULE
Message-ID:  <202105071525.147FPeci026107@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/12 has been updated by kp:

URL: https://cgit.FreeBSD.org/src/commit/?id=5b16c4b6e824ab3a708c75a51c73898cbf98599e

commit 5b16c4b6e824ab3a708c75a51c73898cbf98599e
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2021-03-25 09:39:14 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2021-05-07 08:16:00 +0000

    pf: Implement nvlist variant of DIOCGETRULE
    
    MFC after:      4 weeks
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D29559
    
    (cherry picked from commit d710367d1159423ed4da6628b7ab042d3e44f900)
---
 sys/net/pfvar.h             |   4 +
 sys/netpfil/pf/pf_ioctl.c   | 398 ++++++++++++++++++++++++++++++++++++++++++++
 sys/netpfil/pf/pf_nv.c      |  23 ++-
 sys/netpfil/pf/pf_nv.h      |   7 +
 sys/netpfil/pf/pf_ruleset.c |  47 ++++++
 5 files changed, 473 insertions(+), 6 deletions(-)

diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index eb9f365f2ec9..e6e011d6ef99 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -40,6 +40,7 @@
 #include <sys/counter.h>
 #include <sys/cpuset.h>
 #include <sys/malloc.h>
+#include <sys/nv.h>
 #include <sys/refcount.h>
 #include <sys/sysctl.h>
 #include <sys/lock.h>
@@ -1232,6 +1233,7 @@ struct pfioc_iface {
 #define DIOCADDRULENV	_IOWR('D',  4, struct pfioc_nv)
 #define DIOCGETRULES	_IOWR('D',  6, struct pfioc_rule)
 #define DIOCGETRULE	_IOWR('D',  7, struct pfioc_rule)
+#define DIOCGETRULENV	_IOWR('D',  7, struct pfioc_nv)
 /* XXX cut 8 - 17 */
 #define DIOCCLRSTATES	_IOWR('D', 18, struct pfioc_state_kill)
 #define DIOCGETSTATE	_IOWR('D', 19, struct pfioc_state)
@@ -1636,6 +1638,8 @@ int			 pf_get_ruleset_number(u_int8_t);
 void			 pf_init_kruleset(struct pf_kruleset *);
 int			 pf_kanchor_setup(struct pf_krule *,
 			    const struct pf_kruleset *, const char *);
+int			 pf_kanchor_nvcopyout(const struct pf_kruleset *,
+			    const struct pf_krule *, nvlist_t *);
 int			 pf_kanchor_copyout(const struct pf_kruleset *,
 			    const struct pf_krule *, struct pfioc_rule *);
 void			 pf_kanchor_remove(struct pf_krule *);
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index 53c850a96538..7310fa18410b 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -1631,6 +1631,20 @@ pf_nvaddr_to_addr(const nvlist_t *nvl, struct pf_addr *paddr)
 	return (pf_nvbinary(nvl, "addr", paddr, sizeof(*paddr)));
 }
 
+static nvlist_t *
+pf_addr_to_nvaddr(const struct pf_addr *paddr)
+{
+	nvlist_t *nvl;
+
+	nvl = nvlist_create(0);
+	if (nvl == NULL)
+		return (NULL);
+
+	nvlist_add_binary(nvl, "addr", paddr, sizeof(*paddr));
+
+	return (nvl);
+}
+
 static int
 pf_nvpool_to_pool(const nvlist_t *nvl, struct pf_kpool *kpool)
 {
@@ -1654,6 +1668,33 @@ errout:
 	return (error);
 }
 
+static nvlist_t *
+pf_pool_to_nvpool(const struct pf_kpool *pool)
+{
+	nvlist_t *nvl;
+	nvlist_t *tmp;
+
+	nvl = nvlist_create(0);
+	if (nvl == NULL)
+		return (NULL);
+
+	nvlist_add_binary(nvl, "key", &pool->key, sizeof(pool->key));
+	tmp = pf_addr_to_nvaddr(&pool->counter);
+	if (tmp == NULL)
+		goto error;
+	nvlist_add_nvlist(nvl, "counter", tmp);
+
+	nvlist_add_number(nvl, "tblidx", pool->tblidx);
+	pf_uint16_array_nv(nvl, "proxy_port", pool->proxy_port, 2);
+	nvlist_add_number(nvl, "opts", pool->opts);
+
+	return (nvl);
+
+error:
+	nvlist_destroy(nvl);
+	return (NULL);
+}
+
 static int
 pf_nvaddr_wrap_to_addr_wrap(const nvlist_t *nvl, struct pf_addr_wrap *addr)
 {
@@ -1694,6 +1735,37 @@ errout:
 	return (error);
 }
 
+static nvlist_t *
+pf_addr_wrap_to_nvaddr_wrap(const struct pf_addr_wrap *addr)
+{
+	nvlist_t *nvl;
+	nvlist_t *tmp;
+
+	nvl = nvlist_create(0);
+	if (nvl == NULL)
+		return (NULL);
+
+	nvlist_add_number(nvl, "type", addr->type);
+	nvlist_add_number(nvl, "iflags", addr->iflags);
+	nvlist_add_string(nvl, "ifname", addr->v.ifname);
+	nvlist_add_string(nvl, "tblname", addr->v.tblname);
+
+	tmp = pf_addr_to_nvaddr(&addr->v.a.addr);
+	if (tmp == NULL)
+		goto error;
+	nvlist_add_nvlist(nvl, "addr", tmp);
+	tmp = pf_addr_to_nvaddr(&addr->v.a.mask);
+	if (tmp == NULL)
+		goto error;
+	nvlist_add_nvlist(nvl, "mask", tmp);
+
+	return (nvl);
+
+error:
+	nvlist_destroy(nvl);
+	return (NULL);
+}
+
 static int
 pf_validate_op(uint8_t op)
 {
@@ -1736,6 +1808,31 @@ errout:
 	return (error);
 }
 
+static nvlist_t *
+pf_rule_addr_to_nvrule_addr(const struct pf_rule_addr *addr)
+{
+	nvlist_t *nvl;
+	nvlist_t *tmp;
+
+	nvl = nvlist_create(0);
+	if (nvl == NULL)
+		return (NULL);
+
+	tmp = pf_addr_wrap_to_nvaddr_wrap(&addr->addr);
+	if (tmp == NULL)
+		goto error;
+	nvlist_add_nvlist(nvl, "addr", tmp);
+	pf_uint16_array_nv(nvl, "port", addr->port, 2);
+	nvlist_add_number(nvl, "neg", addr->neg);
+	nvlist_add_number(nvl, "port_op", addr->port_op);
+
+	return (nvl);
+
+error:
+	nvlist_destroy(nvl);
+	return (NULL);
+}
+
 static int
 pf_nvrule_uid_to_rule_uid(const nvlist_t *nvl, struct pf_rule_uid *uid)
 {
@@ -1752,6 +1849,21 @@ errout:
 	return (error);
 }
 
+static nvlist_t *
+pf_rule_uid_to_nvrule_uid(const struct pf_rule_uid *uid)
+{
+	nvlist_t *nvl;
+
+	nvl = nvlist_create(0);
+	if (nvl == NULL)
+		return (NULL);
+
+	pf_uint32_array_nv(nvl, "uid", uid->uid, 2);
+	nvlist_add_number(nvl, "op", uid->op);
+
+	return (nvl);
+}
+
 static int
 pf_nvrule_gid_to_rule_gid(const nvlist_t *nvl, struct pf_rule_gid *gid)
 {
@@ -1913,6 +2025,158 @@ errout:
 	return (error);
 }
 
+static nvlist_t *
+pf_divert_to_nvdivert(const struct pf_krule *rule)
+{
+	nvlist_t *nvl;
+	nvlist_t *tmp;
+
+	nvl = nvlist_create(0);
+	if (nvl == NULL)
+		return (NULL);
+
+	tmp = pf_addr_to_nvaddr(&rule->divert.addr);
+	if (tmp == NULL)
+		goto error;
+	nvlist_add_nvlist(nvl, "addr", tmp);
+	nvlist_add_number(nvl, "port", rule->divert.port);
+
+	return (nvl);
+
+error:
+	nvlist_destroy(nvl);
+	return (NULL);
+}
+
+static nvlist_t *
+pf_krule_to_nvrule(const struct pf_krule *rule)
+{
+	nvlist_t *nvl, *tmp;
+
+	nvl = nvlist_create(0);
+	if (nvl == NULL)
+		return (nvl);
+
+	nvlist_add_number(nvl, "nr", rule->nr);
+	tmp = pf_rule_addr_to_nvrule_addr(&rule->src);
+	if (tmp == NULL)
+		goto error;
+	nvlist_add_nvlist(nvl, "src", tmp);
+	tmp = pf_rule_addr_to_nvrule_addr(&rule->dst);
+	if (tmp == NULL)
+		goto error;
+	nvlist_add_nvlist(nvl, "dst", tmp);
+
+	for (int i = 0; i < PF_SKIP_COUNT; i++) {
+		nvlist_append_number_array(nvl, "skip",
+		    rule->skip[i].ptr ? rule->skip[i].ptr->nr : -1);
+	}
+
+	nvlist_add_string(nvl, "label", rule->label);
+	nvlist_add_string(nvl, "ifname", rule->ifname);
+	nvlist_add_string(nvl, "qname", rule->qname);
+	nvlist_add_string(nvl, "pqname", rule->pqname);
+	nvlist_add_string(nvl, "tagname", rule->tagname);
+	nvlist_add_string(nvl, "match_tagname", rule->match_tagname);
+	nvlist_add_string(nvl, "overload_tblname", rule->overload_tblname);
+
+	tmp = pf_pool_to_nvpool(&rule->rpool);
+	if (tmp == NULL)
+		goto error;
+	nvlist_add_nvlist(nvl, "rpool", tmp);
+
+	nvlist_add_number(nvl, "evaluations",
+	    counter_u64_fetch(rule->evaluations));
+	for (int i = 0; i < 2; i++) {
+		nvlist_append_number_array(nvl, "packets",
+		    counter_u64_fetch(rule->packets[i]));
+		nvlist_append_number_array(nvl, "bytes",
+		    counter_u64_fetch(rule->bytes[i]));
+	}
+
+	nvlist_add_number(nvl, "os_fingerprint", rule->os_fingerprint);
+
+	nvlist_add_number(nvl, "rtableid", rule->rtableid);
+	pf_uint32_array_nv(nvl, "timeout", rule->timeout, PFTM_MAX);
+	nvlist_add_number(nvl, "max_states", rule->max_states);
+	nvlist_add_number(nvl, "max_src_nodes", rule->max_src_nodes);
+	nvlist_add_number(nvl, "max_src_states", rule->max_src_states);
+	nvlist_add_number(nvl, "max_src_conn", rule->max_src_conn);
+	nvlist_add_number(nvl, "max_src_conn_rate.limit",
+	    rule->max_src_conn_rate.limit);
+	nvlist_add_number(nvl, "max_src_conn_rate.seconds",
+	    rule->max_src_conn_rate.seconds);
+	nvlist_add_number(nvl, "qid", rule->qid);
+	nvlist_add_number(nvl, "pqid", rule->pqid);
+	nvlist_add_number(nvl, "prob", rule->prob);
+	nvlist_add_number(nvl, "cuid", rule->cuid);
+	nvlist_add_number(nvl, "cpid", rule->cpid);
+
+	nvlist_add_number(nvl, "states_cur",
+	    counter_u64_fetch(rule->states_cur));
+	nvlist_add_number(nvl, "states_tot",
+	    counter_u64_fetch(rule->states_tot));
+	nvlist_add_number(nvl, "src_nodes",
+	    counter_u64_fetch(rule->src_nodes));
+
+	nvlist_add_number(nvl, "return_icmp", rule->return_icmp);
+	nvlist_add_number(nvl, "return_icmp6", rule->return_icmp6);
+
+	nvlist_add_number(nvl, "max_mss", rule->max_mss);
+	nvlist_add_number(nvl, "scrub_flags", rule->scrub_flags);
+
+	tmp = pf_rule_uid_to_nvrule_uid(&rule->uid);
+	if (tmp == NULL)
+		goto error;
+	nvlist_add_nvlist(nvl, "uid", tmp);
+	tmp = pf_rule_uid_to_nvrule_uid((const struct pf_rule_uid *)&rule->gid);
+	if (tmp == NULL)
+		goto error;
+	nvlist_add_nvlist(nvl, "gid", tmp);
+
+	nvlist_add_number(nvl, "rule_flag", rule->rule_flag);
+	nvlist_add_number(nvl, "action", rule->action);
+	nvlist_add_number(nvl, "direction", rule->direction);
+	nvlist_add_number(nvl, "log", rule->log);
+	nvlist_add_number(nvl, "logif", rule->logif);
+	nvlist_add_number(nvl, "quick", rule->quick);
+	nvlist_add_number(nvl, "ifnot", rule->ifnot);
+	nvlist_add_number(nvl, "match_tag_not", rule->match_tag_not);
+	nvlist_add_number(nvl, "natpass", rule->natpass);
+
+	nvlist_add_number(nvl, "keep_state", rule->keep_state);
+	nvlist_add_number(nvl, "af", rule->af);
+	nvlist_add_number(nvl, "proto", rule->proto);
+	nvlist_add_number(nvl, "type", rule->type);
+	nvlist_add_number(nvl, "code", rule->code);
+	nvlist_add_number(nvl, "flags", rule->flags);
+	nvlist_add_number(nvl, "flagset", rule->flagset);
+	nvlist_add_number(nvl, "min_ttl", rule->min_ttl);
+	nvlist_add_number(nvl, "allow_opts", rule->allow_opts);
+	nvlist_add_number(nvl, "rt", rule->rt);
+	nvlist_add_number(nvl, "return_ttl", rule->return_ttl);
+	nvlist_add_number(nvl, "tos", rule->tos);
+	nvlist_add_number(nvl, "set_tos", rule->set_tos);
+	nvlist_add_number(nvl, "anchor_relative", rule->anchor_relative);
+	nvlist_add_number(nvl, "anchor_wildcard", rule->anchor_wildcard);
+
+	nvlist_add_number(nvl, "flush", rule->flush);
+	nvlist_add_number(nvl, "prio", rule->prio);
+
+	pf_uint8_array_nv(nvl, "set_prio", &rule->prio, 2);
+
+	tmp = pf_divert_to_nvdivert(rule);
+	if (tmp == NULL)
+		goto error;
+	nvlist_add_nvlist(nvl, "divert", tmp);
+
+	return (nvl);
+
+error:
+	nvlist_destroy(nvl);
+	return (NULL);
+}
+
 static int
 pf_rule_to_krule(const struct pf_rule *rule, struct pf_krule *krule)
 {
@@ -2255,6 +2519,7 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
 		switch (cmd) {
 		case DIOCGETRULES:
 		case DIOCGETRULE:
+		case DIOCGETRULENV:
 		case DIOCGETADDRS:
 		case DIOCGETADDR:
 		case DIOCGETSTATE:
@@ -2336,6 +2601,7 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
 		case DIOCIGETIFACES:
 		case DIOCGIFSPEEDV1:
 		case DIOCGIFSPEEDV0:
+		case DIOCGETRULENV:
 			break;
 		case DIOCRCLRTABLES:
 		case DIOCRADDTABLES:
@@ -2571,6 +2837,138 @@ DIOCADDRULENV_error:
 		break;
 	}
 
+	case DIOCGETRULENV: {
+		struct pfioc_nv		*nv = (struct pfioc_nv *)addr;
+		nvlist_t		*nvrule = NULL;
+		nvlist_t		*nvl = NULL;
+		struct pf_kruleset	*ruleset;
+		struct pf_krule		*rule;
+		void			*nvlpacked = NULL;
+		int			 rs_num, nr;
+		bool			 clear_counter = false;
+
+#define	ERROUT(x)	do { error = (x); goto DIOCGETRULENV_error; } while (0)
+
+		if (nv->len > pf_ioctl_maxcount)
+			ERROUT(ENOMEM);
+
+		/* Copy the request in */
+		nvlpacked = malloc(nv->len, M_TEMP, M_WAITOK);
+		if (nvlpacked == NULL)
+			ERROUT(ENOMEM);
+
+		error = copyin(nv->data, nvlpacked, nv->len);
+		if (error)
+			ERROUT(error);
+
+		nvl = nvlist_unpack(nvlpacked, nv->len, 0);
+		if (nvl == NULL)
+			ERROUT(EBADMSG);
+
+		if (! nvlist_exists_string(nvl, "anchor"))
+			ERROUT(EBADMSG);
+		if (! nvlist_exists_number(nvl, "ruleset"))
+			ERROUT(EBADMSG);
+		if (! nvlist_exists_number(nvl, "ticket"))
+			ERROUT(EBADMSG);
+		if (! nvlist_exists_number(nvl, "nr"))
+			ERROUT(EBADMSG);
+
+		if (nvlist_exists_bool(nvl, "clear_counter"))
+			clear_counter = nvlist_get_bool(nvl, "clear_counter");
+
+		if (clear_counter && !(flags & FWRITE))
+			ERROUT(EACCES);
+
+		nr = nvlist_get_number(nvl, "nr");
+
+		PF_RULES_WLOCK();
+		ruleset = pf_find_kruleset(nvlist_get_string(nvl, "anchor"));
+		if (ruleset == NULL) {
+			PF_RULES_WUNLOCK();
+			ERROUT(ENOENT);
+		}
+
+		rs_num = pf_get_ruleset_number(nvlist_get_number(nvl, "ruleset"));
+		if (rs_num >= PF_RULESET_MAX) {
+			PF_RULES_WUNLOCK();
+			ERROUT(EINVAL);
+		}
+
+		if (nvlist_get_number(nvl, "ticket") !=
+		    ruleset->rules[rs_num].active.ticket) {
+			PF_RULES_WUNLOCK();
+			ERROUT(EBUSY);
+			break;
+		}
+
+		if ((error = nvlist_error(nvl))) {
+			PF_RULES_WUNLOCK();
+			ERROUT(error);
+		}
+
+		rule = TAILQ_FIRST(ruleset->rules[rs_num].active.ptr);
+		while ((rule != NULL) && (rule->nr != nr))
+			rule = TAILQ_NEXT(rule, entries);
+		if (rule == NULL) {
+			PF_RULES_WUNLOCK();
+			ERROUT(EBUSY);
+			break;
+		}
+
+		nvrule = pf_krule_to_nvrule(rule);
+
+		nvlist_destroy(nvl);
+		nvl = nvlist_create(0);
+		if (nvl == NULL) {
+			PF_RULES_WUNLOCK();
+			ERROUT(ENOMEM);
+		}
+		nvlist_add_number(nvl, "nr", nr);
+		nvlist_add_nvlist(nvl, "rule", nvrule);
+		nvrule = NULL;
+		if (pf_kanchor_nvcopyout(ruleset, rule, nvl)) {
+			PF_RULES_WUNLOCK();
+			ERROUT(EBUSY);
+		}
+
+		free(nvlpacked, M_TEMP);
+		nvlpacked = nvlist_pack(nvl, &nv->len);
+		if (nvlpacked == NULL) {
+			PF_RULES_WUNLOCK();
+			ERROUT(ENOMEM);
+		}
+
+		if (nv->size == 0) {
+			PF_RULES_WUNLOCK();
+			ERROUT(0);
+		}
+		else if (nv->size < nv->len) {
+			PF_RULES_WUNLOCK();
+			ERROUT(ENOSPC);
+		}
+
+		error = copyout(nvlpacked, nv->data, nv->len);
+
+		if (clear_counter) {
+			counter_u64_zero(rule->evaluations);
+			for (int i = 0; i < 2; i++) {
+				counter_u64_zero(rule->packets[i]);
+				counter_u64_zero(rule->bytes[i]);
+			}
+			counter_u64_zero(rule->states_tot);
+		}
+		PF_RULES_WUNLOCK();
+
+#undef ERROUT
+DIOCGETRULENV_error:
+		free(nvlpacked, M_TEMP);
+		nvlist_destroy(nvrule);
+		nvlist_destroy(nvl);
+
+		break;
+	}
+
 	case DIOCCHANGERULE: {
 		struct pfioc_rule	*pcr = (struct pfioc_rule *)addr;
 		struct pf_kruleset	*ruleset;
diff --git a/sys/netpfil/pf/pf_nv.c b/sys/netpfil/pf/pf_nv.c
index d583844c4086..d88c0b14e435 100644
--- a/sys/netpfil/pf/pf_nv.c
+++ b/sys/netpfil/pf/pf_nv.c
@@ -37,7 +37,7 @@ __FBSDID("$FreeBSD$");
 
 #define	PV_NV_IMPL_UINT(fnname, type, max)					\
 	int									\
-	fnname(const nvlist_t *nvl, const char *name, type *val)		\
+	pf_nv ## fnname(const nvlist_t *nvl, const char *name, type *val)	\
 	{									\
 		uint64_t raw;							\
 		if (! nvlist_exists_number(nvl, name))				\
@@ -49,8 +49,8 @@ __FBSDID("$FreeBSD$");
 		return (0);							\
 	}									\
 	int									\
-	fnname ## _array(const nvlist_t *nvl, const char *name, type *array, 	\
-	    size_t maxelems, size_t *nelems)					\
+	pf_nv ## fnname ## _array(const nvlist_t *nvl, const char *name,	\
+	    type *array, size_t maxelems, size_t *nelems)			\
 	{									\
 		const uint64_t *n;						\
 		size_t nitems;							\
@@ -68,7 +68,18 @@ __FBSDID("$FreeBSD$");
 			array[i] = (type)n[i];					\
 		}								\
 		return (0);							\
+	}									\
+	void									\
+	pf_ ## fnname ## _array_nv(nvlist_t *nvl, const char *name,		\
+	    const type *numbers, size_t count)					\
+	{									\
+		uint64_t tmp;							\
+		for (size_t i = 0; i < count; i++) {				\
+			tmp = numbers[i];					\
+			nvlist_append_number_array(nvl, name, tmp);		\
+		}								\
 	}
+
 int
 pf_nvbinary(const nvlist_t *nvl, const char *name, void *data,
     size_t expected_size)
@@ -90,9 +101,9 @@ pf_nvbinary(const nvlist_t *nvl, const char *name, void *data,
 	return (0);
 }
 
-PV_NV_IMPL_UINT(pf_nvuint8, uint8_t, UINT8_MAX)
-PV_NV_IMPL_UINT(pf_nvuint16, uint16_t, UINT16_MAX);
-PV_NV_IMPL_UINT(pf_nvuint32, uint32_t, UINT32_MAX)
+PV_NV_IMPL_UINT(uint8, uint8_t, UINT8_MAX)
+PV_NV_IMPL_UINT(uint16, uint16_t, UINT16_MAX);
+PV_NV_IMPL_UINT(uint32, uint32_t, UINT32_MAX)
 
 int
 pf_nvint(const nvlist_t *nvl, const char *name, int *val)
diff --git a/sys/netpfil/pf/pf_nv.h b/sys/netpfil/pf/pf_nv.h
index f0db1e880e9e..0a0f9beeef40 100644
--- a/sys/netpfil/pf/pf_nv.h
+++ b/sys/netpfil/pf/pf_nv.h
@@ -36,12 +36,19 @@ int	pf_nvint(const nvlist_t *, const char *, int *);
 int	pf_nvuint8(const nvlist_t *, const char *, uint8_t *);
 int	pf_nvuint8_array(const nvlist_t *, const char *, uint8_t *,
 	    size_t, size_t *);
+void	pf_uint8_array_nv(nvlist_t *, const char *, const uint8_t *,
+	    size_t);
 int	pf_nvuint16(const nvlist_t *, const char *, uint16_t *);
 int	pf_nvuint16_array(const nvlist_t *, const char *, uint16_t *,
 	    size_t, size_t *);
+void	pf_uint16_array_nv(nvlist_t *, const char *, const uint16_t *,
+	    size_t);
 int	pf_nvuint32(const nvlist_t *, const char *, uint32_t *);
 int	pf_nvuint32_array(const nvlist_t *, const char *, uint32_t *,
 	    size_t, size_t *);
+void	pf_uint32_array_nv(nvlist_t *, const char *, const uint32_t *,
+	    size_t);
+
 int	pf_nvstring(const nvlist_t *, const char *, char *, size_t);
 
 #define	PFNV_CHK(x)	do {	\
diff --git a/sys/netpfil/pf/pf_ruleset.c b/sys/netpfil/pf/pf_ruleset.c
index 31a4ed879937..227157c2876d 100644
--- a/sys/netpfil/pf/pf_ruleset.c
+++ b/sys/netpfil/pf/pf_ruleset.c
@@ -336,6 +336,53 @@ pf_kanchor_setup(struct pf_krule *r, const struct pf_kruleset *s,
 	return (0);
 }
 
+int
+pf_kanchor_nvcopyout(const struct pf_kruleset *rs, const struct pf_krule *r,
+    nvlist_t *nvl)
+{
+	char anchor_call[MAXPATHLEN] = { 0 };
+
+	if (r->anchor == NULL)
+		goto done;
+	if (!r->anchor_relative) {
+		strlcpy(anchor_call, "/", sizeof(anchor_call));
+		strlcat(anchor_call, r->anchor->path,
+		    sizeof(anchor_call));
+	} else {
+		char	 a[MAXPATHLEN];
+		char	*p;
+		int	 i;
+		if (rs->anchor == NULL)
+			a[0] = 0;
+		else
+			strlcpy(a, rs->anchor->path, MAXPATHLEN);
+		for (i = 1; i < r->anchor_relative; ++i) {
+			if ((p = strrchr(a, '/')) == NULL)
+				p = a;
+			*p = 0;
+			strlcat(anchor_call, "../",
+			    sizeof(anchor_call));
+		}
+		if (strncmp(a, r->anchor->path, strlen(a))) {
+			printf("pf_anchor_copyout: '%s' '%s'\n", a,
+			    r->anchor->path);
+			return (1);
+		}
+		if (strlen(r->anchor->path) > strlen(a))
+			strlcat(anchor_call, r->anchor->path + (a[0] ?
+			    strlen(a) + 1 : 0), sizeof(anchor_call));
+
+	}
+	if (r->anchor_wildcard)
+		strlcat(anchor_call, anchor_call[0] ? "/*" : "*",
+		    sizeof(anchor_call));
+
+done:
+	nvlist_add_string(nvl, "anchor_call", anchor_call);
+
+	return (0);
+}
+
 int
 pf_kanchor_copyout(const struct pf_kruleset *rs, const struct pf_krule *r,
     struct pfioc_rule *pr)



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202105071525.147FPeci026107>