]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/netpfil/pf/pf_nv.c
pf: Convenience function for optional (numeric) arguments
[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_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
123 PF_NV_IMPL_UINT(uint8, uint8_t, UINT8_MAX);
124 PF_NV_IMPL_UINT(uint16, uint16_t, UINT16_MAX);
125 PF_NV_IMPL_UINT(uint32, uint32_t, UINT32_MAX);
126 PF_NV_IMPL_UINT(uint64, uint64_t, UINT64_MAX);
127
128 int
129 pf_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
145 int
146 pf_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
160 static int
161 pf_nvaddr_to_addr(const nvlist_t *nvl, struct pf_addr *paddr)
162 {
163         return (pf_nvbinary(nvl, "addr", paddr, sizeof(*paddr)));
164 }
165
166 static nvlist_t *
167 pf_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
180 static int
181 pf_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
190 errout:
191         return (error);
192 }
193
194 static nvlist_t *
195 pf_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
210 static int
211 pf_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
234 errout:
235         return (error);
236 }
237
238 static nvlist_t *
239 pf_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
267 error:
268         nvlist_destroy(nvl);
269         return (NULL);
270 }
271
272 static int
273 pf_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
310 errout:
311         return (error);
312 }
313
314 static nvlist_t *
315 pf_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
344 error:
345         nvlist_destroy(nvl);
346         return (NULL);
347 }
348
349 static int
350 pf_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
371 static int
372 pf_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
387 errout:
388         return (error);
389 }
390
391 static nvlist_t *
392 pf_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
412 error:
413         nvlist_destroy(nvl);
414         return (NULL);
415 }
416
417 static int
418 pf_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
429 errout:
430         return (error);
431 }
432
433 static nvlist_t *
434 pf_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
448 static int
449 pf_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
456 int
457 pf_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
480 int
481 pf_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
629 errout:
630         return (error);
631 }
632
633 static nvlist_t *
634 pf_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
652 error:
653         nvlist_destroy(nvl);
654         return (NULL);
655 }
656
657 nvlist_t *
658 pf_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
790 error:
791         nvlist_destroy(nvl);
792         return (NULL);
793 }
794
795 static int
796 pf_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
806 errout:
807         return (error);
808 }
809
810 int
811 pf_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
846 errout:
847         return (error);
848 }
849
850 static nvlist_t *
851 pf_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_append_number_array(nvl, "port", key->port[i]);
865         }
866         nvlist_add_number(nvl, "af", key->af);
867         nvlist_add_number(nvl, "proto", key->proto);
868
869         return (nvl);
870
871 errout:
872         nvlist_destroy(nvl);
873         return (NULL);
874 }
875
876 static nvlist_t *
877 pf_state_scrub_to_nvstate_scrub(const struct pf_state_scrub *scrub)
878 {
879         nvlist_t *nvl;
880
881         nvl = nvlist_create(0);
882         if (nvl == NULL)
883                 return (NULL);
884
885         nvlist_add_bool(nvl, "timestamp", scrub->pfss_flags & PFSS_TIMESTAMP);
886         nvlist_add_number(nvl, "ttl", scrub->pfss_ttl);
887         nvlist_add_number(nvl, "ts_mod", scrub->pfss_ts_mod);
888
889         return (nvl);
890 }
891
892 static nvlist_t *
893 pf_state_peer_to_nvstate_peer(const struct pf_state_peer *peer)
894 {
895         nvlist_t *nvl, *tmp;
896
897         nvl = nvlist_create(0);
898         if (nvl == NULL)
899                 return (NULL);
900
901         if (peer->scrub) {
902                 tmp = pf_state_scrub_to_nvstate_scrub(peer->scrub);
903                 if (tmp == NULL)
904                         goto errout;
905                 nvlist_add_nvlist(nvl, "scrub", tmp);
906                 nvlist_destroy(tmp);
907         }
908
909         nvlist_add_number(nvl, "seqlo", peer->seqlo);
910         nvlist_add_number(nvl, "seqhi", peer->seqhi);
911         nvlist_add_number(nvl, "seqdiff", peer->seqdiff);
912         nvlist_add_number(nvl, "max_win", peer->max_win);
913         nvlist_add_number(nvl, "mss", peer->mss);
914         nvlist_add_number(nvl, "state", peer->state);
915         nvlist_add_number(nvl, "wscale", peer->wscale);
916
917         return (nvl);
918
919 errout:
920         nvlist_destroy(nvl);
921         return (NULL);
922 }
923
924 nvlist_t *
925 pf_state_to_nvstate(const struct pf_state *s)
926 {
927         nvlist_t        *nvl, *tmp;
928         uint32_t         expire, flags = 0;
929
930         nvl = nvlist_create(0);
931         if (nvl == NULL)
932                 return (NULL);
933
934         nvlist_add_number(nvl, "id", s->id);
935         nvlist_add_string(nvl, "ifname", s->kif->pfik_name);
936         nvlist_add_string(nvl, "orig_ifname", s->orig_kif->pfik_name);
937
938         tmp = pf_state_key_to_nvstate_key(s->key[PF_SK_STACK]);
939         if (tmp == NULL)
940                 goto errout;
941         nvlist_add_nvlist(nvl, "stack_key", tmp);
942         nvlist_destroy(tmp);
943
944         tmp = pf_state_key_to_nvstate_key(s->key[PF_SK_WIRE]);
945         if (tmp == NULL)
946                 goto errout;
947         nvlist_add_nvlist(nvl, "wire_key", tmp);
948         nvlist_destroy(tmp);
949
950         tmp = pf_state_peer_to_nvstate_peer(&s->src);
951         if (tmp == NULL)
952                 goto errout;
953         nvlist_add_nvlist(nvl, "src", tmp);
954         nvlist_destroy(tmp);
955
956         tmp = pf_state_peer_to_nvstate_peer(&s->dst);
957         if (tmp == NULL)
958                 goto errout;
959         nvlist_add_nvlist(nvl, "dst", tmp);
960         nvlist_destroy(tmp);
961
962         tmp = pf_addr_to_nvaddr(&s->rt_addr);
963         if (tmp == NULL)
964                 goto errout;
965         nvlist_add_nvlist(nvl, "rt_addr", tmp);
966         nvlist_destroy(tmp);
967
968         nvlist_add_number(nvl, "rule", s->rule.ptr ? s->rule.ptr->nr : -1);
969         nvlist_add_number(nvl, "anchor",
970             s->anchor.ptr ? s->anchor.ptr->nr : -1);
971         nvlist_add_number(nvl, "nat_rule",
972             s->nat_rule.ptr ? s->nat_rule.ptr->nr : -1);
973         nvlist_add_number(nvl, "creation", s->creation);
974
975         expire = pf_state_expires(s);
976         if (expire <= time_uptime)
977                 expire = 0;
978         else
979                 expire = expire - time_uptime;
980         nvlist_add_number(nvl, "expire", expire);
981
982         for (int i = 0; i < 2; i++) {
983                 nvlist_append_number_array(nvl, "packets",
984                     counter_u64_fetch(s->packets[i]));
985                 nvlist_append_number_array(nvl, "bytes",
986                     counter_u64_fetch(s->bytes[i]));
987         }
988
989         nvlist_add_number(nvl, "creatorid", s->creatorid);
990         nvlist_add_number(nvl, "direction", s->direction);
991         nvlist_add_number(nvl, "log", s->log);
992         nvlist_add_number(nvl, "state_flags", s->state_flags);
993         nvlist_add_number(nvl, "timeout", s->timeout);
994         if (s->src_node)
995                 flags |= PFSYNC_FLAG_SRCNODE;
996         if (s->nat_src_node)
997                 flags |= PFSYNC_FLAG_NATSRCNODE;
998         nvlist_add_number(nvl, "sync_flags", flags);
999
1000         return (nvl);
1001
1002 errout:
1003         nvlist_destroy(nvl);
1004         return (NULL);
1005 }