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
102int
103pf_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
123PF_NV_IMPL_UINT(uint8, uint8_t, UINT8_MAX);
124PF_NV_IMPL_UINT(uint16, uint16_t, UINT16_MAX);
125PF_NV_IMPL_UINT(uint32, uint32_t, UINT32_MAX);
126PF_NV_IMPL_UINT(uint64, uint64_t, UINT64_MAX);
127
128int
129pf_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
145int
146pf_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
160static int
161pf_nvaddr_to_addr(const nvlist_t *nvl, struct pf_addr *paddr)
162{
163	return (pf_nvbinary(nvl, "addr", paddr, sizeof(*paddr)));
164}
165
166static nvlist_t *
167pf_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
180static int
181pf_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
190errout:
191	return (error);
192}
193
194static nvlist_t *
195pf_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
210static int
211pf_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
234errout:
235	return (error);
236}
237
238static nvlist_t *
239pf_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
267error:
268	nvlist_destroy(nvl);
269	return (NULL);
270}
271
272static int
273pf_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
310errout:
311	return (error);
312}
313
314static nvlist_t *
315pf_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
344error:
345	nvlist_destroy(nvl);
346	return (NULL);
347}
348
349static int
350pf_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
371static int
372pf_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
387errout:
388	return (error);
389}
390
391static nvlist_t *
392pf_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
412error:
413	nvlist_destroy(nvl);
414	return (NULL);
415}
416
417static int
418pf_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
429errout:
430	return (error);
431}
432
433static nvlist_t *
434pf_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
448static int
449pf_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
456int
457pf_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
480int
481pf_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_nvstring(nvl, "match_tagname", rule->match_tagname,
531	    sizeof(rule->match_tagname)));
532	PFNV_CHK(pf_nvstring(nvl, "overload_tblname", rule->overload_tblname,
533	    sizeof(rule->overload_tblname)));
534
535	if (! nvlist_exists_nvlist(nvl, "rpool"))
536		ERROUT(EINVAL);
537	PFNV_CHK(pf_nvpool_to_pool(nvlist_get_nvlist(nvl, "rpool"),
538	    &rule->rpool));
539
540	PFNV_CHK(pf_nvuint32(nvl, "os_fingerprint", &rule->os_fingerprint));
541
542	PFNV_CHK(pf_nvint(nvl, "rtableid", &rule->rtableid));
543	PFNV_CHK(pf_nvuint32_array(nvl, "timeout", rule->timeout, PFTM_MAX, NULL));
544	PFNV_CHK(pf_nvuint32(nvl, "max_states", &rule->max_states));
545	PFNV_CHK(pf_nvuint32(nvl, "max_src_nodes", &rule->max_src_nodes));
546	PFNV_CHK(pf_nvuint32(nvl, "max_src_states", &rule->max_src_states));
547	PFNV_CHK(pf_nvuint32(nvl, "max_src_conn", &rule->max_src_conn));
548	PFNV_CHK(pf_nvuint32(nvl, "max_src_conn_rate.limit",
549	    &rule->max_src_conn_rate.limit));
550	PFNV_CHK(pf_nvuint32(nvl, "max_src_conn_rate.seconds",
551	    &rule->max_src_conn_rate.seconds));
552	PFNV_CHK(pf_nvuint32(nvl, "prob", &rule->prob));
553	PFNV_CHK(pf_nvuint32(nvl, "cuid", &rule->cuid));
554	PFNV_CHK(pf_nvuint32(nvl, "cpid", &rule->cpid));
555
556	PFNV_CHK(pf_nvuint16(nvl, "return_icmp", &rule->return_icmp));
557	PFNV_CHK(pf_nvuint16(nvl, "return_icmp6", &rule->return_icmp6));
558
559	PFNV_CHK(pf_nvuint16(nvl, "max_mss", &rule->max_mss));
560	PFNV_CHK(pf_nvuint16(nvl, "scrub_flags", &rule->scrub_flags));
561
562	if (! nvlist_exists_nvlist(nvl, "uid"))
563		ERROUT(EINVAL);
564	PFNV_CHK(pf_nvrule_uid_to_rule_uid(nvlist_get_nvlist(nvl, "uid"),
565	    &rule->uid));
566
567	if (! nvlist_exists_nvlist(nvl, "gid"))
568		ERROUT(EINVAL);
569	PFNV_CHK(pf_nvrule_gid_to_rule_gid(nvlist_get_nvlist(nvl, "gid"),
570	    &rule->gid));
571
572	PFNV_CHK(pf_nvuint32(nvl, "rule_flag", &rule->rule_flag));
573	PFNV_CHK(pf_nvuint8(nvl, "action", &rule->action));
574	PFNV_CHK(pf_nvuint8(nvl, "direction", &rule->direction));
575	PFNV_CHK(pf_nvuint8(nvl, "log", &rule->log));
576	PFNV_CHK(pf_nvuint8(nvl, "logif", &rule->logif));
577	PFNV_CHK(pf_nvuint8(nvl, "quick", &rule->quick));
578	PFNV_CHK(pf_nvuint8(nvl, "ifnot", &rule->ifnot));
579	PFNV_CHK(pf_nvuint8(nvl, "match_tag_not", &rule->match_tag_not));
580	PFNV_CHK(pf_nvuint8(nvl, "natpass", &rule->natpass));
581
582	PFNV_CHK(pf_nvuint8(nvl, "keep_state", &rule->keep_state));
583	PFNV_CHK(pf_nvuint8(nvl, "af", &rule->af));
584	PFNV_CHK(pf_nvuint8(nvl, "proto", &rule->proto));
585	PFNV_CHK(pf_nvuint8(nvl, "type", &rule->type));
586	PFNV_CHK(pf_nvuint8(nvl, "code", &rule->code));
587	PFNV_CHK(pf_nvuint8(nvl, "flags", &rule->flags));
588	PFNV_CHK(pf_nvuint8(nvl, "flagset", &rule->flagset));
589	PFNV_CHK(pf_nvuint8(nvl, "min_ttl", &rule->min_ttl));
590	PFNV_CHK(pf_nvuint8(nvl, "allow_opts", &rule->allow_opts));
591	PFNV_CHK(pf_nvuint8(nvl, "rt", &rule->rt));
592	PFNV_CHK(pf_nvuint8(nvl, "return_ttl", &rule->return_ttl));
593	PFNV_CHK(pf_nvuint8(nvl, "tos", &rule->tos));
594	PFNV_CHK(pf_nvuint8(nvl, "set_tos", &rule->set_tos));
595	PFNV_CHK(pf_nvuint8(nvl, "anchor_relative", &rule->anchor_relative));
596	PFNV_CHK(pf_nvuint8(nvl, "anchor_wildcard", &rule->anchor_wildcard));
597
598	PFNV_CHK(pf_nvuint8(nvl, "flush", &rule->flush));
599	PFNV_CHK(pf_nvuint8(nvl, "prio", &rule->prio));
600
601	PFNV_CHK(pf_nvuint8_array(nvl, "set_prio", &rule->prio, 2, NULL));
602
603	if (nvlist_exists_nvlist(nvl, "divert")) {
604		const nvlist_t *nvldivert = nvlist_get_nvlist(nvl, "divert");
605
606		if (! nvlist_exists_nvlist(nvldivert, "addr"))
607			ERROUT(EINVAL);
608		PFNV_CHK(pf_nvaddr_to_addr(nvlist_get_nvlist(nvldivert, "addr"),
609		    &rule->divert.addr));
610		PFNV_CHK(pf_nvuint16(nvldivert, "port", &rule->divert.port));
611	}
612
613	/* Validation */
614#ifndef INET
615	if (rule->af == AF_INET)
616		ERROUT(EAFNOSUPPORT);
617#endif /* INET */
618#ifndef INET6
619	if (rule->af == AF_INET6)
620		ERROUT(EAFNOSUPPORT);
621#endif /* INET6 */
622
623	PFNV_CHK(pf_check_rule_addr(&rule->src));
624	PFNV_CHK(pf_check_rule_addr(&rule->dst));
625
626	return (0);
627
628#undef ERROUT
629errout:
630	return (error);
631}
632
633static nvlist_t *
634pf_divert_to_nvdivert(const struct pf_krule *rule)
635{
636	nvlist_t *nvl;
637	nvlist_t *tmp;
638
639	nvl = nvlist_create(0);
640	if (nvl == NULL)
641		return (NULL);
642
643	tmp = pf_addr_to_nvaddr(&rule->divert.addr);
644	if (tmp == NULL)
645		goto error;
646	nvlist_add_nvlist(nvl, "addr", tmp);
647	nvlist_destroy(tmp);
648	nvlist_add_number(nvl, "port", rule->divert.port);
649
650	return (nvl);
651
652error:
653	nvlist_destroy(nvl);
654	return (NULL);
655}
656
657nvlist_t *
658pf_krule_to_nvrule(const struct pf_krule *rule)
659{
660	nvlist_t *nvl, *tmp;
661
662	nvl = nvlist_create(0);
663	if (nvl == NULL)
664		return (nvl);
665
666	nvlist_add_number(nvl, "nr", rule->nr);
667	tmp = pf_rule_addr_to_nvrule_addr(&rule->src);
668	if (tmp == NULL)
669		goto error;
670	nvlist_add_nvlist(nvl, "src", tmp);
671	nvlist_destroy(tmp);
672	tmp = pf_rule_addr_to_nvrule_addr(&rule->dst);
673	if (tmp == NULL)
674		goto error;
675	nvlist_add_nvlist(nvl, "dst", tmp);
676	nvlist_destroy(tmp);
677
678	for (int i = 0; i < PF_SKIP_COUNT; i++) {
679		nvlist_append_number_array(nvl, "skip",
680		    rule->skip[i].ptr ? rule->skip[i].ptr->nr : -1);
681	}
682
683	for (int i = 0; i < PF_RULE_MAX_LABEL_COUNT; i++) {
684		nvlist_append_string_array(nvl, "labels", rule->label[i]);
685	}
686	nvlist_add_string(nvl, "label", rule->label[0]);
687	nvlist_add_string(nvl, "ifname", rule->ifname);
688	nvlist_add_string(nvl, "qname", rule->qname);
689	nvlist_add_string(nvl, "pqname", rule->pqname);
690	nvlist_add_string(nvl, "tagname", rule->tagname);
691	nvlist_add_string(nvl, "match_tagname", rule->match_tagname);
692	nvlist_add_string(nvl, "overload_tblname", rule->overload_tblname);
693
694	tmp = pf_pool_to_nvpool(&rule->rpool);
695	if (tmp == NULL)
696		goto error;
697	nvlist_add_nvlist(nvl, "rpool", tmp);
698	nvlist_destroy(tmp);
699
700	nvlist_add_number(nvl, "evaluations",
701	    counter_u64_fetch(rule->evaluations));
702	for (int i = 0; i < 2; i++) {
703		nvlist_append_number_array(nvl, "packets",
704		    counter_u64_fetch(rule->packets[i]));
705		nvlist_append_number_array(nvl, "bytes",
706		    counter_u64_fetch(rule->bytes[i]));
707	}
708
709	nvlist_add_number(nvl, "os_fingerprint", rule->os_fingerprint);
710
711	nvlist_add_number(nvl, "rtableid", rule->rtableid);
712	pf_uint32_array_nv(nvl, "timeout", rule->timeout, PFTM_MAX);
713	nvlist_add_number(nvl, "max_states", rule->max_states);
714	nvlist_add_number(nvl, "max_src_nodes", rule->max_src_nodes);
715	nvlist_add_number(nvl, "max_src_states", rule->max_src_states);
716	nvlist_add_number(nvl, "max_src_conn", rule->max_src_conn);
717	nvlist_add_number(nvl, "max_src_conn_rate.limit",
718	    rule->max_src_conn_rate.limit);
719	nvlist_add_number(nvl, "max_src_conn_rate.seconds",
720	    rule->max_src_conn_rate.seconds);
721	nvlist_add_number(nvl, "qid", rule->qid);
722	nvlist_add_number(nvl, "pqid", rule->pqid);
723	nvlist_add_number(nvl, "prob", rule->prob);
724	nvlist_add_number(nvl, "cuid", rule->cuid);
725	nvlist_add_number(nvl, "cpid", rule->cpid);
726
727	nvlist_add_number(nvl, "states_cur",
728	    counter_u64_fetch(rule->states_cur));
729	nvlist_add_number(nvl, "states_tot",
730	    counter_u64_fetch(rule->states_tot));
731	nvlist_add_number(nvl, "src_nodes",
732	    counter_u64_fetch(rule->src_nodes));
733
734	nvlist_add_number(nvl, "return_icmp", rule->return_icmp);
735	nvlist_add_number(nvl, "return_icmp6", rule->return_icmp6);
736
737	nvlist_add_number(nvl, "max_mss", rule->max_mss);
738	nvlist_add_number(nvl, "scrub_flags", rule->scrub_flags);
739
740	tmp = pf_rule_uid_to_nvrule_uid(&rule->uid);
741	if (tmp == NULL)
742		goto error;
743	nvlist_add_nvlist(nvl, "uid", tmp);
744	nvlist_destroy(tmp);
745	tmp = pf_rule_uid_to_nvrule_uid((const struct pf_rule_uid *)&rule->gid);
746	if (tmp == NULL)
747		goto error;
748	nvlist_add_nvlist(nvl, "gid", tmp);
749	nvlist_destroy(tmp);
750
751	nvlist_add_number(nvl, "rule_flag", rule->rule_flag);
752	nvlist_add_number(nvl, "action", rule->action);
753	nvlist_add_number(nvl, "direction", rule->direction);
754	nvlist_add_number(nvl, "log", rule->log);
755	nvlist_add_number(nvl, "logif", rule->logif);
756	nvlist_add_number(nvl, "quick", rule->quick);
757	nvlist_add_number(nvl, "ifnot", rule->ifnot);
758	nvlist_add_number(nvl, "match_tag_not", rule->match_tag_not);
759	nvlist_add_number(nvl, "natpass", rule->natpass);
760
761	nvlist_add_number(nvl, "keep_state", rule->keep_state);
762	nvlist_add_number(nvl, "af", rule->af);
763	nvlist_add_number(nvl, "proto", rule->proto);
764	nvlist_add_number(nvl, "type", rule->type);
765	nvlist_add_number(nvl, "code", rule->code);
766	nvlist_add_number(nvl, "flags", rule->flags);
767	nvlist_add_number(nvl, "flagset", rule->flagset);
768	nvlist_add_number(nvl, "min_ttl", rule->min_ttl);
769	nvlist_add_number(nvl, "allow_opts", rule->allow_opts);
770	nvlist_add_number(nvl, "rt", rule->rt);
771	nvlist_add_number(nvl, "return_ttl", rule->return_ttl);
772	nvlist_add_number(nvl, "tos", rule->tos);
773	nvlist_add_number(nvl, "set_tos", rule->set_tos);
774	nvlist_add_number(nvl, "anchor_relative", rule->anchor_relative);
775	nvlist_add_number(nvl, "anchor_wildcard", rule->anchor_wildcard);
776
777	nvlist_add_number(nvl, "flush", rule->flush);
778	nvlist_add_number(nvl, "prio", rule->prio);
779
780	pf_uint8_array_nv(nvl, "set_prio", &rule->prio, 2);
781
782	tmp = pf_divert_to_nvdivert(rule);
783	if (tmp == NULL)
784		goto error;
785	nvlist_add_nvlist(nvl, "divert", tmp);
786	nvlist_destroy(tmp);
787
788	return (nvl);
789
790error:
791	nvlist_destroy(nvl);
792	return (NULL);
793}
794
795static int
796pf_nvstate_cmp_to_state_cmp(const nvlist_t *nvl, struct pf_state_cmp *cmp)
797{
798	int error = 0;
799
800	bzero(cmp, sizeof(*cmp));
801
802	PFNV_CHK(pf_nvuint64(nvl, "id", &cmp->id));
803	PFNV_CHK(pf_nvuint32(nvl, "creatorid", &cmp->creatorid));
804	PFNV_CHK(pf_nvuint8(nvl, "direction", &cmp->direction));
805
806errout:
807	return (error);
808}
809
810int
811pf_nvstate_kill_to_kstate_kill(const nvlist_t *nvl,
812    struct pf_kstate_kill *kill)
813{
814	int error = 0;
815
816	bzero(kill, sizeof(*kill));
817
818	if (! nvlist_exists_nvlist(nvl, "cmp"))
819		return (EINVAL);
820
821	PFNV_CHK(pf_nvstate_cmp_to_state_cmp(nvlist_get_nvlist(nvl, "cmp"),
822	    &kill->psk_pfcmp));
823	PFNV_CHK(pf_nvuint8(nvl, "af", &kill->psk_af));
824	PFNV_CHK(pf_nvint(nvl, "proto", &kill->psk_proto));
825
826	if (! nvlist_exists_nvlist(nvl, "src"))
827		return (EINVAL);
828	PFNV_CHK(pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "src"),
829	    &kill->psk_src));
830	if (! nvlist_exists_nvlist(nvl, "dst"))
831		return (EINVAL);
832	PFNV_CHK(pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "dst"),
833	    &kill->psk_dst));
834	if (nvlist_exists_nvlist(nvl, "rt_addr")) {
835		PFNV_CHK(pf_nvrule_addr_to_rule_addr(
836		    nvlist_get_nvlist(nvl, "rt_addr"), &kill->psk_rt_addr));
837	}
838
839	PFNV_CHK(pf_nvstring(nvl, "ifname", kill->psk_ifname,
840	    sizeof(kill->psk_ifname)));
841	PFNV_CHK(pf_nvstring(nvl, "label", kill->psk_label,
842	    sizeof(kill->psk_label)));
843	if (nvlist_exists_bool(nvl, "kill_match"))
844		kill->psk_kill_match = nvlist_get_bool(nvl, "kill_match");
845
846errout:
847	return (error);
848}
849
850static nvlist_t *
851pf_state_key_to_nvstate_key(const struct pf_state_key *key)
852{
853	nvlist_t	*nvl, *tmp;
854
855	nvl = nvlist_create(0);
856	if (nvl == NULL)
857		return (NULL);
858
859	for (int i = 0; i < 2; i++) {
860		tmp = pf_addr_to_nvaddr(&key->addr[i]);
861		if (tmp == NULL)
862			goto errout;
863		nvlist_append_nvlist_array(nvl, "addr", tmp);
864		nvlist_destroy(tmp);
865		nvlist_append_number_array(nvl, "port", key->port[i]);
866	}
867	nvlist_add_number(nvl, "af", key->af);
868	nvlist_add_number(nvl, "proto", key->proto);
869
870	return (nvl);
871
872errout:
873	nvlist_destroy(nvl);
874	return (NULL);
875}
876
877static nvlist_t *
878pf_state_scrub_to_nvstate_scrub(const struct pf_state_scrub *scrub)
879{
880	nvlist_t *nvl;
881
882	nvl = nvlist_create(0);
883	if (nvl == NULL)
884		return (NULL);
885
886	nvlist_add_bool(nvl, "timestamp", scrub->pfss_flags & PFSS_TIMESTAMP);
887	nvlist_add_number(nvl, "ttl", scrub->pfss_ttl);
888	nvlist_add_number(nvl, "ts_mod", scrub->pfss_ts_mod);
889
890	return (nvl);
891}
892
893static nvlist_t *
894pf_state_peer_to_nvstate_peer(const struct pf_state_peer *peer)
895{
896	nvlist_t *nvl, *tmp;
897
898	nvl = nvlist_create(0);
899	if (nvl == NULL)
900		return (NULL);
901
902	if (peer->scrub) {
903		tmp = pf_state_scrub_to_nvstate_scrub(peer->scrub);
904		if (tmp == NULL)
905			goto errout;
906		nvlist_add_nvlist(nvl, "scrub", tmp);
907		nvlist_destroy(tmp);
908	}
909
910	nvlist_add_number(nvl, "seqlo", peer->seqlo);
911	nvlist_add_number(nvl, "seqhi", peer->seqhi);
912	nvlist_add_number(nvl, "seqdiff", peer->seqdiff);
913	nvlist_add_number(nvl, "max_win", peer->max_win);
914	nvlist_add_number(nvl, "mss", peer->mss);
915	nvlist_add_number(nvl, "state", peer->state);
916	nvlist_add_number(nvl, "wscale", peer->wscale);
917
918	return (nvl);
919
920errout:
921	nvlist_destroy(nvl);
922	return (NULL);
923}
924
925nvlist_t *
926pf_state_to_nvstate(const struct pf_state *s)
927{
928	nvlist_t	*nvl, *tmp;
929	uint32_t	 expire, flags = 0;
930
931	nvl = nvlist_create(0);
932	if (nvl == NULL)
933		return (NULL);
934
935	nvlist_add_number(nvl, "id", s->id);
936	nvlist_add_string(nvl, "ifname", s->kif->pfik_name);
937	nvlist_add_string(nvl, "orig_ifname", s->orig_kif->pfik_name);
938
939	tmp = pf_state_key_to_nvstate_key(s->key[PF_SK_STACK]);
940	if (tmp == NULL)
941		goto errout;
942	nvlist_add_nvlist(nvl, "stack_key", tmp);
943	nvlist_destroy(tmp);
944
945	tmp = pf_state_key_to_nvstate_key(s->key[PF_SK_WIRE]);
946	if (tmp == NULL)
947		goto errout;
948	nvlist_add_nvlist(nvl, "wire_key", tmp);
949	nvlist_destroy(tmp);
950
951	tmp = pf_state_peer_to_nvstate_peer(&s->src);
952	if (tmp == NULL)
953		goto errout;
954	nvlist_add_nvlist(nvl, "src", tmp);
955	nvlist_destroy(tmp);
956
957	tmp = pf_state_peer_to_nvstate_peer(&s->dst);
958	if (tmp == NULL)
959		goto errout;
960	nvlist_add_nvlist(nvl, "dst", tmp);
961	nvlist_destroy(tmp);
962
963	tmp = pf_addr_to_nvaddr(&s->rt_addr);
964	if (tmp == NULL)
965		goto errout;
966	nvlist_add_nvlist(nvl, "rt_addr", tmp);
967	nvlist_destroy(tmp);
968
969	nvlist_add_number(nvl, "rule", s->rule.ptr ? s->rule.ptr->nr : -1);
970	nvlist_add_number(nvl, "anchor",
971	    s->anchor.ptr ? s->anchor.ptr->nr : -1);
972	nvlist_add_number(nvl, "nat_rule",
973	    s->nat_rule.ptr ? s->nat_rule.ptr->nr : -1);
974	nvlist_add_number(nvl, "creation", s->creation);
975
976	expire = pf_state_expires(s);
977	if (expire <= time_uptime)
978		expire = 0;
979	else
980		expire = expire - time_uptime;
981	nvlist_add_number(nvl, "expire", expire);
982
983	for (int i = 0; i < 2; i++) {
984		nvlist_append_number_array(nvl, "packets",
985		    counter_u64_fetch(s->packets[i]));
986		nvlist_append_number_array(nvl, "bytes",
987		    counter_u64_fetch(s->bytes[i]));
988	}
989
990	nvlist_add_number(nvl, "creatorid", s->creatorid);
991	nvlist_add_number(nvl, "direction", s->direction);
992	nvlist_add_number(nvl, "log", s->log);
993	nvlist_add_number(nvl, "state_flags", s->state_flags);
994	nvlist_add_number(nvl, "timeout", s->timeout);
995	if (s->src_node)
996		flags |= PFSYNC_FLAG_SRCNODE;
997	if (s->nat_src_node)
998		flags |= PFSYNC_FLAG_NATSRCNODE;
999	nvlist_add_number(nvl, "sync_flags", flags);
1000
1001	return (nvl);
1002
1003errout:
1004	nvlist_destroy(nvl);
1005	return (NULL);
1006}
1007