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