xref: /freebsd/sys/netpfil/pf/pf_nv.c (revision 3332f1b444d4a73238e9f59cca27bfc95fe936bd)
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 	uint64_t num;
331 	struct pfr_ktable *kt;
332 
333 	nvl = nvlist_create(0);
334 	if (nvl == NULL)
335 		return (NULL);
336 
337 	nvlist_add_number(nvl, "type", addr->type);
338 	nvlist_add_number(nvl, "iflags", addr->iflags);
339 	if (addr->type == PF_ADDR_DYNIFTL) {
340 		nvlist_add_string(nvl, "ifname", addr->v.ifname);
341 		num = 0;
342 		if (addr->p.dyn != NULL)
343 			num = addr->p.dyn->pfid_acnt4 +
344 			    addr->p.dyn->pfid_acnt6;
345 		nvlist_add_number(nvl, "dyncnt", num);
346 	}
347 	if (addr->type == PF_ADDR_TABLE) {
348 		nvlist_add_string(nvl, "tblname", addr->v.tblname);
349 		num = -1;
350 		kt = addr->p.tbl;
351 		if ((kt->pfrkt_flags & PFR_TFLAG_ACTIVE) &&
352 		    kt->pfrkt_root != NULL)
353 			kt = kt->pfrkt_root;
354 		if (kt->pfrkt_flags & PFR_TFLAG_ACTIVE)
355 			num = kt->pfrkt_cnt;
356 		nvlist_add_number(nvl, "tblcnt", num);
357 	}
358 
359 	tmp = pf_addr_to_nvaddr(&addr->v.a.addr);
360 	if (tmp == NULL)
361 		goto error;
362 	nvlist_add_nvlist(nvl, "addr", tmp);
363 	nvlist_destroy(tmp);
364 	tmp = pf_addr_to_nvaddr(&addr->v.a.mask);
365 	if (tmp == NULL)
366 		goto error;
367 	nvlist_add_nvlist(nvl, "mask", tmp);
368 	nvlist_destroy(tmp);
369 
370 	return (nvl);
371 
372 error:
373 	nvlist_destroy(nvl);
374 	return (NULL);
375 }
376 
377 static int
378 pf_validate_op(uint8_t op)
379 {
380 	switch (op) {
381 	case PF_OP_NONE:
382 	case PF_OP_IRG:
383 	case PF_OP_EQ:
384 	case PF_OP_NE:
385 	case PF_OP_LT:
386 	case PF_OP_LE:
387 	case PF_OP_GT:
388 	case PF_OP_GE:
389 	case PF_OP_XRG:
390 	case PF_OP_RRG:
391 		break;
392 	default:
393 		return (EINVAL);
394 	}
395 
396 	return (0);
397 }
398 
399 static int
400 pf_nvrule_addr_to_rule_addr(const nvlist_t *nvl, struct pf_rule_addr *addr)
401 {
402 	int error = 0;
403 
404 	if (! nvlist_exists_nvlist(nvl, "addr"))
405 		return (EINVAL);
406 
407 	PFNV_CHK(pf_nvaddr_wrap_to_addr_wrap(nvlist_get_nvlist(nvl, "addr"),
408 	    &addr->addr));
409 	PFNV_CHK(pf_nvuint16_array(nvl, "port", addr->port, 2, NULL));
410 	PFNV_CHK(pf_nvuint8(nvl, "neg", &addr->neg));
411 	PFNV_CHK(pf_nvuint8(nvl, "port_op", &addr->port_op));
412 
413 	PFNV_CHK(pf_validate_op(addr->port_op));
414 
415 errout:
416 	return (error);
417 }
418 
419 static nvlist_t *
420 pf_rule_addr_to_nvrule_addr(const struct pf_rule_addr *addr)
421 {
422 	nvlist_t *nvl;
423 	nvlist_t *tmp;
424 
425 	nvl = nvlist_create(0);
426 	if (nvl == NULL)
427 		return (NULL);
428 
429 	tmp = pf_addr_wrap_to_nvaddr_wrap(&addr->addr);
430 	if (tmp == NULL)
431 		goto error;
432 	nvlist_add_nvlist(nvl, "addr", tmp);
433 	nvlist_destroy(tmp);
434 	pf_uint16_array_nv(nvl, "port", addr->port, 2);
435 	nvlist_add_number(nvl, "neg", addr->neg);
436 	nvlist_add_number(nvl, "port_op", addr->port_op);
437 
438 	return (nvl);
439 
440 error:
441 	nvlist_destroy(nvl);
442 	return (NULL);
443 }
444 
445 static int
446 pf_nvrule_uid_to_rule_uid(const nvlist_t *nvl, struct pf_rule_uid *uid)
447 {
448 	int error = 0;
449 
450 	bzero(uid, sizeof(*uid));
451 
452 	PFNV_CHK(pf_nvuint32_array(nvl, "uid", uid->uid, 2, NULL));
453 	PFNV_CHK(pf_nvuint8(nvl, "op", &uid->op));
454 
455 	PFNV_CHK(pf_validate_op(uid->op));
456 
457 errout:
458 	return (error);
459 }
460 
461 static nvlist_t *
462 pf_rule_uid_to_nvrule_uid(const struct pf_rule_uid *uid)
463 {
464 	nvlist_t *nvl;
465 
466 	nvl = nvlist_create(0);
467 	if (nvl == NULL)
468 		return (NULL);
469 
470 	pf_uint32_array_nv(nvl, "uid", uid->uid, 2);
471 	nvlist_add_number(nvl, "op", uid->op);
472 
473 	return (nvl);
474 }
475 
476 static int
477 pf_nvrule_gid_to_rule_gid(const nvlist_t *nvl, struct pf_rule_gid *gid)
478 {
479 	/* Cheat a little. These stucts are the same, other than the name of
480 	 * the first field. */
481 	return (pf_nvrule_uid_to_rule_uid(nvl, (struct pf_rule_uid *)gid));
482 }
483 
484 int
485 pf_check_rule_addr(const struct pf_rule_addr *addr)
486 {
487 
488 	switch (addr->addr.type) {
489 	case PF_ADDR_ADDRMASK:
490 	case PF_ADDR_NOROUTE:
491 	case PF_ADDR_DYNIFTL:
492 	case PF_ADDR_TABLE:
493 	case PF_ADDR_URPFFAILED:
494 	case PF_ADDR_RANGE:
495 		break;
496 	default:
497 		return (EINVAL);
498 	}
499 
500 	if (addr->addr.p.dyn != NULL) {
501 		return (EINVAL);
502 	}
503 
504 	return (0);
505 }
506 
507 
508 int
509 pf_nvrule_to_krule(const nvlist_t *nvl, struct pf_krule *rule)
510 {
511 	int error = 0;
512 
513 #define	ERROUT(x)	ERROUT_FUNCTION(errout, x)
514 
515 	PFNV_CHK(pf_nvuint32(nvl, "nr", &rule->nr));
516 
517 	if (! nvlist_exists_nvlist(nvl, "src"))
518 		ERROUT(EINVAL);
519 
520 	error = pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "src"),
521 	    &rule->src);
522 	if (error != 0)
523 		ERROUT(error);
524 
525 	if (! nvlist_exists_nvlist(nvl, "dst"))
526 		ERROUT(EINVAL);
527 
528 	PFNV_CHK(pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "dst"),
529 	    &rule->dst));
530 
531 	if (nvlist_exists_string(nvl, "label")) {
532 		PFNV_CHK(pf_nvstring(nvl, "label", rule->label[0],
533 		    sizeof(rule->label[0])));
534 	} else if (nvlist_exists_string_array(nvl, "labels")) {
535 		const char *const *strs;
536 		size_t items;
537 		int ret;
538 
539 		strs = nvlist_get_string_array(nvl, "labels", &items);
540 		if (items > PF_RULE_MAX_LABEL_COUNT)
541 			ERROUT(E2BIG);
542 
543 		for (size_t i = 0; i < items; i++) {
544 			ret = strlcpy(rule->label[i], strs[i],
545 			    sizeof(rule->label[0]));
546 			if (ret >= sizeof(rule->label[0]))
547 				ERROUT(E2BIG);
548 		}
549 	}
550 
551 	PFNV_CHK(pf_nvuint32_opt(nvl, "ridentifier", &rule->ridentifier, 0));
552 	PFNV_CHK(pf_nvstring(nvl, "ifname", rule->ifname,
553 	    sizeof(rule->ifname)));
554 	PFNV_CHK(pf_nvstring(nvl, "qname", rule->qname, sizeof(rule->qname)));
555 	PFNV_CHK(pf_nvstring(nvl, "pqname", rule->pqname,
556 	    sizeof(rule->pqname)));
557 	PFNV_CHK(pf_nvstring(nvl, "tagname", rule->tagname,
558 	    sizeof(rule->tagname)));
559 	PFNV_CHK(pf_nvuint16_opt(nvl, "dnpipe", &rule->dnpipe, 0));
560 	PFNV_CHK(pf_nvuint16_opt(nvl, "dnrpipe", &rule->dnrpipe, 0));
561 	PFNV_CHK(pf_nvuint32_opt(nvl, "dnflags", &rule->free_flags, 0));
562 	PFNV_CHK(pf_nvstring(nvl, "match_tagname", rule->match_tagname,
563 	    sizeof(rule->match_tagname)));
564 	PFNV_CHK(pf_nvstring(nvl, "overload_tblname", rule->overload_tblname,
565 	    sizeof(rule->overload_tblname)));
566 
567 	if (! nvlist_exists_nvlist(nvl, "rpool"))
568 		ERROUT(EINVAL);
569 	PFNV_CHK(pf_nvpool_to_pool(nvlist_get_nvlist(nvl, "rpool"),
570 	    &rule->rpool));
571 
572 	PFNV_CHK(pf_nvuint32(nvl, "os_fingerprint", &rule->os_fingerprint));
573 
574 	PFNV_CHK(pf_nvint(nvl, "rtableid", &rule->rtableid));
575 	PFNV_CHK(pf_nvuint32_array(nvl, "timeout", rule->timeout, PFTM_MAX, NULL));
576 	PFNV_CHK(pf_nvuint32(nvl, "max_states", &rule->max_states));
577 	PFNV_CHK(pf_nvuint32(nvl, "max_src_nodes", &rule->max_src_nodes));
578 	PFNV_CHK(pf_nvuint32(nvl, "max_src_states", &rule->max_src_states));
579 	PFNV_CHK(pf_nvuint32(nvl, "max_src_conn", &rule->max_src_conn));
580 	PFNV_CHK(pf_nvuint32(nvl, "max_src_conn_rate.limit",
581 	    &rule->max_src_conn_rate.limit));
582 	PFNV_CHK(pf_nvuint32(nvl, "max_src_conn_rate.seconds",
583 	    &rule->max_src_conn_rate.seconds));
584 	PFNV_CHK(pf_nvuint32(nvl, "prob", &rule->prob));
585 	PFNV_CHK(pf_nvuint32(nvl, "cuid", &rule->cuid));
586 	PFNV_CHK(pf_nvuint32(nvl, "cpid", &rule->cpid));
587 
588 	PFNV_CHK(pf_nvuint16(nvl, "return_icmp", &rule->return_icmp));
589 	PFNV_CHK(pf_nvuint16(nvl, "return_icmp6", &rule->return_icmp6));
590 
591 	PFNV_CHK(pf_nvuint16(nvl, "max_mss", &rule->max_mss));
592 	PFNV_CHK(pf_nvuint16(nvl, "scrub_flags", &rule->scrub_flags));
593 
594 	if (! nvlist_exists_nvlist(nvl, "uid"))
595 		ERROUT(EINVAL);
596 	PFNV_CHK(pf_nvrule_uid_to_rule_uid(nvlist_get_nvlist(nvl, "uid"),
597 	    &rule->uid));
598 
599 	if (! nvlist_exists_nvlist(nvl, "gid"))
600 		ERROUT(EINVAL);
601 	PFNV_CHK(pf_nvrule_gid_to_rule_gid(nvlist_get_nvlist(nvl, "gid"),
602 	    &rule->gid));
603 
604 	PFNV_CHK(pf_nvuint32(nvl, "rule_flag", &rule->rule_flag));
605 	PFNV_CHK(pf_nvuint8(nvl, "action", &rule->action));
606 	PFNV_CHK(pf_nvuint8(nvl, "direction", &rule->direction));
607 	PFNV_CHK(pf_nvuint8(nvl, "log", &rule->log));
608 	PFNV_CHK(pf_nvuint8(nvl, "logif", &rule->logif));
609 	PFNV_CHK(pf_nvuint8(nvl, "quick", &rule->quick));
610 	PFNV_CHK(pf_nvuint8(nvl, "ifnot", &rule->ifnot));
611 	PFNV_CHK(pf_nvuint8(nvl, "match_tag_not", &rule->match_tag_not));
612 	PFNV_CHK(pf_nvuint8(nvl, "natpass", &rule->natpass));
613 
614 	PFNV_CHK(pf_nvuint8(nvl, "keep_state", &rule->keep_state));
615 	PFNV_CHK(pf_nvuint8(nvl, "af", &rule->af));
616 	PFNV_CHK(pf_nvuint8(nvl, "proto", &rule->proto));
617 	PFNV_CHK(pf_nvuint8(nvl, "type", &rule->type));
618 	PFNV_CHK(pf_nvuint8(nvl, "code", &rule->code));
619 	PFNV_CHK(pf_nvuint8(nvl, "flags", &rule->flags));
620 	PFNV_CHK(pf_nvuint8(nvl, "flagset", &rule->flagset));
621 	PFNV_CHK(pf_nvuint8(nvl, "min_ttl", &rule->min_ttl));
622 	PFNV_CHK(pf_nvuint8(nvl, "allow_opts", &rule->allow_opts));
623 	PFNV_CHK(pf_nvuint8(nvl, "rt", &rule->rt));
624 	PFNV_CHK(pf_nvuint8(nvl, "return_ttl", &rule->return_ttl));
625 	PFNV_CHK(pf_nvuint8(nvl, "tos", &rule->tos));
626 	PFNV_CHK(pf_nvuint8(nvl, "set_tos", &rule->set_tos));
627 
628 	PFNV_CHK(pf_nvuint8(nvl, "flush", &rule->flush));
629 	PFNV_CHK(pf_nvuint8(nvl, "prio", &rule->prio));
630 
631 	PFNV_CHK(pf_nvuint8_array(nvl, "set_prio", &rule->prio, 2, NULL));
632 
633 	if (nvlist_exists_nvlist(nvl, "divert")) {
634 		const nvlist_t *nvldivert = nvlist_get_nvlist(nvl, "divert");
635 
636 		if (! nvlist_exists_nvlist(nvldivert, "addr"))
637 			ERROUT(EINVAL);
638 		PFNV_CHK(pf_nvaddr_to_addr(nvlist_get_nvlist(nvldivert, "addr"),
639 		    &rule->divert.addr));
640 		PFNV_CHK(pf_nvuint16(nvldivert, "port", &rule->divert.port));
641 	}
642 
643 	/* Validation */
644 #ifndef INET
645 	if (rule->af == AF_INET)
646 		ERROUT(EAFNOSUPPORT);
647 #endif /* INET */
648 #ifndef INET6
649 	if (rule->af == AF_INET6)
650 		ERROUT(EAFNOSUPPORT);
651 #endif /* INET6 */
652 
653 	PFNV_CHK(pf_check_rule_addr(&rule->src));
654 	PFNV_CHK(pf_check_rule_addr(&rule->dst));
655 
656 	return (0);
657 
658 #undef ERROUT
659 errout:
660 	return (error);
661 }
662 
663 static nvlist_t *
664 pf_divert_to_nvdivert(const struct pf_krule *rule)
665 {
666 	nvlist_t *nvl;
667 	nvlist_t *tmp;
668 
669 	nvl = nvlist_create(0);
670 	if (nvl == NULL)
671 		return (NULL);
672 
673 	tmp = pf_addr_to_nvaddr(&rule->divert.addr);
674 	if (tmp == NULL)
675 		goto error;
676 	nvlist_add_nvlist(nvl, "addr", tmp);
677 	nvlist_destroy(tmp);
678 	nvlist_add_number(nvl, "port", rule->divert.port);
679 
680 	return (nvl);
681 
682 error:
683 	nvlist_destroy(nvl);
684 	return (NULL);
685 }
686 
687 nvlist_t *
688 pf_krule_to_nvrule(struct pf_krule *rule)
689 {
690 	nvlist_t *nvl, *tmp;
691 
692 	nvl = nvlist_create(0);
693 	if (nvl == NULL)
694 		return (nvl);
695 
696 	nvlist_add_number(nvl, "nr", rule->nr);
697 	tmp = pf_rule_addr_to_nvrule_addr(&rule->src);
698 	if (tmp == NULL)
699 		goto error;
700 	nvlist_add_nvlist(nvl, "src", tmp);
701 	nvlist_destroy(tmp);
702 	tmp = pf_rule_addr_to_nvrule_addr(&rule->dst);
703 	if (tmp == NULL)
704 		goto error;
705 	nvlist_add_nvlist(nvl, "dst", tmp);
706 	nvlist_destroy(tmp);
707 
708 	for (int i = 0; i < PF_SKIP_COUNT; i++) {
709 		nvlist_append_number_array(nvl, "skip",
710 		    rule->skip[i].ptr ? rule->skip[i].ptr->nr : -1);
711 	}
712 
713 	for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) {
714 		nvlist_append_string_array(nvl, "labels", rule->label[i]);
715 	}
716 	nvlist_add_string(nvl, "label", rule->label[0]);
717 	nvlist_add_number(nvl, "ridentifier", rule->ridentifier);
718 	nvlist_add_string(nvl, "ifname", rule->ifname);
719 	nvlist_add_string(nvl, "qname", rule->qname);
720 	nvlist_add_string(nvl, "pqname", rule->pqname);
721 	nvlist_add_number(nvl, "dnpipe", rule->dnpipe);
722 	nvlist_add_number(nvl, "dnrpipe", rule->dnrpipe);
723 	nvlist_add_number(nvl, "dnflags", rule->free_flags);
724 	nvlist_add_string(nvl, "tagname", rule->tagname);
725 	nvlist_add_string(nvl, "match_tagname", rule->match_tagname);
726 	nvlist_add_string(nvl, "overload_tblname", rule->overload_tblname);
727 
728 	tmp = pf_pool_to_nvpool(&rule->rpool);
729 	if (tmp == NULL)
730 		goto error;
731 	nvlist_add_nvlist(nvl, "rpool", tmp);
732 	nvlist_destroy(tmp);
733 
734 	nvlist_add_number(nvl, "evaluations",
735 	    pf_counter_u64_fetch(&rule->evaluations));
736 	for (int i = 0; i < 2; i++) {
737 		nvlist_append_number_array(nvl, "packets",
738 		    pf_counter_u64_fetch(&rule->packets[i]));
739 		nvlist_append_number_array(nvl, "bytes",
740 		    pf_counter_u64_fetch(&rule->bytes[i]));
741 	}
742 
743 	nvlist_add_number(nvl, "os_fingerprint", rule->os_fingerprint);
744 
745 	nvlist_add_number(nvl, "rtableid", rule->rtableid);
746 	pf_uint32_array_nv(nvl, "timeout", rule->timeout, PFTM_MAX);
747 	nvlist_add_number(nvl, "max_states", rule->max_states);
748 	nvlist_add_number(nvl, "max_src_nodes", rule->max_src_nodes);
749 	nvlist_add_number(nvl, "max_src_states", rule->max_src_states);
750 	nvlist_add_number(nvl, "max_src_conn", rule->max_src_conn);
751 	nvlist_add_number(nvl, "max_src_conn_rate.limit",
752 	    rule->max_src_conn_rate.limit);
753 	nvlist_add_number(nvl, "max_src_conn_rate.seconds",
754 	    rule->max_src_conn_rate.seconds);
755 	nvlist_add_number(nvl, "qid", rule->qid);
756 	nvlist_add_number(nvl, "pqid", rule->pqid);
757 	nvlist_add_number(nvl, "prob", rule->prob);
758 	nvlist_add_number(nvl, "cuid", rule->cuid);
759 	nvlist_add_number(nvl, "cpid", rule->cpid);
760 
761 	nvlist_add_number(nvl, "states_cur",
762 	    counter_u64_fetch(rule->states_cur));
763 	nvlist_add_number(nvl, "states_tot",
764 	    counter_u64_fetch(rule->states_tot));
765 	nvlist_add_number(nvl, "src_nodes",
766 	    counter_u64_fetch(rule->src_nodes));
767 
768 	nvlist_add_number(nvl, "return_icmp", rule->return_icmp);
769 	nvlist_add_number(nvl, "return_icmp6", rule->return_icmp6);
770 
771 	nvlist_add_number(nvl, "max_mss", rule->max_mss);
772 	nvlist_add_number(nvl, "scrub_flags", rule->scrub_flags);
773 
774 	tmp = pf_rule_uid_to_nvrule_uid(&rule->uid);
775 	if (tmp == NULL)
776 		goto error;
777 	nvlist_add_nvlist(nvl, "uid", tmp);
778 	nvlist_destroy(tmp);
779 	tmp = pf_rule_uid_to_nvrule_uid((const struct pf_rule_uid *)&rule->gid);
780 	if (tmp == NULL)
781 		goto error;
782 	nvlist_add_nvlist(nvl, "gid", tmp);
783 	nvlist_destroy(tmp);
784 
785 	nvlist_add_number(nvl, "rule_flag", rule->rule_flag);
786 	nvlist_add_number(nvl, "action", rule->action);
787 	nvlist_add_number(nvl, "direction", rule->direction);
788 	nvlist_add_number(nvl, "log", rule->log);
789 	nvlist_add_number(nvl, "logif", rule->logif);
790 	nvlist_add_number(nvl, "quick", rule->quick);
791 	nvlist_add_number(nvl, "ifnot", rule->ifnot);
792 	nvlist_add_number(nvl, "match_tag_not", rule->match_tag_not);
793 	nvlist_add_number(nvl, "natpass", rule->natpass);
794 
795 	nvlist_add_number(nvl, "keep_state", rule->keep_state);
796 	nvlist_add_number(nvl, "af", rule->af);
797 	nvlist_add_number(nvl, "proto", rule->proto);
798 	nvlist_add_number(nvl, "type", rule->type);
799 	nvlist_add_number(nvl, "code", rule->code);
800 	nvlist_add_number(nvl, "flags", rule->flags);
801 	nvlist_add_number(nvl, "flagset", rule->flagset);
802 	nvlist_add_number(nvl, "min_ttl", rule->min_ttl);
803 	nvlist_add_number(nvl, "allow_opts", rule->allow_opts);
804 	nvlist_add_number(nvl, "rt", rule->rt);
805 	nvlist_add_number(nvl, "return_ttl", rule->return_ttl);
806 	nvlist_add_number(nvl, "tos", rule->tos);
807 	nvlist_add_number(nvl, "set_tos", rule->set_tos);
808 	nvlist_add_number(nvl, "anchor_relative", rule->anchor_relative);
809 	nvlist_add_number(nvl, "anchor_wildcard", rule->anchor_wildcard);
810 
811 	nvlist_add_number(nvl, "flush", rule->flush);
812 	nvlist_add_number(nvl, "prio", rule->prio);
813 
814 	pf_uint8_array_nv(nvl, "set_prio", &rule->prio, 2);
815 
816 	tmp = pf_divert_to_nvdivert(rule);
817 	if (tmp == NULL)
818 		goto error;
819 	nvlist_add_nvlist(nvl, "divert", tmp);
820 	nvlist_destroy(tmp);
821 
822 	return (nvl);
823 
824 error:
825 	nvlist_destroy(nvl);
826 	return (NULL);
827 }
828 
829 static int
830 pf_nvstate_cmp_to_state_cmp(const nvlist_t *nvl, struct pf_state_cmp *cmp)
831 {
832 	int error = 0;
833 
834 	bzero(cmp, sizeof(*cmp));
835 
836 	PFNV_CHK(pf_nvuint64(nvl, "id", &cmp->id));
837 	PFNV_CHK(pf_nvuint32(nvl, "creatorid", &cmp->creatorid));
838 	PFNV_CHK(pf_nvuint8(nvl, "direction", &cmp->direction));
839 
840 errout:
841 	return (error);
842 }
843 
844 int
845 pf_nvstate_kill_to_kstate_kill(const nvlist_t *nvl,
846     struct pf_kstate_kill *kill)
847 {
848 	int error = 0;
849 
850 	bzero(kill, sizeof(*kill));
851 
852 	if (! nvlist_exists_nvlist(nvl, "cmp"))
853 		return (EINVAL);
854 
855 	PFNV_CHK(pf_nvstate_cmp_to_state_cmp(nvlist_get_nvlist(nvl, "cmp"),
856 	    &kill->psk_pfcmp));
857 	PFNV_CHK(pf_nvuint8(nvl, "af", &kill->psk_af));
858 	PFNV_CHK(pf_nvint(nvl, "proto", &kill->psk_proto));
859 
860 	if (! nvlist_exists_nvlist(nvl, "src"))
861 		return (EINVAL);
862 	PFNV_CHK(pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "src"),
863 	    &kill->psk_src));
864 	if (! nvlist_exists_nvlist(nvl, "dst"))
865 		return (EINVAL);
866 	PFNV_CHK(pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "dst"),
867 	    &kill->psk_dst));
868 	if (nvlist_exists_nvlist(nvl, "rt_addr")) {
869 		PFNV_CHK(pf_nvrule_addr_to_rule_addr(
870 		    nvlist_get_nvlist(nvl, "rt_addr"), &kill->psk_rt_addr));
871 	}
872 
873 	PFNV_CHK(pf_nvstring(nvl, "ifname", kill->psk_ifname,
874 	    sizeof(kill->psk_ifname)));
875 	PFNV_CHK(pf_nvstring(nvl, "label", kill->psk_label,
876 	    sizeof(kill->psk_label)));
877 	PFNV_CHK(pf_nvbool(nvl, "kill_match", &kill->psk_kill_match));
878 
879 errout:
880 	return (error);
881 }
882 
883 static nvlist_t *
884 pf_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 
905 errout:
906 	nvlist_destroy(nvl);
907 	return (NULL);
908 }
909 
910 static nvlist_t *
911 pf_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 
928 nvlist_t *
929 pf_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);
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 
1004 errout:
1005 	nvlist_destroy(nvl);
1006 	return (NULL);
1007 }
1008