1/*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2021 Rubicon Communications, LLC (Netgate)
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 *
27 */
28#include <sys/cdefs.h>
29#include "opt_inet.h"
30#include "opt_inet6.h"
31
32#include <sys/param.h>
33#include <sys/errno.h>
34#include <sys/limits.h>
35#include <sys/queue.h>
36#include <sys/systm.h>
37
38#include <netpfil/pf/pf_nv.h>
39
40#define	PF_NV_IMPL_UINT(fnname, type, max)					\
41	int									\
42	pf_nv ## fnname ## _opt(const nvlist_t *nvl, const char *name,		\
43	    type *val, type dflt)						\
44	{									\
45		uint64_t raw;							\
46		if (! nvlist_exists_number(nvl, name)) {			\
47			*val = dflt;						\
48			return (0);						\
49		}								\
50		raw = nvlist_get_number(nvl, name);				\
51		if (raw > max)							\
52			return (ERANGE);					\
53		*val = (type)raw;						\
54		return (0);							\
55	}									\
56	int									\
57	pf_nv ## fnname(const nvlist_t *nvl, const char *name, type *val)	\
58	{									\
59		uint64_t raw;							\
60		if (! nvlist_exists_number(nvl, name))				\
61			return (EINVAL);					\
62		raw = nvlist_get_number(nvl, name);				\
63		if (raw > max)							\
64			return (ERANGE);					\
65		*val = (type)raw;						\
66		return (0);							\
67	}									\
68	int									\
69	pf_nv ## fnname ## _array(const nvlist_t *nvl, const char *name,	\
70	    type *array, size_t maxelems, size_t *nelems)			\
71	{									\
72		const uint64_t *n;						\
73		size_t nitems;							\
74		bzero(array, sizeof(type) * maxelems);				\
75		if (! nvlist_exists_number_array(nvl, name))			\
76			return (EINVAL);					\
77		n = nvlist_get_number_array(nvl, name, &nitems);		\
78		if (nitems > maxelems)						\
79			return (E2BIG);						\
80		if (nelems != NULL)						\
81			*nelems = nitems;					\
82		for (size_t i = 0; i < nitems; i++) {				\
83			if (n[i] > max)						\
84				return (ERANGE);				\
85			array[i] = (type)n[i];					\
86		}								\
87		return (0);							\
88	}									\
89	void									\
90	pf_ ## fnname ## _array_nv(nvlist_t *nvl, const char *name,		\
91	    const type *numbers, size_t count)					\
92	{									\
93		uint64_t tmp;							\
94		for (size_t i = 0; i < count; i++) {				\
95			tmp = numbers[i];					\
96			nvlist_append_number_array(nvl, name, tmp);		\
97		}								\
98	}
99
100int
101pf_nvbool(const nvlist_t *nvl, const char *name, bool *val)
102{
103	if (! nvlist_exists_bool(nvl, name))
104		return (EINVAL);
105
106	*val = nvlist_get_bool(nvl, name);
107
108	return (0);
109}
110
111int
112pf_nvbinary(const nvlist_t *nvl, const char *name, void *data,
113    size_t expected_size)
114{
115	const uint8_t *nvdata;
116	size_t len;
117
118	bzero(data, expected_size);
119
120	if (! nvlist_exists_binary(nvl, name))
121		return (EINVAL);
122
123	nvdata = (const uint8_t *)nvlist_get_binary(nvl, name, &len);
124	if (len > expected_size)
125		return (EINVAL);
126
127	memcpy(data, nvdata, len);
128
129	return (0);
130}
131
132PF_NV_IMPL_UINT(uint8, uint8_t, UINT8_MAX);
133PF_NV_IMPL_UINT(uint16, uint16_t, UINT16_MAX);
134PF_NV_IMPL_UINT(uint32, uint32_t, UINT32_MAX);
135PF_NV_IMPL_UINT(uint64, uint64_t, UINT64_MAX);
136
137int
138pf_nvint(const nvlist_t *nvl, const char *name, int *val)
139{
140	int64_t raw;
141
142	if (! nvlist_exists_number(nvl, name))
143		return (EINVAL);
144
145	raw = nvlist_get_number(nvl, name);
146	if (raw > INT_MAX || raw < INT_MIN)
147		return (ERANGE);
148
149	*val = (int)raw;
150
151	return (0);
152}
153
154int
155pf_nvstring(const nvlist_t *nvl, const char *name, char *str, size_t maxlen)
156{
157	int ret;
158
159	if (! nvlist_exists_string(nvl, name))
160		return (EINVAL);
161
162	ret = strlcpy(str, nvlist_get_string(nvl, name), maxlen);
163	if (ret >= maxlen)
164		return (EINVAL);
165
166	return (0);
167}
168
169static int
170pf_nvaddr_to_addr(const nvlist_t *nvl, struct pf_addr *paddr)
171{
172	return (pf_nvbinary(nvl, "addr", paddr, sizeof(*paddr)));
173}
174
175static nvlist_t *
176pf_addr_to_nvaddr(const struct pf_addr *paddr)
177{
178	nvlist_t *nvl;
179
180	nvl = nvlist_create(0);
181	if (nvl == NULL)
182		return (NULL);
183
184	nvlist_add_binary(nvl, "addr", paddr, sizeof(*paddr));
185
186	return (nvl);
187}
188
189static int
190pf_nvmape_to_mape(const nvlist_t *nvl, struct pf_mape_portset *mape)
191{
192	int error = 0;
193
194	bzero(mape, sizeof(*mape));
195	PFNV_CHK(pf_nvuint8(nvl, "offset", &mape->offset));
196	PFNV_CHK(pf_nvuint8(nvl, "psidlen", &mape->psidlen));
197	PFNV_CHK(pf_nvuint16(nvl, "psid", &mape->psid));
198
199errout:
200	return (error);
201}
202
203static nvlist_t *
204pf_mape_to_nvmape(const struct pf_mape_portset *mape)
205{
206	nvlist_t *nvl;
207
208	nvl = nvlist_create(0);
209	if (nvl == NULL)
210		return (NULL);
211
212	nvlist_add_number(nvl, "offset", mape->offset);
213	nvlist_add_number(nvl, "psidlen", mape->psidlen);
214	nvlist_add_number(nvl, "psid", mape->psid);
215
216	return (nvl);
217}
218
219static int
220pf_nvpool_to_pool(const nvlist_t *nvl, struct pf_kpool *kpool)
221{
222	int error = 0;
223
224	PFNV_CHK(pf_nvbinary(nvl, "key", &kpool->key, sizeof(kpool->key)));
225
226	if (nvlist_exists_nvlist(nvl, "counter")) {
227		PFNV_CHK(pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "counter"),
228		    &kpool->counter));
229	}
230
231	PFNV_CHK(pf_nvint(nvl, "tblidx", &kpool->tblidx));
232	PFNV_CHK(pf_nvuint16_array(nvl, "proxy_port", kpool->proxy_port, 2,
233	    NULL));
234	PFNV_CHK(pf_nvuint8(nvl, "opts", &kpool->opts));
235
236	if (nvlist_exists_nvlist(nvl, "mape")) {
237		PFNV_CHK(pf_nvmape_to_mape(nvlist_get_nvlist(nvl, "mape"),
238		    &kpool->mape));
239	}
240
241errout:
242	return (error);
243}
244
245static nvlist_t *
246pf_pool_to_nvpool(const struct pf_kpool *pool)
247{
248	nvlist_t *nvl;
249	nvlist_t *tmp;
250
251	nvl = nvlist_create(0);
252	if (nvl == NULL)
253		return (NULL);
254
255	nvlist_add_binary(nvl, "key", &pool->key, sizeof(pool->key));
256	tmp = pf_addr_to_nvaddr(&pool->counter);
257	if (tmp == NULL)
258		goto error;
259	nvlist_add_nvlist(nvl, "counter", tmp);
260	nvlist_destroy(tmp);
261
262	nvlist_add_number(nvl, "tblidx", pool->tblidx);
263	pf_uint16_array_nv(nvl, "proxy_port", pool->proxy_port, 2);
264	nvlist_add_number(nvl, "opts", pool->opts);
265
266	tmp = pf_mape_to_nvmape(&pool->mape);
267	if (tmp == NULL)
268		goto error;
269	nvlist_add_nvlist(nvl, "mape", tmp);
270	nvlist_destroy(tmp);
271
272	return (nvl);
273
274error:
275	nvlist_destroy(nvl);
276	return (NULL);
277}
278
279static int
280pf_nvaddr_wrap_to_addr_wrap(const nvlist_t *nvl, struct pf_addr_wrap *addr)
281{
282	int error = 0;
283
284	bzero(addr, sizeof(*addr));
285
286	PFNV_CHK(pf_nvuint8(nvl, "type", &addr->type));
287	PFNV_CHK(pf_nvuint8(nvl, "iflags", &addr->iflags));
288	if (addr->type == PF_ADDR_DYNIFTL)
289		PFNV_CHK(pf_nvstring(nvl, "ifname", addr->v.ifname,
290		    sizeof(addr->v.ifname)));
291	if (addr->type == PF_ADDR_TABLE)
292		PFNV_CHK(pf_nvstring(nvl, "tblname", addr->v.tblname,
293		    sizeof(addr->v.tblname)));
294
295	if (! nvlist_exists_nvlist(nvl, "addr"))
296		return (EINVAL);
297	PFNV_CHK(pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "addr"),
298	    &addr->v.a.addr));
299
300	if (! nvlist_exists_nvlist(nvl, "mask"))
301		return (EINVAL);
302	PFNV_CHK(pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "mask"),
303	    &addr->v.a.mask));
304
305	switch (addr->type) {
306	case PF_ADDR_DYNIFTL:
307	case PF_ADDR_TABLE:
308	case PF_ADDR_RANGE:
309	case PF_ADDR_ADDRMASK:
310	case PF_ADDR_NOROUTE:
311	case PF_ADDR_URPFFAILED:
312		break;
313	default:
314		return (EINVAL);
315	}
316
317errout:
318	return (error);
319}
320
321static nvlist_t *
322pf_addr_wrap_to_nvaddr_wrap(const struct pf_addr_wrap *addr)
323{
324	nvlist_t *nvl;
325	nvlist_t *tmp;
326	uint64_t num;
327	struct pfr_ktable *kt;
328
329	nvl = nvlist_create(0);
330	if (nvl == NULL)
331		return (NULL);
332
333	nvlist_add_number(nvl, "type", addr->type);
334	nvlist_add_number(nvl, "iflags", addr->iflags);
335	if (addr->type == PF_ADDR_DYNIFTL) {
336		nvlist_add_string(nvl, "ifname", addr->v.ifname);
337		num = 0;
338		if (addr->p.dyn != NULL)
339			num = addr->p.dyn->pfid_acnt4 +
340			    addr->p.dyn->pfid_acnt6;
341		nvlist_add_number(nvl, "dyncnt", num);
342	}
343	if (addr->type == PF_ADDR_TABLE) {
344		nvlist_add_string(nvl, "tblname", addr->v.tblname);
345		num = -1;
346		kt = addr->p.tbl;
347		if ((kt->pfrkt_flags & PFR_TFLAG_ACTIVE) &&
348		    kt->pfrkt_root != NULL)
349			kt = kt->pfrkt_root;
350		if (kt->pfrkt_flags & PFR_TFLAG_ACTIVE)
351			num = kt->pfrkt_cnt;
352		nvlist_add_number(nvl, "tblcnt", num);
353	}
354
355	tmp = pf_addr_to_nvaddr(&addr->v.a.addr);
356	if (tmp == NULL)
357		goto error;
358	nvlist_add_nvlist(nvl, "addr", tmp);
359	nvlist_destroy(tmp);
360	tmp = pf_addr_to_nvaddr(&addr->v.a.mask);
361	if (tmp == NULL)
362		goto error;
363	nvlist_add_nvlist(nvl, "mask", tmp);
364	nvlist_destroy(tmp);
365
366	return (nvl);
367
368error:
369	nvlist_destroy(nvl);
370	return (NULL);
371}
372
373static int
374pf_validate_op(uint8_t op)
375{
376	switch (op) {
377	case PF_OP_NONE:
378	case PF_OP_IRG:
379	case PF_OP_EQ:
380	case PF_OP_NE:
381	case PF_OP_LT:
382	case PF_OP_LE:
383	case PF_OP_GT:
384	case PF_OP_GE:
385	case PF_OP_XRG:
386	case PF_OP_RRG:
387		break;
388	default:
389		return (EINVAL);
390	}
391
392	return (0);
393}
394
395static int
396pf_nvrule_addr_to_rule_addr(const nvlist_t *nvl, struct pf_rule_addr *addr)
397{
398	int error = 0;
399
400	if (! nvlist_exists_nvlist(nvl, "addr"))
401		return (EINVAL);
402
403	PFNV_CHK(pf_nvaddr_wrap_to_addr_wrap(nvlist_get_nvlist(nvl, "addr"),
404	    &addr->addr));
405	PFNV_CHK(pf_nvuint16_array(nvl, "port", addr->port, 2, NULL));
406	PFNV_CHK(pf_nvuint8(nvl, "neg", &addr->neg));
407	PFNV_CHK(pf_nvuint8(nvl, "port_op", &addr->port_op));
408
409	PFNV_CHK(pf_validate_op(addr->port_op));
410
411errout:
412	return (error);
413}
414
415static nvlist_t *
416pf_rule_addr_to_nvrule_addr(const struct pf_rule_addr *addr)
417{
418	nvlist_t *nvl;
419	nvlist_t *tmp;
420
421	nvl = nvlist_create(0);
422	if (nvl == NULL)
423		return (NULL);
424
425	tmp = pf_addr_wrap_to_nvaddr_wrap(&addr->addr);
426	if (tmp == NULL)
427		goto error;
428	nvlist_add_nvlist(nvl, "addr", tmp);
429	nvlist_destroy(tmp);
430	pf_uint16_array_nv(nvl, "port", addr->port, 2);
431	nvlist_add_number(nvl, "neg", addr->neg);
432	nvlist_add_number(nvl, "port_op", addr->port_op);
433
434	return (nvl);
435
436error:
437	nvlist_destroy(nvl);
438	return (NULL);
439}
440
441static int
442pf_nvrule_uid_to_rule_uid(const nvlist_t *nvl, struct pf_rule_uid *uid)
443{
444	int error = 0;
445
446	bzero(uid, sizeof(*uid));
447
448	PFNV_CHK(pf_nvuint32_array(nvl, "uid", uid->uid, 2, NULL));
449	PFNV_CHK(pf_nvuint8(nvl, "op", &uid->op));
450
451	PFNV_CHK(pf_validate_op(uid->op));
452
453errout:
454	return (error);
455}
456
457static nvlist_t *
458pf_rule_uid_to_nvrule_uid(const struct pf_rule_uid *uid)
459{
460	nvlist_t *nvl;
461
462	nvl = nvlist_create(0);
463	if (nvl == NULL)
464		return (NULL);
465
466	pf_uint32_array_nv(nvl, "uid", uid->uid, 2);
467	nvlist_add_number(nvl, "op", uid->op);
468
469	return (nvl);
470}
471
472static int
473pf_nvrule_gid_to_rule_gid(const nvlist_t *nvl, struct pf_rule_gid *gid)
474{
475	/* Cheat a little. These stucts are the same, other than the name of
476	 * the first field. */
477	return (pf_nvrule_uid_to_rule_uid(nvl, (struct pf_rule_uid *)gid));
478}
479
480int
481pf_check_rule_addr(const struct pf_rule_addr *addr)
482{
483
484	switch (addr->addr.type) {
485	case PF_ADDR_ADDRMASK:
486	case PF_ADDR_NOROUTE:
487	case PF_ADDR_DYNIFTL:
488	case PF_ADDR_TABLE:
489	case PF_ADDR_URPFFAILED:
490	case PF_ADDR_RANGE:
491		break;
492	default:
493		return (EINVAL);
494	}
495
496	if (addr->addr.p.dyn != NULL) {
497		return (EINVAL);
498	}
499
500	return (0);
501}
502
503
504int
505pf_nvrule_to_krule(const nvlist_t *nvl, struct pf_krule *rule)
506{
507	int error = 0;
508
509#define	ERROUT(x)	ERROUT_FUNCTION(errout, x)
510
511	PFNV_CHK(pf_nvuint32(nvl, "nr", &rule->nr));
512
513	if (! nvlist_exists_nvlist(nvl, "src"))
514		ERROUT(EINVAL);
515
516	error = pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "src"),
517	    &rule->src);
518	if (error != 0)
519		ERROUT(error);
520
521	if (! nvlist_exists_nvlist(nvl, "dst"))
522		ERROUT(EINVAL);
523
524	PFNV_CHK(pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "dst"),
525	    &rule->dst));
526
527	if (nvlist_exists_string(nvl, "label")) {
528		PFNV_CHK(pf_nvstring(nvl, "label", rule->label[0],
529		    sizeof(rule->label[0])));
530	} else if (nvlist_exists_string_array(nvl, "labels")) {
531		const char *const *strs;
532		size_t items;
533		int ret;
534
535		strs = nvlist_get_string_array(nvl, "labels", &items);
536		if (items > PF_RULE_MAX_LABEL_COUNT)
537			ERROUT(E2BIG);
538
539		for (size_t i = 0; i < items; i++) {
540			ret = strlcpy(rule->label[i], strs[i],
541			    sizeof(rule->label[0]));
542			if (ret >= sizeof(rule->label[0]))
543				ERROUT(E2BIG);
544		}
545	}
546
547	PFNV_CHK(pf_nvuint32_opt(nvl, "ridentifier", &rule->ridentifier, 0));
548	PFNV_CHK(pf_nvstring(nvl, "ifname", rule->ifname,
549	    sizeof(rule->ifname)));
550	PFNV_CHK(pf_nvstring(nvl, "qname", rule->qname, sizeof(rule->qname)));
551	PFNV_CHK(pf_nvstring(nvl, "pqname", rule->pqname,
552	    sizeof(rule->pqname)));
553	PFNV_CHK(pf_nvstring(nvl, "tagname", rule->tagname,
554	    sizeof(rule->tagname)));
555	PFNV_CHK(pf_nvuint16_opt(nvl, "dnpipe", &rule->dnpipe, 0));
556	PFNV_CHK(pf_nvuint16_opt(nvl, "dnrpipe", &rule->dnrpipe, 0));
557	PFNV_CHK(pf_nvuint32_opt(nvl, "dnflags", &rule->free_flags, 0));
558	PFNV_CHK(pf_nvstring(nvl, "match_tagname", rule->match_tagname,
559	    sizeof(rule->match_tagname)));
560	PFNV_CHK(pf_nvstring(nvl, "overload_tblname", rule->overload_tblname,
561	    sizeof(rule->overload_tblname)));
562
563	if (! nvlist_exists_nvlist(nvl, "rpool"))
564		ERROUT(EINVAL);
565	PFNV_CHK(pf_nvpool_to_pool(nvlist_get_nvlist(nvl, "rpool"),
566	    &rule->rpool));
567
568	PFNV_CHK(pf_nvuint32(nvl, "os_fingerprint", &rule->os_fingerprint));
569
570	PFNV_CHK(pf_nvint(nvl, "rtableid", &rule->rtableid));
571	PFNV_CHK(pf_nvuint32_array(nvl, "timeout", rule->timeout, PFTM_MAX, NULL));
572	PFNV_CHK(pf_nvuint32(nvl, "max_states", &rule->max_states));
573	PFNV_CHK(pf_nvuint32(nvl, "max_src_nodes", &rule->max_src_nodes));
574	PFNV_CHK(pf_nvuint32(nvl, "max_src_states", &rule->max_src_states));
575	PFNV_CHK(pf_nvuint32(nvl, "max_src_conn", &rule->max_src_conn));
576	PFNV_CHK(pf_nvuint32(nvl, "max_src_conn_rate.limit",
577	    &rule->max_src_conn_rate.limit));
578	PFNV_CHK(pf_nvuint32(nvl, "max_src_conn_rate.seconds",
579	    &rule->max_src_conn_rate.seconds));
580	PFNV_CHK(pf_nvuint32(nvl, "prob", &rule->prob));
581	PFNV_CHK(pf_nvuint32(nvl, "cuid", &rule->cuid));
582	PFNV_CHK(pf_nvuint32(nvl, "cpid", &rule->cpid));
583
584	PFNV_CHK(pf_nvuint16(nvl, "return_icmp", &rule->return_icmp));
585	PFNV_CHK(pf_nvuint16(nvl, "return_icmp6", &rule->return_icmp6));
586
587	PFNV_CHK(pf_nvuint16(nvl, "max_mss", &rule->max_mss));
588	PFNV_CHK(pf_nvuint16(nvl, "scrub_flags", &rule->scrub_flags));
589
590	if (! nvlist_exists_nvlist(nvl, "uid"))
591		ERROUT(EINVAL);
592	PFNV_CHK(pf_nvrule_uid_to_rule_uid(nvlist_get_nvlist(nvl, "uid"),
593	    &rule->uid));
594
595	if (! nvlist_exists_nvlist(nvl, "gid"))
596		ERROUT(EINVAL);
597	PFNV_CHK(pf_nvrule_gid_to_rule_gid(nvlist_get_nvlist(nvl, "gid"),
598	    &rule->gid));
599
600	PFNV_CHK(pf_nvuint32(nvl, "rule_flag", &rule->rule_flag));
601	PFNV_CHK(pf_nvuint8(nvl, "action", &rule->action));
602	PFNV_CHK(pf_nvuint8(nvl, "direction", &rule->direction));
603	PFNV_CHK(pf_nvuint8(nvl, "log", &rule->log));
604	PFNV_CHK(pf_nvuint8(nvl, "logif", &rule->logif));
605	PFNV_CHK(pf_nvuint8(nvl, "quick", &rule->quick));
606	PFNV_CHK(pf_nvuint8(nvl, "ifnot", &rule->ifnot));
607	PFNV_CHK(pf_nvuint8(nvl, "match_tag_not", &rule->match_tag_not));
608	PFNV_CHK(pf_nvuint8(nvl, "natpass", &rule->natpass));
609
610	PFNV_CHK(pf_nvuint8(nvl, "keep_state", &rule->keep_state));
611	PFNV_CHK(pf_nvuint8(nvl, "af", &rule->af));
612	PFNV_CHK(pf_nvuint8(nvl, "proto", &rule->proto));
613	PFNV_CHK(pf_nvuint8(nvl, "type", &rule->type));
614	PFNV_CHK(pf_nvuint8(nvl, "code", &rule->code));
615	PFNV_CHK(pf_nvuint8(nvl, "flags", &rule->flags));
616	PFNV_CHK(pf_nvuint8(nvl, "flagset", &rule->flagset));
617	PFNV_CHK(pf_nvuint8(nvl, "min_ttl", &rule->min_ttl));
618	PFNV_CHK(pf_nvuint8(nvl, "allow_opts", &rule->allow_opts));
619	PFNV_CHK(pf_nvuint8(nvl, "rt", &rule->rt));
620	PFNV_CHK(pf_nvuint8(nvl, "return_ttl", &rule->return_ttl));
621	PFNV_CHK(pf_nvuint8(nvl, "tos", &rule->tos));
622	PFNV_CHK(pf_nvuint8(nvl, "set_tos", &rule->set_tos));
623
624	PFNV_CHK(pf_nvuint8(nvl, "flush", &rule->flush));
625	PFNV_CHK(pf_nvuint8(nvl, "prio", &rule->prio));
626
627	PFNV_CHK(pf_nvuint8_array(nvl, "set_prio", rule->set_prio, 2, NULL));
628
629	if (nvlist_exists_nvlist(nvl, "divert")) {
630		const nvlist_t *nvldivert = nvlist_get_nvlist(nvl, "divert");
631
632		if (! nvlist_exists_nvlist(nvldivert, "addr"))
633			ERROUT(EINVAL);
634		PFNV_CHK(pf_nvaddr_to_addr(nvlist_get_nvlist(nvldivert, "addr"),
635		    &rule->divert.addr));
636		PFNV_CHK(pf_nvuint16(nvldivert, "port", &rule->divert.port));
637	}
638
639	/* Validation */
640#ifndef INET
641	if (rule->af == AF_INET)
642		ERROUT(EAFNOSUPPORT);
643#endif /* INET */
644#ifndef INET6
645	if (rule->af == AF_INET6)
646		ERROUT(EAFNOSUPPORT);
647#endif /* INET6 */
648
649	PFNV_CHK(pf_check_rule_addr(&rule->src));
650	PFNV_CHK(pf_check_rule_addr(&rule->dst));
651
652	return (0);
653
654#undef ERROUT
655errout:
656	return (error);
657}
658
659static nvlist_t *
660pf_divert_to_nvdivert(const struct pf_krule *rule)
661{
662	nvlist_t *nvl;
663	nvlist_t *tmp;
664
665	nvl = nvlist_create(0);
666	if (nvl == NULL)
667		return (NULL);
668
669	tmp = pf_addr_to_nvaddr(&rule->divert.addr);
670	if (tmp == NULL)
671		goto error;
672	nvlist_add_nvlist(nvl, "addr", tmp);
673	nvlist_destroy(tmp);
674	nvlist_add_number(nvl, "port", rule->divert.port);
675
676	return (nvl);
677
678error:
679	nvlist_destroy(nvl);
680	return (NULL);
681}
682
683nvlist_t *
684pf_krule_to_nvrule(struct pf_krule *rule)
685{
686	nvlist_t *nvl, *tmp;
687
688	nvl = nvlist_create(0);
689	if (nvl == NULL)
690		return (nvl);
691
692	nvlist_add_number(nvl, "nr", rule->nr);
693	tmp = pf_rule_addr_to_nvrule_addr(&rule->src);
694	if (tmp == NULL)
695		goto error;
696	nvlist_add_nvlist(nvl, "src", tmp);
697	nvlist_destroy(tmp);
698	tmp = pf_rule_addr_to_nvrule_addr(&rule->dst);
699	if (tmp == NULL)
700		goto error;
701	nvlist_add_nvlist(nvl, "dst", tmp);
702	nvlist_destroy(tmp);
703
704	for (int i = 0; i < PF_SKIP_COUNT; i++) {
705		nvlist_append_number_array(nvl, "skip",
706		    rule->skip[i].ptr ? rule->skip[i].ptr->nr : -1);
707	}
708
709	for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) {
710		nvlist_append_string_array(nvl, "labels", rule->label[i]);
711	}
712	nvlist_add_string(nvl, "label", rule->label[0]);
713	nvlist_add_number(nvl, "ridentifier", rule->ridentifier);
714	nvlist_add_string(nvl, "ifname", rule->ifname);
715	nvlist_add_string(nvl, "qname", rule->qname);
716	nvlist_add_string(nvl, "pqname", rule->pqname);
717	nvlist_add_number(nvl, "dnpipe", rule->dnpipe);
718	nvlist_add_number(nvl, "dnrpipe", rule->dnrpipe);
719	nvlist_add_number(nvl, "dnflags", rule->free_flags);
720	nvlist_add_string(nvl, "tagname", rule->tagname);
721	nvlist_add_string(nvl, "match_tagname", rule->match_tagname);
722	nvlist_add_string(nvl, "overload_tblname", rule->overload_tblname);
723
724	tmp = pf_pool_to_nvpool(&rule->rpool);
725	if (tmp == NULL)
726		goto error;
727	nvlist_add_nvlist(nvl, "rpool", tmp);
728	nvlist_destroy(tmp);
729
730	nvlist_add_number(nvl, "evaluations",
731	    pf_counter_u64_fetch(&rule->evaluations));
732	for (int i = 0; i < 2; i++) {
733		nvlist_append_number_array(nvl, "packets",
734		    pf_counter_u64_fetch(&rule->packets[i]));
735		nvlist_append_number_array(nvl, "bytes",
736		    pf_counter_u64_fetch(&rule->bytes[i]));
737	}
738	nvlist_add_number(nvl, "timestamp", pf_get_timestamp(rule));
739
740	nvlist_add_number(nvl, "os_fingerprint", rule->os_fingerprint);
741
742	nvlist_add_number(nvl, "rtableid", rule->rtableid);
743	pf_uint32_array_nv(nvl, "timeout", rule->timeout, PFTM_MAX);
744	nvlist_add_number(nvl, "max_states", rule->max_states);
745	nvlist_add_number(nvl, "max_src_nodes", rule->max_src_nodes);
746	nvlist_add_number(nvl, "max_src_states", rule->max_src_states);
747	nvlist_add_number(nvl, "max_src_conn", rule->max_src_conn);
748	nvlist_add_number(nvl, "max_src_conn_rate.limit",
749	    rule->max_src_conn_rate.limit);
750	nvlist_add_number(nvl, "max_src_conn_rate.seconds",
751	    rule->max_src_conn_rate.seconds);
752	nvlist_add_number(nvl, "qid", rule->qid);
753	nvlist_add_number(nvl, "pqid", rule->pqid);
754	nvlist_add_number(nvl, "prob", rule->prob);
755	nvlist_add_number(nvl, "cuid", rule->cuid);
756	nvlist_add_number(nvl, "cpid", rule->cpid);
757
758	nvlist_add_number(nvl, "states_cur",
759	    counter_u64_fetch(rule->states_cur));
760	nvlist_add_number(nvl, "states_tot",
761	    counter_u64_fetch(rule->states_tot));
762	nvlist_add_number(nvl, "src_nodes",
763	    counter_u64_fetch(rule->src_nodes));
764
765	nvlist_add_number(nvl, "return_icmp", rule->return_icmp);
766	nvlist_add_number(nvl, "return_icmp6", rule->return_icmp6);
767
768	nvlist_add_number(nvl, "max_mss", rule->max_mss);
769	nvlist_add_number(nvl, "scrub_flags", rule->scrub_flags);
770
771	tmp = pf_rule_uid_to_nvrule_uid(&rule->uid);
772	if (tmp == NULL)
773		goto error;
774	nvlist_add_nvlist(nvl, "uid", tmp);
775	nvlist_destroy(tmp);
776	tmp = pf_rule_uid_to_nvrule_uid((const struct pf_rule_uid *)&rule->gid);
777	if (tmp == NULL)
778		goto error;
779	nvlist_add_nvlist(nvl, "gid", tmp);
780	nvlist_destroy(tmp);
781
782	nvlist_add_number(nvl, "rule_flag", rule->rule_flag);
783	nvlist_add_number(nvl, "action", rule->action);
784	nvlist_add_number(nvl, "direction", rule->direction);
785	nvlist_add_number(nvl, "log", rule->log);
786	nvlist_add_number(nvl, "logif", rule->logif);
787	nvlist_add_number(nvl, "quick", rule->quick);
788	nvlist_add_number(nvl, "ifnot", rule->ifnot);
789	nvlist_add_number(nvl, "match_tag_not", rule->match_tag_not);
790	nvlist_add_number(nvl, "natpass", rule->natpass);
791
792	nvlist_add_number(nvl, "keep_state", rule->keep_state);
793	nvlist_add_number(nvl, "af", rule->af);
794	nvlist_add_number(nvl, "proto", rule->proto);
795	nvlist_add_number(nvl, "type", rule->type);
796	nvlist_add_number(nvl, "code", rule->code);
797	nvlist_add_number(nvl, "flags", rule->flags);
798	nvlist_add_number(nvl, "flagset", rule->flagset);
799	nvlist_add_number(nvl, "min_ttl", rule->min_ttl);
800	nvlist_add_number(nvl, "allow_opts", rule->allow_opts);
801	nvlist_add_number(nvl, "rt", rule->rt);
802	nvlist_add_number(nvl, "return_ttl", rule->return_ttl);
803	nvlist_add_number(nvl, "tos", rule->tos);
804	nvlist_add_number(nvl, "set_tos", rule->set_tos);
805	nvlist_add_number(nvl, "anchor_relative", rule->anchor_relative);
806	nvlist_add_number(nvl, "anchor_wildcard", rule->anchor_wildcard);
807
808	nvlist_add_number(nvl, "flush", rule->flush);
809	nvlist_add_number(nvl, "prio", rule->prio);
810
811	pf_uint8_array_nv(nvl, "set_prio", rule->set_prio, 2);
812
813	tmp = pf_divert_to_nvdivert(rule);
814	if (tmp == NULL)
815		goto error;
816	nvlist_add_nvlist(nvl, "divert", tmp);
817	nvlist_destroy(tmp);
818
819	return (nvl);
820
821error:
822	nvlist_destroy(nvl);
823	return (NULL);
824}
825
826static int
827pf_nvstate_cmp_to_state_cmp(const nvlist_t *nvl, struct pf_state_cmp *cmp)
828{
829	int error = 0;
830
831	bzero(cmp, sizeof(*cmp));
832
833	PFNV_CHK(pf_nvuint64(nvl, "id", &cmp->id));
834	PFNV_CHK(pf_nvuint32(nvl, "creatorid", &cmp->creatorid));
835	PFNV_CHK(pf_nvuint8(nvl, "direction", &cmp->direction));
836
837errout:
838	return (error);
839}
840
841int
842pf_nvstate_kill_to_kstate_kill(const nvlist_t *nvl,
843    struct pf_kstate_kill *kill)
844{
845	int error = 0;
846
847	bzero(kill, sizeof(*kill));
848
849	if (! nvlist_exists_nvlist(nvl, "cmp"))
850		return (EINVAL);
851
852	PFNV_CHK(pf_nvstate_cmp_to_state_cmp(nvlist_get_nvlist(nvl, "cmp"),
853	    &kill->psk_pfcmp));
854	PFNV_CHK(pf_nvuint8(nvl, "af", &kill->psk_af));
855	PFNV_CHK(pf_nvint(nvl, "proto", &kill->psk_proto));
856
857	if (! nvlist_exists_nvlist(nvl, "src"))
858		return (EINVAL);
859	PFNV_CHK(pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "src"),
860	    &kill->psk_src));
861	if (! nvlist_exists_nvlist(nvl, "dst"))
862		return (EINVAL);
863	PFNV_CHK(pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "dst"),
864	    &kill->psk_dst));
865	if (nvlist_exists_nvlist(nvl, "rt_addr")) {
866		PFNV_CHK(pf_nvrule_addr_to_rule_addr(
867		    nvlist_get_nvlist(nvl, "rt_addr"), &kill->psk_rt_addr));
868	}
869
870	PFNV_CHK(pf_nvstring(nvl, "ifname", kill->psk_ifname,
871	    sizeof(kill->psk_ifname)));
872	PFNV_CHK(pf_nvstring(nvl, "label", kill->psk_label,
873	    sizeof(kill->psk_label)));
874	PFNV_CHK(pf_nvbool(nvl, "kill_match", &kill->psk_kill_match));
875
876	if (nvlist_exists_bool(nvl, "nat"))
877		PFNV_CHK(pf_nvbool(nvl, "nat", &kill->psk_nat));
878
879errout:
880	return (error);
881}
882
883static nvlist_t *
884pf_state_key_to_nvstate_key(const struct pf_state_key *key)
885{
886	nvlist_t	*nvl, *tmp;
887
888	nvl = nvlist_create(0);
889	if (nvl == NULL)
890		return (NULL);
891
892	for (int i = 0; i < 2; i++) {
893		tmp = pf_addr_to_nvaddr(&key->addr[i]);
894		if (tmp == NULL)
895			goto errout;
896		nvlist_append_nvlist_array(nvl, "addr", tmp);
897		nvlist_destroy(tmp);
898		nvlist_append_number_array(nvl, "port", key->port[i]);
899	}
900	nvlist_add_number(nvl, "af", key->af);
901	nvlist_add_number(nvl, "proto", key->proto);
902
903	return (nvl);
904
905errout:
906	nvlist_destroy(nvl);
907	return (NULL);
908}
909
910static nvlist_t *
911pf_state_peer_to_nvstate_peer(const struct pf_state_peer *peer)
912{
913	nvlist_t *nvl;
914
915	nvl = nvlist_create(0);
916	if (nvl == NULL)
917		return (NULL);
918
919	nvlist_add_number(nvl, "seqlo", peer->seqlo);
920	nvlist_add_number(nvl, "seqhi", peer->seqhi);
921	nvlist_add_number(nvl, "seqdiff", peer->seqdiff);
922	nvlist_add_number(nvl, "state", peer->state);
923	nvlist_add_number(nvl, "wscale", peer->wscale);
924
925	return (nvl);
926}
927
928nvlist_t *
929pf_state_to_nvstate(const struct pf_kstate *s)
930{
931	nvlist_t	*nvl, *tmp;
932	uint32_t	 expire, flags = 0;
933
934	nvl = nvlist_create(0);
935	if (nvl == NULL)
936		return (NULL);
937
938	nvlist_add_number(nvl, "id", s->id);
939	nvlist_add_string(nvl, "ifname", s->kif->pfik_name);
940	nvlist_add_string(nvl, "orig_ifname", s->orig_kif->pfik_name);
941
942	tmp = pf_state_key_to_nvstate_key(s->key[PF_SK_STACK]);
943	if (tmp == NULL)
944		goto errout;
945	nvlist_add_nvlist(nvl, "stack_key", tmp);
946	nvlist_destroy(tmp);
947
948	tmp = pf_state_key_to_nvstate_key(s->key[PF_SK_WIRE]);
949	if (tmp == NULL)
950		goto errout;
951	nvlist_add_nvlist(nvl, "wire_key", tmp);
952	nvlist_destroy(tmp);
953
954	tmp = pf_state_peer_to_nvstate_peer(&s->src);
955	if (tmp == NULL)
956		goto errout;
957	nvlist_add_nvlist(nvl, "src", tmp);
958	nvlist_destroy(tmp);
959
960	tmp = pf_state_peer_to_nvstate_peer(&s->dst);
961	if (tmp == NULL)
962		goto errout;
963	nvlist_add_nvlist(nvl, "dst", tmp);
964	nvlist_destroy(tmp);
965
966	tmp = pf_addr_to_nvaddr(&s->rt_addr);
967	if (tmp == NULL)
968		goto errout;
969	nvlist_add_nvlist(nvl, "rt_addr", tmp);
970	nvlist_destroy(tmp);
971
972	nvlist_add_number(nvl, "rule", s->rule.ptr ? s->rule.ptr->nr : -1);
973	nvlist_add_number(nvl, "anchor",
974	    s->anchor.ptr ? s->anchor.ptr->nr : -1);
975	nvlist_add_number(nvl, "nat_rule",
976	    s->nat_rule.ptr ? s->nat_rule.ptr->nr : -1);
977	nvlist_add_number(nvl, "creation", s->creation / 1000);
978
979	expire = pf_state_expires(s);
980	if (expire <= time_uptime)
981		expire = 0;
982	else
983		expire = expire - time_uptime;
984	nvlist_add_number(nvl, "expire", expire);
985
986	for (int i = 0; i < 2; i++) {
987		nvlist_append_number_array(nvl, "packets",
988		    s->packets[i]);
989		nvlist_append_number_array(nvl, "bytes",
990		    s->bytes[i]);
991	}
992
993	nvlist_add_number(nvl, "creatorid", s->creatorid);
994	nvlist_add_number(nvl, "direction", s->direction);
995	nvlist_add_number(nvl, "state_flags", s->state_flags);
996	if (s->src_node)
997		flags |= PFSYNC_FLAG_SRCNODE;
998	if (s->nat_src_node)
999		flags |= PFSYNC_FLAG_NATSRCNODE;
1000	nvlist_add_number(nvl, "sync_flags", flags);
1001
1002	return (nvl);
1003
1004errout:
1005	nvlist_destroy(nvl);
1006	return (NULL);
1007}
1008
1009static int
1010pf_nveth_rule_addr_to_keth_rule_addr(const nvlist_t *nvl,
1011    struct pf_keth_rule_addr *krule)
1012{
1013	static const u_int8_t EMPTY_MAC[ETHER_ADDR_LEN] = { 0 };
1014	int error = 0;
1015
1016	PFNV_CHK(pf_nvbinary(nvl, "addr", &krule->addr, sizeof(krule->addr)));
1017	PFNV_CHK(pf_nvbool(nvl, "neg", &krule->neg));
1018	if (nvlist_exists_binary(nvl, "mask"))
1019		PFNV_CHK(pf_nvbinary(nvl, "mask", &krule->mask,
1020		    sizeof(krule->mask)));
1021
1022	/* To make checks for 'is this address set?' easier. */
1023	if (memcmp(krule->addr, EMPTY_MAC, ETHER_ADDR_LEN) != 0)
1024		krule->isset = 1;
1025
1026errout:
1027	return (error);
1028}
1029
1030static nvlist_t*
1031pf_keth_rule_addr_to_nveth_rule_addr(const struct pf_keth_rule_addr *krule)
1032{
1033	nvlist_t *nvl;
1034
1035	nvl = nvlist_create(0);
1036	if (nvl == NULL)
1037		return (NULL);
1038
1039	nvlist_add_binary(nvl, "addr", &krule->addr, sizeof(krule->addr));
1040	nvlist_add_binary(nvl, "mask", &krule->mask, sizeof(krule->mask));
1041	nvlist_add_bool(nvl, "neg", krule->neg);
1042
1043	return (nvl);
1044}
1045
1046nvlist_t*
1047pf_keth_rule_to_nveth_rule(const struct pf_keth_rule *krule)
1048{
1049	nvlist_t *nvl, *addr;
1050
1051	nvl = nvlist_create(0);
1052	if (nvl == NULL)
1053		return (NULL);
1054
1055	for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) {
1056		nvlist_append_string_array(nvl, "labels", krule->label[i]);
1057	}
1058	nvlist_add_number(nvl, "ridentifier", krule->ridentifier);
1059
1060	nvlist_add_number(nvl, "nr", krule->nr);
1061	nvlist_add_bool(nvl, "quick", krule->quick);
1062	nvlist_add_string(nvl, "ifname", krule->ifname);
1063	nvlist_add_bool(nvl, "ifnot", krule->ifnot);
1064	nvlist_add_number(nvl, "direction", krule->direction);
1065	nvlist_add_number(nvl, "proto", krule->proto);
1066	nvlist_add_string(nvl, "match_tagname", krule->match_tagname);
1067	nvlist_add_number(nvl, "match_tag", krule->match_tag);
1068	nvlist_add_bool(nvl, "match_tag_not", krule->match_tag_not);
1069
1070	addr = pf_keth_rule_addr_to_nveth_rule_addr(&krule->src);
1071	if (addr == NULL) {
1072		nvlist_destroy(nvl);
1073		return (NULL);
1074	}
1075	nvlist_add_nvlist(nvl, "src", addr);
1076	nvlist_destroy(addr);
1077
1078	addr = pf_keth_rule_addr_to_nveth_rule_addr(&krule->dst);
1079	if (addr == NULL) {
1080		nvlist_destroy(nvl);
1081		return (NULL);
1082	}
1083	nvlist_add_nvlist(nvl, "dst", addr);
1084	nvlist_destroy(addr);
1085
1086	addr = pf_rule_addr_to_nvrule_addr(&krule->ipsrc);
1087	if (addr == NULL) {
1088		nvlist_destroy(nvl);
1089		return (NULL);
1090	}
1091	nvlist_add_nvlist(nvl, "ipsrc", addr);
1092	nvlist_destroy(addr);
1093
1094	addr = pf_rule_addr_to_nvrule_addr(&krule->ipdst);
1095	if (addr == NULL) {
1096		nvlist_destroy(nvl);
1097		return (NULL);
1098	}
1099	nvlist_add_nvlist(nvl, "ipdst", addr);
1100	nvlist_destroy(addr);
1101
1102	nvlist_add_number(nvl, "evaluations",
1103	    counter_u64_fetch(krule->evaluations));
1104	nvlist_add_number(nvl, "packets-in",
1105	    counter_u64_fetch(krule->packets[0]));
1106	nvlist_add_number(nvl, "packets-out",
1107	    counter_u64_fetch(krule->packets[1]));
1108	nvlist_add_number(nvl, "bytes-in",
1109	    counter_u64_fetch(krule->bytes[0]));
1110	nvlist_add_number(nvl, "bytes-out",
1111	    counter_u64_fetch(krule->bytes[1]));
1112
1113	nvlist_add_number(nvl, "timestamp", pf_get_timestamp(krule));
1114	nvlist_add_string(nvl, "qname", krule->qname);
1115	nvlist_add_string(nvl, "tagname", krule->tagname);
1116
1117	nvlist_add_number(nvl, "dnpipe", krule->dnpipe);
1118	nvlist_add_number(nvl, "dnflags", krule->dnflags);
1119
1120	nvlist_add_number(nvl, "anchor_relative", krule->anchor_relative);
1121	nvlist_add_number(nvl, "anchor_wildcard", krule->anchor_wildcard);
1122
1123	nvlist_add_string(nvl, "bridge_to", krule->bridge_to_name);
1124	nvlist_add_number(nvl, "action", krule->action);
1125
1126	return (nvl);
1127}
1128
1129int
1130pf_nveth_rule_to_keth_rule(const nvlist_t *nvl,
1131    struct pf_keth_rule *krule)
1132{
1133	int error = 0;
1134
1135#define ERROUT(x)	ERROUT_FUNCTION(errout, x)
1136
1137	bzero(krule, sizeof(*krule));
1138
1139	if (nvlist_exists_string_array(nvl, "labels")) {
1140		const char *const *strs;
1141		size_t items;
1142		int ret;
1143
1144		strs = nvlist_get_string_array(nvl, "labels", &items);
1145		if (items > PF_RULE_MAX_LABEL_COUNT)
1146			ERROUT(E2BIG);
1147
1148		for (size_t i = 0; i < items; i++) {
1149			ret = strlcpy(krule->label[i], strs[i],
1150			    sizeof(krule->label[0]));
1151			if (ret >= sizeof(krule->label[0]))
1152				ERROUT(E2BIG);
1153		}
1154	}
1155
1156	PFNV_CHK(pf_nvuint32_opt(nvl, "ridentifier", &krule->ridentifier, 0));
1157
1158	PFNV_CHK(pf_nvuint32(nvl, "nr", &krule->nr));
1159	PFNV_CHK(pf_nvbool(nvl, "quick", &krule->quick));
1160	PFNV_CHK(pf_nvstring(nvl, "ifname", krule->ifname,
1161	    sizeof(krule->ifname)));
1162	PFNV_CHK(pf_nvbool(nvl, "ifnot", &krule->ifnot));
1163	PFNV_CHK(pf_nvuint8(nvl, "direction", &krule->direction));
1164	PFNV_CHK(pf_nvuint16(nvl, "proto", &krule->proto));
1165
1166	if (nvlist_exists_nvlist(nvl, "src")) {
1167		error = pf_nveth_rule_addr_to_keth_rule_addr(
1168		    nvlist_get_nvlist(nvl, "src"), &krule->src);
1169		if (error)
1170			return (error);
1171	}
1172	if (nvlist_exists_nvlist(nvl, "dst")) {
1173		error = pf_nveth_rule_addr_to_keth_rule_addr(
1174		    nvlist_get_nvlist(nvl, "dst"), &krule->dst);
1175		if (error)
1176			return (error);
1177	}
1178
1179	if (nvlist_exists_nvlist(nvl, "ipsrc")) {
1180		error = pf_nvrule_addr_to_rule_addr(
1181		    nvlist_get_nvlist(nvl, "ipsrc"), &krule->ipsrc);
1182		if (error != 0)
1183			return (error);
1184
1185		if (krule->ipsrc.addr.type != PF_ADDR_ADDRMASK &&
1186		    krule->ipsrc.addr.type != PF_ADDR_TABLE)
1187			return (EINVAL);
1188	}
1189
1190	if (nvlist_exists_nvlist(nvl, "ipdst")) {
1191		error = pf_nvrule_addr_to_rule_addr(
1192		    nvlist_get_nvlist(nvl, "ipdst"), &krule->ipdst);
1193		if (error != 0)
1194			return (error);
1195
1196		if (krule->ipdst.addr.type != PF_ADDR_ADDRMASK &&
1197		    krule->ipdst.addr.type != PF_ADDR_TABLE)
1198			return (EINVAL);
1199	}
1200
1201	if (nvlist_exists_string(nvl, "match_tagname")) {
1202		PFNV_CHK(pf_nvstring(nvl, "match_tagname", krule->match_tagname,
1203		    sizeof(krule->match_tagname)));
1204		PFNV_CHK(pf_nvbool(nvl, "match_tag_not", &krule->match_tag_not));
1205	}
1206
1207	PFNV_CHK(pf_nvstring(nvl, "qname", krule->qname, sizeof(krule->qname)));
1208	PFNV_CHK(pf_nvstring(nvl, "tagname", krule->tagname,
1209	    sizeof(krule->tagname)));
1210
1211	PFNV_CHK(pf_nvuint16_opt(nvl, "dnpipe", &krule->dnpipe, 0));
1212	PFNV_CHK(pf_nvuint32_opt(nvl, "dnflags", &krule->dnflags, 0));
1213	PFNV_CHK(pf_nvstring(nvl, "bridge_to", krule->bridge_to_name,
1214	    sizeof(krule->bridge_to_name)));
1215
1216	PFNV_CHK(pf_nvuint8(nvl, "action", &krule->action));
1217
1218	if (krule->action != PF_PASS && krule->action != PF_DROP &&
1219	    krule->action != PF_MATCH)
1220		return (EBADMSG);
1221
1222#undef ERROUT
1223errout:
1224	return (error);
1225}
1226