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