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