xref: /freebsd/sys/netpfil/pf/pf_nv.c (revision 19e4f2f289fb8d2b14576a65ca9e6f931dbb6a02)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
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 __FBSDID("$FreeBSD$");
30 
31 #include "opt_inet.h"
32 #include "opt_inet6.h"
33 
34 #include <sys/param.h>
35 #include <sys/errno.h>
36 #include <sys/limits.h>
37 #include <sys/queue.h>
38 #include <sys/systm.h>
39 
40 #include <netpfil/pf/pf_nv.h>
41 
42 #define	PF_NV_IMPL_UINT(fnname, type, max)					\
43 	int									\
44 	pf_nv ## fnname ## _opt(const nvlist_t *nvl, const char *name,		\
45 	    type *val, type dflt)						\
46 	{									\
47 		uint64_t raw;							\
48 		if (! nvlist_exists_number(nvl, name)) {			\
49 			*val = dflt;						\
50 			return (0);						\
51 		}								\
52 		raw = nvlist_get_number(nvl, name);				\
53 		if (raw > max)							\
54 			return (ERANGE);					\
55 		*val = (type)raw;						\
56 		return (0);							\
57 	}									\
58 	int									\
59 	pf_nv ## fnname(const nvlist_t *nvl, const char *name, type *val)	\
60 	{									\
61 		uint64_t raw;							\
62 		if (! nvlist_exists_number(nvl, name))				\
63 			return (EINVAL);					\
64 		raw = nvlist_get_number(nvl, name);				\
65 		if (raw > max)							\
66 			return (ERANGE);					\
67 		*val = (type)raw;						\
68 		return (0);							\
69 	}									\
70 	int									\
71 	pf_nv ## fnname ## _array(const nvlist_t *nvl, const char *name,	\
72 	    type *array, size_t maxelems, size_t *nelems)			\
73 	{									\
74 		const uint64_t *n;						\
75 		size_t nitems;							\
76 		bzero(array, sizeof(type) * maxelems);				\
77 		if (! nvlist_exists_number_array(nvl, name))			\
78 			return (EINVAL);					\
79 		n = nvlist_get_number_array(nvl, name, &nitems);		\
80 		if (nitems != maxelems)						\
81 			return (E2BIG);						\
82 		if (nelems != NULL)						\
83 			*nelems = nitems;					\
84 		for (size_t i = 0; i < nitems; i++) {				\
85 			if (n[i] > max)						\
86 				return (ERANGE);				\
87 			array[i] = (type)n[i];					\
88 		}								\
89 		return (0);							\
90 	}									\
91 	void									\
92 	pf_ ## fnname ## _array_nv(nvlist_t *nvl, const char *name,		\
93 	    const type *numbers, size_t count)					\
94 	{									\
95 		uint64_t tmp;							\
96 		for (size_t i = 0; i < count; i++) {				\
97 			tmp = numbers[i];					\
98 			nvlist_append_number_array(nvl, name, tmp);		\
99 		}								\
100 	}
101 
102 int
103 pf_nvbinary(const nvlist_t *nvl, const char *name, void *data,
104     size_t expected_size)
105 {
106 	const uint8_t *nvdata;
107 	size_t len;
108 
109 	bzero(data, expected_size);
110 
111 	if (! nvlist_exists_binary(nvl, name))
112 		return (EINVAL);
113 
114 	nvdata = (const uint8_t *)nvlist_get_binary(nvl, name, &len);
115 	if (len > expected_size)
116 		return (EINVAL);
117 
118 	memcpy(data, nvdata, len);
119 
120 	return (0);
121 }
122 
123 PF_NV_IMPL_UINT(uint8, uint8_t, UINT8_MAX);
124 PF_NV_IMPL_UINT(uint16, uint16_t, UINT16_MAX);
125 PF_NV_IMPL_UINT(uint32, uint32_t, UINT32_MAX);
126 PF_NV_IMPL_UINT(uint64, uint64_t, UINT64_MAX);
127 
128 int
129 pf_nvint(const nvlist_t *nvl, const char *name, int *val)
130 {
131 	int64_t raw;
132 
133 	if (! nvlist_exists_number(nvl, name))
134 		return (EINVAL);
135 
136 	raw = nvlist_get_number(nvl, name);
137 	if (raw > INT_MAX || raw < INT_MIN)
138 		return (ERANGE);
139 
140 	*val = (int)raw;
141 
142 	return (0);
143 }
144 
145 int
146 pf_nvstring(const nvlist_t *nvl, const char *name, char *str, size_t maxlen)
147 {
148 	int ret;
149 
150 	if (! nvlist_exists_string(nvl, name))
151 		return (EINVAL);
152 
153 	ret = strlcpy(str, nvlist_get_string(nvl, name), maxlen);
154 	if (ret >= maxlen)
155 		return (EINVAL);
156 
157 	return (0);
158 }
159 
160 static int
161 pf_nvaddr_to_addr(const nvlist_t *nvl, struct pf_addr *paddr)
162 {
163 	return (pf_nvbinary(nvl, "addr", paddr, sizeof(*paddr)));
164 }
165 
166 static nvlist_t *
167 pf_addr_to_nvaddr(const struct pf_addr *paddr)
168 {
169 	nvlist_t *nvl;
170 
171 	nvl = nvlist_create(0);
172 	if (nvl == NULL)
173 		return (NULL);
174 
175 	nvlist_add_binary(nvl, "addr", paddr, sizeof(*paddr));
176 
177 	return (nvl);
178 }
179 
180 static int
181 pf_nvmape_to_mape(const nvlist_t *nvl, struct pf_mape_portset *mape)
182 {
183 	int error = 0;
184 
185 	bzero(mape, sizeof(*mape));
186 	PFNV_CHK(pf_nvuint8(nvl, "offset", &mape->offset));
187 	PFNV_CHK(pf_nvuint8(nvl, "psidlen", &mape->psidlen));
188 	PFNV_CHK(pf_nvuint16(nvl, "psid", &mape->psid));
189 
190 errout:
191 	return (error);
192 }
193 
194 static nvlist_t *
195 pf_mape_to_nvmape(const struct pf_mape_portset *mape)
196 {
197 	nvlist_t *nvl;
198 
199 	nvl = nvlist_create(0);
200 	if (nvl == NULL)
201 		return (NULL);
202 
203 	nvlist_add_number(nvl, "offset", mape->offset);
204 	nvlist_add_number(nvl, "psidlen", mape->psidlen);
205 	nvlist_add_number(nvl, "psid", mape->psid);
206 
207 	return (nvl);
208 }
209 
210 static int
211 pf_nvpool_to_pool(const nvlist_t *nvl, struct pf_kpool *kpool)
212 {
213 	int error = 0;
214 
215 	bzero(kpool, sizeof(*kpool));
216 
217 	PFNV_CHK(pf_nvbinary(nvl, "key", &kpool->key, sizeof(kpool->key)));
218 
219 	if (nvlist_exists_nvlist(nvl, "counter")) {
220 		PFNV_CHK(pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "counter"),
221 		    &kpool->counter));
222 	}
223 
224 	PFNV_CHK(pf_nvint(nvl, "tblidx", &kpool->tblidx));
225 	PFNV_CHK(pf_nvuint16_array(nvl, "proxy_port", kpool->proxy_port, 2,
226 	    NULL));
227 	PFNV_CHK(pf_nvuint8(nvl, "opts", &kpool->opts));
228 
229 	if (nvlist_exists_nvlist(nvl, "mape")) {
230 		PFNV_CHK(pf_nvmape_to_mape(nvlist_get_nvlist(nvl, "mape"),
231 		    &kpool->mape));
232 	}
233 
234 errout:
235 	return (error);
236 }
237 
238 static nvlist_t *
239 pf_pool_to_nvpool(const struct pf_kpool *pool)
240 {
241 	nvlist_t *nvl;
242 	nvlist_t *tmp;
243 
244 	nvl = nvlist_create(0);
245 	if (nvl == NULL)
246 		return (NULL);
247 
248 	nvlist_add_binary(nvl, "key", &pool->key, sizeof(pool->key));
249 	tmp = pf_addr_to_nvaddr(&pool->counter);
250 	if (tmp == NULL)
251 		goto error;
252 	nvlist_add_nvlist(nvl, "counter", tmp);
253 	nvlist_destroy(tmp);
254 
255 	nvlist_add_number(nvl, "tblidx", pool->tblidx);
256 	pf_uint16_array_nv(nvl, "proxy_port", pool->proxy_port, 2);
257 	nvlist_add_number(nvl, "opts", pool->opts);
258 
259 	tmp = pf_mape_to_nvmape(&pool->mape);
260 	if (tmp == NULL)
261 		goto error;
262 	nvlist_add_nvlist(nvl, "mape", tmp);
263 	nvlist_destroy(tmp);
264 
265 	return (nvl);
266 
267 error:
268 	nvlist_destroy(nvl);
269 	return (NULL);
270 }
271 
272 static int
273 pf_nvaddr_wrap_to_addr_wrap(const nvlist_t *nvl, struct pf_addr_wrap *addr)
274 {
275 	int error = 0;
276 
277 	bzero(addr, sizeof(*addr));
278 
279 	PFNV_CHK(pf_nvuint8(nvl, "type", &addr->type));
280 	PFNV_CHK(pf_nvuint8(nvl, "iflags", &addr->iflags));
281 	if (addr->type == PF_ADDR_DYNIFTL)
282 		PFNV_CHK(pf_nvstring(nvl, "ifname", addr->v.ifname,
283 		    sizeof(addr->v.ifname)));
284 	if (addr->type == PF_ADDR_TABLE)
285 		PFNV_CHK(pf_nvstring(nvl, "tblname", addr->v.tblname,
286 		    sizeof(addr->v.tblname)));
287 
288 	if (! nvlist_exists_nvlist(nvl, "addr"))
289 		return (EINVAL);
290 	PFNV_CHK(pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "addr"),
291 	    &addr->v.a.addr));
292 
293 	if (! nvlist_exists_nvlist(nvl, "mask"))
294 		return (EINVAL);
295 	PFNV_CHK(pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "mask"),
296 	    &addr->v.a.mask));
297 
298 	switch (addr->type) {
299 	case PF_ADDR_DYNIFTL:
300 	case PF_ADDR_TABLE:
301 	case PF_ADDR_RANGE:
302 	case PF_ADDR_ADDRMASK:
303 	case PF_ADDR_NOROUTE:
304 	case PF_ADDR_URPFFAILED:
305 		break;
306 	default:
307 		return (EINVAL);
308 	}
309 
310 errout:
311 	return (error);
312 }
313 
314 static nvlist_t *
315 pf_addr_wrap_to_nvaddr_wrap(const struct pf_addr_wrap *addr)
316 {
317 	nvlist_t *nvl;
318 	nvlist_t *tmp;
319 
320 	nvl = nvlist_create(0);
321 	if (nvl == NULL)
322 		return (NULL);
323 
324 	nvlist_add_number(nvl, "type", addr->type);
325 	nvlist_add_number(nvl, "iflags", addr->iflags);
326 	if (addr->type == PF_ADDR_DYNIFTL)
327 		nvlist_add_string(nvl, "ifname", addr->v.ifname);
328 	if (addr->type == PF_ADDR_TABLE)
329 		nvlist_add_string(nvl, "tblname", addr->v.tblname);
330 
331 	tmp = pf_addr_to_nvaddr(&addr->v.a.addr);
332 	if (tmp == NULL)
333 		goto error;
334 	nvlist_add_nvlist(nvl, "addr", tmp);
335 	nvlist_destroy(tmp);
336 	tmp = pf_addr_to_nvaddr(&addr->v.a.mask);
337 	if (tmp == NULL)
338 		goto error;
339 	nvlist_add_nvlist(nvl, "mask", tmp);
340 	nvlist_destroy(tmp);
341 
342 	return (nvl);
343 
344 error:
345 	nvlist_destroy(nvl);
346 	return (NULL);
347 }
348 
349 static int
350 pf_validate_op(uint8_t op)
351 {
352 	switch (op) {
353 	case PF_OP_NONE:
354 	case PF_OP_IRG:
355 	case PF_OP_EQ:
356 	case PF_OP_NE:
357 	case PF_OP_LT:
358 	case PF_OP_LE:
359 	case PF_OP_GT:
360 	case PF_OP_GE:
361 	case PF_OP_XRG:
362 	case PF_OP_RRG:
363 		break;
364 	default:
365 		return (EINVAL);
366 	}
367 
368 	return (0);
369 }
370 
371 static int
372 pf_nvrule_addr_to_rule_addr(const nvlist_t *nvl, struct pf_rule_addr *addr)
373 {
374 	int error = 0;
375 
376 	if (! nvlist_exists_nvlist(nvl, "addr"))
377 		return (EINVAL);
378 
379 	PFNV_CHK(pf_nvaddr_wrap_to_addr_wrap(nvlist_get_nvlist(nvl, "addr"),
380 	    &addr->addr));
381 	PFNV_CHK(pf_nvuint16_array(nvl, "port", addr->port, 2, NULL));
382 	PFNV_CHK(pf_nvuint8(nvl, "neg", &addr->neg));
383 	PFNV_CHK(pf_nvuint8(nvl, "port_op", &addr->port_op));
384 
385 	PFNV_CHK(pf_validate_op(addr->port_op));
386 
387 errout:
388 	return (error);
389 }
390 
391 static nvlist_t *
392 pf_rule_addr_to_nvrule_addr(const struct pf_rule_addr *addr)
393 {
394 	nvlist_t *nvl;
395 	nvlist_t *tmp;
396 
397 	nvl = nvlist_create(0);
398 	if (nvl == NULL)
399 		return (NULL);
400 
401 	tmp = pf_addr_wrap_to_nvaddr_wrap(&addr->addr);
402 	if (tmp == NULL)
403 		goto error;
404 	nvlist_add_nvlist(nvl, "addr", tmp);
405 	nvlist_destroy(tmp);
406 	pf_uint16_array_nv(nvl, "port", addr->port, 2);
407 	nvlist_add_number(nvl, "neg", addr->neg);
408 	nvlist_add_number(nvl, "port_op", addr->port_op);
409 
410 	return (nvl);
411 
412 error:
413 	nvlist_destroy(nvl);
414 	return (NULL);
415 }
416 
417 static int
418 pf_nvrule_uid_to_rule_uid(const nvlist_t *nvl, struct pf_rule_uid *uid)
419 {
420 	int error = 0;
421 
422 	bzero(uid, sizeof(*uid));
423 
424 	PFNV_CHK(pf_nvuint32_array(nvl, "uid", uid->uid, 2, NULL));
425 	PFNV_CHK(pf_nvuint8(nvl, "op", &uid->op));
426 
427 	PFNV_CHK(pf_validate_op(uid->op));
428 
429 errout:
430 	return (error);
431 }
432 
433 static nvlist_t *
434 pf_rule_uid_to_nvrule_uid(const struct pf_rule_uid *uid)
435 {
436 	nvlist_t *nvl;
437 
438 	nvl = nvlist_create(0);
439 	if (nvl == NULL)
440 		return (NULL);
441 
442 	pf_uint32_array_nv(nvl, "uid", uid->uid, 2);
443 	nvlist_add_number(nvl, "op", uid->op);
444 
445 	return (nvl);
446 }
447 
448 static int
449 pf_nvrule_gid_to_rule_gid(const nvlist_t *nvl, struct pf_rule_gid *gid)
450 {
451 	/* Cheat a little. These stucts are the same, other than the name of
452 	 * the first field. */
453 	return (pf_nvrule_uid_to_rule_uid(nvl, (struct pf_rule_uid *)gid));
454 }
455 
456 int
457 pf_check_rule_addr(const struct pf_rule_addr *addr)
458 {
459 
460 	switch (addr->addr.type) {
461 	case PF_ADDR_ADDRMASK:
462 	case PF_ADDR_NOROUTE:
463 	case PF_ADDR_DYNIFTL:
464 	case PF_ADDR_TABLE:
465 	case PF_ADDR_URPFFAILED:
466 	case PF_ADDR_RANGE:
467 		break;
468 	default:
469 		return (EINVAL);
470 	}
471 
472 	if (addr->addr.p.dyn != NULL) {
473 		return (EINVAL);
474 	}
475 
476 	return (0);
477 }
478 
479 
480 int
481 pf_nvrule_to_krule(const nvlist_t *nvl, struct pf_krule *rule)
482 {
483 	int error = 0;
484 
485 #define	ERROUT(x)	ERROUT_FUNCTION(errout, x)
486 
487 	PFNV_CHK(pf_nvuint32(nvl, "nr", &rule->nr));
488 
489 	if (! nvlist_exists_nvlist(nvl, "src"))
490 		ERROUT(EINVAL);
491 
492 	error = pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "src"),
493 	    &rule->src);
494 	if (error != 0)
495 		ERROUT(error);
496 
497 	if (! nvlist_exists_nvlist(nvl, "dst"))
498 		ERROUT(EINVAL);
499 
500 	PFNV_CHK(pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "dst"),
501 	    &rule->dst));
502 
503 	if (nvlist_exists_string(nvl, "label")) {
504 		PFNV_CHK(pf_nvstring(nvl, "label", rule->label[0],
505 		    sizeof(rule->label[0])));
506 	} else if (nvlist_exists_string_array(nvl, "labels")) {
507 		const char *const *strs;
508 		size_t items;
509 		int ret;
510 
511 		strs = nvlist_get_string_array(nvl, "labels", &items);
512 		if (items > PF_RULE_MAX_LABEL_COUNT)
513 			ERROUT(E2BIG);
514 
515 		for (size_t i = 0; i < items; i++) {
516 			ret = strlcpy(rule->label[i], strs[i],
517 			    sizeof(rule->label[0]));
518 			if (ret >= sizeof(rule->label[0]))
519 				ERROUT(E2BIG);
520 		}
521 	}
522 
523 	PFNV_CHK(pf_nvstring(nvl, "ifname", rule->ifname,
524 	    sizeof(rule->ifname)));
525 	PFNV_CHK(pf_nvstring(nvl, "qname", rule->qname, sizeof(rule->qname)));
526 	PFNV_CHK(pf_nvstring(nvl, "pqname", rule->pqname,
527 	    sizeof(rule->pqname)));
528 	PFNV_CHK(pf_nvstring(nvl, "tagname", rule->tagname,
529 	    sizeof(rule->tagname)));
530 	PFNV_CHK(pf_nvuint16_opt(nvl, "dnpipe", &rule->dnpipe, 0));
531 	PFNV_CHK(pf_nvuint16_opt(nvl, "dnrpipe", &rule->dnrpipe, 0));
532 	PFNV_CHK(pf_nvuint32_opt(nvl, "dnflags", &rule->free_flags, 0));
533 	PFNV_CHK(pf_nvstring(nvl, "match_tagname", rule->match_tagname,
534 	    sizeof(rule->match_tagname)));
535 	PFNV_CHK(pf_nvstring(nvl, "overload_tblname", rule->overload_tblname,
536 	    sizeof(rule->overload_tblname)));
537 
538 	if (! nvlist_exists_nvlist(nvl, "rpool"))
539 		ERROUT(EINVAL);
540 	PFNV_CHK(pf_nvpool_to_pool(nvlist_get_nvlist(nvl, "rpool"),
541 	    &rule->rpool));
542 
543 	PFNV_CHK(pf_nvuint32(nvl, "os_fingerprint", &rule->os_fingerprint));
544 
545 	PFNV_CHK(pf_nvint(nvl, "rtableid", &rule->rtableid));
546 	PFNV_CHK(pf_nvuint32_array(nvl, "timeout", rule->timeout, PFTM_MAX, NULL));
547 	PFNV_CHK(pf_nvuint32(nvl, "max_states", &rule->max_states));
548 	PFNV_CHK(pf_nvuint32(nvl, "max_src_nodes", &rule->max_src_nodes));
549 	PFNV_CHK(pf_nvuint32(nvl, "max_src_states", &rule->max_src_states));
550 	PFNV_CHK(pf_nvuint32(nvl, "max_src_conn", &rule->max_src_conn));
551 	PFNV_CHK(pf_nvuint32(nvl, "max_src_conn_rate.limit",
552 	    &rule->max_src_conn_rate.limit));
553 	PFNV_CHK(pf_nvuint32(nvl, "max_src_conn_rate.seconds",
554 	    &rule->max_src_conn_rate.seconds));
555 	PFNV_CHK(pf_nvuint32(nvl, "prob", &rule->prob));
556 	PFNV_CHK(pf_nvuint32(nvl, "cuid", &rule->cuid));
557 	PFNV_CHK(pf_nvuint32(nvl, "cpid", &rule->cpid));
558 
559 	PFNV_CHK(pf_nvuint16(nvl, "return_icmp", &rule->return_icmp));
560 	PFNV_CHK(pf_nvuint16(nvl, "return_icmp6", &rule->return_icmp6));
561 
562 	PFNV_CHK(pf_nvuint16(nvl, "max_mss", &rule->max_mss));
563 	PFNV_CHK(pf_nvuint16(nvl, "scrub_flags", &rule->scrub_flags));
564 
565 	if (! nvlist_exists_nvlist(nvl, "uid"))
566 		ERROUT(EINVAL);
567 	PFNV_CHK(pf_nvrule_uid_to_rule_uid(nvlist_get_nvlist(nvl, "uid"),
568 	    &rule->uid));
569 
570 	if (! nvlist_exists_nvlist(nvl, "gid"))
571 		ERROUT(EINVAL);
572 	PFNV_CHK(pf_nvrule_gid_to_rule_gid(nvlist_get_nvlist(nvl, "gid"),
573 	    &rule->gid));
574 
575 	PFNV_CHK(pf_nvuint32(nvl, "rule_flag", &rule->rule_flag));
576 	PFNV_CHK(pf_nvuint8(nvl, "action", &rule->action));
577 	PFNV_CHK(pf_nvuint8(nvl, "direction", &rule->direction));
578 	PFNV_CHK(pf_nvuint8(nvl, "log", &rule->log));
579 	PFNV_CHK(pf_nvuint8(nvl, "logif", &rule->logif));
580 	PFNV_CHK(pf_nvuint8(nvl, "quick", &rule->quick));
581 	PFNV_CHK(pf_nvuint8(nvl, "ifnot", &rule->ifnot));
582 	PFNV_CHK(pf_nvuint8(nvl, "match_tag_not", &rule->match_tag_not));
583 	PFNV_CHK(pf_nvuint8(nvl, "natpass", &rule->natpass));
584 
585 	PFNV_CHK(pf_nvuint8(nvl, "keep_state", &rule->keep_state));
586 	PFNV_CHK(pf_nvuint8(nvl, "af", &rule->af));
587 	PFNV_CHK(pf_nvuint8(nvl, "proto", &rule->proto));
588 	PFNV_CHK(pf_nvuint8(nvl, "type", &rule->type));
589 	PFNV_CHK(pf_nvuint8(nvl, "code", &rule->code));
590 	PFNV_CHK(pf_nvuint8(nvl, "flags", &rule->flags));
591 	PFNV_CHK(pf_nvuint8(nvl, "flagset", &rule->flagset));
592 	PFNV_CHK(pf_nvuint8(nvl, "min_ttl", &rule->min_ttl));
593 	PFNV_CHK(pf_nvuint8(nvl, "allow_opts", &rule->allow_opts));
594 	PFNV_CHK(pf_nvuint8(nvl, "rt", &rule->rt));
595 	PFNV_CHK(pf_nvuint8(nvl, "return_ttl", &rule->return_ttl));
596 	PFNV_CHK(pf_nvuint8(nvl, "tos", &rule->tos));
597 	PFNV_CHK(pf_nvuint8(nvl, "set_tos", &rule->set_tos));
598 	PFNV_CHK(pf_nvuint8(nvl, "anchor_relative", &rule->anchor_relative));
599 	PFNV_CHK(pf_nvuint8(nvl, "anchor_wildcard", &rule->anchor_wildcard));
600 
601 	PFNV_CHK(pf_nvuint8(nvl, "flush", &rule->flush));
602 	PFNV_CHK(pf_nvuint8(nvl, "prio", &rule->prio));
603 
604 	PFNV_CHK(pf_nvuint8_array(nvl, "set_prio", &rule->prio, 2, NULL));
605 
606 	if (nvlist_exists_nvlist(nvl, "divert")) {
607 		const nvlist_t *nvldivert = nvlist_get_nvlist(nvl, "divert");
608 
609 		if (! nvlist_exists_nvlist(nvldivert, "addr"))
610 			ERROUT(EINVAL);
611 		PFNV_CHK(pf_nvaddr_to_addr(nvlist_get_nvlist(nvldivert, "addr"),
612 		    &rule->divert.addr));
613 		PFNV_CHK(pf_nvuint16(nvldivert, "port", &rule->divert.port));
614 	}
615 
616 	/* Validation */
617 #ifndef INET
618 	if (rule->af == AF_INET)
619 		ERROUT(EAFNOSUPPORT);
620 #endif /* INET */
621 #ifndef INET6
622 	if (rule->af == AF_INET6)
623 		ERROUT(EAFNOSUPPORT);
624 #endif /* INET6 */
625 
626 	PFNV_CHK(pf_check_rule_addr(&rule->src));
627 	PFNV_CHK(pf_check_rule_addr(&rule->dst));
628 
629 	return (0);
630 
631 #undef ERROUT
632 errout:
633 	return (error);
634 }
635 
636 static nvlist_t *
637 pf_divert_to_nvdivert(const struct pf_krule *rule)
638 {
639 	nvlist_t *nvl;
640 	nvlist_t *tmp;
641 
642 	nvl = nvlist_create(0);
643 	if (nvl == NULL)
644 		return (NULL);
645 
646 	tmp = pf_addr_to_nvaddr(&rule->divert.addr);
647 	if (tmp == NULL)
648 		goto error;
649 	nvlist_add_nvlist(nvl, "addr", tmp);
650 	nvlist_destroy(tmp);
651 	nvlist_add_number(nvl, "port", rule->divert.port);
652 
653 	return (nvl);
654 
655 error:
656 	nvlist_destroy(nvl);
657 	return (NULL);
658 }
659 
660 nvlist_t *
661 pf_krule_to_nvrule(struct pf_krule *rule)
662 {
663 	nvlist_t *nvl, *tmp;
664 
665 	nvl = nvlist_create(0);
666 	if (nvl == NULL)
667 		return (nvl);
668 
669 	nvlist_add_number(nvl, "nr", rule->nr);
670 	tmp = pf_rule_addr_to_nvrule_addr(&rule->src);
671 	if (tmp == NULL)
672 		goto error;
673 	nvlist_add_nvlist(nvl, "src", tmp);
674 	nvlist_destroy(tmp);
675 	tmp = pf_rule_addr_to_nvrule_addr(&rule->dst);
676 	if (tmp == NULL)
677 		goto error;
678 	nvlist_add_nvlist(nvl, "dst", tmp);
679 	nvlist_destroy(tmp);
680 
681 	for (int i = 0; i < PF_SKIP_COUNT; i++) {
682 		nvlist_append_number_array(nvl, "skip",
683 		    rule->skip[i].ptr ? rule->skip[i].ptr->nr : -1);
684 	}
685 
686 	for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) {
687 		nvlist_append_string_array(nvl, "labels", rule->label[i]);
688 	}
689 	nvlist_add_string(nvl, "label", rule->label[0]);
690 	nvlist_add_string(nvl, "ifname", rule->ifname);
691 	nvlist_add_string(nvl, "qname", rule->qname);
692 	nvlist_add_string(nvl, "pqname", rule->pqname);
693 	nvlist_add_number(nvl, "dnpipe", rule->dnpipe);
694 	nvlist_add_number(nvl, "dnrpipe", rule->dnrpipe);
695 	nvlist_add_number(nvl, "dnflags", rule->free_flags);
696 	nvlist_add_string(nvl, "tagname", rule->tagname);
697 	nvlist_add_string(nvl, "match_tagname", rule->match_tagname);
698 	nvlist_add_string(nvl, "overload_tblname", rule->overload_tblname);
699 
700 	tmp = pf_pool_to_nvpool(&rule->rpool);
701 	if (tmp == NULL)
702 		goto error;
703 	nvlist_add_nvlist(nvl, "rpool", tmp);
704 	nvlist_destroy(tmp);
705 
706 	nvlist_add_number(nvl, "evaluations",
707 	    pf_counter_u64_fetch(&rule->evaluations));
708 	for (int i = 0; i < 2; i++) {
709 		nvlist_append_number_array(nvl, "packets",
710 		    pf_counter_u64_fetch(&rule->packets[i]));
711 		nvlist_append_number_array(nvl, "bytes",
712 		    pf_counter_u64_fetch(&rule->bytes[i]));
713 	}
714 
715 	nvlist_add_number(nvl, "os_fingerprint", rule->os_fingerprint);
716 
717 	nvlist_add_number(nvl, "rtableid", rule->rtableid);
718 	pf_uint32_array_nv(nvl, "timeout", rule->timeout, PFTM_MAX);
719 	nvlist_add_number(nvl, "max_states", rule->max_states);
720 	nvlist_add_number(nvl, "max_src_nodes", rule->max_src_nodes);
721 	nvlist_add_number(nvl, "max_src_states", rule->max_src_states);
722 	nvlist_add_number(nvl, "max_src_conn", rule->max_src_conn);
723 	nvlist_add_number(nvl, "max_src_conn_rate.limit",
724 	    rule->max_src_conn_rate.limit);
725 	nvlist_add_number(nvl, "max_src_conn_rate.seconds",
726 	    rule->max_src_conn_rate.seconds);
727 	nvlist_add_number(nvl, "qid", rule->qid);
728 	nvlist_add_number(nvl, "pqid", rule->pqid);
729 	nvlist_add_number(nvl, "prob", rule->prob);
730 	nvlist_add_number(nvl, "cuid", rule->cuid);
731 	nvlist_add_number(nvl, "cpid", rule->cpid);
732 
733 	nvlist_add_number(nvl, "states_cur",
734 	    counter_u64_fetch(rule->states_cur));
735 	nvlist_add_number(nvl, "states_tot",
736 	    counter_u64_fetch(rule->states_tot));
737 	nvlist_add_number(nvl, "src_nodes",
738 	    counter_u64_fetch(rule->src_nodes));
739 
740 	nvlist_add_number(nvl, "return_icmp", rule->return_icmp);
741 	nvlist_add_number(nvl, "return_icmp6", rule->return_icmp6);
742 
743 	nvlist_add_number(nvl, "max_mss", rule->max_mss);
744 	nvlist_add_number(nvl, "scrub_flags", rule->scrub_flags);
745 
746 	tmp = pf_rule_uid_to_nvrule_uid(&rule->uid);
747 	if (tmp == NULL)
748 		goto error;
749 	nvlist_add_nvlist(nvl, "uid", tmp);
750 	nvlist_destroy(tmp);
751 	tmp = pf_rule_uid_to_nvrule_uid((const struct pf_rule_uid *)&rule->gid);
752 	if (tmp == NULL)
753 		goto error;
754 	nvlist_add_nvlist(nvl, "gid", tmp);
755 	nvlist_destroy(tmp);
756 
757 	nvlist_add_number(nvl, "rule_flag", rule->rule_flag);
758 	nvlist_add_number(nvl, "action", rule->action);
759 	nvlist_add_number(nvl, "direction", rule->direction);
760 	nvlist_add_number(nvl, "log", rule->log);
761 	nvlist_add_number(nvl, "logif", rule->logif);
762 	nvlist_add_number(nvl, "quick", rule->quick);
763 	nvlist_add_number(nvl, "ifnot", rule->ifnot);
764 	nvlist_add_number(nvl, "match_tag_not", rule->match_tag_not);
765 	nvlist_add_number(nvl, "natpass", rule->natpass);
766 
767 	nvlist_add_number(nvl, "keep_state", rule->keep_state);
768 	nvlist_add_number(nvl, "af", rule->af);
769 	nvlist_add_number(nvl, "proto", rule->proto);
770 	nvlist_add_number(nvl, "type", rule->type);
771 	nvlist_add_number(nvl, "code", rule->code);
772 	nvlist_add_number(nvl, "flags", rule->flags);
773 	nvlist_add_number(nvl, "flagset", rule->flagset);
774 	nvlist_add_number(nvl, "min_ttl", rule->min_ttl);
775 	nvlist_add_number(nvl, "allow_opts", rule->allow_opts);
776 	nvlist_add_number(nvl, "rt", rule->rt);
777 	nvlist_add_number(nvl, "return_ttl", rule->return_ttl);
778 	nvlist_add_number(nvl, "tos", rule->tos);
779 	nvlist_add_number(nvl, "set_tos", rule->set_tos);
780 	nvlist_add_number(nvl, "anchor_relative", rule->anchor_relative);
781 	nvlist_add_number(nvl, "anchor_wildcard", rule->anchor_wildcard);
782 
783 	nvlist_add_number(nvl, "flush", rule->flush);
784 	nvlist_add_number(nvl, "prio", rule->prio);
785 
786 	pf_uint8_array_nv(nvl, "set_prio", &rule->prio, 2);
787 
788 	tmp = pf_divert_to_nvdivert(rule);
789 	if (tmp == NULL)
790 		goto error;
791 	nvlist_add_nvlist(nvl, "divert", tmp);
792 	nvlist_destroy(tmp);
793 
794 	return (nvl);
795 
796 error:
797 	nvlist_destroy(nvl);
798 	return (NULL);
799 }
800 
801 static int
802 pf_nvstate_cmp_to_state_cmp(const nvlist_t *nvl, struct pf_state_cmp *cmp)
803 {
804 	int error = 0;
805 
806 	bzero(cmp, sizeof(*cmp));
807 
808 	PFNV_CHK(pf_nvuint64(nvl, "id", &cmp->id));
809 	PFNV_CHK(pf_nvuint32(nvl, "creatorid", &cmp->creatorid));
810 	PFNV_CHK(pf_nvuint8(nvl, "direction", &cmp->direction));
811 
812 errout:
813 	return (error);
814 }
815 
816 int
817 pf_nvstate_kill_to_kstate_kill(const nvlist_t *nvl,
818     struct pf_kstate_kill *kill)
819 {
820 	int error = 0;
821 
822 	bzero(kill, sizeof(*kill));
823 
824 	if (! nvlist_exists_nvlist(nvl, "cmp"))
825 		return (EINVAL);
826 
827 	PFNV_CHK(pf_nvstate_cmp_to_state_cmp(nvlist_get_nvlist(nvl, "cmp"),
828 	    &kill->psk_pfcmp));
829 	PFNV_CHK(pf_nvuint8(nvl, "af", &kill->psk_af));
830 	PFNV_CHK(pf_nvint(nvl, "proto", &kill->psk_proto));
831 
832 	if (! nvlist_exists_nvlist(nvl, "src"))
833 		return (EINVAL);
834 	PFNV_CHK(pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "src"),
835 	    &kill->psk_src));
836 	if (! nvlist_exists_nvlist(nvl, "dst"))
837 		return (EINVAL);
838 	PFNV_CHK(pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "dst"),
839 	    &kill->psk_dst));
840 	if (nvlist_exists_nvlist(nvl, "rt_addr")) {
841 		PFNV_CHK(pf_nvrule_addr_to_rule_addr(
842 		    nvlist_get_nvlist(nvl, "rt_addr"), &kill->psk_rt_addr));
843 	}
844 
845 	PFNV_CHK(pf_nvstring(nvl, "ifname", kill->psk_ifname,
846 	    sizeof(kill->psk_ifname)));
847 	PFNV_CHK(pf_nvstring(nvl, "label", kill->psk_label,
848 	    sizeof(kill->psk_label)));
849 	if (nvlist_exists_bool(nvl, "kill_match"))
850 		kill->psk_kill_match = nvlist_get_bool(nvl, "kill_match");
851 
852 errout:
853 	return (error);
854 }
855 
856 static nvlist_t *
857 pf_state_key_to_nvstate_key(const struct pf_state_key *key)
858 {
859 	nvlist_t	*nvl, *tmp;
860 
861 	nvl = nvlist_create(0);
862 	if (nvl == NULL)
863 		return (NULL);
864 
865 	for (int i = 0; i < 2; i++) {
866 		tmp = pf_addr_to_nvaddr(&key->addr[i]);
867 		if (tmp == NULL)
868 			goto errout;
869 		nvlist_append_nvlist_array(nvl, "addr", tmp);
870 		nvlist_destroy(tmp);
871 		nvlist_append_number_array(nvl, "port", key->port[i]);
872 	}
873 	nvlist_add_number(nvl, "af", key->af);
874 	nvlist_add_number(nvl, "proto", key->proto);
875 
876 	return (nvl);
877 
878 errout:
879 	nvlist_destroy(nvl);
880 	return (NULL);
881 }
882 
883 static nvlist_t *
884 pf_state_peer_to_nvstate_peer(const struct pf_state_peer *peer)
885 {
886 	nvlist_t *nvl;
887 
888 	nvl = nvlist_create(0);
889 	if (nvl == NULL)
890 		return (NULL);
891 
892 	nvlist_add_number(nvl, "seqlo", peer->seqlo);
893 	nvlist_add_number(nvl, "seqhi", peer->seqhi);
894 	nvlist_add_number(nvl, "seqdiff", peer->seqdiff);
895 	nvlist_add_number(nvl, "state", peer->state);
896 	nvlist_add_number(nvl, "wscale", peer->wscale);
897 
898 	return (nvl);
899 }
900 
901 nvlist_t *
902 pf_state_to_nvstate(const struct pf_kstate *s)
903 {
904 	nvlist_t	*nvl, *tmp;
905 	uint32_t	 expire, flags = 0;
906 
907 	nvl = nvlist_create(0);
908 	if (nvl == NULL)
909 		return (NULL);
910 
911 	nvlist_add_number(nvl, "id", s->id);
912 	nvlist_add_string(nvl, "ifname", s->kif->pfik_name);
913 	nvlist_add_string(nvl, "orig_ifname", s->orig_kif->pfik_name);
914 
915 	tmp = pf_state_key_to_nvstate_key(s->key[PF_SK_STACK]);
916 	if (tmp == NULL)
917 		goto errout;
918 	nvlist_add_nvlist(nvl, "stack_key", tmp);
919 	nvlist_destroy(tmp);
920 
921 	tmp = pf_state_key_to_nvstate_key(s->key[PF_SK_WIRE]);
922 	if (tmp == NULL)
923 		goto errout;
924 	nvlist_add_nvlist(nvl, "wire_key", tmp);
925 	nvlist_destroy(tmp);
926 
927 	tmp = pf_state_peer_to_nvstate_peer(&s->src);
928 	if (tmp == NULL)
929 		goto errout;
930 	nvlist_add_nvlist(nvl, "src", tmp);
931 	nvlist_destroy(tmp);
932 
933 	tmp = pf_state_peer_to_nvstate_peer(&s->dst);
934 	if (tmp == NULL)
935 		goto errout;
936 	nvlist_add_nvlist(nvl, "dst", tmp);
937 	nvlist_destroy(tmp);
938 
939 	tmp = pf_addr_to_nvaddr(&s->rt_addr);
940 	if (tmp == NULL)
941 		goto errout;
942 	nvlist_add_nvlist(nvl, "rt_addr", tmp);
943 	nvlist_destroy(tmp);
944 
945 	nvlist_add_number(nvl, "rule", s->rule.ptr ? s->rule.ptr->nr : -1);
946 	nvlist_add_number(nvl, "anchor",
947 	    s->anchor.ptr ? s->anchor.ptr->nr : -1);
948 	nvlist_add_number(nvl, "nat_rule",
949 	    s->nat_rule.ptr ? s->nat_rule.ptr->nr : -1);
950 	nvlist_add_number(nvl, "creation", s->creation);
951 
952 	expire = pf_state_expires(s);
953 	if (expire <= time_uptime)
954 		expire = 0;
955 	else
956 		expire = expire - time_uptime;
957 	nvlist_add_number(nvl, "expire", expire);
958 
959 	for (int i = 0; i < 2; i++) {
960 		nvlist_append_number_array(nvl, "packets",
961 		    s->packets[i]);
962 		nvlist_append_number_array(nvl, "bytes",
963 		    s->bytes[i]);
964 	}
965 
966 	nvlist_add_number(nvl, "creatorid", s->creatorid);
967 	nvlist_add_number(nvl, "direction", s->direction);
968 	nvlist_add_number(nvl, "state_flags", s->state_flags);
969 	if (s->src_node)
970 		flags |= PFSYNC_FLAG_SRCNODE;
971 	if (s->nat_src_node)
972 		flags |= PFSYNC_FLAG_NATSRCNODE;
973 	nvlist_add_number(nvl, "sync_flags", flags);
974 
975 	return (nvl);
976 
977 errout:
978 	nvlist_destroy(nvl);
979 	return (NULL);
980 }
981