xref: /freebsd/sys/netpfil/pf/pf_nv.c (revision 63b3c1c77036814c85d36fe7a48c704db7c6fc9c)
15c62ededSKristof Provost /*-
25c62ededSKristof Provost  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
35c62ededSKristof Provost  *
45c62ededSKristof Provost  * Copyright (c) 2021 Rubicon Communications, LLC (Netgate)
55c62ededSKristof Provost  *
65c62ededSKristof Provost  * Redistribution and use in source and binary forms, with or without
75c62ededSKristof Provost  * modification, are permitted provided that the following conditions
85c62ededSKristof Provost  * are met:
95c62ededSKristof Provost  * 1. Redistributions of source code must retain the above copyright
105c62ededSKristof Provost  *    notice, this list of conditions and the following disclaimer.
115c62ededSKristof Provost  * 2. Redistributions in binary form must reproduce the above copyright
125c62ededSKristof Provost  *    notice, this list of conditions and the following disclaimer in the
135c62ededSKristof Provost  *    documentation and/or other materials provided with the distribution.
145c62ededSKristof Provost  *
155c62ededSKristof Provost  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
165c62ededSKristof Provost  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
175c62ededSKristof Provost  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
185c62ededSKristof Provost  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
195c62ededSKristof Provost  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
205c62ededSKristof Provost  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
215c62ededSKristof Provost  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
225c62ededSKristof Provost  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
235c62ededSKristof Provost  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
245c62ededSKristof Provost  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
255c62ededSKristof Provost  * SUCH DAMAGE.
265c62ededSKristof Provost  *
275c62ededSKristof Provost  */
285c62ededSKristof Provost #include <sys/cdefs.h>
295c62ededSKristof Provost __FBSDID("$FreeBSD$");
305c62ededSKristof Provost 
313032c353SKristof Provost #include "opt_inet.h"
323032c353SKristof Provost #include "opt_inet6.h"
333032c353SKristof Provost 
345c62ededSKristof Provost #include <sys/param.h>
355c62ededSKristof Provost #include <sys/errno.h>
365c62ededSKristof Provost #include <sys/limits.h>
373032c353SKristof Provost #include <sys/queue.h>
385c62ededSKristof Provost #include <sys/systm.h>
395c62ededSKristof Provost 
405c62ededSKristof Provost #include <netpfil/pf/pf_nv.h>
415c62ededSKristof Provost 
42eaabed8aSKristof Provost #define	PF_NV_IMPL_UINT(fnname, type, max)					\
435c62ededSKristof Provost 	int									\
447c434289SKristof Provost 	pf_nv ## fnname ## _opt(const nvlist_t *nvl, const char *name,		\
457c434289SKristof Provost 	    type *val, type dflt)						\
467c434289SKristof Provost 	{									\
477c434289SKristof Provost 		uint64_t raw;							\
487c434289SKristof Provost 		if (! nvlist_exists_number(nvl, name)) {			\
497c434289SKristof Provost 			*val = dflt;						\
507c434289SKristof Provost 			return (0);						\
517c434289SKristof Provost 		}								\
527c434289SKristof Provost 		raw = nvlist_get_number(nvl, name);				\
537c434289SKristof Provost 		if (raw > max)							\
547c434289SKristof Provost 			return (ERANGE);					\
557c434289SKristof Provost 		*val = (type)raw;						\
567c434289SKristof Provost 		return (0);							\
577c434289SKristof Provost 	}									\
587c434289SKristof Provost 	int									\
59d710367dSKristof Provost 	pf_nv ## fnname(const nvlist_t *nvl, const char *name, type *val)	\
605c62ededSKristof Provost 	{									\
615c62ededSKristof Provost 		uint64_t raw;							\
625c62ededSKristof Provost 		if (! nvlist_exists_number(nvl, name))				\
635c62ededSKristof Provost 			return (EINVAL);					\
645c62ededSKristof Provost 		raw = nvlist_get_number(nvl, name);				\
655c62ededSKristof Provost 		if (raw > max)							\
665c62ededSKristof Provost 			return (ERANGE);					\
675c62ededSKristof Provost 		*val = (type)raw;						\
685c62ededSKristof Provost 		return (0);							\
695c62ededSKristof Provost 	}									\
705c62ededSKristof Provost 	int									\
71d710367dSKristof Provost 	pf_nv ## fnname ## _array(const nvlist_t *nvl, const char *name,	\
72d710367dSKristof Provost 	    type *array, size_t maxelems, size_t *nelems)			\
735c62ededSKristof Provost 	{									\
745c62ededSKristof Provost 		const uint64_t *n;						\
755c62ededSKristof Provost 		size_t nitems;							\
765c62ededSKristof Provost 		bzero(array, sizeof(type) * maxelems);				\
775c62ededSKristof Provost 		if (! nvlist_exists_number_array(nvl, name))			\
785c62ededSKristof Provost 			return (EINVAL);					\
795c62ededSKristof Provost 		n = nvlist_get_number_array(nvl, name, &nitems);		\
805c62ededSKristof Provost 		if (nitems != maxelems)						\
815c62ededSKristof Provost 			return (E2BIG);						\
825c62ededSKristof Provost 		if (nelems != NULL)						\
835c62ededSKristof Provost 			*nelems = nitems;					\
845c62ededSKristof Provost 		for (size_t i = 0; i < nitems; i++) {				\
855c62ededSKristof Provost 			if (n[i] > max)						\
865c62ededSKristof Provost 				return (ERANGE);				\
875c62ededSKristof Provost 			array[i] = (type)n[i];					\
885c62ededSKristof Provost 		}								\
895c62ededSKristof Provost 		return (0);							\
90d710367dSKristof Provost 	}									\
91d710367dSKristof Provost 	void									\
92d710367dSKristof Provost 	pf_ ## fnname ## _array_nv(nvlist_t *nvl, const char *name,		\
93d710367dSKristof Provost 	    const type *numbers, size_t count)					\
94d710367dSKristof Provost 	{									\
95d710367dSKristof Provost 		uint64_t tmp;							\
96d710367dSKristof Provost 		for (size_t i = 0; i < count; i++) {				\
97d710367dSKristof Provost 			tmp = numbers[i];					\
98d710367dSKristof Provost 			nvlist_append_number_array(nvl, name, tmp);		\
99d710367dSKristof Provost 		}								\
1005c62ededSKristof Provost 	}
101d710367dSKristof Provost 
1025c62ededSKristof Provost int
1035c62ededSKristof Provost pf_nvbinary(const nvlist_t *nvl, const char *name, void *data,
1045c62ededSKristof Provost     size_t expected_size)
1055c62ededSKristof Provost {
1065c62ededSKristof Provost 	const uint8_t *nvdata;
1075c62ededSKristof Provost 	size_t len;
1085c62ededSKristof Provost 
1095c62ededSKristof Provost 	bzero(data, expected_size);
1105c62ededSKristof Provost 
1115c62ededSKristof Provost 	if (! nvlist_exists_binary(nvl, name))
1125c62ededSKristof Provost 		return (EINVAL);
1135c62ededSKristof Provost 
1145c62ededSKristof Provost 	nvdata = (const uint8_t *)nvlist_get_binary(nvl, name, &len);
1155c62ededSKristof Provost 	if (len > expected_size)
1165c62ededSKristof Provost 		return (EINVAL);
1175c62ededSKristof Provost 
1185c62ededSKristof Provost 	memcpy(data, nvdata, len);
1195c62ededSKristof Provost 
1205c62ededSKristof Provost 	return (0);
1215c62ededSKristof Provost }
1225c62ededSKristof Provost 
123eaabed8aSKristof Provost PF_NV_IMPL_UINT(uint8, uint8_t, UINT8_MAX);
124eaabed8aSKristof Provost PF_NV_IMPL_UINT(uint16, uint16_t, UINT16_MAX);
125eaabed8aSKristof Provost PF_NV_IMPL_UINT(uint32, uint32_t, UINT32_MAX);
1267606a45dSKristof Provost PF_NV_IMPL_UINT(uint64, uint64_t, UINT64_MAX);
1275c62ededSKristof Provost 
1285c62ededSKristof Provost int
1295c62ededSKristof Provost pf_nvint(const nvlist_t *nvl, const char *name, int *val)
1305c62ededSKristof Provost {
1315c62ededSKristof Provost 	int64_t raw;
1325c62ededSKristof Provost 
1335c62ededSKristof Provost 	if (! nvlist_exists_number(nvl, name))
1345c62ededSKristof Provost 		return (EINVAL);
1355c62ededSKristof Provost 
1365c62ededSKristof Provost 	raw = nvlist_get_number(nvl, name);
1375c62ededSKristof Provost 	if (raw > INT_MAX || raw < INT_MIN)
1385c62ededSKristof Provost 		return (ERANGE);
1395c62ededSKristof Provost 
1405c62ededSKristof Provost 	*val = (int)raw;
1415c62ededSKristof Provost 
1425c62ededSKristof Provost 	return (0);
1435c62ededSKristof Provost }
1445c62ededSKristof Provost 
1455c62ededSKristof Provost int
1465c62ededSKristof Provost pf_nvstring(const nvlist_t *nvl, const char *name, char *str, size_t maxlen)
1475c62ededSKristof Provost {
1485c62ededSKristof Provost 	int ret;
1495c62ededSKristof Provost 
1505c62ededSKristof Provost 	if (! nvlist_exists_string(nvl, name))
1515c62ededSKristof Provost 		return (EINVAL);
1525c62ededSKristof Provost 
1535c62ededSKristof Provost 	ret = strlcpy(str, nvlist_get_string(nvl, name), maxlen);
1545c62ededSKristof Provost 	if (ret >= maxlen)
1555c62ededSKristof Provost 		return (EINVAL);
1565c62ededSKristof Provost 
1575c62ededSKristof Provost 	return (0);
1585c62ededSKristof Provost }
1593032c353SKristof Provost 
1603032c353SKristof Provost static int
1613032c353SKristof Provost pf_nvaddr_to_addr(const nvlist_t *nvl, struct pf_addr *paddr)
1623032c353SKristof Provost {
1633032c353SKristof Provost 	return (pf_nvbinary(nvl, "addr", paddr, sizeof(*paddr)));
1643032c353SKristof Provost }
1653032c353SKristof Provost 
1663032c353SKristof Provost static nvlist_t *
1673032c353SKristof Provost pf_addr_to_nvaddr(const struct pf_addr *paddr)
1683032c353SKristof Provost {
1693032c353SKristof Provost 	nvlist_t *nvl;
1703032c353SKristof Provost 
1713032c353SKristof Provost 	nvl = nvlist_create(0);
1723032c353SKristof Provost 	if (nvl == NULL)
1733032c353SKristof Provost 		return (NULL);
1743032c353SKristof Provost 
1753032c353SKristof Provost 	nvlist_add_binary(nvl, "addr", paddr, sizeof(*paddr));
1763032c353SKristof Provost 
1773032c353SKristof Provost 	return (nvl);
1783032c353SKristof Provost }
1793032c353SKristof Provost 
1803032c353SKristof Provost static int
1813032c353SKristof Provost pf_nvmape_to_mape(const nvlist_t *nvl, struct pf_mape_portset *mape)
1823032c353SKristof Provost {
1833032c353SKristof Provost 	int error = 0;
1843032c353SKristof Provost 
1853032c353SKristof Provost 	bzero(mape, sizeof(*mape));
1863032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "offset", &mape->offset));
1873032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "psidlen", &mape->psidlen));
1883032c353SKristof Provost 	PFNV_CHK(pf_nvuint16(nvl, "psid", &mape->psid));
1893032c353SKristof Provost 
1903032c353SKristof Provost errout:
1913032c353SKristof Provost 	return (error);
1923032c353SKristof Provost }
1933032c353SKristof Provost 
1943032c353SKristof Provost static nvlist_t *
1953032c353SKristof Provost pf_mape_to_nvmape(const struct pf_mape_portset *mape)
1963032c353SKristof Provost {
1973032c353SKristof Provost 	nvlist_t *nvl;
1983032c353SKristof Provost 
1993032c353SKristof Provost 	nvl = nvlist_create(0);
2003032c353SKristof Provost 	if (nvl == NULL)
2013032c353SKristof Provost 		return (NULL);
2023032c353SKristof Provost 
2033032c353SKristof Provost 	nvlist_add_number(nvl, "offset", mape->offset);
2043032c353SKristof Provost 	nvlist_add_number(nvl, "psidlen", mape->psidlen);
2053032c353SKristof Provost 	nvlist_add_number(nvl, "psid", mape->psid);
2063032c353SKristof Provost 
2073032c353SKristof Provost 	return (nvl);
2083032c353SKristof Provost }
2093032c353SKristof Provost 
2103032c353SKristof Provost static int
2113032c353SKristof Provost pf_nvpool_to_pool(const nvlist_t *nvl, struct pf_kpool *kpool)
2123032c353SKristof Provost {
2133032c353SKristof Provost 	int error = 0;
2143032c353SKristof Provost 
2153032c353SKristof Provost 	bzero(kpool, sizeof(*kpool));
2163032c353SKristof Provost 
2173032c353SKristof Provost 	PFNV_CHK(pf_nvbinary(nvl, "key", &kpool->key, sizeof(kpool->key)));
2183032c353SKristof Provost 
2193032c353SKristof Provost 	if (nvlist_exists_nvlist(nvl, "counter")) {
2203032c353SKristof Provost 		PFNV_CHK(pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "counter"),
2213032c353SKristof Provost 		    &kpool->counter));
2223032c353SKristof Provost 	}
2233032c353SKristof Provost 
2243032c353SKristof Provost 	PFNV_CHK(pf_nvint(nvl, "tblidx", &kpool->tblidx));
2253032c353SKristof Provost 	PFNV_CHK(pf_nvuint16_array(nvl, "proxy_port", kpool->proxy_port, 2,
2263032c353SKristof Provost 	    NULL));
2273032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "opts", &kpool->opts));
2283032c353SKristof Provost 
2293032c353SKristof Provost 	if (nvlist_exists_nvlist(nvl, "mape")) {
2303032c353SKristof Provost 		PFNV_CHK(pf_nvmape_to_mape(nvlist_get_nvlist(nvl, "mape"),
2313032c353SKristof Provost 		    &kpool->mape));
2323032c353SKristof Provost 	}
2333032c353SKristof Provost 
2343032c353SKristof Provost errout:
2353032c353SKristof Provost 	return (error);
2363032c353SKristof Provost }
2373032c353SKristof Provost 
2383032c353SKristof Provost static nvlist_t *
2393032c353SKristof Provost pf_pool_to_nvpool(const struct pf_kpool *pool)
2403032c353SKristof Provost {
2413032c353SKristof Provost 	nvlist_t *nvl;
2423032c353SKristof Provost 	nvlist_t *tmp;
2433032c353SKristof Provost 
2443032c353SKristof Provost 	nvl = nvlist_create(0);
2453032c353SKristof Provost 	if (nvl == NULL)
2463032c353SKristof Provost 		return (NULL);
2473032c353SKristof Provost 
2483032c353SKristof Provost 	nvlist_add_binary(nvl, "key", &pool->key, sizeof(pool->key));
2493032c353SKristof Provost 	tmp = pf_addr_to_nvaddr(&pool->counter);
2503032c353SKristof Provost 	if (tmp == NULL)
2513032c353SKristof Provost 		goto error;
2523032c353SKristof Provost 	nvlist_add_nvlist(nvl, "counter", tmp);
2533032c353SKristof Provost 	nvlist_destroy(tmp);
2543032c353SKristof Provost 
2553032c353SKristof Provost 	nvlist_add_number(nvl, "tblidx", pool->tblidx);
2563032c353SKristof Provost 	pf_uint16_array_nv(nvl, "proxy_port", pool->proxy_port, 2);
2573032c353SKristof Provost 	nvlist_add_number(nvl, "opts", pool->opts);
2583032c353SKristof Provost 
2593032c353SKristof Provost 	tmp = pf_mape_to_nvmape(&pool->mape);
2603032c353SKristof Provost 	if (tmp == NULL)
2613032c353SKristof Provost 		goto error;
2623032c353SKristof Provost 	nvlist_add_nvlist(nvl, "mape", tmp);
2633032c353SKristof Provost 	nvlist_destroy(tmp);
2643032c353SKristof Provost 
2653032c353SKristof Provost 	return (nvl);
2663032c353SKristof Provost 
2673032c353SKristof Provost error:
2683032c353SKristof Provost 	nvlist_destroy(nvl);
2693032c353SKristof Provost 	return (NULL);
2703032c353SKristof Provost }
2713032c353SKristof Provost 
2723032c353SKristof Provost static int
2733032c353SKristof Provost pf_nvaddr_wrap_to_addr_wrap(const nvlist_t *nvl, struct pf_addr_wrap *addr)
2743032c353SKristof Provost {
2753032c353SKristof Provost 	int error = 0;
2763032c353SKristof Provost 
2773032c353SKristof Provost 	bzero(addr, sizeof(*addr));
2783032c353SKristof Provost 
2793032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "type", &addr->type));
2803032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "iflags", &addr->iflags));
2813032c353SKristof Provost 	if (addr->type == PF_ADDR_DYNIFTL)
2823032c353SKristof Provost 		PFNV_CHK(pf_nvstring(nvl, "ifname", addr->v.ifname,
2833032c353SKristof Provost 		    sizeof(addr->v.ifname)));
2843032c353SKristof Provost 	if (addr->type == PF_ADDR_TABLE)
2853032c353SKristof Provost 		PFNV_CHK(pf_nvstring(nvl, "tblname", addr->v.tblname,
2863032c353SKristof Provost 		    sizeof(addr->v.tblname)));
2873032c353SKristof Provost 
2883032c353SKristof Provost 	if (! nvlist_exists_nvlist(nvl, "addr"))
2893032c353SKristof Provost 		return (EINVAL);
2903032c353SKristof Provost 	PFNV_CHK(pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "addr"),
2913032c353SKristof Provost 	    &addr->v.a.addr));
2923032c353SKristof Provost 
2933032c353SKristof Provost 	if (! nvlist_exists_nvlist(nvl, "mask"))
2943032c353SKristof Provost 		return (EINVAL);
2953032c353SKristof Provost 	PFNV_CHK(pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "mask"),
2963032c353SKristof Provost 	    &addr->v.a.mask));
2973032c353SKristof Provost 
2983032c353SKristof Provost 	switch (addr->type) {
2993032c353SKristof Provost 	case PF_ADDR_DYNIFTL:
3003032c353SKristof Provost 	case PF_ADDR_TABLE:
3013032c353SKristof Provost 	case PF_ADDR_RANGE:
3023032c353SKristof Provost 	case PF_ADDR_ADDRMASK:
3033032c353SKristof Provost 	case PF_ADDR_NOROUTE:
3043032c353SKristof Provost 	case PF_ADDR_URPFFAILED:
3053032c353SKristof Provost 		break;
3063032c353SKristof Provost 	default:
3073032c353SKristof Provost 		return (EINVAL);
3083032c353SKristof Provost 	}
3093032c353SKristof Provost 
3103032c353SKristof Provost errout:
3113032c353SKristof Provost 	return (error);
3123032c353SKristof Provost }
3133032c353SKristof Provost 
3143032c353SKristof Provost static nvlist_t *
3153032c353SKristof Provost pf_addr_wrap_to_nvaddr_wrap(const struct pf_addr_wrap *addr)
3163032c353SKristof Provost {
3173032c353SKristof Provost 	nvlist_t *nvl;
3183032c353SKristof Provost 	nvlist_t *tmp;
3193032c353SKristof Provost 
3203032c353SKristof Provost 	nvl = nvlist_create(0);
3213032c353SKristof Provost 	if (nvl == NULL)
3223032c353SKristof Provost 		return (NULL);
3233032c353SKristof Provost 
3243032c353SKristof Provost 	nvlist_add_number(nvl, "type", addr->type);
3253032c353SKristof Provost 	nvlist_add_number(nvl, "iflags", addr->iflags);
3263032c353SKristof Provost 	if (addr->type == PF_ADDR_DYNIFTL)
3273032c353SKristof Provost 		nvlist_add_string(nvl, "ifname", addr->v.ifname);
3283032c353SKristof Provost 	if (addr->type == PF_ADDR_TABLE)
3293032c353SKristof Provost 		nvlist_add_string(nvl, "tblname", addr->v.tblname);
3303032c353SKristof Provost 
3313032c353SKristof Provost 	tmp = pf_addr_to_nvaddr(&addr->v.a.addr);
3323032c353SKristof Provost 	if (tmp == NULL)
3333032c353SKristof Provost 		goto error;
3343032c353SKristof Provost 	nvlist_add_nvlist(nvl, "addr", tmp);
3353032c353SKristof Provost 	nvlist_destroy(tmp);
3363032c353SKristof Provost 	tmp = pf_addr_to_nvaddr(&addr->v.a.mask);
3373032c353SKristof Provost 	if (tmp == NULL)
3383032c353SKristof Provost 		goto error;
3393032c353SKristof Provost 	nvlist_add_nvlist(nvl, "mask", tmp);
3403032c353SKristof Provost 	nvlist_destroy(tmp);
3413032c353SKristof Provost 
3423032c353SKristof Provost 	return (nvl);
3433032c353SKristof Provost 
3443032c353SKristof Provost error:
3453032c353SKristof Provost 	nvlist_destroy(nvl);
3463032c353SKristof Provost 	return (NULL);
3473032c353SKristof Provost }
3483032c353SKristof Provost 
3493032c353SKristof Provost static int
3503032c353SKristof Provost pf_validate_op(uint8_t op)
3513032c353SKristof Provost {
3523032c353SKristof Provost 	switch (op) {
3533032c353SKristof Provost 	case PF_OP_NONE:
3543032c353SKristof Provost 	case PF_OP_IRG:
3553032c353SKristof Provost 	case PF_OP_EQ:
3563032c353SKristof Provost 	case PF_OP_NE:
3573032c353SKristof Provost 	case PF_OP_LT:
3583032c353SKristof Provost 	case PF_OP_LE:
3593032c353SKristof Provost 	case PF_OP_GT:
3603032c353SKristof Provost 	case PF_OP_GE:
3613032c353SKristof Provost 	case PF_OP_XRG:
3623032c353SKristof Provost 	case PF_OP_RRG:
3633032c353SKristof Provost 		break;
3643032c353SKristof Provost 	default:
3653032c353SKristof Provost 		return (EINVAL);
3663032c353SKristof Provost 	}
3673032c353SKristof Provost 
3683032c353SKristof Provost 	return (0);
3693032c353SKristof Provost }
3703032c353SKristof Provost 
3713032c353SKristof Provost static int
3723032c353SKristof Provost pf_nvrule_addr_to_rule_addr(const nvlist_t *nvl, struct pf_rule_addr *addr)
3733032c353SKristof Provost {
3743032c353SKristof Provost 	int error = 0;
3753032c353SKristof Provost 
3763032c353SKristof Provost 	if (! nvlist_exists_nvlist(nvl, "addr"))
3773032c353SKristof Provost 		return (EINVAL);
3783032c353SKristof Provost 
3793032c353SKristof Provost 	PFNV_CHK(pf_nvaddr_wrap_to_addr_wrap(nvlist_get_nvlist(nvl, "addr"),
3803032c353SKristof Provost 	    &addr->addr));
3813032c353SKristof Provost 	PFNV_CHK(pf_nvuint16_array(nvl, "port", addr->port, 2, NULL));
3823032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "neg", &addr->neg));
3833032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "port_op", &addr->port_op));
3843032c353SKristof Provost 
3853032c353SKristof Provost 	PFNV_CHK(pf_validate_op(addr->port_op));
3863032c353SKristof Provost 
3873032c353SKristof Provost errout:
3883032c353SKristof Provost 	return (error);
3893032c353SKristof Provost }
3903032c353SKristof Provost 
3913032c353SKristof Provost static nvlist_t *
3923032c353SKristof Provost pf_rule_addr_to_nvrule_addr(const struct pf_rule_addr *addr)
3933032c353SKristof Provost {
3943032c353SKristof Provost 	nvlist_t *nvl;
3953032c353SKristof Provost 	nvlist_t *tmp;
3963032c353SKristof Provost 
3973032c353SKristof Provost 	nvl = nvlist_create(0);
3983032c353SKristof Provost 	if (nvl == NULL)
3993032c353SKristof Provost 		return (NULL);
4003032c353SKristof Provost 
4013032c353SKristof Provost 	tmp = pf_addr_wrap_to_nvaddr_wrap(&addr->addr);
4023032c353SKristof Provost 	if (tmp == NULL)
4033032c353SKristof Provost 		goto error;
4043032c353SKristof Provost 	nvlist_add_nvlist(nvl, "addr", tmp);
4053032c353SKristof Provost 	nvlist_destroy(tmp);
4063032c353SKristof Provost 	pf_uint16_array_nv(nvl, "port", addr->port, 2);
4073032c353SKristof Provost 	nvlist_add_number(nvl, "neg", addr->neg);
4083032c353SKristof Provost 	nvlist_add_number(nvl, "port_op", addr->port_op);
4093032c353SKristof Provost 
4103032c353SKristof Provost 	return (nvl);
4113032c353SKristof Provost 
4123032c353SKristof Provost error:
4133032c353SKristof Provost 	nvlist_destroy(nvl);
4143032c353SKristof Provost 	return (NULL);
4153032c353SKristof Provost }
4163032c353SKristof Provost 
4173032c353SKristof Provost static int
4183032c353SKristof Provost pf_nvrule_uid_to_rule_uid(const nvlist_t *nvl, struct pf_rule_uid *uid)
4193032c353SKristof Provost {
4203032c353SKristof Provost 	int error = 0;
4213032c353SKristof Provost 
4223032c353SKristof Provost 	bzero(uid, sizeof(*uid));
4233032c353SKristof Provost 
4243032c353SKristof Provost 	PFNV_CHK(pf_nvuint32_array(nvl, "uid", uid->uid, 2, NULL));
4253032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "op", &uid->op));
4263032c353SKristof Provost 
4273032c353SKristof Provost 	PFNV_CHK(pf_validate_op(uid->op));
4283032c353SKristof Provost 
4293032c353SKristof Provost errout:
4303032c353SKristof Provost 	return (error);
4313032c353SKristof Provost }
4323032c353SKristof Provost 
4333032c353SKristof Provost static nvlist_t *
4343032c353SKristof Provost pf_rule_uid_to_nvrule_uid(const struct pf_rule_uid *uid)
4353032c353SKristof Provost {
4363032c353SKristof Provost 	nvlist_t *nvl;
4373032c353SKristof Provost 
4383032c353SKristof Provost 	nvl = nvlist_create(0);
4393032c353SKristof Provost 	if (nvl == NULL)
4403032c353SKristof Provost 		return (NULL);
4413032c353SKristof Provost 
4423032c353SKristof Provost 	pf_uint32_array_nv(nvl, "uid", uid->uid, 2);
4433032c353SKristof Provost 	nvlist_add_number(nvl, "op", uid->op);
4443032c353SKristof Provost 
4453032c353SKristof Provost 	return (nvl);
4463032c353SKristof Provost }
4473032c353SKristof Provost 
4483032c353SKristof Provost static int
4493032c353SKristof Provost pf_nvrule_gid_to_rule_gid(const nvlist_t *nvl, struct pf_rule_gid *gid)
4503032c353SKristof Provost {
4513032c353SKristof Provost 	/* Cheat a little. These stucts are the same, other than the name of
4523032c353SKristof Provost 	 * the first field. */
4533032c353SKristof Provost 	return (pf_nvrule_uid_to_rule_uid(nvl, (struct pf_rule_uid *)gid));
4543032c353SKristof Provost }
4553032c353SKristof Provost 
4563032c353SKristof Provost int
4573032c353SKristof Provost pf_check_rule_addr(const struct pf_rule_addr *addr)
4583032c353SKristof Provost {
4593032c353SKristof Provost 
4603032c353SKristof Provost 	switch (addr->addr.type) {
4613032c353SKristof Provost 	case PF_ADDR_ADDRMASK:
4623032c353SKristof Provost 	case PF_ADDR_NOROUTE:
4633032c353SKristof Provost 	case PF_ADDR_DYNIFTL:
4643032c353SKristof Provost 	case PF_ADDR_TABLE:
4653032c353SKristof Provost 	case PF_ADDR_URPFFAILED:
4663032c353SKristof Provost 	case PF_ADDR_RANGE:
4673032c353SKristof Provost 		break;
4683032c353SKristof Provost 	default:
4693032c353SKristof Provost 		return (EINVAL);
4703032c353SKristof Provost 	}
4713032c353SKristof Provost 
4723032c353SKristof Provost 	if (addr->addr.p.dyn != NULL) {
4733032c353SKristof Provost 		return (EINVAL);
4743032c353SKristof Provost 	}
4753032c353SKristof Provost 
4763032c353SKristof Provost 	return (0);
4773032c353SKristof Provost }
4783032c353SKristof Provost 
4793032c353SKristof Provost 
4803032c353SKristof Provost int
4813032c353SKristof Provost pf_nvrule_to_krule(const nvlist_t *nvl, struct pf_krule *rule)
4823032c353SKristof Provost {
4833032c353SKristof Provost 	int error = 0;
4843032c353SKristof Provost 
4853032c353SKristof Provost #define	ERROUT(x)	ERROUT_FUNCTION(errout, x)
4863032c353SKristof Provost 
4873032c353SKristof Provost 	PFNV_CHK(pf_nvuint32(nvl, "nr", &rule->nr));
4883032c353SKristof Provost 
4893032c353SKristof Provost 	if (! nvlist_exists_nvlist(nvl, "src"))
4903032c353SKristof Provost 		ERROUT(EINVAL);
4913032c353SKristof Provost 
4923032c353SKristof Provost 	error = pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "src"),
4933032c353SKristof Provost 	    &rule->src);
4943032c353SKristof Provost 	if (error != 0)
4953032c353SKristof Provost 		ERROUT(error);
4963032c353SKristof Provost 
4973032c353SKristof Provost 	if (! nvlist_exists_nvlist(nvl, "dst"))
4983032c353SKristof Provost 		ERROUT(EINVAL);
4993032c353SKristof Provost 
5003032c353SKristof Provost 	PFNV_CHK(pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "dst"),
5013032c353SKristof Provost 	    &rule->dst));
5023032c353SKristof Provost 
5033032c353SKristof Provost 	if (nvlist_exists_string(nvl, "label")) {
5043032c353SKristof Provost 		PFNV_CHK(pf_nvstring(nvl, "label", rule->label[0],
5053032c353SKristof Provost 		    sizeof(rule->label[0])));
5063032c353SKristof Provost 	} else if (nvlist_exists_string_array(nvl, "labels")) {
5073032c353SKristof Provost 		const char *const *strs;
5083032c353SKristof Provost 		size_t items;
5093032c353SKristof Provost 		int ret;
5103032c353SKristof Provost 
5113032c353SKristof Provost 		strs = nvlist_get_string_array(nvl, "labels", &items);
5123032c353SKristof Provost 		if (items > PF_RULE_MAX_LABEL_COUNT)
5133032c353SKristof Provost 			ERROUT(E2BIG);
5143032c353SKristof Provost 
5153032c353SKristof Provost 		for (size_t i = 0; i < items; i++) {
5163032c353SKristof Provost 			ret = strlcpy(rule->label[i], strs[i],
5173032c353SKristof Provost 			    sizeof(rule->label[0]));
5183032c353SKristof Provost 			if (ret >= sizeof(rule->label[0]))
5193032c353SKristof Provost 				ERROUT(E2BIG);
5203032c353SKristof Provost 		}
5213032c353SKristof Provost 	}
5223032c353SKristof Provost 
5233032c353SKristof Provost 	PFNV_CHK(pf_nvstring(nvl, "ifname", rule->ifname,
5243032c353SKristof Provost 	    sizeof(rule->ifname)));
5253032c353SKristof Provost 	PFNV_CHK(pf_nvstring(nvl, "qname", rule->qname, sizeof(rule->qname)));
5263032c353SKristof Provost 	PFNV_CHK(pf_nvstring(nvl, "pqname", rule->pqname,
5273032c353SKristof Provost 	    sizeof(rule->pqname)));
5283032c353SKristof Provost 	PFNV_CHK(pf_nvstring(nvl, "tagname", rule->tagname,
5293032c353SKristof Provost 	    sizeof(rule->tagname)));
530*63b3c1c7SKristof Provost 	PFNV_CHK(pf_nvuint16_opt(nvl, "dnpipe", &rule->dnpipe, 0));
531*63b3c1c7SKristof Provost 	PFNV_CHK(pf_nvuint16_opt(nvl, "dnrpipe", &rule->dnrpipe, 0));
532*63b3c1c7SKristof Provost 	PFNV_CHK(pf_nvuint32_opt(nvl, "dnflags", &rule->free_flags, 0));
5333032c353SKristof Provost 	PFNV_CHK(pf_nvstring(nvl, "match_tagname", rule->match_tagname,
5343032c353SKristof Provost 	    sizeof(rule->match_tagname)));
5353032c353SKristof Provost 	PFNV_CHK(pf_nvstring(nvl, "overload_tblname", rule->overload_tblname,
5363032c353SKristof Provost 	    sizeof(rule->overload_tblname)));
5373032c353SKristof Provost 
5383032c353SKristof Provost 	if (! nvlist_exists_nvlist(nvl, "rpool"))
5393032c353SKristof Provost 		ERROUT(EINVAL);
5403032c353SKristof Provost 	PFNV_CHK(pf_nvpool_to_pool(nvlist_get_nvlist(nvl, "rpool"),
5413032c353SKristof Provost 	    &rule->rpool));
5423032c353SKristof Provost 
5433032c353SKristof Provost 	PFNV_CHK(pf_nvuint32(nvl, "os_fingerprint", &rule->os_fingerprint));
5443032c353SKristof Provost 
5453032c353SKristof Provost 	PFNV_CHK(pf_nvint(nvl, "rtableid", &rule->rtableid));
5463032c353SKristof Provost 	PFNV_CHK(pf_nvuint32_array(nvl, "timeout", rule->timeout, PFTM_MAX, NULL));
5473032c353SKristof Provost 	PFNV_CHK(pf_nvuint32(nvl, "max_states", &rule->max_states));
5483032c353SKristof Provost 	PFNV_CHK(pf_nvuint32(nvl, "max_src_nodes", &rule->max_src_nodes));
5493032c353SKristof Provost 	PFNV_CHK(pf_nvuint32(nvl, "max_src_states", &rule->max_src_states));
5503032c353SKristof Provost 	PFNV_CHK(pf_nvuint32(nvl, "max_src_conn", &rule->max_src_conn));
5513032c353SKristof Provost 	PFNV_CHK(pf_nvuint32(nvl, "max_src_conn_rate.limit",
5523032c353SKristof Provost 	    &rule->max_src_conn_rate.limit));
5533032c353SKristof Provost 	PFNV_CHK(pf_nvuint32(nvl, "max_src_conn_rate.seconds",
5543032c353SKristof Provost 	    &rule->max_src_conn_rate.seconds));
5553032c353SKristof Provost 	PFNV_CHK(pf_nvuint32(nvl, "prob", &rule->prob));
5563032c353SKristof Provost 	PFNV_CHK(pf_nvuint32(nvl, "cuid", &rule->cuid));
5573032c353SKristof Provost 	PFNV_CHK(pf_nvuint32(nvl, "cpid", &rule->cpid));
5583032c353SKristof Provost 
5593032c353SKristof Provost 	PFNV_CHK(pf_nvuint16(nvl, "return_icmp", &rule->return_icmp));
5603032c353SKristof Provost 	PFNV_CHK(pf_nvuint16(nvl, "return_icmp6", &rule->return_icmp6));
5613032c353SKristof Provost 
5623032c353SKristof Provost 	PFNV_CHK(pf_nvuint16(nvl, "max_mss", &rule->max_mss));
5633032c353SKristof Provost 	PFNV_CHK(pf_nvuint16(nvl, "scrub_flags", &rule->scrub_flags));
5643032c353SKristof Provost 
5653032c353SKristof Provost 	if (! nvlist_exists_nvlist(nvl, "uid"))
5663032c353SKristof Provost 		ERROUT(EINVAL);
5673032c353SKristof Provost 	PFNV_CHK(pf_nvrule_uid_to_rule_uid(nvlist_get_nvlist(nvl, "uid"),
5683032c353SKristof Provost 	    &rule->uid));
5693032c353SKristof Provost 
5703032c353SKristof Provost 	if (! nvlist_exists_nvlist(nvl, "gid"))
5713032c353SKristof Provost 		ERROUT(EINVAL);
5723032c353SKristof Provost 	PFNV_CHK(pf_nvrule_gid_to_rule_gid(nvlist_get_nvlist(nvl, "gid"),
5733032c353SKristof Provost 	    &rule->gid));
5743032c353SKristof Provost 
5753032c353SKristof Provost 	PFNV_CHK(pf_nvuint32(nvl, "rule_flag", &rule->rule_flag));
5763032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "action", &rule->action));
5773032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "direction", &rule->direction));
5783032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "log", &rule->log));
5793032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "logif", &rule->logif));
5803032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "quick", &rule->quick));
5813032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "ifnot", &rule->ifnot));
5823032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "match_tag_not", &rule->match_tag_not));
5833032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "natpass", &rule->natpass));
5843032c353SKristof Provost 
5853032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "keep_state", &rule->keep_state));
5863032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "af", &rule->af));
5873032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "proto", &rule->proto));
5883032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "type", &rule->type));
5893032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "code", &rule->code));
5903032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "flags", &rule->flags));
5913032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "flagset", &rule->flagset));
5923032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "min_ttl", &rule->min_ttl));
5933032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "allow_opts", &rule->allow_opts));
5943032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "rt", &rule->rt));
5953032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "return_ttl", &rule->return_ttl));
5963032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "tos", &rule->tos));
5973032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "set_tos", &rule->set_tos));
5983032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "anchor_relative", &rule->anchor_relative));
5993032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "anchor_wildcard", &rule->anchor_wildcard));
6003032c353SKristof Provost 
6013032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "flush", &rule->flush));
6023032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "prio", &rule->prio));
6033032c353SKristof Provost 
6043032c353SKristof Provost 	PFNV_CHK(pf_nvuint8_array(nvl, "set_prio", &rule->prio, 2, NULL));
6053032c353SKristof Provost 
6063032c353SKristof Provost 	if (nvlist_exists_nvlist(nvl, "divert")) {
6073032c353SKristof Provost 		const nvlist_t *nvldivert = nvlist_get_nvlist(nvl, "divert");
6083032c353SKristof Provost 
6093032c353SKristof Provost 		if (! nvlist_exists_nvlist(nvldivert, "addr"))
6103032c353SKristof Provost 			ERROUT(EINVAL);
6113032c353SKristof Provost 		PFNV_CHK(pf_nvaddr_to_addr(nvlist_get_nvlist(nvldivert, "addr"),
6123032c353SKristof Provost 		    &rule->divert.addr));
6133032c353SKristof Provost 		PFNV_CHK(pf_nvuint16(nvldivert, "port", &rule->divert.port));
6143032c353SKristof Provost 	}
6153032c353SKristof Provost 
6163032c353SKristof Provost 	/* Validation */
6173032c353SKristof Provost #ifndef INET
6183032c353SKristof Provost 	if (rule->af == AF_INET)
6193032c353SKristof Provost 		ERROUT(EAFNOSUPPORT);
6203032c353SKristof Provost #endif /* INET */
6213032c353SKristof Provost #ifndef INET6
6223032c353SKristof Provost 	if (rule->af == AF_INET6)
6233032c353SKristof Provost 		ERROUT(EAFNOSUPPORT);
6243032c353SKristof Provost #endif /* INET6 */
6253032c353SKristof Provost 
6263032c353SKristof Provost 	PFNV_CHK(pf_check_rule_addr(&rule->src));
6273032c353SKristof Provost 	PFNV_CHK(pf_check_rule_addr(&rule->dst));
6283032c353SKristof Provost 
6293032c353SKristof Provost 	return (0);
6303032c353SKristof Provost 
6313032c353SKristof Provost #undef ERROUT
6323032c353SKristof Provost errout:
6333032c353SKristof Provost 	return (error);
6343032c353SKristof Provost }
6353032c353SKristof Provost 
6363032c353SKristof Provost static nvlist_t *
6373032c353SKristof Provost pf_divert_to_nvdivert(const struct pf_krule *rule)
6383032c353SKristof Provost {
6393032c353SKristof Provost 	nvlist_t *nvl;
6403032c353SKristof Provost 	nvlist_t *tmp;
6413032c353SKristof Provost 
6423032c353SKristof Provost 	nvl = nvlist_create(0);
6433032c353SKristof Provost 	if (nvl == NULL)
6443032c353SKristof Provost 		return (NULL);
6453032c353SKristof Provost 
6463032c353SKristof Provost 	tmp = pf_addr_to_nvaddr(&rule->divert.addr);
6473032c353SKristof Provost 	if (tmp == NULL)
6483032c353SKristof Provost 		goto error;
6493032c353SKristof Provost 	nvlist_add_nvlist(nvl, "addr", tmp);
6503032c353SKristof Provost 	nvlist_destroy(tmp);
6513032c353SKristof Provost 	nvlist_add_number(nvl, "port", rule->divert.port);
6523032c353SKristof Provost 
6533032c353SKristof Provost 	return (nvl);
6543032c353SKristof Provost 
6553032c353SKristof Provost error:
6563032c353SKristof Provost 	nvlist_destroy(nvl);
6573032c353SKristof Provost 	return (NULL);
6583032c353SKristof Provost }
6593032c353SKristof Provost 
6603032c353SKristof Provost nvlist_t *
66102cf67ccSMateusz Guzik pf_krule_to_nvrule(struct pf_krule *rule)
6623032c353SKristof Provost {
6633032c353SKristof Provost 	nvlist_t *nvl, *tmp;
6643032c353SKristof Provost 
6653032c353SKristof Provost 	nvl = nvlist_create(0);
6663032c353SKristof Provost 	if (nvl == NULL)
6673032c353SKristof Provost 		return (nvl);
6683032c353SKristof Provost 
6693032c353SKristof Provost 	nvlist_add_number(nvl, "nr", rule->nr);
6703032c353SKristof Provost 	tmp = pf_rule_addr_to_nvrule_addr(&rule->src);
6713032c353SKristof Provost 	if (tmp == NULL)
6723032c353SKristof Provost 		goto error;
6733032c353SKristof Provost 	nvlist_add_nvlist(nvl, "src", tmp);
6743032c353SKristof Provost 	nvlist_destroy(tmp);
6753032c353SKristof Provost 	tmp = pf_rule_addr_to_nvrule_addr(&rule->dst);
6763032c353SKristof Provost 	if (tmp == NULL)
6773032c353SKristof Provost 		goto error;
6783032c353SKristof Provost 	nvlist_add_nvlist(nvl, "dst", tmp);
6793032c353SKristof Provost 	nvlist_destroy(tmp);
6803032c353SKristof Provost 
6813032c353SKristof Provost 	for (int i = 0; i < PF_SKIP_COUNT; i++) {
6823032c353SKristof Provost 		nvlist_append_number_array(nvl, "skip",
6833032c353SKristof Provost 		    rule->skip[i].ptr ? rule->skip[i].ptr->nr : -1);
6843032c353SKristof Provost 	}
6853032c353SKristof Provost 
6863032c353SKristof Provost 	for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) {
6873032c353SKristof Provost 		nvlist_append_string_array(nvl, "labels", rule->label[i]);
6883032c353SKristof Provost 	}
6893032c353SKristof Provost 	nvlist_add_string(nvl, "label", rule->label[0]);
6903032c353SKristof Provost 	nvlist_add_string(nvl, "ifname", rule->ifname);
6913032c353SKristof Provost 	nvlist_add_string(nvl, "qname", rule->qname);
6923032c353SKristof Provost 	nvlist_add_string(nvl, "pqname", rule->pqname);
693*63b3c1c7SKristof Provost 	nvlist_add_number(nvl, "dnpipe", rule->dnpipe);
694*63b3c1c7SKristof Provost 	nvlist_add_number(nvl, "dnrpipe", rule->dnrpipe);
695*63b3c1c7SKristof Provost 	nvlist_add_number(nvl, "dnflags", rule->free_flags);
6963032c353SKristof Provost 	nvlist_add_string(nvl, "tagname", rule->tagname);
6973032c353SKristof Provost 	nvlist_add_string(nvl, "match_tagname", rule->match_tagname);
6983032c353SKristof Provost 	nvlist_add_string(nvl, "overload_tblname", rule->overload_tblname);
6993032c353SKristof Provost 
7003032c353SKristof Provost 	tmp = pf_pool_to_nvpool(&rule->rpool);
7013032c353SKristof Provost 	if (tmp == NULL)
7023032c353SKristof Provost 		goto error;
7033032c353SKristof Provost 	nvlist_add_nvlist(nvl, "rpool", tmp);
7043032c353SKristof Provost 	nvlist_destroy(tmp);
7053032c353SKristof Provost 
7063032c353SKristof Provost 	nvlist_add_number(nvl, "evaluations",
70702cf67ccSMateusz Guzik 	    pf_counter_u64_fetch(&rule->evaluations));
7083032c353SKristof Provost 	for (int i = 0; i < 2; i++) {
7093032c353SKristof Provost 		nvlist_append_number_array(nvl, "packets",
71002cf67ccSMateusz Guzik 		    pf_counter_u64_fetch(&rule->packets[i]));
7113032c353SKristof Provost 		nvlist_append_number_array(nvl, "bytes",
71202cf67ccSMateusz Guzik 		    pf_counter_u64_fetch(&rule->bytes[i]));
7133032c353SKristof Provost 	}
7143032c353SKristof Provost 
7153032c353SKristof Provost 	nvlist_add_number(nvl, "os_fingerprint", rule->os_fingerprint);
7163032c353SKristof Provost 
7173032c353SKristof Provost 	nvlist_add_number(nvl, "rtableid", rule->rtableid);
7183032c353SKristof Provost 	pf_uint32_array_nv(nvl, "timeout", rule->timeout, PFTM_MAX);
7193032c353SKristof Provost 	nvlist_add_number(nvl, "max_states", rule->max_states);
7203032c353SKristof Provost 	nvlist_add_number(nvl, "max_src_nodes", rule->max_src_nodes);
7213032c353SKristof Provost 	nvlist_add_number(nvl, "max_src_states", rule->max_src_states);
7223032c353SKristof Provost 	nvlist_add_number(nvl, "max_src_conn", rule->max_src_conn);
7233032c353SKristof Provost 	nvlist_add_number(nvl, "max_src_conn_rate.limit",
7243032c353SKristof Provost 	    rule->max_src_conn_rate.limit);
7253032c353SKristof Provost 	nvlist_add_number(nvl, "max_src_conn_rate.seconds",
7263032c353SKristof Provost 	    rule->max_src_conn_rate.seconds);
7273032c353SKristof Provost 	nvlist_add_number(nvl, "qid", rule->qid);
7283032c353SKristof Provost 	nvlist_add_number(nvl, "pqid", rule->pqid);
7293032c353SKristof Provost 	nvlist_add_number(nvl, "prob", rule->prob);
7303032c353SKristof Provost 	nvlist_add_number(nvl, "cuid", rule->cuid);
7313032c353SKristof Provost 	nvlist_add_number(nvl, "cpid", rule->cpid);
7323032c353SKristof Provost 
7333032c353SKristof Provost 	nvlist_add_number(nvl, "states_cur",
7343032c353SKristof Provost 	    counter_u64_fetch(rule->states_cur));
7353032c353SKristof Provost 	nvlist_add_number(nvl, "states_tot",
7363032c353SKristof Provost 	    counter_u64_fetch(rule->states_tot));
7373032c353SKristof Provost 	nvlist_add_number(nvl, "src_nodes",
7383032c353SKristof Provost 	    counter_u64_fetch(rule->src_nodes));
7393032c353SKristof Provost 
7403032c353SKristof Provost 	nvlist_add_number(nvl, "return_icmp", rule->return_icmp);
7413032c353SKristof Provost 	nvlist_add_number(nvl, "return_icmp6", rule->return_icmp6);
7423032c353SKristof Provost 
7433032c353SKristof Provost 	nvlist_add_number(nvl, "max_mss", rule->max_mss);
7443032c353SKristof Provost 	nvlist_add_number(nvl, "scrub_flags", rule->scrub_flags);
7453032c353SKristof Provost 
7463032c353SKristof Provost 	tmp = pf_rule_uid_to_nvrule_uid(&rule->uid);
7473032c353SKristof Provost 	if (tmp == NULL)
7483032c353SKristof Provost 		goto error;
7493032c353SKristof Provost 	nvlist_add_nvlist(nvl, "uid", tmp);
7503032c353SKristof Provost 	nvlist_destroy(tmp);
7513032c353SKristof Provost 	tmp = pf_rule_uid_to_nvrule_uid((const struct pf_rule_uid *)&rule->gid);
7523032c353SKristof Provost 	if (tmp == NULL)
7533032c353SKristof Provost 		goto error;
7543032c353SKristof Provost 	nvlist_add_nvlist(nvl, "gid", tmp);
7553032c353SKristof Provost 	nvlist_destroy(tmp);
7563032c353SKristof Provost 
7573032c353SKristof Provost 	nvlist_add_number(nvl, "rule_flag", rule->rule_flag);
7583032c353SKristof Provost 	nvlist_add_number(nvl, "action", rule->action);
7593032c353SKristof Provost 	nvlist_add_number(nvl, "direction", rule->direction);
7603032c353SKristof Provost 	nvlist_add_number(nvl, "log", rule->log);
7613032c353SKristof Provost 	nvlist_add_number(nvl, "logif", rule->logif);
7623032c353SKristof Provost 	nvlist_add_number(nvl, "quick", rule->quick);
7633032c353SKristof Provost 	nvlist_add_number(nvl, "ifnot", rule->ifnot);
7643032c353SKristof Provost 	nvlist_add_number(nvl, "match_tag_not", rule->match_tag_not);
7653032c353SKristof Provost 	nvlist_add_number(nvl, "natpass", rule->natpass);
7663032c353SKristof Provost 
7673032c353SKristof Provost 	nvlist_add_number(nvl, "keep_state", rule->keep_state);
7683032c353SKristof Provost 	nvlist_add_number(nvl, "af", rule->af);
7693032c353SKristof Provost 	nvlist_add_number(nvl, "proto", rule->proto);
7703032c353SKristof Provost 	nvlist_add_number(nvl, "type", rule->type);
7713032c353SKristof Provost 	nvlist_add_number(nvl, "code", rule->code);
7723032c353SKristof Provost 	nvlist_add_number(nvl, "flags", rule->flags);
7733032c353SKristof Provost 	nvlist_add_number(nvl, "flagset", rule->flagset);
7743032c353SKristof Provost 	nvlist_add_number(nvl, "min_ttl", rule->min_ttl);
7753032c353SKristof Provost 	nvlist_add_number(nvl, "allow_opts", rule->allow_opts);
7763032c353SKristof Provost 	nvlist_add_number(nvl, "rt", rule->rt);
7773032c353SKristof Provost 	nvlist_add_number(nvl, "return_ttl", rule->return_ttl);
7783032c353SKristof Provost 	nvlist_add_number(nvl, "tos", rule->tos);
7793032c353SKristof Provost 	nvlist_add_number(nvl, "set_tos", rule->set_tos);
7803032c353SKristof Provost 	nvlist_add_number(nvl, "anchor_relative", rule->anchor_relative);
7813032c353SKristof Provost 	nvlist_add_number(nvl, "anchor_wildcard", rule->anchor_wildcard);
7823032c353SKristof Provost 
7833032c353SKristof Provost 	nvlist_add_number(nvl, "flush", rule->flush);
7843032c353SKristof Provost 	nvlist_add_number(nvl, "prio", rule->prio);
7853032c353SKristof Provost 
7863032c353SKristof Provost 	pf_uint8_array_nv(nvl, "set_prio", &rule->prio, 2);
7873032c353SKristof Provost 
7883032c353SKristof Provost 	tmp = pf_divert_to_nvdivert(rule);
7893032c353SKristof Provost 	if (tmp == NULL)
7903032c353SKristof Provost 		goto error;
7913032c353SKristof Provost 	nvlist_add_nvlist(nvl, "divert", tmp);
7923032c353SKristof Provost 	nvlist_destroy(tmp);
7933032c353SKristof Provost 
7943032c353SKristof Provost 	return (nvl);
7953032c353SKristof Provost 
7963032c353SKristof Provost error:
7973032c353SKristof Provost 	nvlist_destroy(nvl);
7983032c353SKristof Provost 	return (NULL);
7993032c353SKristof Provost }
8003032c353SKristof Provost 
8013032c353SKristof Provost static int
8023032c353SKristof Provost pf_nvstate_cmp_to_state_cmp(const nvlist_t *nvl, struct pf_state_cmp *cmp)
8033032c353SKristof Provost {
8043032c353SKristof Provost 	int error = 0;
8053032c353SKristof Provost 
8063032c353SKristof Provost 	bzero(cmp, sizeof(*cmp));
8073032c353SKristof Provost 
8083032c353SKristof Provost 	PFNV_CHK(pf_nvuint64(nvl, "id", &cmp->id));
8093032c353SKristof Provost 	PFNV_CHK(pf_nvuint32(nvl, "creatorid", &cmp->creatorid));
8103032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "direction", &cmp->direction));
8113032c353SKristof Provost 
8123032c353SKristof Provost errout:
8133032c353SKristof Provost 	return (error);
8143032c353SKristof Provost }
8153032c353SKristof Provost 
8163032c353SKristof Provost int
8173032c353SKristof Provost pf_nvstate_kill_to_kstate_kill(const nvlist_t *nvl,
8183032c353SKristof Provost     struct pf_kstate_kill *kill)
8193032c353SKristof Provost {
8203032c353SKristof Provost 	int error = 0;
8213032c353SKristof Provost 
8223032c353SKristof Provost 	bzero(kill, sizeof(*kill));
8233032c353SKristof Provost 
8243032c353SKristof Provost 	if (! nvlist_exists_nvlist(nvl, "cmp"))
8253032c353SKristof Provost 		return (EINVAL);
8263032c353SKristof Provost 
8273032c353SKristof Provost 	PFNV_CHK(pf_nvstate_cmp_to_state_cmp(nvlist_get_nvlist(nvl, "cmp"),
8283032c353SKristof Provost 	    &kill->psk_pfcmp));
8293032c353SKristof Provost 	PFNV_CHK(pf_nvuint8(nvl, "af", &kill->psk_af));
8303032c353SKristof Provost 	PFNV_CHK(pf_nvint(nvl, "proto", &kill->psk_proto));
8313032c353SKristof Provost 
8323032c353SKristof Provost 	if (! nvlist_exists_nvlist(nvl, "src"))
8333032c353SKristof Provost 		return (EINVAL);
8343032c353SKristof Provost 	PFNV_CHK(pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "src"),
8353032c353SKristof Provost 	    &kill->psk_src));
8363032c353SKristof Provost 	if (! nvlist_exists_nvlist(nvl, "dst"))
8373032c353SKristof Provost 		return (EINVAL);
8383032c353SKristof Provost 	PFNV_CHK(pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "dst"),
8393032c353SKristof Provost 	    &kill->psk_dst));
8403032c353SKristof Provost 	if (nvlist_exists_nvlist(nvl, "rt_addr")) {
8413032c353SKristof Provost 		PFNV_CHK(pf_nvrule_addr_to_rule_addr(
8423032c353SKristof Provost 		    nvlist_get_nvlist(nvl, "rt_addr"), &kill->psk_rt_addr));
8433032c353SKristof Provost 	}
8443032c353SKristof Provost 
8453032c353SKristof Provost 	PFNV_CHK(pf_nvstring(nvl, "ifname", kill->psk_ifname,
8463032c353SKristof Provost 	    sizeof(kill->psk_ifname)));
8473032c353SKristof Provost 	PFNV_CHK(pf_nvstring(nvl, "label", kill->psk_label,
8483032c353SKristof Provost 	    sizeof(kill->psk_label)));
8493032c353SKristof Provost 	if (nvlist_exists_bool(nvl, "kill_match"))
8503032c353SKristof Provost 		kill->psk_kill_match = nvlist_get_bool(nvl, "kill_match");
8513032c353SKristof Provost 
8523032c353SKristof Provost errout:
8533032c353SKristof Provost 	return (error);
8543032c353SKristof Provost }
8553032c353SKristof Provost 
8563032c353SKristof Provost static nvlist_t *
8573032c353SKristof Provost pf_state_key_to_nvstate_key(const struct pf_state_key *key)
8583032c353SKristof Provost {
8593032c353SKristof Provost 	nvlist_t	*nvl, *tmp;
8603032c353SKristof Provost 
8613032c353SKristof Provost 	nvl = nvlist_create(0);
8623032c353SKristof Provost 	if (nvl == NULL)
8633032c353SKristof Provost 		return (NULL);
8643032c353SKristof Provost 
8653032c353SKristof Provost 	for (int i = 0; i < 2; i++) {
8663032c353SKristof Provost 		tmp = pf_addr_to_nvaddr(&key->addr[i]);
8673032c353SKristof Provost 		if (tmp == NULL)
8683032c353SKristof Provost 			goto errout;
8693032c353SKristof Provost 		nvlist_append_nvlist_array(nvl, "addr", tmp);
8700f86492bSKristof Provost 		nvlist_destroy(tmp);
8713032c353SKristof Provost 		nvlist_append_number_array(nvl, "port", key->port[i]);
8723032c353SKristof Provost 	}
8733032c353SKristof Provost 	nvlist_add_number(nvl, "af", key->af);
8743032c353SKristof Provost 	nvlist_add_number(nvl, "proto", key->proto);
8753032c353SKristof Provost 
8763032c353SKristof Provost 	return (nvl);
8773032c353SKristof Provost 
8783032c353SKristof Provost errout:
8793032c353SKristof Provost 	nvlist_destroy(nvl);
8803032c353SKristof Provost 	return (NULL);
8813032c353SKristof Provost }
8823032c353SKristof Provost 
8833032c353SKristof Provost static nvlist_t *
88434285eefSKristof Provost pf_state_peer_to_nvstate_peer(const struct pf_state_peer *peer)
8853032c353SKristof Provost {
8863032c353SKristof Provost 	nvlist_t *nvl;
8873032c353SKristof Provost 
8883032c353SKristof Provost 	nvl = nvlist_create(0);
8893032c353SKristof Provost 	if (nvl == NULL)
8903032c353SKristof Provost 		return (NULL);
8913032c353SKristof Provost 
8923032c353SKristof Provost 	nvlist_add_number(nvl, "seqlo", peer->seqlo);
8933032c353SKristof Provost 	nvlist_add_number(nvl, "seqhi", peer->seqhi);
8943032c353SKristof Provost 	nvlist_add_number(nvl, "seqdiff", peer->seqdiff);
8953032c353SKristof Provost 	nvlist_add_number(nvl, "state", peer->state);
8963032c353SKristof Provost 	nvlist_add_number(nvl, "wscale", peer->wscale);
8973032c353SKristof Provost 
8983032c353SKristof Provost 	return (nvl);
8993032c353SKristof Provost }
9003032c353SKristof Provost 
9013032c353SKristof Provost nvlist_t *
902211cddf9SKristof Provost pf_state_to_nvstate(const struct pf_kstate *s)
9033032c353SKristof Provost {
9043032c353SKristof Provost 	nvlist_t	*nvl, *tmp;
9053032c353SKristof Provost 	uint32_t	 expire, flags = 0;
9063032c353SKristof Provost 
9073032c353SKristof Provost 	nvl = nvlist_create(0);
9083032c353SKristof Provost 	if (nvl == NULL)
9093032c353SKristof Provost 		return (NULL);
9103032c353SKristof Provost 
9113032c353SKristof Provost 	nvlist_add_number(nvl, "id", s->id);
9123032c353SKristof Provost 	nvlist_add_string(nvl, "ifname", s->kif->pfik_name);
9133032c353SKristof Provost 	nvlist_add_string(nvl, "orig_ifname", s->orig_kif->pfik_name);
9143032c353SKristof Provost 
9153032c353SKristof Provost 	tmp = pf_state_key_to_nvstate_key(s->key[PF_SK_STACK]);
9163032c353SKristof Provost 	if (tmp == NULL)
9173032c353SKristof Provost 		goto errout;
9183032c353SKristof Provost 	nvlist_add_nvlist(nvl, "stack_key", tmp);
9193032c353SKristof Provost 	nvlist_destroy(tmp);
9203032c353SKristof Provost 
9213032c353SKristof Provost 	tmp = pf_state_key_to_nvstate_key(s->key[PF_SK_WIRE]);
9223032c353SKristof Provost 	if (tmp == NULL)
9233032c353SKristof Provost 		goto errout;
9243032c353SKristof Provost 	nvlist_add_nvlist(nvl, "wire_key", tmp);
9253032c353SKristof Provost 	nvlist_destroy(tmp);
9263032c353SKristof Provost 
9273032c353SKristof Provost 	tmp = pf_state_peer_to_nvstate_peer(&s->src);
9283032c353SKristof Provost 	if (tmp == NULL)
9293032c353SKristof Provost 		goto errout;
9303032c353SKristof Provost 	nvlist_add_nvlist(nvl, "src", tmp);
9313032c353SKristof Provost 	nvlist_destroy(tmp);
9323032c353SKristof Provost 
9333032c353SKristof Provost 	tmp = pf_state_peer_to_nvstate_peer(&s->dst);
9343032c353SKristof Provost 	if (tmp == NULL)
9353032c353SKristof Provost 		goto errout;
9363032c353SKristof Provost 	nvlist_add_nvlist(nvl, "dst", tmp);
9373032c353SKristof Provost 	nvlist_destroy(tmp);
9383032c353SKristof Provost 
9393032c353SKristof Provost 	tmp = pf_addr_to_nvaddr(&s->rt_addr);
9403032c353SKristof Provost 	if (tmp == NULL)
9413032c353SKristof Provost 		goto errout;
9423032c353SKristof Provost 	nvlist_add_nvlist(nvl, "rt_addr", tmp);
9433032c353SKristof Provost 	nvlist_destroy(tmp);
9443032c353SKristof Provost 
9453032c353SKristof Provost 	nvlist_add_number(nvl, "rule", s->rule.ptr ? s->rule.ptr->nr : -1);
9463032c353SKristof Provost 	nvlist_add_number(nvl, "anchor",
9473032c353SKristof Provost 	    s->anchor.ptr ? s->anchor.ptr->nr : -1);
9483032c353SKristof Provost 	nvlist_add_number(nvl, "nat_rule",
9493032c353SKristof Provost 	    s->nat_rule.ptr ? s->nat_rule.ptr->nr : -1);
9503032c353SKristof Provost 	nvlist_add_number(nvl, "creation", s->creation);
9513032c353SKristof Provost 
9523032c353SKristof Provost 	expire = pf_state_expires(s);
9533032c353SKristof Provost 	if (expire <= time_uptime)
9543032c353SKristof Provost 		expire = 0;
9553032c353SKristof Provost 	else
9563032c353SKristof Provost 		expire = expire - time_uptime;
9573032c353SKristof Provost 	nvlist_add_number(nvl, "expire", expire);
9583032c353SKristof Provost 
9593032c353SKristof Provost 	for (int i = 0; i < 2; i++) {
9603032c353SKristof Provost 		nvlist_append_number_array(nvl, "packets",
96155cc305dSMateusz Guzik 		    s->packets[i]);
9623032c353SKristof Provost 		nvlist_append_number_array(nvl, "bytes",
96355cc305dSMateusz Guzik 		    s->bytes[i]);
9643032c353SKristof Provost 	}
9653032c353SKristof Provost 
9663032c353SKristof Provost 	nvlist_add_number(nvl, "creatorid", s->creatorid);
9673032c353SKristof Provost 	nvlist_add_number(nvl, "direction", s->direction);
9683032c353SKristof Provost 	nvlist_add_number(nvl, "state_flags", s->state_flags);
9693032c353SKristof Provost 	if (s->src_node)
9703032c353SKristof Provost 		flags |= PFSYNC_FLAG_SRCNODE;
9713032c353SKristof Provost 	if (s->nat_src_node)
9723032c353SKristof Provost 		flags |= PFSYNC_FLAG_NATSRCNODE;
9733032c353SKristof Provost 	nvlist_add_number(nvl, "sync_flags", flags);
9743032c353SKristof Provost 
9753032c353SKristof Provost 	return (nvl);
9763032c353SKristof Provost 
9773032c353SKristof Provost errout:
9783032c353SKristof Provost 	nvlist_destroy(nvl);
9793032c353SKristof Provost 	return (NULL);
9803032c353SKristof Provost }
981