]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libpfctl/libpfctl.c
file: Fix cross-compilation on Darwin/macOS
[FreeBSD/FreeBSD.git] / lib / libpfctl / libpfctl.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2021 Rubicon Communications, LLC (Netgate)
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  *    - Redistributions of source code must retain the above copyright
12  *      notice, this list of conditions and the following disclaimer.
13  *    - Redistributions in binary form must reproduce the above
14  *      copyright notice, this list of conditions and the following
15  *      disclaimer in the documentation and/or other materials provided
16  *      with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
22  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
28  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  * $FreeBSD$
32  */
33
34 #include <sys/cdefs.h>
35
36 #include <sys/ioctl.h>
37 #include <sys/nv.h>
38 #include <sys/queue.h>
39 #include <sys/types.h>
40
41 #include <net/if.h>
42 #include <net/pfvar.h>
43 #include <netinet/in.h>
44
45 #include <assert.h>
46 #include <err.h>
47 #include <errno.h>
48 #include <stdlib.h>
49 #include <string.h>
50
51 #include "libpfctl.h"
52
53 const char* PFCTL_SYNCOOKIES_MODE_NAMES[] = {
54         "never",
55         "always",
56         "adaptive"
57 };
58
59 static int      _pfctl_clear_states(int , const struct pfctl_kill *,
60                     unsigned int *, uint64_t);
61
62 static void
63 pf_nvuint_8_array(const nvlist_t *nvl, const char *name, size_t maxelems,
64     uint8_t *numbers, size_t *nelems)
65 {
66         const uint64_t *tmp;
67         size_t elems;
68
69         tmp = nvlist_get_number_array(nvl, name, &elems);
70         assert(elems <= maxelems);
71
72         for (size_t i = 0; i < elems; i++)
73                 numbers[i] = tmp[i];
74
75         if (nelems)
76                 *nelems = elems;
77 }
78
79 static void
80 pf_nvuint_16_array(const nvlist_t *nvl, const char *name, size_t maxelems,
81     uint16_t *numbers, size_t *nelems)
82 {
83         const uint64_t *tmp;
84         size_t elems;
85
86         tmp = nvlist_get_number_array(nvl, name, &elems);
87         assert(elems <= maxelems);
88
89         for (size_t i = 0; i < elems; i++)
90                 numbers[i] = tmp[i];
91
92         if (nelems)
93                 *nelems = elems;
94 }
95
96 static void
97 pf_nvuint_32_array(const nvlist_t *nvl, const char *name, size_t maxelems,
98     uint32_t *numbers, size_t *nelems)
99 {
100         const uint64_t *tmp;
101         size_t elems;
102
103         tmp = nvlist_get_number_array(nvl, name, &elems);
104         assert(elems <= maxelems);
105
106         for (size_t i = 0; i < elems; i++)
107                 numbers[i] = tmp[i];
108
109         if (nelems)
110                 *nelems = elems;
111 }
112
113 static void
114 pf_nvuint_64_array(const nvlist_t *nvl, const char *name, size_t maxelems,
115     uint64_t *numbers, size_t *nelems)
116 {
117         const uint64_t *tmp;
118         size_t elems;
119
120         tmp = nvlist_get_number_array(nvl, name, &elems);
121         assert(elems <= maxelems);
122
123         for (size_t i = 0; i < elems; i++)
124                 numbers[i] = tmp[i];
125
126         if (nelems)
127                 *nelems = elems;
128 }
129
130 static void
131 _pfctl_get_status_counters(const nvlist_t *nvl,
132     struct pfctl_status_counters *counters)
133 {
134         const uint64_t          *ids, *counts;
135         const char *const       *names;
136         size_t id_len, counter_len, names_len;
137
138         ids = nvlist_get_number_array(nvl, "ids", &id_len);
139         counts = nvlist_get_number_array(nvl, "counters", &counter_len);
140         names = nvlist_get_string_array(nvl, "names", &names_len);
141         assert(id_len == counter_len);
142         assert(counter_len == names_len);
143
144         TAILQ_INIT(counters);
145
146         for (size_t i = 0; i < id_len; i++) {
147                 struct pfctl_status_counter *c;
148
149                 c = malloc(sizeof(*c));
150
151                 c->id = ids[i];
152                 c->counter = counts[i];
153                 c->name = strdup(names[i]);
154
155                 TAILQ_INSERT_TAIL(counters, c, entry);
156         }
157 }
158
159 struct pfctl_status *
160 pfctl_get_status(int dev)
161 {
162         struct pfioc_nv  nv;
163         struct pfctl_status     *status;
164         nvlist_t        *nvl;
165         size_t           len;
166         const void      *chksum;
167
168         status = calloc(1, sizeof(*status));
169         if (status == NULL)
170                 return (NULL);
171
172         nv.data = malloc(4096);
173         nv.len = nv.size = 4096;
174
175         if (ioctl(dev, DIOCGETSTATUSNV, &nv)) {
176                 free(nv.data);
177                 free(status);
178                 return (NULL);
179         }
180
181         nvl = nvlist_unpack(nv.data, nv.len, 0);
182         free(nv.data);
183         if (nvl == NULL) {
184                 free(status);
185                 return (NULL);
186         }
187
188         status->running = nvlist_get_bool(nvl, "running");
189         status->since = nvlist_get_number(nvl, "since");
190         status->debug = nvlist_get_number(nvl, "debug");
191         status->hostid = nvlist_get_number(nvl, "hostid");
192         status->states = nvlist_get_number(nvl, "states");
193         status->src_nodes = nvlist_get_number(nvl, "src_nodes");
194
195         strlcpy(status->ifname, nvlist_get_string(nvl, "ifname"),
196             IFNAMSIZ);
197         chksum = nvlist_get_binary(nvl, "chksum", &len);
198         assert(len == PF_MD5_DIGEST_LENGTH);
199         memcpy(status->pf_chksum, chksum, len);
200
201         _pfctl_get_status_counters(nvlist_get_nvlist(nvl, "counters"),
202             &status->counters);
203         _pfctl_get_status_counters(nvlist_get_nvlist(nvl, "lcounters"),
204             &status->lcounters);
205         _pfctl_get_status_counters(nvlist_get_nvlist(nvl, "fcounters"),
206             &status->fcounters);
207         _pfctl_get_status_counters(nvlist_get_nvlist(nvl, "scounters"),
208             &status->scounters);
209
210         pf_nvuint_64_array(nvl, "pcounters", 2 * 2 * 3,
211             (uint64_t *)status->pcounters, NULL);
212         pf_nvuint_64_array(nvl, "bcounters", 2 * 2,
213             (uint64_t *)status->bcounters, NULL);
214
215         nvlist_destroy(nvl);
216
217         return (status);
218 }
219
220 void
221 pfctl_free_status(struct pfctl_status *status)
222 {
223         struct pfctl_status_counter *c, *tmp;
224
225         TAILQ_FOREACH_SAFE(c, &status->counters, entry, tmp) {
226                 free(c->name);
227                 free(c);
228         }
229         TAILQ_FOREACH_SAFE(c, &status->lcounters, entry, tmp) {
230                 free(c->name);
231                 free(c);
232         }
233         TAILQ_FOREACH_SAFE(c, &status->fcounters, entry, tmp) {
234                 free(c->name);
235                 free(c);
236         }
237         TAILQ_FOREACH_SAFE(c, &status->scounters, entry, tmp) {
238                 free(c->name);
239                 free(c);
240         }
241
242         free(status);
243 }
244
245 static void
246 pfctl_nv_add_addr(nvlist_t *nvparent, const char *name,
247     const struct pf_addr *addr)
248 {
249         nvlist_t *nvl = nvlist_create(0);
250
251         nvlist_add_binary(nvl, "addr", addr, sizeof(*addr));
252
253         nvlist_add_nvlist(nvparent, name, nvl);
254         nvlist_destroy(nvl);
255 }
256
257 static void
258 pf_nvaddr_to_addr(const nvlist_t *nvl, struct pf_addr *addr)
259 {
260         size_t len;
261         const void *data;
262
263         data = nvlist_get_binary(nvl, "addr", &len);
264         assert(len == sizeof(struct pf_addr));
265         memcpy(addr, data, len);
266 }
267
268 static void
269 pfctl_nv_add_addr_wrap(nvlist_t *nvparent, const char *name,
270     const struct pf_addr_wrap *addr)
271 {
272         nvlist_t *nvl = nvlist_create(0);
273
274         nvlist_add_number(nvl, "type", addr->type);
275         nvlist_add_number(nvl, "iflags", addr->iflags);
276         if (addr->type == PF_ADDR_DYNIFTL)
277                 nvlist_add_string(nvl, "ifname", addr->v.ifname);
278         if (addr->type == PF_ADDR_TABLE)
279                 nvlist_add_string(nvl, "tblname", addr->v.tblname);
280         pfctl_nv_add_addr(nvl, "addr", &addr->v.a.addr);
281         pfctl_nv_add_addr(nvl, "mask", &addr->v.a.mask);
282
283         nvlist_add_nvlist(nvparent, name, nvl);
284         nvlist_destroy(nvl);
285 }
286
287 static void
288 pf_nvaddr_wrap_to_addr_wrap(const nvlist_t *nvl, struct pf_addr_wrap *addr)
289 {
290         bzero(addr, sizeof(*addr));
291
292         addr->type = nvlist_get_number(nvl, "type");
293         addr->iflags = nvlist_get_number(nvl, "iflags");
294         if (addr->type == PF_ADDR_DYNIFTL) {
295                 strlcpy(addr->v.ifname, nvlist_get_string(nvl, "ifname"),
296                     IFNAMSIZ);
297                 addr->p.dyncnt = nvlist_get_number(nvl, "dyncnt");
298         }
299         if (addr->type == PF_ADDR_TABLE) {
300                 strlcpy(addr->v.tblname, nvlist_get_string(nvl, "tblname"),
301                     PF_TABLE_NAME_SIZE);
302                 addr->p.tblcnt = nvlist_get_number(nvl, "tblcnt");
303         }
304
305         pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "addr"), &addr->v.a.addr);
306         pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "mask"), &addr->v.a.mask);
307 }
308
309 static void
310 pfctl_nv_add_rule_addr(nvlist_t *nvparent, const char *name,
311     const struct pf_rule_addr *addr)
312 {
313         uint64_t ports[2];
314         nvlist_t *nvl = nvlist_create(0);
315
316         pfctl_nv_add_addr_wrap(nvl, "addr", &addr->addr);
317         ports[0] = addr->port[0];
318         ports[1] = addr->port[1];
319         nvlist_add_number_array(nvl, "port", ports, 2);
320         nvlist_add_number(nvl, "neg", addr->neg);
321         nvlist_add_number(nvl, "port_op", addr->port_op);
322
323         nvlist_add_nvlist(nvparent, name, nvl);
324         nvlist_destroy(nvl);
325 }
326
327 static void
328 pf_nvrule_addr_to_rule_addr(const nvlist_t *nvl, struct pf_rule_addr *addr)
329 {
330         pf_nvaddr_wrap_to_addr_wrap(nvlist_get_nvlist(nvl, "addr"), &addr->addr);
331
332         pf_nvuint_16_array(nvl, "port", 2, addr->port, NULL);
333         addr->neg = nvlist_get_number(nvl, "neg");
334         addr->port_op = nvlist_get_number(nvl, "port_op");
335 }
336
337 static void
338 pfctl_nv_add_mape(nvlist_t *nvparent, const char *name,
339     const struct pf_mape_portset *mape)
340 {
341         nvlist_t *nvl = nvlist_create(0);
342
343         nvlist_add_number(nvl, "offset", mape->offset);
344         nvlist_add_number(nvl, "psidlen", mape->psidlen);
345         nvlist_add_number(nvl, "psid", mape->psid);
346         nvlist_add_nvlist(nvparent, name, nvl);
347         nvlist_destroy(nvl);
348 }
349
350 static void
351 pfctl_nv_add_pool(nvlist_t *nvparent, const char *name,
352     const struct pfctl_pool *pool)
353 {
354         uint64_t ports[2];
355         nvlist_t *nvl = nvlist_create(0);
356
357         nvlist_add_binary(nvl, "key", &pool->key, sizeof(pool->key));
358         pfctl_nv_add_addr(nvl, "counter", &pool->counter);
359         nvlist_add_number(nvl, "tblidx", pool->tblidx);
360
361         ports[0] = pool->proxy_port[0];
362         ports[1] = pool->proxy_port[1];
363         nvlist_add_number_array(nvl, "proxy_port", ports, 2);
364         nvlist_add_number(nvl, "opts", pool->opts);
365         pfctl_nv_add_mape(nvl, "mape", &pool->mape);
366
367         nvlist_add_nvlist(nvparent, name, nvl);
368         nvlist_destroy(nvl);
369 }
370
371 static void
372 pf_nvmape_to_mape(const nvlist_t *nvl, struct pf_mape_portset *mape)
373 {
374         mape->offset = nvlist_get_number(nvl, "offset");
375         mape->psidlen = nvlist_get_number(nvl, "psidlen");
376         mape->psid = nvlist_get_number(nvl, "psid");
377 }
378
379 static void
380 pf_nvpool_to_pool(const nvlist_t *nvl, struct pfctl_pool *pool)
381 {
382         size_t len;
383         const void *data;
384
385         data = nvlist_get_binary(nvl, "key", &len);
386         assert(len == sizeof(pool->key));
387         memcpy(&pool->key, data, len);
388
389         pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "counter"), &pool->counter);
390
391         pool->tblidx = nvlist_get_number(nvl, "tblidx");
392         pf_nvuint_16_array(nvl, "proxy_port", 2, pool->proxy_port, NULL);
393         pool->opts = nvlist_get_number(nvl, "opts");
394
395         if (nvlist_exists_nvlist(nvl, "mape"))
396                 pf_nvmape_to_mape(nvlist_get_nvlist(nvl, "mape"), &pool->mape);
397 }
398
399 static void
400 pfctl_nv_add_uid(nvlist_t *nvparent, const char *name,
401     const struct pf_rule_uid *uid)
402 {
403         uint64_t uids[2];
404         nvlist_t *nvl = nvlist_create(0);
405
406         uids[0] = uid->uid[0];
407         uids[1] = uid->uid[1];
408         nvlist_add_number_array(nvl, "uid", uids, 2);
409         nvlist_add_number(nvl, "op", uid->op);
410
411         nvlist_add_nvlist(nvparent, name, nvl);
412         nvlist_destroy(nvl);
413 }
414
415 static void
416 pf_nvrule_uid_to_rule_uid(const nvlist_t *nvl, struct pf_rule_uid *uid)
417 {
418         pf_nvuint_32_array(nvl, "uid", 2, uid->uid, NULL);
419         uid->op = nvlist_get_number(nvl, "op");
420 }
421
422 static void
423 pfctl_nv_add_divert(nvlist_t *nvparent, const char *name,
424     const struct pfctl_rule *r)
425 {
426         nvlist_t *nvl = nvlist_create(0);
427
428         pfctl_nv_add_addr(nvl, "addr", &r->divert.addr);
429         nvlist_add_number(nvl, "port", r->divert.port);
430
431         nvlist_add_nvlist(nvparent, name, nvl);
432         nvlist_destroy(nvl);
433 }
434
435 static void
436 pf_nvdivert_to_divert(const nvlist_t *nvl, struct pfctl_rule *rule)
437 {
438         pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "addr"), &rule->divert.addr);
439         rule->divert.port = nvlist_get_number(nvl, "port");
440 }
441
442 static void
443 pf_nvrule_to_rule(const nvlist_t *nvl, struct pfctl_rule *rule)
444 {
445         const uint64_t *skip;
446         const char *const *labels;
447         size_t skipcount, labelcount;
448
449         rule->nr = nvlist_get_number(nvl, "nr");
450
451         pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "src"), &rule->src);
452         pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "dst"), &rule->dst);
453
454         skip = nvlist_get_number_array(nvl, "skip", &skipcount);
455         assert(skip);
456         assert(skipcount == PF_SKIP_COUNT);
457         for (int i = 0; i < PF_SKIP_COUNT; i++)
458                 rule->skip[i].nr = skip[i];
459
460         labels = nvlist_get_string_array(nvl, "labels", &labelcount);
461         assert(labelcount <= PF_RULE_MAX_LABEL_COUNT);
462         for (size_t i = 0; i < labelcount; i++)
463                 strlcpy(rule->label[i], labels[i], PF_RULE_LABEL_SIZE);
464         rule->ridentifier = nvlist_get_number(nvl, "ridentifier");
465         strlcpy(rule->ifname, nvlist_get_string(nvl, "ifname"), IFNAMSIZ);
466         strlcpy(rule->qname, nvlist_get_string(nvl, "qname"), PF_QNAME_SIZE);
467         strlcpy(rule->pqname, nvlist_get_string(nvl, "pqname"), PF_QNAME_SIZE);
468         strlcpy(rule->tagname, nvlist_get_string(nvl, "tagname"),
469             PF_TAG_NAME_SIZE);
470         strlcpy(rule->match_tagname, nvlist_get_string(nvl, "match_tagname"),
471             PF_TAG_NAME_SIZE);
472
473         strlcpy(rule->overload_tblname, nvlist_get_string(nvl, "overload_tblname"),
474             PF_TABLE_NAME_SIZE);
475
476         pf_nvpool_to_pool(nvlist_get_nvlist(nvl, "rpool"), &rule->rpool);
477
478         rule->evaluations = nvlist_get_number(nvl, "evaluations");
479         pf_nvuint_64_array(nvl, "packets", 2, rule->packets, NULL);
480         pf_nvuint_64_array(nvl, "bytes", 2, rule->bytes, NULL);
481
482         rule->os_fingerprint = nvlist_get_number(nvl, "os_fingerprint");
483
484         rule->rtableid = nvlist_get_number(nvl, "rtableid");
485         pf_nvuint_32_array(nvl, "timeout", PFTM_MAX, rule->timeout, NULL);
486         rule->max_states = nvlist_get_number(nvl, "max_states");
487         rule->max_src_nodes = nvlist_get_number(nvl, "max_src_nodes");
488         rule->max_src_states = nvlist_get_number(nvl, "max_src_states");
489         rule->max_src_conn = nvlist_get_number(nvl, "max_src_conn");
490         rule->max_src_conn_rate.limit =
491             nvlist_get_number(nvl, "max_src_conn_rate.limit");
492         rule->max_src_conn_rate.seconds =
493             nvlist_get_number(nvl, "max_src_conn_rate.seconds");
494         rule->qid = nvlist_get_number(nvl, "qid");
495         rule->pqid = nvlist_get_number(nvl, "pqid");
496         rule->prob = nvlist_get_number(nvl, "prob");
497         rule->cuid = nvlist_get_number(nvl, "cuid");
498         rule->cpid = nvlist_get_number(nvl, "cpid");
499
500         rule->return_icmp = nvlist_get_number(nvl, "return_icmp");
501         rule->return_icmp6 = nvlist_get_number(nvl, "return_icmp6");
502         rule->max_mss = nvlist_get_number(nvl, "max_mss");
503         rule->scrub_flags = nvlist_get_number(nvl, "scrub_flags");
504
505         pf_nvrule_uid_to_rule_uid(nvlist_get_nvlist(nvl, "uid"), &rule->uid);
506         pf_nvrule_uid_to_rule_uid(nvlist_get_nvlist(nvl, "gid"),
507             (struct pf_rule_uid *)&rule->gid);
508
509         rule->rule_flag = nvlist_get_number(nvl, "rule_flag");
510         rule->action = nvlist_get_number(nvl, "action");
511         rule->direction = nvlist_get_number(nvl, "direction");
512         rule->log = nvlist_get_number(nvl, "log");
513         rule->logif = nvlist_get_number(nvl, "logif");
514         rule->quick = nvlist_get_number(nvl, "quick");
515         rule->ifnot = nvlist_get_number(nvl, "ifnot");
516         rule->match_tag_not = nvlist_get_number(nvl, "match_tag_not");
517         rule->natpass = nvlist_get_number(nvl, "natpass");
518
519         rule->keep_state = nvlist_get_number(nvl, "keep_state");
520         rule->af = nvlist_get_number(nvl, "af");
521         rule->proto = nvlist_get_number(nvl, "proto");
522         rule->type = nvlist_get_number(nvl, "type");
523         rule->code = nvlist_get_number(nvl, "code");
524         rule->flags = nvlist_get_number(nvl, "flags");
525         rule->flagset = nvlist_get_number(nvl, "flagset");
526         rule->min_ttl = nvlist_get_number(nvl, "min_ttl");
527         rule->allow_opts = nvlist_get_number(nvl, "allow_opts");
528         rule->rt = nvlist_get_number(nvl, "rt");
529         rule->return_ttl  = nvlist_get_number(nvl, "return_ttl");
530         rule->tos = nvlist_get_number(nvl, "tos");
531         rule->set_tos = nvlist_get_number(nvl, "set_tos");
532         rule->anchor_relative = nvlist_get_number(nvl, "anchor_relative");
533         rule->anchor_wildcard = nvlist_get_number(nvl, "anchor_wildcard");
534
535         rule->flush = nvlist_get_number(nvl, "flush");
536         rule->prio = nvlist_get_number(nvl, "prio");
537         pf_nvuint_8_array(nvl, "set_prio", 2, rule->set_prio, NULL);
538
539         pf_nvdivert_to_divert(nvlist_get_nvlist(nvl, "divert"), rule);
540
541         rule->states_cur = nvlist_get_number(nvl, "states_cur");
542         rule->states_tot = nvlist_get_number(nvl, "states_tot");
543         rule->src_nodes = nvlist_get_number(nvl, "src_nodes");
544 }
545
546 int
547 pfctl_add_rule(int dev, const struct pfctl_rule *r, const char *anchor,
548     const char *anchor_call, uint32_t ticket, uint32_t pool_ticket)
549 {
550         struct pfioc_nv nv;
551         uint64_t timeouts[PFTM_MAX];
552         uint64_t set_prio[2];
553         nvlist_t *nvl, *nvlr;
554         size_t labelcount;
555         int ret;
556
557         nvl = nvlist_create(0);
558         nvlr = nvlist_create(0);
559
560         nvlist_add_number(nvl, "ticket", ticket);
561         nvlist_add_number(nvl, "pool_ticket", pool_ticket);
562         nvlist_add_string(nvl, "anchor", anchor);
563         nvlist_add_string(nvl, "anchor_call", anchor_call);
564
565         nvlist_add_number(nvlr, "nr", r->nr);
566         pfctl_nv_add_rule_addr(nvlr, "src", &r->src);
567         pfctl_nv_add_rule_addr(nvlr, "dst", &r->dst);
568
569         labelcount = 0;
570         while (r->label[labelcount][0] != 0 &&
571             labelcount < PF_RULE_MAX_LABEL_COUNT) {
572                 nvlist_append_string_array(nvlr, "labels",
573                     r->label[labelcount]);
574                 labelcount++;
575         }
576         nvlist_add_number(nvlr, "ridentifier", r->ridentifier);
577
578         nvlist_add_string(nvlr, "ifname", r->ifname);
579         nvlist_add_string(nvlr, "qname", r->qname);
580         nvlist_add_string(nvlr, "pqname", r->pqname);
581         nvlist_add_string(nvlr, "tagname", r->tagname);
582         nvlist_add_string(nvlr, "match_tagname", r->match_tagname);
583         nvlist_add_string(nvlr, "overload_tblname", r->overload_tblname);
584
585         pfctl_nv_add_pool(nvlr, "rpool", &r->rpool);
586
587         nvlist_add_number(nvlr, "os_fingerprint", r->os_fingerprint);
588
589         nvlist_add_number(nvlr, "rtableid", r->rtableid);
590         for (int i = 0; i < PFTM_MAX; i++)
591                 timeouts[i] = r->timeout[i];
592         nvlist_add_number_array(nvlr, "timeout", timeouts, PFTM_MAX);
593         nvlist_add_number(nvlr, "max_states", r->max_states);
594         nvlist_add_number(nvlr, "max_src_nodes", r->max_src_nodes);
595         nvlist_add_number(nvlr, "max_src_states", r->max_src_states);
596         nvlist_add_number(nvlr, "max_src_conn", r->max_src_conn);
597         nvlist_add_number(nvlr, "max_src_conn_rate.limit",
598             r->max_src_conn_rate.limit);
599         nvlist_add_number(nvlr, "max_src_conn_rate.seconds",
600             r->max_src_conn_rate.seconds);
601         nvlist_add_number(nvlr, "prob", r->prob);
602         nvlist_add_number(nvlr, "cuid", r->cuid);
603         nvlist_add_number(nvlr, "cpid", r->cpid);
604
605         nvlist_add_number(nvlr, "return_icmp", r->return_icmp);
606         nvlist_add_number(nvlr, "return_icmp6", r->return_icmp6);
607
608         nvlist_add_number(nvlr, "max_mss", r->max_mss);
609         nvlist_add_number(nvlr, "scrub_flags", r->scrub_flags);
610
611         pfctl_nv_add_uid(nvlr, "uid", &r->uid);
612         pfctl_nv_add_uid(nvlr, "gid", (const struct pf_rule_uid *)&r->gid);
613
614         nvlist_add_number(nvlr, "rule_flag", r->rule_flag);
615         nvlist_add_number(nvlr, "action", r->action);
616         nvlist_add_number(nvlr, "direction", r->direction);
617         nvlist_add_number(nvlr, "log", r->log);
618         nvlist_add_number(nvlr, "logif", r->logif);
619         nvlist_add_number(nvlr, "quick", r->quick);
620         nvlist_add_number(nvlr, "ifnot", r->ifnot);
621         nvlist_add_number(nvlr, "match_tag_not", r->match_tag_not);
622         nvlist_add_number(nvlr, "natpass", r->natpass);
623
624         nvlist_add_number(nvlr, "keep_state", r->keep_state);
625         nvlist_add_number(nvlr, "af", r->af);
626         nvlist_add_number(nvlr, "proto", r->proto);
627         nvlist_add_number(nvlr, "type", r->type);
628         nvlist_add_number(nvlr, "code", r->code);
629         nvlist_add_number(nvlr, "flags", r->flags);
630         nvlist_add_number(nvlr, "flagset", r->flagset);
631         nvlist_add_number(nvlr, "min_ttl", r->min_ttl);
632         nvlist_add_number(nvlr, "allow_opts", r->allow_opts);
633         nvlist_add_number(nvlr, "rt", r->rt);
634         nvlist_add_number(nvlr, "return_ttl", r->return_ttl);
635         nvlist_add_number(nvlr, "tos", r->tos);
636         nvlist_add_number(nvlr, "set_tos", r->set_tos);
637         nvlist_add_number(nvlr, "anchor_relative", r->anchor_relative);
638         nvlist_add_number(nvlr, "anchor_wildcard", r->anchor_wildcard);
639
640         nvlist_add_number(nvlr, "flush", r->flush);
641
642         nvlist_add_number(nvlr, "prio", r->prio);
643         set_prio[0] = r->set_prio[0];
644         set_prio[1] = r->set_prio[1];
645         nvlist_add_number_array(nvlr, "set_prio", set_prio, 2);
646
647         pfctl_nv_add_divert(nvlr, "divert", r);
648
649         nvlist_add_nvlist(nvl, "rule", nvlr);
650         nvlist_destroy(nvlr);
651
652         /* Now do the call. */
653         nv.data = nvlist_pack(nvl, &nv.len);
654         nv.size = nv.len;
655
656         ret = ioctl(dev, DIOCADDRULENV, &nv);
657
658         free(nv.data);
659         nvlist_destroy(nvl);
660
661         return (ret);
662 }
663
664 int
665 pfctl_get_rule(int dev, uint32_t nr, uint32_t ticket, const char *anchor,
666     uint32_t ruleset, struct pfctl_rule *rule, char *anchor_call)
667 {
668         return (pfctl_get_clear_rule(dev, nr, ticket, anchor, ruleset, rule,
669             anchor_call, false));
670 }
671
672 int     pfctl_get_clear_rule(int dev, uint32_t nr, uint32_t ticket,
673             const char *anchor, uint32_t ruleset, struct pfctl_rule *rule,
674             char *anchor_call, bool clear)
675 {
676         struct pfioc_nv nv;
677         nvlist_t *nvl;
678         void *nvlpacked;
679         int ret;
680
681         nvl = nvlist_create(0);
682         if (nvl == 0)
683                 return (ENOMEM);
684
685         nvlist_add_number(nvl, "nr", nr);
686         nvlist_add_number(nvl, "ticket", ticket);
687         nvlist_add_string(nvl, "anchor", anchor);
688         nvlist_add_number(nvl, "ruleset", ruleset);
689
690         if (clear)
691                 nvlist_add_bool(nvl, "clear_counter", true);
692
693         nvlpacked = nvlist_pack(nvl, &nv.len);
694         if (nvlpacked == NULL) {
695                 nvlist_destroy(nvl);
696                 return (ENOMEM);
697         }
698         nv.data = malloc(8182);
699         nv.size = 8192;
700         assert(nv.len <= nv.size);
701         memcpy(nv.data, nvlpacked, nv.len);
702         nvlist_destroy(nvl);
703         nvl = NULL;
704         free(nvlpacked);
705
706         ret = ioctl(dev, DIOCGETRULENV, &nv);
707         if (ret != 0) {
708                 free(nv.data);
709                 return (ret);
710         }
711
712         nvl = nvlist_unpack(nv.data, nv.len, 0);
713         if (nvl == NULL) {
714                 free(nv.data);
715                 return (EIO);
716         }
717
718         pf_nvrule_to_rule(nvlist_get_nvlist(nvl, "rule"), rule);
719
720         if (anchor_call)
721                 strlcpy(anchor_call, nvlist_get_string(nvl, "anchor_call"),
722                     MAXPATHLEN);
723
724         free(nv.data);
725         nvlist_destroy(nvl);
726
727         return (0);
728 }
729
730 int
731 pfctl_set_keepcounters(int dev, bool keep)
732 {
733         struct pfioc_nv  nv;
734         nvlist_t        *nvl;
735         int              ret;
736
737         nvl = nvlist_create(0);
738
739         nvlist_add_bool(nvl, "keep_counters", keep);
740
741         nv.data = nvlist_pack(nvl, &nv.len);
742         nv.size = nv.len;
743
744         nvlist_destroy(nvl);
745
746         ret = ioctl(dev, DIOCKEEPCOUNTERS, &nv);
747
748         free(nv.data);
749         return (ret);
750 }
751
752 static void
753 pfctl_nv_add_state_cmp(nvlist_t *nvl, const char *name,
754     const struct pfctl_state_cmp *cmp)
755 {
756         nvlist_t        *nv;
757
758         nv = nvlist_create(0);
759
760         nvlist_add_number(nv, "id", cmp->id);
761         nvlist_add_number(nv, "creatorid", cmp->creatorid);
762         nvlist_add_number(nv, "direction", cmp->direction);
763
764         nvlist_add_nvlist(nvl, name, nv);
765         nvlist_destroy(nv);
766 }
767
768 static void
769 pf_state_key_export_to_state_key(struct pfctl_state_key *ps,
770     const struct pf_state_key_export *s)
771 {
772         bcopy(s->addr, ps->addr, sizeof(ps->addr[0]) * 2);
773         ps->port[0] = s->port[0];
774         ps->port[1] = s->port[1];
775 }
776
777 static void
778 pf_state_peer_export_to_state_peer(struct pfctl_state_peer *ps,
779     const struct pf_state_peer_export *s)
780 {
781         /* Ignore scrub. */
782         ps->seqlo = s->seqlo;
783         ps->seqhi = s->seqhi;
784         ps->seqdiff = s->seqdiff;
785         /* Ignore max_win & mss */
786         ps->state = s->state;
787         ps->wscale = s->wscale;
788 }
789
790 static void
791 pf_state_export_to_state(struct pfctl_state *ps, const struct pf_state_export *s)
792 {
793         assert(s->version >= PF_STATE_VERSION);
794
795         ps->id = s->id;
796         strlcpy(ps->ifname, s->ifname, sizeof(ps->ifname));
797         strlcpy(ps->orig_ifname, s->orig_ifname, sizeof(ps->orig_ifname));
798         pf_state_key_export_to_state_key(&ps->key[0], &s->key[0]);
799         pf_state_key_export_to_state_key(&ps->key[1], &s->key[1]);
800         pf_state_peer_export_to_state_peer(&ps->src, &s->src);
801         pf_state_peer_export_to_state_peer(&ps->dst, &s->dst);
802         bcopy(&s->rt_addr, &ps->rt_addr, sizeof(ps->rt_addr));
803         ps->rule = ntohl(s->rule);
804         ps->anchor = ntohl(s->anchor);
805         ps->nat_rule = ntohl(s->nat_rule);
806         ps->creation = ntohl(s->creation);
807         ps->expire = ntohl(s->expire);
808         ps->packets[0] = s->packets[0];
809         ps->packets[1] = s->packets[1];
810         ps->bytes[0] = s->bytes[0];
811         ps->bytes[1] = s->bytes[1];
812         ps->creatorid = s->creatorid;
813         ps->key[0].proto = s->proto;
814         ps->key[1].proto = s->proto;
815         ps->key[0].af = s->af;
816         ps->key[1].af = s->af;
817         ps->direction = s->direction;
818         ps->state_flags = s->state_flags;
819         ps->sync_flags = s->sync_flags;
820 }
821
822 int
823 pfctl_get_states(int dev, struct pfctl_states *states)
824 {
825         struct pfioc_states_v2 ps;
826         struct pf_state_export *p;
827         char *inbuf = NULL, *newinbuf = NULL;
828         unsigned int len = 0;
829         int i, error;
830
831         bzero(&ps, sizeof(ps));
832         ps.ps_req_version = PF_STATE_VERSION;
833
834         bzero(states, sizeof(*states));
835         TAILQ_INIT(&states->states);
836
837         for (;;) {
838                 ps.ps_len = len;
839                 if (len) {
840                         newinbuf = realloc(inbuf, len);
841                         if (newinbuf == NULL)
842                                 return (ENOMEM);
843                         ps.ps_buf = inbuf = newinbuf;
844                 }
845                 if ((error = ioctl(dev, DIOCGETSTATESV2, &ps)) < 0) {
846                         free(inbuf);
847                         return (error);
848                 }
849                 if (ps.ps_len + sizeof(struct pfioc_states_v2) < len)
850                         break;
851                 if (len == 0 && ps.ps_len == 0)
852                         goto out;
853                 if (len == 0 && ps.ps_len != 0)
854                         len = ps.ps_len;
855                 if (ps.ps_len == 0)
856                         goto out;      /* no states */
857                 len *= 2;
858         }
859         p = ps.ps_states;
860
861         for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) {
862                 struct pfctl_state *s = malloc(sizeof(*s));
863                 if (s == NULL) {
864                         pfctl_free_states(states);
865                         error = ENOMEM;
866                         goto out;
867                 }
868
869                 pf_state_export_to_state(s, p);
870                 TAILQ_INSERT_TAIL(&states->states, s, entry);
871         }
872
873 out:
874         free(inbuf);
875         return (error);
876 }
877
878 void
879 pfctl_free_states(struct pfctl_states *states)
880 {
881         struct pfctl_state *s, *tmp;
882
883         TAILQ_FOREACH_SAFE(s, &states->states, entry, tmp) {
884                 free(s);
885         }
886
887         bzero(states, sizeof(*states));
888 }
889
890 static int
891 _pfctl_clear_states(int dev, const struct pfctl_kill *kill,
892     unsigned int *killed, uint64_t ioctlval)
893 {
894         struct pfioc_nv  nv;
895         nvlist_t        *nvl;
896         int              ret;
897
898         nvl = nvlist_create(0);
899
900         pfctl_nv_add_state_cmp(nvl, "cmp", &kill->cmp);
901         nvlist_add_number(nvl, "af", kill->af);
902         nvlist_add_number(nvl, "proto", kill->proto);
903         pfctl_nv_add_rule_addr(nvl, "src", &kill->src);
904         pfctl_nv_add_rule_addr(nvl, "dst", &kill->dst);
905         pfctl_nv_add_rule_addr(nvl, "rt_addr", &kill->rt_addr);
906         nvlist_add_string(nvl, "ifname", kill->ifname);
907         nvlist_add_string(nvl, "label", kill->label);
908         nvlist_add_bool(nvl, "kill_match", kill->kill_match);
909
910         nv.data = nvlist_pack(nvl, &nv.len);
911         nv.size = nv.len;
912         nvlist_destroy(nvl);
913         nvl = NULL;
914
915         ret = ioctl(dev, ioctlval, &nv);
916         if (ret != 0) {
917                 free(nv.data);
918                 return (ret);
919         }
920
921         nvl = nvlist_unpack(nv.data, nv.len, 0);
922         if (nvl == NULL) {
923                 free(nv.data);
924                 return (EIO);
925         }
926
927         if (killed)
928                 *killed = nvlist_get_number(nvl, "killed");
929
930         nvlist_destroy(nvl);
931         free(nv.data);
932
933         return (ret);
934 }
935
936 int
937 pfctl_clear_states(int dev, const struct pfctl_kill *kill,
938     unsigned int *killed)
939 {
940         return (_pfctl_clear_states(dev, kill, killed, DIOCCLRSTATESNV));
941 }
942
943 int
944 pfctl_kill_states(int dev, const struct pfctl_kill *kill, unsigned int *killed)
945 {
946         return (_pfctl_clear_states(dev, kill, killed, DIOCKILLSTATESNV));
947 }
948
949 static int
950 pfctl_get_limit(int dev, const int index, uint *limit)
951 {
952         struct pfioc_limit pl;
953
954         bzero(&pl, sizeof(pl));
955         pl.index = index;
956
957         if (ioctl(dev, DIOCGETLIMIT, &pl) == -1)
958                 return (errno);
959
960         *limit = pl.limit;
961
962         return (0);
963 }
964
965 int
966 pfctl_set_syncookies(int dev, const struct pfctl_syncookies *s)
967 {
968         struct pfioc_nv  nv;
969         nvlist_t        *nvl;
970         int              ret;
971         uint             state_limit;
972
973         ret = pfctl_get_limit(dev, PF_LIMIT_STATES, &state_limit);
974         if (ret != 0)
975                 return (ret);
976
977         nvl = nvlist_create(0);
978
979         nvlist_add_bool(nvl, "enabled", s->mode != PFCTL_SYNCOOKIES_NEVER);
980         nvlist_add_bool(nvl, "adaptive", s->mode == PFCTL_SYNCOOKIES_ADAPTIVE);
981         nvlist_add_number(nvl, "highwater", state_limit * s->highwater / 100);
982         nvlist_add_number(nvl, "lowwater", state_limit * s->lowwater / 100);
983
984         nv.data = nvlist_pack(nvl, &nv.len);
985         nv.size = nv.len;
986         nvlist_destroy(nvl);
987         nvl = NULL;
988
989         ret = ioctl(dev, DIOCSETSYNCOOKIES, &nv);
990
991         free(nv.data);
992         return (ret);
993 }
994
995 int
996 pfctl_get_syncookies(int dev, struct pfctl_syncookies *s)
997 {
998         struct pfioc_nv  nv;
999         nvlist_t        *nvl;
1000         int              ret;
1001         uint             state_limit;
1002         bool             enabled, adaptive;
1003
1004         ret = pfctl_get_limit(dev, PF_LIMIT_STATES, &state_limit);
1005         if (ret != 0)
1006                 return (ret);
1007
1008         bzero(s, sizeof(*s));
1009
1010         nv.data = malloc(256);
1011         nv.len = nv.size = 256;
1012
1013         if (ioctl(dev, DIOCGETSYNCOOKIES, &nv)) {
1014                 free(nv.data);
1015                 return (errno);
1016         }
1017
1018         nvl = nvlist_unpack(nv.data, nv.len, 0);
1019         free(nv.data);
1020         if (nvl == NULL) {
1021                 return (EIO);
1022         }
1023
1024         enabled = nvlist_get_bool(nvl, "enabled");
1025         adaptive = nvlist_get_bool(nvl, "adaptive");
1026
1027         if (enabled) {
1028                 if (adaptive)
1029                         s->mode = PFCTL_SYNCOOKIES_ADAPTIVE;
1030                 else
1031                         s->mode = PFCTL_SYNCOOKIES_ALWAYS;
1032         } else {
1033                 s->mode = PFCTL_SYNCOOKIES_NEVER;
1034         }
1035
1036         s->highwater = nvlist_get_number(nvl, "highwater") * 100 / state_limit;
1037         s->lowwater = nvlist_get_number(nvl, "lowwater") * 100 / state_limit;
1038
1039         nvlist_destroy(nvl);
1040
1041         return (0);
1042 }