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
32 #include <sys/cdefs.h>
33
34 #include <sys/ioctl.h>
35 #include <sys/nv.h>
36 #include <sys/queue.h>
37 #include <sys/types.h>
38
39 #include <net/if.h>
40 #include <net/pfvar.h>
41 #include <netinet/in.h>
42
43 #include <netpfil/pf/pf_nl.h>
44 #include <netlink/netlink.h>
45 #include <netlink/netlink_generic.h>
46 #include <netlink/netlink_snl.h>
47 #include <netlink/netlink_snl_generic.h>
48 #include <netlink/netlink_snl_route.h>
49
50 #include <assert.h>
51 #include <err.h>
52 #include <errno.h>
53 #include <fcntl.h>
54 #include <stdlib.h>
55 #include <string.h>
56
57 #include "libpfctl.h"
58
59 struct pfctl_handle {
60 int fd;
61 struct snl_state ss;
62 int family_id;
63 };
64
65 const char* PFCTL_SYNCOOKIES_MODE_NAMES[] = {
66 "never",
67 "always",
68 "adaptive"
69 };
70
71 static int _pfctl_clear_states(int , const struct pfctl_kill *,
72 unsigned int *, uint64_t);
73 static void _pfctl_verify_parsers(void);
74
75 struct pfctl_handle *
pfctl_open(const char * pf_device)76 pfctl_open(const char *pf_device)
77 {
78 struct pfctl_handle *h;
79
80 _pfctl_verify_parsers();
81
82 h = calloc(1, sizeof(struct pfctl_handle));
83
84 h->fd = open(pf_device, O_RDWR);
85 if (h->fd < 0)
86 goto error;
87
88 if (!snl_init(&h->ss, NETLINK_GENERIC))
89 goto error;
90
91 h->family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
92 if (h->family_id == 0)
93 goto error;
94
95 return (h);
96 error:
97 if (h->fd != -1)
98 close(h->fd);
99 snl_free(&h->ss);
100 free(h);
101
102 return (NULL);
103 }
104
105 void
pfctl_close(struct pfctl_handle * h)106 pfctl_close(struct pfctl_handle *h)
107 {
108 close(h->fd);
109 snl_free(&h->ss);
110 free(h);
111 }
112
113 int
pfctl_fd(struct pfctl_handle * h)114 pfctl_fd(struct pfctl_handle *h)
115 {
116 return (h->fd);
117 }
118
119 static int
pfctl_do_netlink_cmd(struct pfctl_handle * h,uint cmd)120 pfctl_do_netlink_cmd(struct pfctl_handle *h, uint cmd)
121 {
122 struct snl_errmsg_data e = {};
123 struct snl_writer nw;
124 struct nlmsghdr *hdr;
125 uint32_t seq_id;
126
127 snl_init_writer(&h->ss, &nw);
128 hdr = snl_create_genl_msg_request(&nw, h->family_id, cmd);
129
130 hdr = snl_finalize_msg(&nw);
131 if (hdr == NULL) {
132 e.error = ENOMEM;
133 goto out;
134 }
135 seq_id = hdr->nlmsg_seq;
136
137 if (! snl_send_message(&h->ss, hdr)) {
138 e.error = ENXIO;
139 goto out;
140 }
141
142 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
143 }
144
145 out:
146 snl_clear_lb(&h->ss);
147 return (e.error);
148 }
149
150 static int
pfctl_do_ioctl(int dev,uint cmd,size_t size,nvlist_t ** nvl)151 pfctl_do_ioctl(int dev, uint cmd, size_t size, nvlist_t **nvl)
152 {
153 struct pfioc_nv nv;
154 void *data;
155 size_t nvlen;
156 int ret;
157
158 data = nvlist_pack(*nvl, &nvlen);
159 if (nvlen > size)
160 size = nvlen;
161
162 retry:
163 nv.data = malloc(size);
164 if (nv.data == NULL) {
165 ret = ENOMEM;
166 goto out;
167 }
168
169 memcpy(nv.data, data, nvlen);
170
171 nv.len = nvlen;
172 nv.size = size;
173
174 ret = ioctl(dev, cmd, &nv);
175 if (ret == -1 && errno == ENOSPC) {
176 size *= 2;
177 free(nv.data);
178 goto retry;
179 }
180
181 nvlist_destroy(*nvl);
182 *nvl = NULL;
183
184 if (ret == 0) {
185 *nvl = nvlist_unpack(nv.data, nv.len, 0);
186 if (*nvl == NULL) {
187 ret = EIO;
188 goto out;
189 }
190 } else {
191 ret = errno;
192 }
193
194 out:
195 free(data);
196 free(nv.data);
197
198 return (ret);
199 }
200
201 static void
pf_nvuint_8_array(const nvlist_t * nvl,const char * name,size_t maxelems,uint8_t * numbers,size_t * nelems)202 pf_nvuint_8_array(const nvlist_t *nvl, const char *name, size_t maxelems,
203 uint8_t *numbers, size_t *nelems)
204 {
205 const uint64_t *tmp;
206 size_t elems;
207
208 tmp = nvlist_get_number_array(nvl, name, &elems);
209 assert(elems <= maxelems);
210
211 for (size_t i = 0; i < elems; i++)
212 numbers[i] = tmp[i];
213
214 if (nelems)
215 *nelems = elems;
216 }
217
218 static void
pf_nvuint_16_array(const nvlist_t * nvl,const char * name,size_t maxelems,uint16_t * numbers,size_t * nelems)219 pf_nvuint_16_array(const nvlist_t *nvl, const char *name, size_t maxelems,
220 uint16_t *numbers, size_t *nelems)
221 {
222 const uint64_t *tmp;
223 size_t elems;
224
225 tmp = nvlist_get_number_array(nvl, name, &elems);
226 assert(elems <= maxelems);
227
228 for (size_t i = 0; i < elems; i++)
229 numbers[i] = tmp[i];
230
231 if (nelems)
232 *nelems = elems;
233 }
234
235 static void
pf_nvuint_32_array(const nvlist_t * nvl,const char * name,size_t maxelems,uint32_t * numbers,size_t * nelems)236 pf_nvuint_32_array(const nvlist_t *nvl, const char *name, size_t maxelems,
237 uint32_t *numbers, size_t *nelems)
238 {
239 const uint64_t *tmp;
240 size_t elems;
241
242 tmp = nvlist_get_number_array(nvl, name, &elems);
243
244 for (size_t i = 0; i < elems && i < maxelems; i++)
245 numbers[i] = tmp[i];
246
247 if (nelems)
248 *nelems = elems;
249 }
250
251 static void
pf_nvuint_64_array(const nvlist_t * nvl,const char * name,size_t maxelems,uint64_t * numbers,size_t * nelems)252 pf_nvuint_64_array(const nvlist_t *nvl, const char *name, size_t maxelems,
253 uint64_t *numbers, size_t *nelems)
254 {
255 const uint64_t *tmp;
256 size_t elems;
257
258 tmp = nvlist_get_number_array(nvl, name, &elems);
259 assert(elems <= maxelems);
260
261 for (size_t i = 0; i < elems; i++)
262 numbers[i] = tmp[i];
263
264 if (nelems)
265 *nelems = elems;
266 }
267
268 int
pfctl_startstop(struct pfctl_handle * h,int start)269 pfctl_startstop(struct pfctl_handle *h, int start)
270 {
271 return (pfctl_do_netlink_cmd(h, start ? PFNL_CMD_START : PFNL_CMD_STOP));
272 }
273
274 static void
_pfctl_get_status_counters(const nvlist_t * nvl,struct pfctl_status_counters * counters)275 _pfctl_get_status_counters(const nvlist_t *nvl,
276 struct pfctl_status_counters *counters)
277 {
278 const uint64_t *ids, *counts;
279 const char *const *names;
280 size_t id_len, counter_len, names_len;
281
282 ids = nvlist_get_number_array(nvl, "ids", &id_len);
283 counts = nvlist_get_number_array(nvl, "counters", &counter_len);
284 names = nvlist_get_string_array(nvl, "names", &names_len);
285 assert(id_len == counter_len);
286 assert(counter_len == names_len);
287
288 TAILQ_INIT(counters);
289
290 for (size_t i = 0; i < id_len; i++) {
291 struct pfctl_status_counter *c;
292
293 c = malloc(sizeof(*c));
294 if (c == NULL)
295 continue;
296
297 c->id = ids[i];
298 c->counter = counts[i];
299 c->name = strdup(names[i]);
300
301 TAILQ_INSERT_TAIL(counters, c, entry);
302 }
303 }
304
305 #define _OUT(_field) offsetof(struct pfctl_status_counter, _field)
306 static const struct snl_attr_parser ap_counter[] = {
307 { .type = PF_C_COUNTER, .off = _OUT(counter), .cb = snl_attr_get_uint64 },
308 { .type = PF_C_NAME, .off = _OUT(name), .cb = snl_attr_get_string },
309 { .type = PF_C_ID, .off = _OUT(id), .cb = snl_attr_get_uint32 },
310 };
311 SNL_DECLARE_ATTR_PARSER(counter_parser, ap_counter);
312 #undef _OUT
313
314 static bool
snl_attr_get_counters(struct snl_state * ss,struct nlattr * nla,const void * arg __unused,void * target)315 snl_attr_get_counters(struct snl_state *ss, struct nlattr *nla,
316 const void *arg __unused, void *target)
317 {
318 struct pfctl_status_counter counter = {};
319 struct pfctl_status_counter *c;
320 bool error;
321
322 error = snl_parse_header(ss, NLA_DATA(nla), NLA_DATA_LEN(nla), &counter_parser, &counter);
323 if (! error)
324 return (error);
325
326 c = malloc(sizeof(*c));
327 if (c == NULL)
328 return (false);
329
330 c->id = counter.id;
331 c->counter = counter.counter;
332 c->name = strdup(counter.name);
333
334 TAILQ_INSERT_TAIL((struct pfctl_status_counters *)target, c, entry);
335
336 return (error);
337 }
338
339 struct snl_uint64_array {
340 uint64_t *array;
341 size_t count;
342 size_t max;
343 };
344 static bool
snl_attr_get_uint64_element(struct snl_state * ss,struct nlattr * nla,const void * arg,void * target)345 snl_attr_get_uint64_element(struct snl_state *ss, struct nlattr *nla,
346 const void *arg, void *target)
347 {
348 bool error;
349 uint64_t value;
350 struct snl_uint64_array *t = (struct snl_uint64_array *)target;
351
352 if (t->count >= t->max)
353 return (false);
354
355 error = snl_attr_get_uint64(ss, nla, arg, &value);
356 if (! error)
357 return (error);
358
359 t->array[t->count++] = value;
360
361 return (true);
362 }
363
364 static const struct snl_attr_parser ap_array[] = {
365 { .cb = snl_attr_get_uint64_element },
366 };
367 SNL_DECLARE_ATTR_PARSER(array_parser, ap_array);
368 static bool
snl_attr_get_uint64_array(struct snl_state * ss,struct nlattr * nla,const void * arg,void * target)369 snl_attr_get_uint64_array(struct snl_state *ss, struct nlattr *nla,
370 const void *arg, void *target)
371 {
372 struct snl_uint64_array a = {
373 .array = target,
374 .count = 0,
375 .max = (size_t)arg,
376 };
377 bool error;
378
379 error = snl_parse_header(ss, NLA_DATA(nla), NLA_DATA_LEN(nla), &array_parser, &a);
380 if (! error)
381 return (error);
382
383 return (true);
384 }
385
386 #define _OUT(_field) offsetof(struct pfctl_status, _field)
387 static const struct snl_attr_parser ap_getstatus[] = {
388 { .type = PF_GS_IFNAME, .off = _OUT(ifname), .arg_u32 = IFNAMSIZ, .cb = snl_attr_copy_string },
389 { .type = PF_GS_RUNNING, .off = _OUT(running), .cb = snl_attr_get_bool },
390 { .type = PF_GS_SINCE, .off = _OUT(since), .cb = snl_attr_get_uint32 },
391 { .type = PF_GS_DEBUG, .off = _OUT(debug), .cb = snl_attr_get_uint32 },
392 { .type = PF_GS_HOSTID, .off = _OUT(hostid), .cb = snl_attr_get_uint32 },
393 { .type = PF_GS_STATES, .off = _OUT(states), .cb = snl_attr_get_uint32 },
394 { .type = PF_GS_SRC_NODES, .off = _OUT(src_nodes), .cb = snl_attr_get_uint32 },
395 { .type = PF_GS_REASSEMBLE, .off = _OUT(reass), .cb = snl_attr_get_uint32 },
396 { .type = PF_GS_SYNCOOKIES_ACTIVE, .off = _OUT(syncookies_active), .cb = snl_attr_get_uint32 },
397 { .type = PF_GS_COUNTERS, .off = _OUT(counters), .cb = snl_attr_get_counters },
398 { .type = PF_GS_LCOUNTERS, .off = _OUT(lcounters), .cb = snl_attr_get_counters },
399 { .type = PF_GS_FCOUNTERS, .off = _OUT(fcounters), .cb = snl_attr_get_counters },
400 { .type = PF_GS_SCOUNTERS, .off = _OUT(scounters), .cb = snl_attr_get_counters },
401 { .type = PF_GS_CHKSUM, .off = _OUT(pf_chksum), .arg_u32 = PF_MD5_DIGEST_LENGTH, .cb = snl_attr_get_bytes },
402 { .type = PF_GS_PCOUNTERS, .off = _OUT(pcounters), .arg_u32 = 2 * 2 * 2, .cb = snl_attr_get_uint64_array },
403 { .type = PF_GS_BCOUNTERS, .off = _OUT(bcounters), .arg_u32 = 2 * 2, .cb = snl_attr_get_uint64_array },
404 { .type = PF_GS_NCOUNTERS, .off = _OUT(ncounters), .cb = snl_attr_get_counters },
405 { .type = PF_GS_FRAGMENTS, .off = _OUT(fragments), .cb = snl_attr_get_uint64 },
406 };
407 SNL_DECLARE_PARSER(getstatus_parser, struct genlmsghdr, snl_f_p_empty, ap_getstatus);
408 #undef _OUT
409
410 struct pfctl_status *
pfctl_get_status_h(struct pfctl_handle * h)411 pfctl_get_status_h(struct pfctl_handle *h)
412 {
413 struct pfctl_status *status = NULL;
414 struct snl_errmsg_data e = {};
415 struct nlmsghdr *hdr;
416 struct snl_writer nw;
417 uint32_t seq_id;
418
419 snl_init_writer(&h->ss, &nw);
420 hdr = snl_create_genl_msg_request(&nw, h->family_id,
421 PFNL_CMD_GET_STATUS);
422 hdr->nlmsg_flags |= NLM_F_DUMP;
423
424 hdr = snl_finalize_msg(&nw);
425 if (hdr == NULL)
426 goto out;
427
428 seq_id = hdr->nlmsg_seq;
429 if (! snl_send_message(&h->ss, hdr))
430 goto out;
431
432 status = calloc(1, sizeof(*status));
433 if (status == NULL)
434 goto out;
435
436 TAILQ_INIT(&status->counters);
437 TAILQ_INIT(&status->lcounters);
438 TAILQ_INIT(&status->fcounters);
439 TAILQ_INIT(&status->scounters);
440 TAILQ_INIT(&status->ncounters);
441
442 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
443 if (! snl_parse_nlmsg(&h->ss, hdr, &getstatus_parser, status))
444 continue;
445 }
446
447 out:
448 snl_clear_lb(&h->ss);
449 return (status);
450 }
451
452 struct pfctl_status *
pfctl_get_status(int dev)453 pfctl_get_status(int dev)
454 {
455 struct pfctl_status *status;
456 nvlist_t *nvl;
457 size_t len;
458 const void *chksum;
459
460 status = calloc(1, sizeof(*status));
461 if (status == NULL)
462 return (NULL);
463
464 nvl = nvlist_create(0);
465
466 if (pfctl_do_ioctl(dev, DIOCGETSTATUSNV, 4096, &nvl)) {
467 nvlist_destroy(nvl);
468 free(status);
469 return (NULL);
470 }
471
472 status->running = nvlist_get_bool(nvl, "running");
473 status->since = nvlist_get_number(nvl, "since");
474 status->debug = nvlist_get_number(nvl, "debug");
475 status->hostid = ntohl(nvlist_get_number(nvl, "hostid"));
476 status->states = nvlist_get_number(nvl, "states");
477 status->src_nodes = nvlist_get_number(nvl, "src_nodes");
478 status->syncookies_active = nvlist_get_bool(nvl, "syncookies_active");
479 status->reass = nvlist_get_number(nvl, "reass");
480
481 strlcpy(status->ifname, nvlist_get_string(nvl, "ifname"),
482 IFNAMSIZ);
483 chksum = nvlist_get_binary(nvl, "chksum", &len);
484 assert(len == PF_MD5_DIGEST_LENGTH);
485 memcpy(status->pf_chksum, chksum, len);
486
487 _pfctl_get_status_counters(nvlist_get_nvlist(nvl, "counters"),
488 &status->counters);
489 _pfctl_get_status_counters(nvlist_get_nvlist(nvl, "lcounters"),
490 &status->lcounters);
491 _pfctl_get_status_counters(nvlist_get_nvlist(nvl, "fcounters"),
492 &status->fcounters);
493 _pfctl_get_status_counters(nvlist_get_nvlist(nvl, "scounters"),
494 &status->scounters);
495
496 pf_nvuint_64_array(nvl, "pcounters", 2 * 2 * 2,
497 (uint64_t *)status->pcounters, NULL);
498 pf_nvuint_64_array(nvl, "bcounters", 2 * 2,
499 (uint64_t *)status->bcounters, NULL);
500
501 nvlist_destroy(nvl);
502
503 return (status);
504 }
505 int
pfctl_clear_status(struct pfctl_handle * h)506 pfctl_clear_status(struct pfctl_handle *h)
507 {
508 return (pfctl_do_netlink_cmd(h, PFNL_CMD_CLEAR_STATUS));
509 }
510
511 static uint64_t
_pfctl_status_counter(struct pfctl_status_counters * counters,uint64_t id)512 _pfctl_status_counter(struct pfctl_status_counters *counters, uint64_t id)
513 {
514 struct pfctl_status_counter *c;
515
516 TAILQ_FOREACH(c, counters, entry) {
517 if (c->id == id)
518 return (c->counter);
519 }
520
521 return (0);
522 }
523
524 uint64_t
pfctl_status_counter(struct pfctl_status * status,int id)525 pfctl_status_counter(struct pfctl_status *status, int id)
526 {
527 return (_pfctl_status_counter(&status->counters, id));
528 }
529
530 uint64_t
pfctl_status_lcounter(struct pfctl_status * status,int id)531 pfctl_status_lcounter(struct pfctl_status *status, int id)
532 {
533 return (_pfctl_status_counter(&status->lcounters, id));
534 }
535
536 uint64_t
pfctl_status_fcounter(struct pfctl_status * status,int id)537 pfctl_status_fcounter(struct pfctl_status *status, int id)
538 {
539 return (_pfctl_status_counter(&status->fcounters, id));
540 }
541
542 uint64_t
pfctl_status_scounter(struct pfctl_status * status,int id)543 pfctl_status_scounter(struct pfctl_status *status, int id)
544 {
545 return (_pfctl_status_counter(&status->scounters, id));
546 }
547
548 void
pfctl_free_status(struct pfctl_status * status)549 pfctl_free_status(struct pfctl_status *status)
550 {
551 struct pfctl_status_counter *c, *tmp;
552
553 if (status == NULL)
554 return;
555
556 TAILQ_FOREACH_SAFE(c, &status->counters, entry, tmp) {
557 free(c->name);
558 free(c);
559 }
560 TAILQ_FOREACH_SAFE(c, &status->lcounters, entry, tmp) {
561 free(c->name);
562 free(c);
563 }
564 TAILQ_FOREACH_SAFE(c, &status->fcounters, entry, tmp) {
565 free(c->name);
566 free(c);
567 }
568 TAILQ_FOREACH_SAFE(c, &status->scounters, entry, tmp) {
569 free(c->name);
570 free(c);
571 }
572 TAILQ_FOREACH_SAFE(c, &status->ncounters, entry, tmp) {
573 free(c->name);
574 free(c);
575 }
576
577 free(status);
578 }
579
580 static void
pfctl_nv_add_addr(nvlist_t * nvparent,const char * name,const struct pf_addr * addr)581 pfctl_nv_add_addr(nvlist_t *nvparent, const char *name,
582 const struct pf_addr *addr)
583 {
584 nvlist_t *nvl = nvlist_create(0);
585
586 nvlist_add_binary(nvl, "addr", addr, sizeof(*addr));
587
588 nvlist_add_nvlist(nvparent, name, nvl);
589 nvlist_destroy(nvl);
590 }
591
592 static void
pf_nvaddr_to_addr(const nvlist_t * nvl,struct pf_addr * addr)593 pf_nvaddr_to_addr(const nvlist_t *nvl, struct pf_addr *addr)
594 {
595 size_t len;
596 const void *data;
597
598 data = nvlist_get_binary(nvl, "addr", &len);
599 assert(len == sizeof(struct pf_addr));
600 memcpy(addr, data, len);
601 }
602
603 static void
pfctl_nv_add_addr_wrap(nvlist_t * nvparent,const char * name,const struct pf_addr_wrap * addr)604 pfctl_nv_add_addr_wrap(nvlist_t *nvparent, const char *name,
605 const struct pf_addr_wrap *addr)
606 {
607 nvlist_t *nvl = nvlist_create(0);
608
609 nvlist_add_number(nvl, "type", addr->type);
610 nvlist_add_number(nvl, "iflags", addr->iflags);
611 if (addr->type == PF_ADDR_DYNIFTL)
612 nvlist_add_string(nvl, "ifname", addr->v.ifname);
613 if (addr->type == PF_ADDR_TABLE)
614 nvlist_add_string(nvl, "tblname", addr->v.tblname);
615 pfctl_nv_add_addr(nvl, "addr", &addr->v.a.addr);
616 pfctl_nv_add_addr(nvl, "mask", &addr->v.a.mask);
617
618 nvlist_add_nvlist(nvparent, name, nvl);
619 nvlist_destroy(nvl);
620 }
621
622 static void
pf_nvaddr_wrap_to_addr_wrap(const nvlist_t * nvl,struct pf_addr_wrap * addr)623 pf_nvaddr_wrap_to_addr_wrap(const nvlist_t *nvl, struct pf_addr_wrap *addr)
624 {
625 bzero(addr, sizeof(*addr));
626
627 addr->type = nvlist_get_number(nvl, "type");
628 addr->iflags = nvlist_get_number(nvl, "iflags");
629 if (addr->type == PF_ADDR_DYNIFTL) {
630 strlcpy(addr->v.ifname, nvlist_get_string(nvl, "ifname"),
631 IFNAMSIZ);
632 addr->p.dyncnt = nvlist_get_number(nvl, "dyncnt");
633 }
634 if (addr->type == PF_ADDR_TABLE) {
635 strlcpy(addr->v.tblname, nvlist_get_string(nvl, "tblname"),
636 PF_TABLE_NAME_SIZE);
637 addr->p.tblcnt = nvlist_get_number(nvl, "tblcnt");
638 }
639
640 pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "addr"), &addr->v.a.addr);
641 pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "mask"), &addr->v.a.mask);
642 }
643
644 static void
pfctl_nv_add_rule_addr(nvlist_t * nvparent,const char * name,const struct pf_rule_addr * addr)645 pfctl_nv_add_rule_addr(nvlist_t *nvparent, const char *name,
646 const struct pf_rule_addr *addr)
647 {
648 uint64_t ports[2];
649 nvlist_t *nvl = nvlist_create(0);
650
651 pfctl_nv_add_addr_wrap(nvl, "addr", &addr->addr);
652 ports[0] = addr->port[0];
653 ports[1] = addr->port[1];
654 nvlist_add_number_array(nvl, "port", ports, 2);
655 nvlist_add_number(nvl, "neg", addr->neg);
656 nvlist_add_number(nvl, "port_op", addr->port_op);
657
658 nvlist_add_nvlist(nvparent, name, nvl);
659 nvlist_destroy(nvl);
660 }
661
662 static void
pf_nvrule_addr_to_rule_addr(const nvlist_t * nvl,struct pf_rule_addr * addr)663 pf_nvrule_addr_to_rule_addr(const nvlist_t *nvl, struct pf_rule_addr *addr)
664 {
665 pf_nvaddr_wrap_to_addr_wrap(nvlist_get_nvlist(nvl, "addr"), &addr->addr);
666
667 pf_nvuint_16_array(nvl, "port", 2, addr->port, NULL);
668 addr->neg = nvlist_get_number(nvl, "neg");
669 addr->port_op = nvlist_get_number(nvl, "port_op");
670 }
671
672 static void
pf_nvmape_to_mape(const nvlist_t * nvl,struct pf_mape_portset * mape)673 pf_nvmape_to_mape(const nvlist_t *nvl, struct pf_mape_portset *mape)
674 {
675 mape->offset = nvlist_get_number(nvl, "offset");
676 mape->psidlen = nvlist_get_number(nvl, "psidlen");
677 mape->psid = nvlist_get_number(nvl, "psid");
678 }
679
680 static void
pf_nvpool_to_pool(const nvlist_t * nvl,struct pfctl_pool * pool)681 pf_nvpool_to_pool(const nvlist_t *nvl, struct pfctl_pool *pool)
682 {
683 size_t len;
684 const void *data;
685
686 data = nvlist_get_binary(nvl, "key", &len);
687 assert(len == sizeof(pool->key));
688 memcpy(&pool->key, data, len);
689
690 pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "counter"), &pool->counter);
691
692 pool->tblidx = nvlist_get_number(nvl, "tblidx");
693 pf_nvuint_16_array(nvl, "proxy_port", 2, pool->proxy_port, NULL);
694 pool->opts = nvlist_get_number(nvl, "opts");
695
696 if (nvlist_exists_nvlist(nvl, "mape"))
697 pf_nvmape_to_mape(nvlist_get_nvlist(nvl, "mape"), &pool->mape);
698 }
699
700 static void
pf_nvrule_uid_to_rule_uid(const nvlist_t * nvl,struct pf_rule_uid * uid)701 pf_nvrule_uid_to_rule_uid(const nvlist_t *nvl, struct pf_rule_uid *uid)
702 {
703 pf_nvuint_32_array(nvl, "uid", 2, uid->uid, NULL);
704 uid->op = nvlist_get_number(nvl, "op");
705 }
706
707 static void
pf_nvdivert_to_divert(const nvlist_t * nvl,struct pfctl_rule * rule)708 pf_nvdivert_to_divert(const nvlist_t *nvl, struct pfctl_rule *rule)
709 {
710 pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "addr"), &rule->divert.addr);
711 rule->divert.port = nvlist_get_number(nvl, "port");
712 }
713
714 static void
pf_nvrule_to_rule(const nvlist_t * nvl,struct pfctl_rule * rule)715 pf_nvrule_to_rule(const nvlist_t *nvl, struct pfctl_rule *rule)
716 {
717 const uint64_t *skip;
718 const char *const *labels;
719 size_t skipcount, labelcount;
720
721 rule->nr = nvlist_get_number(nvl, "nr");
722
723 pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "src"), &rule->src);
724 pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "dst"), &rule->dst);
725
726 skip = nvlist_get_number_array(nvl, "skip", &skipcount);
727 assert(skip);
728 assert(skipcount == PF_SKIP_COUNT);
729 for (int i = 0; i < PF_SKIP_COUNT; i++)
730 rule->skip[i].nr = skip[i];
731
732 labels = nvlist_get_string_array(nvl, "labels", &labelcount);
733 assert(labelcount <= PF_RULE_MAX_LABEL_COUNT);
734 for (size_t i = 0; i < labelcount; i++)
735 strlcpy(rule->label[i], labels[i], PF_RULE_LABEL_SIZE);
736 rule->ridentifier = nvlist_get_number(nvl, "ridentifier");
737 strlcpy(rule->ifname, nvlist_get_string(nvl, "ifname"), IFNAMSIZ);
738 strlcpy(rule->qname, nvlist_get_string(nvl, "qname"), PF_QNAME_SIZE);
739 strlcpy(rule->pqname, nvlist_get_string(nvl, "pqname"), PF_QNAME_SIZE);
740 strlcpy(rule->tagname, nvlist_get_string(nvl, "tagname"),
741 PF_TAG_NAME_SIZE);
742 strlcpy(rule->match_tagname, nvlist_get_string(nvl, "match_tagname"),
743 PF_TAG_NAME_SIZE);
744
745 strlcpy(rule->overload_tblname, nvlist_get_string(nvl, "overload_tblname"),
746 PF_TABLE_NAME_SIZE);
747
748 pf_nvpool_to_pool(nvlist_get_nvlist(nvl, "rpool"), &rule->rdr);
749
750 rule->evaluations = nvlist_get_number(nvl, "evaluations");
751 pf_nvuint_64_array(nvl, "packets", 2, rule->packets, NULL);
752 pf_nvuint_64_array(nvl, "bytes", 2, rule->bytes, NULL);
753
754 if (nvlist_exists_number(nvl, "timestamp")) {
755 rule->last_active_timestamp = nvlist_get_number(nvl, "timestamp");
756 }
757
758 rule->os_fingerprint = nvlist_get_number(nvl, "os_fingerprint");
759
760 rule->rtableid = nvlist_get_number(nvl, "rtableid");
761 pf_nvuint_32_array(nvl, "timeout", PFTM_MAX, rule->timeout, NULL);
762 rule->max_states = nvlist_get_number(nvl, "max_states");
763 rule->max_src_nodes = nvlist_get_number(nvl, "max_src_nodes");
764 rule->max_src_states = nvlist_get_number(nvl, "max_src_states");
765 rule->max_src_conn = nvlist_get_number(nvl, "max_src_conn");
766 rule->max_src_conn_rate.limit =
767 nvlist_get_number(nvl, "max_src_conn_rate.limit");
768 rule->max_src_conn_rate.seconds =
769 nvlist_get_number(nvl, "max_src_conn_rate.seconds");
770 rule->qid = nvlist_get_number(nvl, "qid");
771 rule->pqid = nvlist_get_number(nvl, "pqid");
772 rule->dnpipe = nvlist_get_number(nvl, "dnpipe");
773 rule->dnrpipe = nvlist_get_number(nvl, "dnrpipe");
774 rule->free_flags = nvlist_get_number(nvl, "dnflags");
775 rule->prob = nvlist_get_number(nvl, "prob");
776 rule->cuid = nvlist_get_number(nvl, "cuid");
777 rule->cpid = nvlist_get_number(nvl, "cpid");
778
779 rule->return_icmp = nvlist_get_number(nvl, "return_icmp");
780 rule->return_icmp6 = nvlist_get_number(nvl, "return_icmp6");
781 rule->max_mss = nvlist_get_number(nvl, "max_mss");
782 rule->scrub_flags = nvlist_get_number(nvl, "scrub_flags");
783
784 pf_nvrule_uid_to_rule_uid(nvlist_get_nvlist(nvl, "uid"), &rule->uid);
785 pf_nvrule_uid_to_rule_uid(nvlist_get_nvlist(nvl, "gid"),
786 (struct pf_rule_uid *)&rule->gid);
787
788 rule->rule_flag = nvlist_get_number(nvl, "rule_flag");
789 rule->action = nvlist_get_number(nvl, "action");
790 rule->direction = nvlist_get_number(nvl, "direction");
791 rule->log = nvlist_get_number(nvl, "log");
792 rule->logif = nvlist_get_number(nvl, "logif");
793 rule->quick = nvlist_get_number(nvl, "quick");
794 rule->ifnot = nvlist_get_number(nvl, "ifnot");
795 rule->match_tag_not = nvlist_get_number(nvl, "match_tag_not");
796 rule->natpass = nvlist_get_number(nvl, "natpass");
797
798 rule->keep_state = nvlist_get_number(nvl, "keep_state");
799 rule->af = nvlist_get_number(nvl, "af");
800 rule->proto = nvlist_get_number(nvl, "proto");
801 rule->type = nvlist_get_number(nvl, "type");
802 rule->code = nvlist_get_number(nvl, "code");
803 rule->flags = nvlist_get_number(nvl, "flags");
804 rule->flagset = nvlist_get_number(nvl, "flagset");
805 rule->min_ttl = nvlist_get_number(nvl, "min_ttl");
806 rule->allow_opts = nvlist_get_number(nvl, "allow_opts");
807 rule->rt = nvlist_get_number(nvl, "rt");
808 rule->return_ttl = nvlist_get_number(nvl, "return_ttl");
809 rule->tos = nvlist_get_number(nvl, "tos");
810 rule->set_tos = nvlist_get_number(nvl, "set_tos");
811 rule->anchor_relative = nvlist_get_number(nvl, "anchor_relative");
812 rule->anchor_wildcard = nvlist_get_number(nvl, "anchor_wildcard");
813
814 rule->flush = nvlist_get_number(nvl, "flush");
815 rule->prio = nvlist_get_number(nvl, "prio");
816 pf_nvuint_8_array(nvl, "set_prio", 2, rule->set_prio, NULL);
817
818 pf_nvdivert_to_divert(nvlist_get_nvlist(nvl, "divert"), rule);
819
820 rule->states_cur = nvlist_get_number(nvl, "states_cur");
821 rule->states_tot = nvlist_get_number(nvl, "states_tot");
822 rule->src_nodes = nvlist_get_number(nvl, "src_nodes");
823 }
824
825 static void
pfctl_nveth_addr_to_eth_addr(const nvlist_t * nvl,struct pfctl_eth_addr * addr)826 pfctl_nveth_addr_to_eth_addr(const nvlist_t *nvl, struct pfctl_eth_addr *addr)
827 {
828 static const u_int8_t EMPTY_MAC[ETHER_ADDR_LEN] = { 0 };
829 size_t len;
830 const void *data;
831
832 data = nvlist_get_binary(nvl, "addr", &len);
833 assert(len == sizeof(addr->addr));
834 memcpy(addr->addr, data, sizeof(addr->addr));
835
836 data = nvlist_get_binary(nvl, "mask", &len);
837 assert(len == sizeof(addr->mask));
838 memcpy(addr->mask, data, sizeof(addr->mask));
839
840 addr->neg = nvlist_get_bool(nvl, "neg");
841
842 /* To make checks for 'is this address set?' easier. */
843 addr->isset = memcmp(addr->addr, EMPTY_MAC, ETHER_ADDR_LEN) != 0;
844 }
845
846 static nvlist_t *
pfctl_eth_addr_to_nveth_addr(const struct pfctl_eth_addr * addr)847 pfctl_eth_addr_to_nveth_addr(const struct pfctl_eth_addr *addr)
848 {
849 nvlist_t *nvl;
850
851 nvl = nvlist_create(0);
852 if (nvl == NULL)
853 return (NULL);
854
855 nvlist_add_bool(nvl, "neg", addr->neg);
856 nvlist_add_binary(nvl, "addr", &addr->addr, ETHER_ADDR_LEN);
857 nvlist_add_binary(nvl, "mask", &addr->mask, ETHER_ADDR_LEN);
858
859 return (nvl);
860 }
861
862 static void
pfctl_nveth_rule_to_eth_rule(const nvlist_t * nvl,struct pfctl_eth_rule * rule)863 pfctl_nveth_rule_to_eth_rule(const nvlist_t *nvl, struct pfctl_eth_rule *rule)
864 {
865 const char *const *labels;
866 size_t labelcount, i;
867
868 rule->nr = nvlist_get_number(nvl, "nr");
869 rule->quick = nvlist_get_bool(nvl, "quick");
870 strlcpy(rule->ifname, nvlist_get_string(nvl, "ifname"), IFNAMSIZ);
871 rule->ifnot = nvlist_get_bool(nvl, "ifnot");
872 rule->direction = nvlist_get_number(nvl, "direction");
873 rule->proto = nvlist_get_number(nvl, "proto");
874 strlcpy(rule->match_tagname, nvlist_get_string(nvl, "match_tagname"),
875 PF_TAG_NAME_SIZE);
876 rule->match_tag = nvlist_get_number(nvl, "match_tag");
877 rule->match_tag_not = nvlist_get_bool(nvl, "match_tag_not");
878
879 labels = nvlist_get_string_array(nvl, "labels", &labelcount);
880 assert(labelcount <= PF_RULE_MAX_LABEL_COUNT);
881 for (i = 0; i < labelcount; i++)
882 strlcpy(rule->label[i], labels[i], PF_RULE_LABEL_SIZE);
883 rule->ridentifier = nvlist_get_number(nvl, "ridentifier");
884
885 pfctl_nveth_addr_to_eth_addr(nvlist_get_nvlist(nvl, "src"),
886 &rule->src);
887 pfctl_nveth_addr_to_eth_addr(nvlist_get_nvlist(nvl, "dst"),
888 &rule->dst);
889
890 pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "ipsrc"),
891 &rule->ipsrc);
892 pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "ipdst"),
893 &rule->ipdst);
894
895 rule->evaluations = nvlist_get_number(nvl, "evaluations");
896 rule->packets[0] = nvlist_get_number(nvl, "packets-in");
897 rule->packets[1] = nvlist_get_number(nvl, "packets-out");
898 rule->bytes[0] = nvlist_get_number(nvl, "bytes-in");
899 rule->bytes[1] = nvlist_get_number(nvl, "bytes-out");
900
901 if (nvlist_exists_number(nvl, "timestamp")) {
902 rule->last_active_timestamp = nvlist_get_number(nvl, "timestamp");
903 }
904
905 strlcpy(rule->qname, nvlist_get_string(nvl, "qname"), PF_QNAME_SIZE);
906 strlcpy(rule->tagname, nvlist_get_string(nvl, "tagname"),
907 PF_TAG_NAME_SIZE);
908
909 rule->dnpipe = nvlist_get_number(nvl, "dnpipe");
910 rule->dnflags = nvlist_get_number(nvl, "dnflags");
911
912 rule->anchor_relative = nvlist_get_number(nvl, "anchor_relative");
913 rule->anchor_wildcard = nvlist_get_number(nvl, "anchor_wildcard");
914
915 strlcpy(rule->bridge_to, nvlist_get_string(nvl, "bridge_to"),
916 IFNAMSIZ);
917
918 rule->action = nvlist_get_number(nvl, "action");
919 }
920
921 int
pfctl_get_eth_rulesets_info(int dev,struct pfctl_eth_rulesets_info * ri,const char * path)922 pfctl_get_eth_rulesets_info(int dev, struct pfctl_eth_rulesets_info *ri,
923 const char *path)
924 {
925 nvlist_t *nvl;
926 int ret;
927
928 bzero(ri, sizeof(*ri));
929
930 nvl = nvlist_create(0);
931 nvlist_add_string(nvl, "path", path);
932
933 if ((ret = pfctl_do_ioctl(dev, DIOCGETETHRULESETS, 256, &nvl)) != 0)
934 goto out;
935
936 ri->nr = nvlist_get_number(nvl, "nr");
937
938 out:
939 nvlist_destroy(nvl);
940 return (ret);
941 }
942
943 int
pfctl_get_eth_ruleset(int dev,const char * path,int nr,struct pfctl_eth_ruleset_info * ri)944 pfctl_get_eth_ruleset(int dev, const char *path, int nr,
945 struct pfctl_eth_ruleset_info *ri)
946 {
947 nvlist_t *nvl;
948 int ret;
949
950 bzero(ri, sizeof(*ri));
951
952 nvl = nvlist_create(0);
953 nvlist_add_string(nvl, "path", path);
954 nvlist_add_number(nvl, "nr", nr);
955
956 if ((ret = pfctl_do_ioctl(dev, DIOCGETETHRULESET, 1024, &nvl)) != 0)
957 goto out;
958
959 ri->nr = nvlist_get_number(nvl, "nr");
960 strlcpy(ri->path, nvlist_get_string(nvl, "path"), MAXPATHLEN);
961 strlcpy(ri->name, nvlist_get_string(nvl, "name"),
962 PF_ANCHOR_NAME_SIZE);
963
964 out:
965 nvlist_destroy(nvl);
966 return (ret);
967 }
968
969 int
pfctl_get_eth_rules_info(int dev,struct pfctl_eth_rules_info * rules,const char * path)970 pfctl_get_eth_rules_info(int dev, struct pfctl_eth_rules_info *rules,
971 const char *path)
972 {
973 nvlist_t *nvl;
974 int ret;
975
976 bzero(rules, sizeof(*rules));
977
978 nvl = nvlist_create(0);
979 nvlist_add_string(nvl, "anchor", path);
980
981 if ((ret = pfctl_do_ioctl(dev, DIOCGETETHRULES, 1024, &nvl)) != 0)
982 goto out;
983
984 rules->nr = nvlist_get_number(nvl, "nr");
985 rules->ticket = nvlist_get_number(nvl, "ticket");
986
987 out:
988 nvlist_destroy(nvl);
989 return (ret);
990 }
991
992 int
pfctl_get_eth_rule(int dev,uint32_t nr,uint32_t ticket,const char * path,struct pfctl_eth_rule * rule,bool clear,char * anchor_call)993 pfctl_get_eth_rule(int dev, uint32_t nr, uint32_t ticket,
994 const char *path, struct pfctl_eth_rule *rule, bool clear,
995 char *anchor_call)
996 {
997 nvlist_t *nvl;
998 int ret;
999
1000 nvl = nvlist_create(0);
1001
1002 nvlist_add_string(nvl, "anchor", path);
1003 nvlist_add_number(nvl, "ticket", ticket);
1004 nvlist_add_number(nvl, "nr", nr);
1005 nvlist_add_bool(nvl, "clear", clear);
1006
1007 if ((ret = pfctl_do_ioctl(dev, DIOCGETETHRULE, 4096, &nvl)) != 0)
1008 goto out;
1009
1010 pfctl_nveth_rule_to_eth_rule(nvl, rule);
1011
1012 if (anchor_call)
1013 strlcpy(anchor_call, nvlist_get_string(nvl, "anchor_call"),
1014 MAXPATHLEN);
1015
1016 out:
1017 nvlist_destroy(nvl);
1018 return (ret);
1019 }
1020
1021 int
pfctl_add_eth_rule(int dev,const struct pfctl_eth_rule * r,const char * anchor,const char * anchor_call,uint32_t ticket)1022 pfctl_add_eth_rule(int dev, const struct pfctl_eth_rule *r, const char *anchor,
1023 const char *anchor_call, uint32_t ticket)
1024 {
1025 struct pfioc_nv nv;
1026 nvlist_t *nvl, *addr;
1027 void *packed;
1028 int error = 0;
1029 size_t labelcount, size;
1030
1031 nvl = nvlist_create(0);
1032
1033 nvlist_add_number(nvl, "ticket", ticket);
1034 nvlist_add_string(nvl, "anchor", anchor);
1035 nvlist_add_string(nvl, "anchor_call", anchor_call);
1036
1037 nvlist_add_number(nvl, "nr", r->nr);
1038 nvlist_add_bool(nvl, "quick", r->quick);
1039 nvlist_add_string(nvl, "ifname", r->ifname);
1040 nvlist_add_bool(nvl, "ifnot", r->ifnot);
1041 nvlist_add_number(nvl, "direction", r->direction);
1042 nvlist_add_number(nvl, "proto", r->proto);
1043 nvlist_add_string(nvl, "match_tagname", r->match_tagname);
1044 nvlist_add_bool(nvl, "match_tag_not", r->match_tag_not);
1045
1046 addr = pfctl_eth_addr_to_nveth_addr(&r->src);
1047 if (addr == NULL) {
1048 nvlist_destroy(nvl);
1049 return (ENOMEM);
1050 }
1051 nvlist_add_nvlist(nvl, "src", addr);
1052 nvlist_destroy(addr);
1053
1054 addr = pfctl_eth_addr_to_nveth_addr(&r->dst);
1055 if (addr == NULL) {
1056 nvlist_destroy(nvl);
1057 return (ENOMEM);
1058 }
1059 nvlist_add_nvlist(nvl, "dst", addr);
1060 nvlist_destroy(addr);
1061
1062 pfctl_nv_add_rule_addr(nvl, "ipsrc", &r->ipsrc);
1063 pfctl_nv_add_rule_addr(nvl, "ipdst", &r->ipdst);
1064
1065 labelcount = 0;
1066 while (labelcount < PF_RULE_MAX_LABEL_COUNT &&
1067 r->label[labelcount][0] != 0) {
1068 nvlist_append_string_array(nvl, "labels",
1069 r->label[labelcount]);
1070 labelcount++;
1071 }
1072 nvlist_add_number(nvl, "ridentifier", r->ridentifier);
1073
1074 nvlist_add_string(nvl, "qname", r->qname);
1075 nvlist_add_string(nvl, "tagname", r->tagname);
1076 nvlist_add_number(nvl, "dnpipe", r->dnpipe);
1077 nvlist_add_number(nvl, "dnflags", r->dnflags);
1078
1079 nvlist_add_string(nvl, "bridge_to", r->bridge_to);
1080
1081 nvlist_add_number(nvl, "action", r->action);
1082
1083 packed = nvlist_pack(nvl, &size);
1084 if (packed == NULL) {
1085 nvlist_destroy(nvl);
1086 return (ENOMEM);
1087 }
1088
1089 nv.len = size;
1090 nv.size = size;
1091 nv.data = packed;
1092
1093 if (ioctl(dev, DIOCADDETHRULE, &nv) != 0)
1094 error = errno;
1095
1096 free(packed);
1097 nvlist_destroy(nvl);
1098
1099 return (error);
1100 }
1101
1102 static void
snl_add_msg_attr_addr_wrap(struct snl_writer * nw,uint32_t type,const struct pf_addr_wrap * addr)1103 snl_add_msg_attr_addr_wrap(struct snl_writer *nw, uint32_t type, const struct pf_addr_wrap *addr)
1104 {
1105 int off;
1106
1107 off = snl_add_msg_attr_nested(nw, type);
1108
1109 snl_add_msg_attr_ip6(nw, PF_AT_ADDR, &addr->v.a.addr.v6);
1110 snl_add_msg_attr_ip6(nw, PF_AT_MASK, &addr->v.a.mask.v6);
1111
1112 if (addr->type == PF_ADDR_DYNIFTL)
1113 snl_add_msg_attr_string(nw, PF_AT_IFNAME, addr->v.ifname);
1114 if (addr->type == PF_ADDR_TABLE)
1115 snl_add_msg_attr_string(nw, PF_AT_TABLENAME, addr->v.tblname);
1116 snl_add_msg_attr_u8(nw, PF_AT_TYPE, addr->type);
1117 snl_add_msg_attr_u8(nw, PF_AT_IFLAGS, addr->iflags);
1118
1119 snl_end_attr_nested(nw, off);
1120 }
1121
1122 static void
snl_add_msg_attr_pool_addr(struct snl_writer * nw,uint32_t type,const struct pf_pooladdr * pa)1123 snl_add_msg_attr_pool_addr(struct snl_writer *nw, uint32_t type, const struct pf_pooladdr *pa)
1124 {
1125 int off;
1126
1127 off = snl_add_msg_attr_nested(nw, type);
1128
1129 snl_add_msg_attr_string(nw, PF_PA_IFNAME, pa->ifname);
1130 snl_add_msg_attr_addr_wrap(nw, PF_PA_ADDR, &pa->addr);
1131
1132 snl_end_attr_nested(nw, off);
1133 }
1134
1135 static void
snl_add_msg_attr_rule_addr(struct snl_writer * nw,uint32_t type,const struct pf_rule_addr * addr)1136 snl_add_msg_attr_rule_addr(struct snl_writer *nw, uint32_t type, const struct pf_rule_addr *addr)
1137 {
1138 int off;
1139
1140 off = snl_add_msg_attr_nested(nw, type);
1141
1142 snl_add_msg_attr_addr_wrap(nw, PF_RAT_ADDR, &addr->addr);
1143 snl_add_msg_attr_u16(nw, PF_RAT_SRC_PORT, addr->port[0]);
1144 snl_add_msg_attr_u16(nw, PF_RAT_DST_PORT, addr->port[1]);
1145 snl_add_msg_attr_u8(nw, PF_RAT_NEG, addr->neg);
1146 snl_add_msg_attr_u8(nw, PF_RAT_OP, addr->port_op);
1147
1148 snl_end_attr_nested(nw, off);
1149 }
1150
1151 static void
snl_add_msg_attr_rule_labels(struct snl_writer * nw,uint32_t type,const char labels[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE])1152 snl_add_msg_attr_rule_labels(struct snl_writer *nw, uint32_t type, const char labels[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE])
1153 {
1154 int off, i = 0;
1155
1156 off = snl_add_msg_attr_nested(nw, type);
1157
1158 while (i < PF_RULE_MAX_LABEL_COUNT &&
1159 labels[i][0] != 0) {
1160 snl_add_msg_attr_string(nw, PF_LT_LABEL, labels[i]);
1161 i++;
1162 }
1163
1164 snl_end_attr_nested(nw, off);
1165 }
1166
1167 static void
snl_add_msg_attr_mape(struct snl_writer * nw,uint32_t type,const struct pf_mape_portset * me)1168 snl_add_msg_attr_mape(struct snl_writer *nw, uint32_t type, const struct pf_mape_portset *me)
1169 {
1170 int off;
1171
1172 off = snl_add_msg_attr_nested(nw, type);
1173
1174 snl_add_msg_attr_u8(nw, PF_MET_OFFSET, me->offset);
1175 snl_add_msg_attr_u8(nw, PF_MET_PSID_LEN, me->psidlen);
1176 snl_add_msg_attr_u16(nw, PF_MET_PSID, me->psid);
1177
1178 snl_end_attr_nested(nw, off);
1179 }
1180
1181 static void
snl_add_msg_attr_rpool(struct snl_writer * nw,uint32_t type,const struct pfctl_pool * pool)1182 snl_add_msg_attr_rpool(struct snl_writer *nw, uint32_t type, const struct pfctl_pool *pool)
1183 {
1184 int off;
1185
1186 off = snl_add_msg_attr_nested(nw, type);
1187
1188 snl_add_msg_attr(nw, PF_PT_KEY, sizeof(pool->key), &pool->key);
1189 snl_add_msg_attr_ip6(nw, PF_PT_COUNTER, &pool->counter.v6);
1190 snl_add_msg_attr_u32(nw, PF_PT_TBLIDX, pool->tblidx);
1191 snl_add_msg_attr_u16(nw, PF_PT_PROXY_SRC_PORT, pool->proxy_port[0]);
1192 snl_add_msg_attr_u16(nw, PF_PT_PROXY_DST_PORT, pool->proxy_port[1]);
1193 snl_add_msg_attr_u8(nw, PF_PT_OPTS, pool->opts);
1194 snl_add_msg_attr_mape(nw, PF_PT_MAPE, &pool->mape);
1195
1196 snl_end_attr_nested(nw, off);
1197 }
1198
1199 static void
snl_add_msg_attr_timeouts(struct snl_writer * nw,uint32_t type,const uint32_t * timeouts)1200 snl_add_msg_attr_timeouts(struct snl_writer *nw, uint32_t type, const uint32_t *timeouts)
1201 {
1202 int off;
1203
1204 off = snl_add_msg_attr_nested(nw, type);
1205
1206 for (int i = 0; i < PFTM_MAX; i++)
1207 snl_add_msg_attr_u32(nw, PF_TT_TIMEOUT, timeouts[i]);
1208
1209 snl_end_attr_nested(nw, off);
1210 }
1211
1212 static void
snl_add_msg_attr_uid(struct snl_writer * nw,uint32_t type,const struct pf_rule_uid * uid)1213 snl_add_msg_attr_uid(struct snl_writer *nw, uint32_t type, const struct pf_rule_uid *uid)
1214 {
1215 int off;
1216
1217 off = snl_add_msg_attr_nested(nw, type);
1218
1219 snl_add_msg_attr_u32(nw, PF_RUT_UID_LOW, uid->uid[0]);
1220 snl_add_msg_attr_u32(nw, PF_RUT_UID_HIGH, uid->uid[1]);
1221 snl_add_msg_attr_u8(nw, PF_RUT_OP, uid->op);
1222
1223 snl_end_attr_nested(nw, off);
1224 }
1225
1226 static void
snl_add_msg_attr_threshold(struct snl_writer * nw,uint32_t type,const struct pfctl_threshold * th)1227 snl_add_msg_attr_threshold(struct snl_writer *nw, uint32_t type, const struct pfctl_threshold *th)
1228 {
1229 int off;
1230
1231 off = snl_add_msg_attr_nested(nw, type);
1232
1233 snl_add_msg_attr_u32(nw, PF_TH_LIMIT, th->limit);
1234 snl_add_msg_attr_u32(nw, PF_TH_SECONDS, th->seconds);
1235
1236 snl_end_attr_nested(nw, off);
1237 }
1238
1239 static void
snl_add_msg_attr_pf_rule(struct snl_writer * nw,uint32_t type,const struct pfctl_rule * r)1240 snl_add_msg_attr_pf_rule(struct snl_writer *nw, uint32_t type, const struct pfctl_rule *r)
1241 {
1242 int off;
1243
1244 off = snl_add_msg_attr_nested(nw, type);
1245
1246 snl_add_msg_attr_rule_addr(nw, PF_RT_SRC, &r->src);
1247 snl_add_msg_attr_rule_addr(nw, PF_RT_DST, &r->dst);
1248 snl_add_msg_attr_rule_labels(nw, PF_RT_LABELS, r->label);
1249 snl_add_msg_attr_u32(nw, PF_RT_RIDENTIFIER, r->ridentifier);
1250 snl_add_msg_attr_string(nw, PF_RT_IFNAME, r->ifname);
1251 snl_add_msg_attr_string(nw, PF_RT_QNAME, r->qname);
1252 snl_add_msg_attr_string(nw, PF_RT_PQNAME, r->pqname);
1253 snl_add_msg_attr_string(nw, PF_RT_TAGNAME, r->tagname);
1254 snl_add_msg_attr_string(nw, PF_RT_MATCH_TAGNAME, r->match_tagname);
1255 snl_add_msg_attr_string(nw, PF_RT_OVERLOAD_TBLNAME, r->overload_tblname);
1256 snl_add_msg_attr_rpool(nw, PF_RT_RPOOL_RDR, &r->rdr);
1257 snl_add_msg_attr_rpool(nw, PF_RT_RPOOL_NAT, &r->nat);
1258 snl_add_msg_attr_rpool(nw, PF_RT_RPOOL_RT, &r->route);
1259 snl_add_msg_attr_threshold(nw, PF_RT_PKTRATE, &r->pktrate);
1260 snl_add_msg_attr_u32(nw, PF_RT_OS_FINGERPRINT, r->os_fingerprint);
1261 snl_add_msg_attr_u32(nw, PF_RT_RTABLEID, r->rtableid);
1262 snl_add_msg_attr_timeouts(nw, PF_RT_TIMEOUT, r->timeout);
1263 snl_add_msg_attr_u32(nw, PF_RT_MAX_STATES, r->max_states);
1264 snl_add_msg_attr_u32(nw, PF_RT_MAX_SRC_NODES, r->max_src_nodes);
1265 snl_add_msg_attr_u32(nw, PF_RT_MAX_SRC_STATES, r->max_src_states);
1266 snl_add_msg_attr_u32(nw, PF_RT_MAX_SRC_CONN, r->max_src_conn);
1267 snl_add_msg_attr_u32(nw, PF_RT_MAX_SRC_CONN_RATE_LIMIT, r->max_src_conn_rate.limit);
1268 snl_add_msg_attr_u32(nw, PF_RT_MAX_SRC_CONN_RATE_SECS, r->max_src_conn_rate.seconds);
1269 snl_add_msg_attr_u16(nw, PF_RT_MAX_PKT_SIZE, r->max_pkt_size);
1270
1271 snl_add_msg_attr_u16(nw, PF_RT_DNPIPE, r->dnpipe);
1272 snl_add_msg_attr_u16(nw, PF_RT_DNRPIPE, r->dnrpipe);
1273 snl_add_msg_attr_u32(nw, PF_RT_DNFLAGS, r->free_flags);
1274
1275 snl_add_msg_attr_u32(nw, PF_RT_NR, r->nr);
1276 snl_add_msg_attr_u32(nw, PF_RT_PROB, r->prob);
1277 snl_add_msg_attr_u32(nw, PF_RT_CUID, r->cuid);
1278 snl_add_msg_attr_u32(nw, PF_RT_CPID, r->cpid);
1279
1280 snl_add_msg_attr_u16(nw, PF_RT_RETURN_ICMP, r->return_icmp);
1281 snl_add_msg_attr_u16(nw, PF_RT_RETURN_ICMP6, r->return_icmp6);
1282 snl_add_msg_attr_u16(nw, PF_RT_MAX_MSS, r->max_mss);
1283 snl_add_msg_attr_u16(nw, PF_RT_SCRUB_FLAGS, r->scrub_flags);
1284
1285 snl_add_msg_attr_uid(nw, PF_RT_UID, &r->uid);
1286 snl_add_msg_attr_uid(nw, PF_RT_GID, (const struct pf_rule_uid *)&r->gid);
1287 snl_add_msg_attr_string(nw, PF_RT_RCV_IFNAME, r->rcv_ifname);
1288 snl_add_msg_attr_bool(nw, PF_RT_RCV_IFNOT, r->rcvifnot);
1289
1290 snl_add_msg_attr_u32(nw, PF_RT_RULE_FLAG, r->rule_flag);
1291 snl_add_msg_attr_u8(nw, PF_RT_ACTION, r->action);
1292 snl_add_msg_attr_u8(nw, PF_RT_DIRECTION, r->direction);
1293 snl_add_msg_attr_u8(nw, PF_RT_LOG, r->log);
1294 snl_add_msg_attr_u8(nw, PF_RT_LOGIF, r->logif);
1295 snl_add_msg_attr_u8(nw, PF_RT_QUICK, r->quick);
1296 snl_add_msg_attr_u8(nw, PF_RT_IF_NOT, r->ifnot);
1297 snl_add_msg_attr_u8(nw, PF_RT_MATCH_TAG_NOT, r->match_tag_not);
1298 snl_add_msg_attr_u8(nw, PF_RT_NATPASS, r->natpass);
1299 snl_add_msg_attr_u8(nw, PF_RT_KEEP_STATE, r->keep_state);
1300 snl_add_msg_attr_u8(nw, PF_RT_AF, r->af);
1301 snl_add_msg_attr_u8(nw, PF_RT_PROTO, r->proto);
1302 snl_add_msg_attr_u16(nw, PF_RT_TYPE_2, r->type);
1303 snl_add_msg_attr_u16(nw, PF_RT_CODE_2, r->code);
1304 snl_add_msg_attr_u8(nw, PF_RT_FLAGS, r->flags);
1305 snl_add_msg_attr_u8(nw, PF_RT_FLAGSET, r->flagset);
1306 snl_add_msg_attr_u8(nw, PF_RT_MIN_TTL, r->min_ttl);
1307 snl_add_msg_attr_u8(nw, PF_RT_ALLOW_OPTS, r->allow_opts);
1308 snl_add_msg_attr_u8(nw, PF_RT_RT, r->rt);
1309 snl_add_msg_attr_u8(nw, PF_RT_RETURN_TTL, r->return_ttl);
1310 snl_add_msg_attr_u8(nw, PF_RT_TOS, r->tos);
1311 snl_add_msg_attr_u8(nw, PF_RT_SET_TOS, r->set_tos);
1312
1313 snl_add_msg_attr_u8(nw, PF_RT_ANCHOR_RELATIVE, r->anchor_relative);
1314 snl_add_msg_attr_u8(nw, PF_RT_ANCHOR_WILDCARD, r->anchor_wildcard);
1315 snl_add_msg_attr_u8(nw, PF_RT_FLUSH, r->flush);
1316 snl_add_msg_attr_u8(nw, PF_RT_PRIO, r->prio);
1317 snl_add_msg_attr_u8(nw, PF_RT_SET_PRIO, r->set_prio[0]);
1318 snl_add_msg_attr_u8(nw, PF_RT_SET_PRIO_REPLY, r->set_prio[1]);
1319 snl_add_msg_attr_u8(nw, PF_RT_NAF, r->naf);
1320
1321 snl_add_msg_attr_ip6(nw, PF_RT_DIVERT_ADDRESS, &r->divert.addr.v6);
1322 snl_add_msg_attr_u16(nw, PF_RT_DIVERT_PORT, r->divert.port);
1323
1324 snl_add_msg_attr_u8(nw, PF_RT_STATE_LIMIT, r->statelim.id);
1325 snl_add_msg_attr_u32(nw, PF_RT_STATE_LIMIT_ACTION, r->statelim.limiter_action);
1326 snl_add_msg_attr_u8(nw, PF_RT_SOURCE_LIMIT, r->sourcelim.id);
1327 snl_add_msg_attr_u32(nw, PF_RT_SOURCE_LIMIT_ACTION, r->sourcelim.limiter_action);
1328
1329 snl_end_attr_nested(nw, off);
1330 }
1331
1332 int
pfctl_add_rule(int dev __unused,const struct pfctl_rule * r,const char * anchor,const char * anchor_call,uint32_t ticket,uint32_t pool_ticket)1333 pfctl_add_rule(int dev __unused, const struct pfctl_rule *r, const char *anchor,
1334 const char *anchor_call, uint32_t ticket, uint32_t pool_ticket)
1335 {
1336 struct pfctl_handle *h;
1337 int ret;
1338
1339 h = pfctl_open(PF_DEVICE);
1340 if (h == NULL)
1341 return (ENODEV);
1342
1343 ret = pfctl_add_rule_h(h, r, anchor, anchor_call, ticket, pool_ticket);
1344
1345 pfctl_close(h);
1346
1347 return (ret);
1348 }
1349
1350 int
pfctl_add_rule_h(struct pfctl_handle * h,const struct pfctl_rule * r,const char * anchor,const char * anchor_call,uint32_t ticket,uint32_t pool_ticket)1351 pfctl_add_rule_h(struct pfctl_handle *h, const struct pfctl_rule *r,
1352 const char *anchor, const char *anchor_call, uint32_t ticket,
1353 uint32_t pool_ticket)
1354 {
1355 struct snl_writer nw;
1356 struct snl_errmsg_data e = {};
1357 struct nlmsghdr *hdr;
1358 uint32_t seq_id;
1359
1360 snl_init_writer(&h->ss, &nw);
1361 hdr = snl_create_genl_msg_request(&nw, h->family_id,
1362 PFNL_CMD_ADDRULE);
1363 hdr->nlmsg_flags |= NLM_F_DUMP;
1364 snl_add_msg_attr_u32(&nw, PF_ART_TICKET, ticket);
1365 snl_add_msg_attr_u32(&nw, PF_ART_POOL_TICKET, pool_ticket);
1366 snl_add_msg_attr_string(&nw, PF_ART_ANCHOR, anchor);
1367 snl_add_msg_attr_string(&nw, PF_ART_ANCHOR_CALL, anchor_call);
1368
1369 snl_add_msg_attr_pf_rule(&nw, PF_ART_RULE, r);
1370
1371 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
1372 e.error = ENXIO;
1373 goto out;
1374 }
1375
1376 seq_id = hdr->nlmsg_seq;
1377
1378 if (! snl_send_message(&h->ss, hdr)) {
1379 e.error = ENXIO;
1380 goto out;
1381 }
1382
1383 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
1384 }
1385
1386 out:
1387 snl_clear_lb(&h->ss);
1388 return (e.error);
1389 }
1390
1391 #define _IN(_field) offsetof(struct genlmsghdr, _field)
1392 #define _OUT(_field) offsetof(struct pfctl_rules_info, _field)
1393 static struct snl_attr_parser ap_getrules[] = {
1394 { .type = PF_GR_NR, .off = _OUT(nr), .cb = snl_attr_get_uint32 },
1395 { .type = PF_GR_TICKET, .off = _OUT(ticket), .cb = snl_attr_get_uint32 },
1396 };
1397 #undef _IN
1398 #undef _OUT
1399 SNL_DECLARE_PARSER(getrules_parser, struct genlmsghdr, snl_f_p_empty, ap_getrules);
1400
1401 int
pfctl_get_rules_info_h(struct pfctl_handle * h,struct pfctl_rules_info * rules,uint32_t ruleset,const char * path)1402 pfctl_get_rules_info_h(struct pfctl_handle *h, struct pfctl_rules_info *rules, uint32_t ruleset,
1403 const char *path)
1404 {
1405 struct snl_errmsg_data e = {};
1406 struct nlmsghdr *hdr;
1407 struct snl_writer nw;
1408 uint32_t seq_id;
1409
1410 snl_init_writer(&h->ss, &nw);
1411 hdr = snl_create_genl_msg_request(&nw, h->family_id,
1412 PFNL_CMD_GETRULES);
1413 hdr->nlmsg_flags |= NLM_F_DUMP;
1414
1415 snl_add_msg_attr_string(&nw, PF_GR_ANCHOR, path);
1416 snl_add_msg_attr_u8(&nw, PF_GR_ACTION, ruleset);
1417
1418 hdr = snl_finalize_msg(&nw);
1419 if (hdr == NULL) {
1420 e.error = ENOMEM;
1421 goto out;
1422 }
1423
1424 seq_id = hdr->nlmsg_seq;
1425 if (! snl_send_message(&h->ss, hdr)) {
1426 e.error = ENXIO;
1427 goto out;
1428 }
1429
1430 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
1431 if (! snl_parse_nlmsg(&h->ss, hdr, &getrules_parser, rules))
1432 continue;
1433 }
1434
1435 out:
1436 snl_clear_lb(&h->ss);
1437 return (e.error);
1438 }
1439
1440 int
pfctl_get_rules_info(int dev __unused,struct pfctl_rules_info * rules,uint32_t ruleset,const char * path)1441 pfctl_get_rules_info(int dev __unused, struct pfctl_rules_info *rules, uint32_t ruleset,
1442 const char *path)
1443 {
1444 struct pfctl_handle *h;
1445 int error;
1446
1447 h = pfctl_open(PF_DEVICE);
1448 if (h == NULL)
1449 return (ENOTSUP);
1450 error = pfctl_get_rules_info_h(h, rules, ruleset, path);
1451 pfctl_close(h);
1452
1453 return (error);
1454 }
1455
1456 int
pfctl_get_rule_h(struct pfctl_handle * h,uint32_t nr,uint32_t ticket,const char * anchor,uint32_t ruleset,struct pfctl_rule * rule,char * anchor_call)1457 pfctl_get_rule_h(struct pfctl_handle *h, uint32_t nr, uint32_t ticket, const char *anchor,
1458 uint32_t ruleset, struct pfctl_rule *rule, char *anchor_call)
1459 {
1460 return (pfctl_get_clear_rule_h(h, nr, ticket, anchor, ruleset, rule,
1461 anchor_call, false));
1462 }
1463
1464 int
pfctl_get_rule(int dev,uint32_t nr,uint32_t ticket,const char * anchor,uint32_t ruleset,struct pfctl_rule * rule,char * anchor_call)1465 pfctl_get_rule(int dev, uint32_t nr, uint32_t ticket, const char *anchor,
1466 uint32_t ruleset, struct pfctl_rule *rule, char *anchor_call)
1467 {
1468 return (pfctl_get_clear_rule(dev, nr, ticket, anchor, ruleset, rule,
1469 anchor_call, false));
1470 }
1471
1472 #define _OUT(_field) offsetof(struct pf_addr_wrap, _field)
1473 static const struct snl_attr_parser ap_addr_wrap[] = {
1474 { .type = PF_AT_ADDR, .off = _OUT(v.a.addr), .cb = snl_attr_get_in6_addr },
1475 { .type = PF_AT_MASK, .off = _OUT(v.a.mask), .cb = snl_attr_get_in6_addr },
1476 { .type = PF_AT_IFNAME, .off = _OUT(v.ifname), .arg = (void *)IFNAMSIZ,.cb = snl_attr_copy_string },
1477 { .type = PF_AT_TABLENAME, .off = _OUT(v.tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = snl_attr_copy_string },
1478 { .type = PF_AT_TYPE, .off = _OUT(type), .cb = snl_attr_get_uint8 },
1479 { .type = PF_AT_IFLAGS, .off = _OUT(iflags), .cb = snl_attr_get_uint8 },
1480 { .type = PF_AT_TBLCNT, .off = _OUT(p.tblcnt), .cb = snl_attr_get_uint32 },
1481 { .type = PF_AT_DYNCNT, .off = _OUT(p.dyncnt), .cb = snl_attr_get_uint32 },
1482 };
1483 SNL_DECLARE_ATTR_PARSER(addr_wrap_parser, ap_addr_wrap);
1484 #undef _OUT
1485
1486 #define _OUT(_field) offsetof(struct pf_rule_addr, _field)
1487 static struct snl_attr_parser ap_rule_addr[] = {
1488 { .type = PF_RAT_ADDR, .off = _OUT(addr), .arg = &addr_wrap_parser, .cb = snl_attr_get_nested },
1489 { .type = PF_RAT_SRC_PORT, .off = _OUT(port[0]), .cb = snl_attr_get_uint16 },
1490 { .type = PF_RAT_DST_PORT, .off = _OUT(port[1]), .cb = snl_attr_get_uint16 },
1491 { .type = PF_RAT_NEG, .off = _OUT(neg), .cb = snl_attr_get_uint8 },
1492 { .type = PF_RAT_OP, .off = _OUT(port_op), .cb = snl_attr_get_uint8 },
1493 };
1494 #undef _OUT
1495 SNL_DECLARE_ATTR_PARSER(rule_addr_parser, ap_rule_addr);
1496
1497 struct snl_parsed_labels
1498 {
1499 char labels[PF_RULE_MAX_LABEL_COUNT][PF_RULE_LABEL_SIZE];
1500 uint32_t i;
1501 };
1502
1503 static bool
snl_attr_get_pf_rule_labels(struct snl_state * ss,struct nlattr * nla,const void * arg __unused,void * target)1504 snl_attr_get_pf_rule_labels(struct snl_state *ss, struct nlattr *nla,
1505 const void *arg __unused, void *target)
1506 {
1507 struct snl_parsed_labels *l = (struct snl_parsed_labels *)target;
1508 bool ret;
1509
1510 if (l->i >= PF_RULE_MAX_LABEL_COUNT)
1511 return (false);
1512
1513 ret = snl_attr_copy_string(ss, nla, (void *)PF_RULE_LABEL_SIZE,
1514 l->labels[l->i]);
1515 if (ret)
1516 l->i++;
1517
1518 return (ret);
1519 }
1520
1521 #define _OUT(_field) offsetof(struct nl_parsed_labels, _field)
1522 static const struct snl_attr_parser ap_labels[] = {
1523 { .type = PF_LT_LABEL, .off = 0, .cb = snl_attr_get_pf_rule_labels },
1524 };
1525 SNL_DECLARE_ATTR_PARSER(rule_labels_parser, ap_labels);
1526 #undef _OUT
1527
1528 static bool
snl_attr_get_nested_pf_rule_labels(struct snl_state * ss,struct nlattr * nla,const void * arg __unused,void * target)1529 snl_attr_get_nested_pf_rule_labels(struct snl_state *ss, struct nlattr *nla,
1530 const void *arg __unused, void *target)
1531 {
1532 struct snl_parsed_labels parsed_labels = { };
1533 bool error;
1534
1535 /* Assumes target points to the beginning of the structure */
1536 error = snl_parse_header(ss, NLA_DATA(nla), NLA_DATA_LEN(nla), &rule_labels_parser, &parsed_labels);
1537 if (! error)
1538 return (error);
1539
1540 memcpy(target, parsed_labels.labels, sizeof(parsed_labels.labels));
1541
1542 return (true);
1543 }
1544
1545 #define _OUT(_field) offsetof(struct pf_mape_portset, _field)
1546 static const struct snl_attr_parser ap_mape_portset[] = {
1547 { .type = PF_MET_OFFSET, .off = _OUT(offset), .cb = snl_attr_get_uint8 },
1548 { .type = PF_MET_PSID_LEN, .off = _OUT(psidlen), .cb = snl_attr_get_uint8 },
1549 {. type = PF_MET_PSID, .off = _OUT(psid), .cb = snl_attr_get_uint16 },
1550 };
1551 SNL_DECLARE_ATTR_PARSER(mape_portset_parser, ap_mape_portset);
1552 #undef _OUT
1553
1554 #define _OUT(_field) offsetof(struct pfctl_pool, _field)
1555 static const struct snl_attr_parser ap_pool[] = {
1556 { .type = PF_PT_KEY, .off = _OUT(key), .arg = (void *)sizeof(struct pf_poolhashkey), .cb = snl_attr_get_bytes },
1557 { .type = PF_PT_COUNTER, .off = _OUT(counter), .cb = snl_attr_get_in6_addr },
1558 { .type = PF_PT_TBLIDX, .off = _OUT(tblidx), .cb = snl_attr_get_uint32 },
1559 { .type = PF_PT_PROXY_SRC_PORT, .off = _OUT(proxy_port[0]), .cb = snl_attr_get_uint16 },
1560 { .type = PF_PT_PROXY_DST_PORT, .off = _OUT(proxy_port[1]), .cb = snl_attr_get_uint16 },
1561 { .type = PF_PT_OPTS, .off = _OUT(opts), .cb = snl_attr_get_uint8 },
1562 { .type = PF_PT_MAPE, .off = _OUT(mape), .arg = &mape_portset_parser, .cb = snl_attr_get_nested },
1563 };
1564 SNL_DECLARE_ATTR_PARSER(pool_parser, ap_pool);
1565 #undef _OUT
1566
1567 struct nl_parsed_timeouts
1568 {
1569 uint32_t timeouts[PFTM_MAX];
1570 uint32_t i;
1571 };
1572
1573 static bool
snl_attr_get_pf_timeout(struct snl_state * ss,struct nlattr * nla,const void * arg __unused,void * target)1574 snl_attr_get_pf_timeout(struct snl_state *ss, struct nlattr *nla,
1575 const void *arg __unused, void *target)
1576 {
1577 struct nl_parsed_timeouts *t = (struct nl_parsed_timeouts *)target;
1578 bool ret;
1579
1580 if (t->i >= PFTM_MAX)
1581 return (false);
1582
1583 ret = snl_attr_get_uint32(ss, nla, NULL, &t->timeouts[t->i]);
1584 if (ret)
1585 t->i++;
1586
1587 return (ret);
1588 }
1589
1590 #define _OUT(_field) offsetof(struct nl_parsed_timeout, _field)
1591 static const struct snl_attr_parser ap_timeouts[] = {
1592 { .type = PF_TT_TIMEOUT, .off = 0, .cb = snl_attr_get_pf_timeout },
1593 };
1594 SNL_DECLARE_ATTR_PARSER(timeout_parser, ap_timeouts);
1595 #undef _OUT
1596
1597 static bool
snl_attr_get_nested_timeouts(struct snl_state * ss,struct nlattr * nla,const void * arg __unused,void * target)1598 snl_attr_get_nested_timeouts(struct snl_state *ss, struct nlattr *nla,
1599 const void *arg __unused, void *target)
1600 {
1601 struct nl_parsed_timeouts parsed_timeouts = { };
1602 bool error;
1603
1604 /* Assumes target points to the beginning of the structure */
1605 error = snl_parse_header(ss, NLA_DATA(nla), NLA_DATA_LEN(nla), &timeout_parser, &parsed_timeouts);
1606 if (! error)
1607 return (error);
1608
1609 memcpy(target, parsed_timeouts.timeouts, sizeof(parsed_timeouts.timeouts));
1610
1611 return (true);
1612 }
1613
1614 #define _OUT(_field) offsetof(struct pf_rule_uid, _field)
1615 static const struct snl_attr_parser ap_rule_uid[] = {
1616 { .type = PF_RUT_UID_LOW, .off = _OUT(uid[0]), .cb = snl_attr_get_uint32 },
1617 { .type = PF_RUT_UID_HIGH, .off = _OUT(uid[1]), .cb = snl_attr_get_uint32 },
1618 { .type = PF_RUT_OP, .off = _OUT(op), .cb = snl_attr_get_uint8 },
1619 };
1620 SNL_DECLARE_ATTR_PARSER(rule_uid_parser, ap_rule_uid);
1621 #undef _OUT
1622
1623 #define _OUT(_field) offsetof(struct pfctl_threshold, _field)
1624 static const struct snl_attr_parser ap_pfctl_threshold[] = {
1625 { .type = PF_TH_LIMIT, .off = _OUT(limit), .cb = snl_attr_get_uint32 },
1626 { .type = PF_TH_SECONDS, .off = _OUT(seconds), .cb = snl_attr_get_uint32 },
1627 { .type = PF_TH_COUNT, .off = _OUT(count), .cb = snl_attr_get_uint32 },
1628 };
1629 SNL_DECLARE_ATTR_PARSER(pfctl_threshold_parser, ap_pfctl_threshold);
1630 #undef _OUT
1631
1632 struct pfctl_nl_get_rule {
1633 struct pfctl_rule r;
1634 char anchor_call[MAXPATHLEN];
1635 };
1636 #define _OUT(_field) offsetof(struct pfctl_nl_get_rule, _field)
1637 static struct snl_attr_parser ap_getrule[] = {
1638 { .type = PF_RT_SRC, .off = _OUT(r.src), .arg = &rule_addr_parser,.cb = snl_attr_get_nested },
1639 { .type = PF_RT_DST, .off = _OUT(r.dst), .arg = &rule_addr_parser,.cb = snl_attr_get_nested },
1640 { .type = PF_RT_RIDENTIFIER, .off = _OUT(r.ridentifier), .cb = snl_attr_get_uint32 },
1641 { .type = PF_RT_LABELS, .off = _OUT(r.label), .arg = &rule_labels_parser,.cb = snl_attr_get_nested_pf_rule_labels },
1642 { .type = PF_RT_IFNAME, .off = _OUT(r.ifname), .arg = (void *)IFNAMSIZ, .cb = snl_attr_copy_string },
1643 { .type = PF_RT_QNAME, .off = _OUT(r.qname), .arg = (void *)PF_QNAME_SIZE, .cb = snl_attr_copy_string },
1644 { .type = PF_RT_PQNAME, .off = _OUT(r.pqname), .arg = (void *)PF_QNAME_SIZE, .cb = snl_attr_copy_string },
1645 { .type = PF_RT_TAGNAME, .off = _OUT(r.tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = snl_attr_copy_string },
1646 { .type = PF_RT_MATCH_TAGNAME, .off = _OUT(r.match_tagname), .arg = (void *)PF_TAG_NAME_SIZE, .cb = snl_attr_copy_string },
1647 { .type = PF_RT_OVERLOAD_TBLNAME, .off = _OUT(r.overload_tblname), .arg = (void *)PF_TABLE_NAME_SIZE, .cb = snl_attr_copy_string },
1648 { .type = PF_RT_RPOOL_RDR, .off = _OUT(r.rdr), .arg = &pool_parser, .cb = snl_attr_get_nested },
1649 { .type = PF_RT_OS_FINGERPRINT, .off = _OUT(r.os_fingerprint), .cb = snl_attr_get_uint32 },
1650 { .type = PF_RT_RTABLEID, .off = _OUT(r.rtableid), .cb = snl_attr_get_uint32 },
1651 { .type = PF_RT_TIMEOUT, .off = _OUT(r.timeout), .arg = &timeout_parser, .cb = snl_attr_get_nested_timeouts },
1652 { .type = PF_RT_MAX_STATES, .off = _OUT(r.max_states), .cb = snl_attr_get_uint32 },
1653 { .type = PF_RT_MAX_SRC_NODES, .off = _OUT(r.max_src_nodes), .cb = snl_attr_get_uint32 },
1654 { .type = PF_RT_MAX_SRC_STATES, .off = _OUT(r.max_src_states), .cb = snl_attr_get_uint32 },
1655 { .type = PF_RT_MAX_SRC_CONN_RATE_LIMIT, .off = _OUT(r.max_src_conn_rate.limit), .cb = snl_attr_get_uint32 },
1656 { .type = PF_RT_MAX_SRC_CONN_RATE_SECS, .off = _OUT(r.max_src_conn_rate.seconds), .cb = snl_attr_get_uint32 },
1657 { .type = PF_RT_DNPIPE, .off = _OUT(r.dnpipe), .cb = snl_attr_get_uint16 },
1658 { .type = PF_RT_DNRPIPE, .off = _OUT(r.dnrpipe), .cb = snl_attr_get_uint16 },
1659 { .type = PF_RT_DNFLAGS, .off = _OUT(r.free_flags), .cb = snl_attr_get_uint32 },
1660 { .type = PF_RT_NR, .off = _OUT(r.nr), .cb = snl_attr_get_uint32 },
1661 { .type = PF_RT_PROB, .off = _OUT(r.prob), .cb = snl_attr_get_uint32 },
1662 { .type = PF_RT_CUID, .off = _OUT(r.cuid), .cb = snl_attr_get_uint32 },
1663 {. type = PF_RT_CPID, .off = _OUT(r.cpid), .cb = snl_attr_get_uint32 },
1664 { .type = PF_RT_RETURN_ICMP, .off = _OUT(r.return_icmp), .cb = snl_attr_get_uint16 },
1665 { .type = PF_RT_RETURN_ICMP6, .off = _OUT(r.return_icmp6), .cb = snl_attr_get_uint16 },
1666 { .type = PF_RT_MAX_MSS, .off = _OUT(r.max_mss), .cb = snl_attr_get_uint16 },
1667 { .type = PF_RT_SCRUB_FLAGS, .off = _OUT(r.scrub_flags), .cb = snl_attr_get_uint16 },
1668 { .type = PF_RT_UID, .off = _OUT(r.uid), .arg = &rule_uid_parser, .cb = snl_attr_get_nested },
1669 { .type = PF_RT_GID, .off = _OUT(r.gid), .arg = &rule_uid_parser, .cb = snl_attr_get_nested },
1670 { .type = PF_RT_RULE_FLAG, .off = _OUT(r.rule_flag), .cb = snl_attr_get_uint32 },
1671 { .type = PF_RT_ACTION, .off = _OUT(r.action), .cb = snl_attr_get_uint8 },
1672 { .type = PF_RT_DIRECTION, .off = _OUT(r.direction), .cb = snl_attr_get_uint8 },
1673 { .type = PF_RT_LOG, .off = _OUT(r.log), .cb = snl_attr_get_uint8 },
1674 { .type = PF_RT_LOGIF, .off = _OUT(r.logif), .cb = snl_attr_get_uint8 },
1675 { .type = PF_RT_QUICK, .off = _OUT(r.quick), .cb = snl_attr_get_uint8 },
1676 { .type = PF_RT_IF_NOT, .off = _OUT(r.ifnot), .cb = snl_attr_get_uint8 },
1677 { .type = PF_RT_MATCH_TAG_NOT, .off = _OUT(r.match_tag_not), .cb = snl_attr_get_uint8 },
1678 { .type = PF_RT_NATPASS, .off = _OUT(r.natpass), .cb = snl_attr_get_uint8 },
1679 { .type = PF_RT_KEEP_STATE, .off = _OUT(r.keep_state), .cb = snl_attr_get_uint8 },
1680 { .type = PF_RT_AF, .off = _OUT(r.af), .cb = snl_attr_get_uint8 },
1681 { .type = PF_RT_PROTO, .off = _OUT(r.proto), .cb = snl_attr_get_uint8 },
1682 { .type = PF_RT_TYPE, .off = _OUT(r.type), .cb = snl_attr_get_uint8 },
1683 { .type = PF_RT_CODE, .off = _OUT(r.code), .cb = snl_attr_get_uint8 },
1684 { .type = PF_RT_FLAGS, .off = _OUT(r.flags), .cb = snl_attr_get_uint8 },
1685 { .type = PF_RT_FLAGSET, .off = _OUT(r.flagset), .cb = snl_attr_get_uint8 },
1686 { .type = PF_RT_MIN_TTL, .off = _OUT(r.min_ttl), .cb = snl_attr_get_uint8 },
1687 { .type = PF_RT_ALLOW_OPTS, .off = _OUT(r.allow_opts), .cb = snl_attr_get_uint8 },
1688 { .type = PF_RT_RT, .off = _OUT(r.rt), .cb = snl_attr_get_uint8 },
1689 { .type = PF_RT_RETURN_TTL, .off = _OUT(r.return_ttl), .cb = snl_attr_get_uint8 },
1690 { .type = PF_RT_TOS, .off = _OUT(r.tos), .cb = snl_attr_get_uint8 },
1691 { .type = PF_RT_SET_TOS, .off = _OUT(r.set_tos), .cb = snl_attr_get_uint8 },
1692 { .type = PF_RT_ANCHOR_RELATIVE, .off = _OUT(r.anchor_relative), .cb = snl_attr_get_uint8 },
1693 { .type = PF_RT_ANCHOR_WILDCARD, .off = _OUT(r.anchor_wildcard), .cb = snl_attr_get_uint8 },
1694 { .type = PF_RT_FLUSH, .off = _OUT(r.flush), .cb = snl_attr_get_uint8 },
1695 { .type = PF_RT_PRIO, .off = _OUT(r.prio), .cb = snl_attr_get_uint8 },
1696 { .type = PF_RT_SET_PRIO, .off = _OUT(r.set_prio[0]), .cb = snl_attr_get_uint8 },
1697 { .type = PF_RT_SET_PRIO_REPLY, .off = _OUT(r.set_prio[1]), .cb = snl_attr_get_uint8 },
1698 { .type = PF_RT_DIVERT_ADDRESS, .off = _OUT(r.divert.addr), .cb = snl_attr_get_in6_addr },
1699 { .type = PF_RT_DIVERT_PORT, .off = _OUT(r.divert.port), .cb = snl_attr_get_uint16 },
1700 { .type = PF_RT_PACKETS_IN, .off = _OUT(r.packets[0]), .cb = snl_attr_get_uint64 },
1701 { .type = PF_RT_PACKETS_OUT, .off = _OUT(r.packets[1]), .cb = snl_attr_get_uint64 },
1702 { .type = PF_RT_BYTES_IN, .off = _OUT(r.bytes[0]), .cb = snl_attr_get_uint64 },
1703 { .type = PF_RT_BYTES_OUT, .off = _OUT(r.bytes[1]), .cb = snl_attr_get_uint64 },
1704 { .type = PF_RT_EVALUATIONS, .off = _OUT(r.evaluations), .cb = snl_attr_get_uint64 },
1705 { .type = PF_RT_TIMESTAMP, .off = _OUT(r.last_active_timestamp), .cb = snl_attr_get_uint64 },
1706 { .type = PF_RT_STATES_CUR, .off = _OUT(r.states_cur), .cb = snl_attr_get_uint64 },
1707 { .type = PF_RT_STATES_TOTAL, .off = _OUT(r.states_tot), .cb = snl_attr_get_uint64 },
1708 { .type = PF_RT_SRC_NODES, .off = _OUT(r.src_nodes), .cb = snl_attr_get_uint64 },
1709 { .type = PF_RT_ANCHOR_CALL, .off = _OUT(anchor_call), .arg = (void*)MAXPATHLEN, .cb = snl_attr_copy_string },
1710 { .type = PF_RT_RCV_IFNAME, .off = _OUT(r.rcv_ifname), .arg = (void*)IFNAMSIZ, .cb = snl_attr_copy_string },
1711 { .type = PF_RT_MAX_SRC_CONN, .off = _OUT(r.max_src_conn), .cb = snl_attr_get_uint32 },
1712 { .type = PF_RT_RPOOL_NAT, .off = _OUT(r.nat), .arg = &pool_parser, .cb = snl_attr_get_nested },
1713 { .type = PF_RT_NAF, .off = _OUT(r.naf), .cb = snl_attr_get_uint8 },
1714 { .type = PF_RT_RPOOL_RT, .off = _OUT(r.route), .arg = &pool_parser, .cb = snl_attr_get_nested },
1715 { .type = PF_RT_RCV_IFNOT, .off = _OUT(r.rcvifnot),.cb = snl_attr_get_bool },
1716 { .type = PF_RT_SRC_NODES_LIMIT, .off = _OUT(r.src_nodes_type[PF_SN_LIMIT]), .cb = snl_attr_get_uint64 },
1717 { .type = PF_RT_SRC_NODES_NAT, .off = _OUT(r.src_nodes_type[PF_SN_NAT]), .cb = snl_attr_get_uint64 },
1718 { .type = PF_RT_SRC_NODES_ROUTE, .off = _OUT(r.src_nodes_type[PF_SN_ROUTE]), .cb = snl_attr_get_uint64 },
1719 { .type = PF_RT_PKTRATE, .off = _OUT(r.pktrate), .arg = &pfctl_threshold_parser, .cb = snl_attr_get_nested },
1720 { .type = PF_RT_MAX_PKT_SIZE, .off =_OUT(r.max_pkt_size), .cb = snl_attr_get_uint16 },
1721 { .type = PF_RT_TYPE_2, .off = _OUT(r.type), .cb = snl_attr_get_uint16 },
1722 { .type = PF_RT_CODE_2, .off = _OUT(r.code), .cb = snl_attr_get_uint16 },
1723 { .type = PF_RT_EXPTIME, .off = _OUT(r.exptime), .cb = snl_attr_get_time_t },
1724 { .type = PF_RT_STATE_LIMIT, .off = _OUT(r.statelim.id), .cb = snl_attr_get_uint8 },
1725 { .type = PF_RT_SOURCE_LIMIT, .off = _OUT(r.sourcelim.id), .cb = snl_attr_get_uint8 },
1726 { .type = PF_RT_STATE_LIMIT_ACTION, .off = _OUT(r.statelim.limiter_action), .cb = snl_attr_get_uint32 },
1727 { .type = PF_RT_SOURCE_LIMIT_ACTION, .off = _OUT(r.sourcelim.limiter_action), .cb = snl_attr_get_uint32 },
1728 };
1729 #undef _OUT
1730 SNL_DECLARE_PARSER(getrule_parser, struct genlmsghdr, snl_f_p_empty, ap_getrule);
1731
1732 int
pfctl_get_clear_rule_h(struct pfctl_handle * h,uint32_t nr,uint32_t ticket,const char * anchor,uint32_t ruleset,struct pfctl_rule * rule,char * anchor_call,bool clear)1733 pfctl_get_clear_rule_h(struct pfctl_handle *h, uint32_t nr, uint32_t ticket,
1734 const char *anchor, uint32_t ruleset, struct pfctl_rule *rule,
1735 char *anchor_call, bool clear)
1736 {
1737 struct pfctl_nl_get_rule attrs = {};
1738 struct snl_errmsg_data e = {};
1739 struct nlmsghdr *hdr;
1740 struct snl_writer nw;
1741 uint32_t seq_id;
1742
1743 snl_init_writer(&h->ss, &nw);
1744 hdr = snl_create_genl_msg_request(&nw, h->family_id,
1745 PFNL_CMD_GETRULE);
1746 hdr->nlmsg_flags |= NLM_F_DUMP;
1747
1748 snl_add_msg_attr_string(&nw, PF_GR_ANCHOR, anchor);
1749 snl_add_msg_attr_u8(&nw, PF_GR_ACTION, ruleset);
1750 snl_add_msg_attr_u32(&nw, PF_GR_NR, nr);
1751 snl_add_msg_attr_u32(&nw, PF_GR_TICKET, ticket);
1752 snl_add_msg_attr_u8(&nw, PF_GR_CLEAR, clear);
1753
1754 hdr = snl_finalize_msg(&nw);
1755 if (hdr == NULL) {
1756 e.error = ENOMEM;
1757 goto out;
1758 }
1759
1760 seq_id = hdr->nlmsg_seq;
1761 if (! snl_send_message(&h->ss, hdr)) {
1762 e.error = ENXIO;
1763 goto out;
1764 }
1765
1766 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
1767 if (! snl_parse_nlmsg(&h->ss, hdr, &getrule_parser, &attrs))
1768 continue;
1769 }
1770
1771 memcpy(rule, &attrs.r, sizeof(attrs.r));
1772 strlcpy(anchor_call, attrs.anchor_call, MAXPATHLEN);
1773
1774 out:
1775 snl_clear_lb(&h->ss);
1776 return (e.error);
1777 }
1778
1779 int
pfctl_get_clear_rule(int dev,uint32_t nr,uint32_t ticket,const char * anchor,uint32_t ruleset,struct pfctl_rule * rule,char * anchor_call,bool clear)1780 pfctl_get_clear_rule(int dev, uint32_t nr, uint32_t ticket,
1781 const char *anchor, uint32_t ruleset, struct pfctl_rule *rule,
1782 char *anchor_call, bool clear)
1783 {
1784 nvlist_t *nvl;
1785 int ret;
1786
1787 nvl = nvlist_create(0);
1788 if (nvl == 0)
1789 return (ENOMEM);
1790
1791 nvlist_add_number(nvl, "nr", nr);
1792 nvlist_add_number(nvl, "ticket", ticket);
1793 nvlist_add_string(nvl, "anchor", anchor);
1794 nvlist_add_number(nvl, "ruleset", ruleset);
1795
1796 if (clear)
1797 nvlist_add_bool(nvl, "clear_counter", true);
1798
1799 if ((ret = pfctl_do_ioctl(dev, DIOCGETRULENV, 8192, &nvl)) != 0)
1800 goto out;
1801
1802 pf_nvrule_to_rule(nvlist_get_nvlist(nvl, "rule"), rule);
1803
1804 if (anchor_call)
1805 strlcpy(anchor_call, nvlist_get_string(nvl, "anchor_call"),
1806 MAXPATHLEN);
1807
1808 out:
1809 nvlist_destroy(nvl);
1810 return (ret);
1811 }
1812
1813 int
pfctl_set_keepcounters(int dev,bool keep)1814 pfctl_set_keepcounters(int dev, bool keep)
1815 {
1816 struct pfioc_nv nv;
1817 nvlist_t *nvl;
1818 int ret;
1819
1820 nvl = nvlist_create(0);
1821
1822 nvlist_add_bool(nvl, "keep_counters", keep);
1823
1824 nv.data = nvlist_pack(nvl, &nv.len);
1825 nv.size = nv.len;
1826
1827 nvlist_destroy(nvl);
1828
1829 ret = ioctl(dev, DIOCKEEPCOUNTERS, &nv);
1830
1831 free(nv.data);
1832 return (ret);
1833 }
1834
1835 struct pfctl_creator {
1836 uint32_t id;
1837 };
1838 #define _IN(_field) offsetof(struct genlmsghdr, _field)
1839 #define _OUT(_field) offsetof(struct pfctl_creator, _field)
1840 static struct snl_attr_parser ap_creators[] = {
1841 { .type = PF_ST_CREATORID, .off = _OUT(id), .cb = snl_attr_get_uint32 },
1842 };
1843 #undef _IN
1844 #undef _OUT
1845 SNL_DECLARE_PARSER(creator_parser, struct genlmsghdr, snl_f_p_empty, ap_creators);
1846
1847 int
pfctl_get_creatorids(struct pfctl_handle * h,uint32_t * creators,size_t * len)1848 pfctl_get_creatorids(struct pfctl_handle *h, uint32_t *creators, size_t *len)
1849 {
1850 struct snl_errmsg_data e = {};
1851 struct nlmsghdr *hdr;
1852 struct snl_writer nw;
1853 size_t i = 0;
1854
1855 snl_init_writer(&h->ss, &nw);
1856 hdr = snl_create_genl_msg_request(&nw, h->family_id,
1857 PFNL_CMD_GETCREATORS);
1858 hdr->nlmsg_flags |= NLM_F_DUMP;
1859 hdr = snl_finalize_msg(&nw);
1860 if (hdr == NULL) {
1861 e.error = ENOMEM;
1862 goto out;
1863 }
1864
1865 uint32_t seq_id = hdr->nlmsg_seq;
1866
1867 if (! snl_send_message(&h->ss, hdr)) {
1868 e.error = ENXIO;
1869 goto out;
1870 }
1871
1872 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
1873 struct pfctl_creator c;
1874 bzero(&c, sizeof(c));
1875
1876 if (!snl_parse_nlmsg(&h->ss, hdr, &creator_parser, &c))
1877 continue;
1878
1879 creators[i] = c.id;
1880 i++;
1881 if (i > *len) {
1882 e.error = E2BIG;
1883 goto out;
1884 }
1885 }
1886
1887 *len = i;
1888
1889 out:
1890 snl_clear_lb(&h->ss);
1891 return (e.error);
1892 }
1893
1894 static inline bool
snl_attr_get_pfaddr(struct snl_state * ss __unused,struct nlattr * nla,const void * arg __unused,void * target)1895 snl_attr_get_pfaddr(struct snl_state *ss __unused, struct nlattr *nla,
1896 const void *arg __unused, void *target)
1897 {
1898 memcpy(target, NLA_DATA(nla), NLA_DATA_LEN(nla));
1899 return (true);
1900 }
1901
1902 static inline bool
snl_attr_store_ifname(struct snl_state * ss __unused,struct nlattr * nla,const void * arg __unused,void * target)1903 snl_attr_store_ifname(struct snl_state *ss __unused, struct nlattr *nla,
1904 const void *arg __unused, void *target)
1905 {
1906 size_t maxlen = NLA_DATA_LEN(nla);
1907
1908 if (strnlen((char *)NLA_DATA(nla), maxlen) < maxlen) {
1909 strlcpy(target, (char *)NLA_DATA(nla), maxlen);
1910 return (true);
1911 }
1912 return (false);
1913 }
1914
1915 #define _OUT(_field) offsetof(struct pfctl_state_peer, _field)
1916 static const struct snl_attr_parser nla_p_speer[] = {
1917 { .type = PF_STP_SEQLO, .off = _OUT(seqlo), .cb = snl_attr_get_uint32 },
1918 { .type = PF_STP_SEQHI, .off = _OUT(seqhi), .cb = snl_attr_get_uint32 },
1919 { .type = PF_STP_SEQDIFF, .off = _OUT(seqdiff), .cb = snl_attr_get_uint32 },
1920 { .type = PF_STP_STATE, .off = _OUT(state), .cb = snl_attr_get_uint8 },
1921 { .type = PF_STP_WSCALE, .off = _OUT(wscale), .cb = snl_attr_get_uint8 },
1922 };
1923 SNL_DECLARE_ATTR_PARSER(speer_parser, nla_p_speer);
1924 #undef _OUT
1925
1926 #define _OUT(_field) offsetof(struct pfctl_state_key, _field)
1927 static const struct snl_attr_parser nla_p_skey[] = {
1928 { .type = PF_STK_ADDR0, .off = _OUT(addr[0]), .cb = snl_attr_get_pfaddr },
1929 { .type = PF_STK_ADDR1, .off = _OUT(addr[1]), .cb = snl_attr_get_pfaddr },
1930 { .type = PF_STK_PORT0, .off = _OUT(port[0]), .cb = snl_attr_get_uint16 },
1931 { .type = PF_STK_PORT1, .off = _OUT(port[1]), .cb = snl_attr_get_uint16 },
1932 { .type = PF_STK_AF, .off = _OUT(af), .cb = snl_attr_get_uint8 },
1933 { .type = PF_STK_PROTO, .off = _OUT(proto), .cb = snl_attr_get_uint16 },
1934 };
1935 SNL_DECLARE_ATTR_PARSER(skey_parser, nla_p_skey);
1936 #undef _OUT
1937
1938 SNL_DECLARE_ATTR_PARSER(rule_parser, ap_getrule);
1939
1940 #define _IN(_field) offsetof(struct genlmsghdr, _field)
1941 #define _OUT(_field) offsetof(struct pfctl_state, _field)
1942 static struct snl_attr_parser ap_state[] = {
1943 { .type = PF_ST_ID, .off = _OUT(id), .cb = snl_attr_get_uint64 },
1944 { .type = PF_ST_CREATORID, .off = _OUT(creatorid), .cb = snl_attr_get_uint32 },
1945 { .type = PF_ST_IFNAME, .off = _OUT(ifname), .cb = snl_attr_store_ifname },
1946 { .type = PF_ST_ORIG_IFNAME, .off = _OUT(orig_ifname), .cb = snl_attr_store_ifname },
1947 { .type = PF_ST_KEY_WIRE, .off = _OUT(key[0]), .arg = &skey_parser, .cb = snl_attr_get_nested },
1948 { .type = PF_ST_KEY_STACK, .off = _OUT(key[1]), .arg = &skey_parser, .cb = snl_attr_get_nested },
1949 { .type = PF_ST_PEER_SRC, .off = _OUT(src), .arg = &speer_parser, .cb = snl_attr_get_nested },
1950 { .type = PF_ST_PEER_DST, .off = _OUT(dst), .arg = &speer_parser, .cb = snl_attr_get_nested },
1951 { .type = PF_ST_RT_ADDR, .off = _OUT(rt_addr), .cb = snl_attr_get_pfaddr },
1952 { .type = PF_ST_RULE, .off = _OUT(rule), .cb = snl_attr_get_uint32 },
1953 { .type = PF_ST_ANCHOR, .off = _OUT(anchor), .cb = snl_attr_get_uint32 },
1954 { .type = PF_ST_NAT_RULE, .off = _OUT(nat_rule), .cb = snl_attr_get_uint32 },
1955 { .type = PF_ST_CREATION, .off = _OUT(creation), .cb = snl_attr_get_uint32 },
1956 { .type = PF_ST_EXPIRE, .off = _OUT(expire), .cb = snl_attr_get_uint32 },
1957 { .type = PF_ST_PACKETS0, .off = _OUT(packets[0]), .cb = snl_attr_get_uint64 },
1958 { .type = PF_ST_PACKETS1, .off = _OUT(packets[1]), .cb = snl_attr_get_uint64 },
1959 { .type = PF_ST_BYTES0, .off = _OUT(bytes[0]), .cb = snl_attr_get_uint64 },
1960 { .type = PF_ST_BYTES1, .off = _OUT(bytes[1]), .cb = snl_attr_get_uint64 },
1961 { .type = PF_ST_DIRECTION, .off = _OUT(direction), .cb = snl_attr_get_uint8 },
1962 { .type = PF_ST_LOG, .off = _OUT(log), .cb = snl_attr_get_uint8 },
1963 { .type = PF_ST_STATE_FLAGS, .off = _OUT(state_flags), .cb = snl_attr_get_uint16 },
1964 { .type = PF_ST_SYNC_FLAGS, .off = _OUT(sync_flags), .cb = snl_attr_get_uint8 },
1965 { .type = PF_ST_RTABLEID, .off = _OUT(rtableid), .cb = snl_attr_get_int32 },
1966 { .type = PF_ST_MIN_TTL, .off = _OUT(min_ttl), .cb = snl_attr_get_uint8 },
1967 { .type = PF_ST_MAX_MSS, .off = _OUT(max_mss), .cb = snl_attr_get_uint16 },
1968 { .type = PF_ST_DNPIPE, .off = _OUT(dnpipe), .cb = snl_attr_get_uint16 },
1969 { .type = PF_ST_DNRPIPE, .off = _OUT(dnrpipe), .cb = snl_attr_get_uint16 },
1970 { .type = PF_ST_RT, .off = _OUT(rt), .cb = snl_attr_get_uint8 },
1971 { .type = PF_ST_RT_IFNAME, .off = _OUT(rt_ifname), .cb = snl_attr_store_ifname },
1972 { .type = PF_ST_SRC_NODE_FLAGS, .off = _OUT(src_node_flags), .cb = snl_attr_get_uint8 },
1973 { .type = PF_ST_RT_AF, .off = _OUT(rt_af), .cb = snl_attr_get_uint8 },
1974 { .type = PF_ST_CREATED_BY_RULE, .off = _OUT(created_by_rule), .arg = &rule_parser, .cb = snl_attr_get_nested },
1975 };
1976 #undef _IN
1977 #undef _OUT
1978 SNL_DECLARE_PARSER(state_parser, struct genlmsghdr, snl_f_p_empty, ap_state);
1979
1980 int
pfctl_get_states_h(struct pfctl_handle * h,struct pfctl_state_filter * filter,pfctl_get_state_fn f,void * arg)1981 pfctl_get_states_h(struct pfctl_handle *h, struct pfctl_state_filter *filter, pfctl_get_state_fn f, void *arg)
1982 {
1983 struct nlmsghdr *hdr;
1984 struct snl_writer nw;
1985 int ret;
1986
1987 snl_init_writer(&h->ss, &nw);
1988 hdr = snl_create_genl_msg_request(&nw, h->family_id,
1989 PFNL_CMD_GETSTATES);
1990 hdr->nlmsg_flags |= NLM_F_DUMP;
1991 snl_add_msg_attr_string(&nw, PF_ST_IFNAME, filter->ifname);
1992 snl_add_msg_attr_u16(&nw, PF_ST_PROTO, filter->proto);
1993 snl_add_msg_attr_u8(&nw, PF_ST_AF, filter->af);
1994 snl_add_msg_attr_ip6(&nw, PF_ST_FILTER_ADDR, &filter->addr.v6);
1995 snl_add_msg_attr_ip6(&nw, PF_ST_FILTER_MASK, &filter->mask.v6);
1996 snl_add_msg_attr_bool(&nw, PF_ST_INCLUDE_RULE, filter->include_rule);
1997
1998 hdr = snl_finalize_msg(&nw);
1999 if (hdr == NULL) {
2000 ret = ENOMEM;
2001 goto out;
2002 }
2003
2004 uint32_t seq_id = hdr->nlmsg_seq;
2005
2006 if (! snl_send_message(&h->ss, hdr)) {
2007 ret = ENXIO;
2008 goto out;
2009 }
2010
2011 struct snl_errmsg_data e = {};
2012 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
2013 struct pfctl_state s;
2014 bzero(&s, sizeof(s));
2015 if (!snl_parse_nlmsg(&h->ss, hdr, &state_parser, &s))
2016 continue;
2017
2018 ret = f(&s, arg);
2019 if (ret != 0) {
2020 goto out;
2021 }
2022 }
2023
2024 ret = e.error;
2025 out:
2026 snl_clear_lb(&h->ss);
2027 return (ret);
2028 }
2029
2030 int
pfctl_get_states_iter(pfctl_get_state_fn f,void * arg)2031 pfctl_get_states_iter(pfctl_get_state_fn f, void *arg)
2032 {
2033 struct pfctl_state_filter filter = {};
2034 return (pfctl_get_filtered_states_iter(&filter, f, arg));
2035 }
2036
2037 int
pfctl_get_filtered_states_iter(struct pfctl_state_filter * filter,pfctl_get_state_fn f,void * arg)2038 pfctl_get_filtered_states_iter(struct pfctl_state_filter *filter, pfctl_get_state_fn f, void *arg)
2039 {
2040 struct pfctl_handle h = {};
2041 int error;
2042
2043 snl_init(&h.ss, NETLINK_GENERIC);
2044 error = pfctl_get_states_h(&h, filter, f, arg);
2045 snl_free(&h.ss);
2046
2047 return (error);
2048 }
2049
2050 static int
pfctl_append_states(struct pfctl_state * s,void * arg)2051 pfctl_append_states(struct pfctl_state *s, void *arg)
2052 {
2053 struct pfctl_state *new;
2054 struct pfctl_states *states = (struct pfctl_states *)arg;
2055
2056 new = malloc(sizeof(*s));
2057 if (new == NULL)
2058 return (ENOMEM);
2059
2060 memcpy(new, s, sizeof(*s));
2061
2062 TAILQ_INSERT_TAIL(&states->states, new, entry);
2063
2064 return (0);
2065 }
2066
2067 int
pfctl_get_states(int dev __unused,struct pfctl_states * states)2068 pfctl_get_states(int dev __unused, struct pfctl_states *states)
2069 {
2070 int ret;
2071
2072 bzero(states, sizeof(*states));
2073 TAILQ_INIT(&states->states);
2074
2075 ret = pfctl_get_states_iter(pfctl_append_states, states);
2076 if (ret != 0) {
2077 pfctl_free_states(states);
2078 return (ret);
2079 }
2080
2081 return (0);
2082 }
2083
2084 void
pfctl_free_states(struct pfctl_states * states)2085 pfctl_free_states(struct pfctl_states *states)
2086 {
2087 struct pfctl_state *s, *tmp;
2088
2089 TAILQ_FOREACH_SAFE(s, &states->states, entry, tmp) {
2090 free(s);
2091 }
2092
2093 bzero(states, sizeof(*states));
2094 }
2095
2096 struct pfctl_nl_clear_states {
2097 uint32_t killed;
2098 };
2099 #define _OUT(_field) offsetof(struct pfctl_nl_clear_states, _field)
2100 static struct snl_attr_parser ap_clear_states[] = {
2101 { .type = PF_CS_KILLED, .off = _OUT(killed), .cb = snl_attr_get_uint32 },
2102 };
2103 #undef _OUT
2104 SNL_DECLARE_PARSER(clear_states_parser, struct genlmsghdr, snl_f_p_empty, ap_clear_states);
2105
2106 static int
_pfctl_clear_states_h(struct pfctl_handle * h,const struct pfctl_kill * kill,unsigned int * killed,int cmd)2107 _pfctl_clear_states_h(struct pfctl_handle *h, const struct pfctl_kill *kill,
2108 unsigned int *killed, int cmd)
2109 {
2110 struct snl_writer nw;
2111 struct snl_errmsg_data e = {};
2112 struct pfctl_nl_clear_states attrs = {};
2113 struct nlmsghdr *hdr;
2114 uint32_t seq_id;
2115
2116 snl_init_writer(&h->ss, &nw);
2117 hdr = snl_create_genl_msg_request(&nw, h->family_id, cmd);
2118 hdr->nlmsg_flags |= NLM_F_DUMP;
2119
2120 snl_add_msg_attr_u64(&nw, PF_CS_CMP_ID, kill->cmp.id);
2121 snl_add_msg_attr_u32(&nw, PF_CS_CMP_CREATORID, htonl(kill->cmp.creatorid));
2122 snl_add_msg_attr_u8(&nw, PF_CS_CMP_DIR, kill->cmp.direction);
2123 snl_add_msg_attr_u8(&nw, PF_CS_AF, kill->af);
2124 snl_add_msg_attr_u8(&nw, PF_CS_PROTO, kill->proto);
2125 snl_add_msg_attr_rule_addr(&nw, PF_CS_SRC, &kill->src);
2126 snl_add_msg_attr_rule_addr(&nw, PF_CS_DST, &kill->dst);
2127 snl_add_msg_attr_rule_addr(&nw, PF_CS_RT_ADDR, &kill->rt_addr);
2128 snl_add_msg_attr_string(&nw, PF_CS_IFNAME, kill->ifname);
2129 snl_add_msg_attr_string(&nw, PF_CS_LABEL, kill->label);
2130 snl_add_msg_attr_bool(&nw, PF_CS_KILL_MATCH, kill->kill_match);
2131 snl_add_msg_attr_bool(&nw, PF_CS_NAT, kill->nat);
2132
2133 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
2134 e.error = ENXIO;
2135 goto out;
2136 }
2137
2138 seq_id = hdr->nlmsg_seq;
2139
2140 if (! snl_send_message(&h->ss, hdr)) {
2141 e.error = ENXIO;
2142 goto out;
2143 }
2144
2145 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
2146 if (! snl_parse_nlmsg(&h->ss, hdr, &clear_states_parser, &attrs))
2147 continue;
2148 }
2149
2150 if (killed)
2151 *killed = attrs.killed;
2152
2153 out:
2154 snl_clear_lb(&h->ss);
2155 return (e.error);
2156 }
2157
2158 int
pfctl_clear_states_h(struct pfctl_handle * h,const struct pfctl_kill * kill,unsigned int * killed)2159 pfctl_clear_states_h(struct pfctl_handle *h, const struct pfctl_kill *kill,
2160 unsigned int *killed)
2161 {
2162 return(_pfctl_clear_states_h(h, kill, killed, PFNL_CMD_CLRSTATES));
2163 }
2164
2165 int
pfctl_kill_states_h(struct pfctl_handle * h,const struct pfctl_kill * kill,unsigned int * killed)2166 pfctl_kill_states_h(struct pfctl_handle *h, const struct pfctl_kill *kill,
2167 unsigned int *killed)
2168 {
2169 return(_pfctl_clear_states_h(h, kill, killed, PFNL_CMD_KILLSTATES));
2170 }
2171
2172 static int
_pfctl_clear_states(int dev __unused,const struct pfctl_kill * kill,unsigned int * killed,uint64_t cmd)2173 _pfctl_clear_states(int dev __unused, const struct pfctl_kill *kill,
2174 unsigned int *killed, uint64_t cmd)
2175 {
2176 struct pfctl_handle *h;
2177 int ret;
2178
2179 h = pfctl_open(PF_DEVICE);
2180 if (h == NULL)
2181 return (ENODEV);
2182
2183 ret = _pfctl_clear_states_h(h, kill, killed, cmd);
2184 pfctl_close(h);
2185
2186 return (ret);
2187 }
2188
2189 int
pfctl_clear_states(int dev __unused,const struct pfctl_kill * kill,unsigned int * killed)2190 pfctl_clear_states(int dev __unused, const struct pfctl_kill *kill,
2191 unsigned int *killed)
2192 {
2193 return (_pfctl_clear_states(dev, kill, killed, PFNL_CMD_CLRSTATES));
2194 }
2195
2196 int
pfctl_kill_states(int dev __unused,const struct pfctl_kill * kill,unsigned int * killed)2197 pfctl_kill_states(int dev __unused, const struct pfctl_kill *kill, unsigned int *killed)
2198 {
2199 return (_pfctl_clear_states(dev, kill, killed, PFNL_CMD_KILLSTATES));
2200 }
2201
2202 int
pfctl_clear_rules(int dev,const char * anchorname)2203 pfctl_clear_rules(int dev, const char *anchorname)
2204 {
2205 struct pfioc_trans trans;
2206 struct pfioc_trans_e transe[2];
2207 int ret;
2208
2209 bzero(&trans, sizeof(trans));
2210 bzero(&transe, sizeof(transe));
2211
2212 transe[0].rs_num = PF_RULESET_SCRUB;
2213 if (strlcpy(transe[0].anchor, anchorname, sizeof(transe[0].anchor))
2214 >= sizeof(transe[0].anchor))
2215 return (E2BIG);
2216
2217 transe[1].rs_num = PF_RULESET_FILTER;
2218 if (strlcpy(transe[1].anchor, anchorname, sizeof(transe[1].anchor))
2219 >= sizeof(transe[1].anchor))
2220 return (E2BIG);
2221
2222 trans.size = 2;
2223 trans.esize = sizeof(transe[0]);
2224 trans.array = transe;
2225
2226 ret = ioctl(dev, DIOCXBEGIN, &trans);
2227 if (ret != 0)
2228 return (errno);
2229 ret = ioctl(dev, DIOCXCOMMIT, &trans);
2230 if (ret != 0)
2231 return (errno);
2232
2233 return (0);
2234 }
2235
2236 int
pfctl_clear_nat(int dev,const char * anchorname)2237 pfctl_clear_nat(int dev, const char *anchorname)
2238 {
2239 struct pfioc_trans trans;
2240 struct pfioc_trans_e transe[3];
2241 int ret;
2242
2243 bzero(&trans, sizeof(trans));
2244 bzero(&transe, sizeof(transe));
2245
2246 transe[0].rs_num = PF_RULESET_NAT;
2247 if (strlcpy(transe[0].anchor, anchorname, sizeof(transe[0].anchor))
2248 >= sizeof(transe[0].anchor))
2249 return (E2BIG);
2250
2251 transe[1].rs_num = PF_RULESET_BINAT;
2252 if (strlcpy(transe[1].anchor, anchorname, sizeof(transe[1].anchor))
2253 >= sizeof(transe[0].anchor))
2254 return (E2BIG);
2255
2256 transe[2].rs_num = PF_RULESET_RDR;
2257 if (strlcpy(transe[2].anchor, anchorname, sizeof(transe[2].anchor))
2258 >= sizeof(transe[2].anchor))
2259 return (E2BIG);
2260
2261 trans.size = 3;
2262 trans.esize = sizeof(transe[0]);
2263 trans.array = transe;
2264
2265 ret = ioctl(dev, DIOCXBEGIN, &trans);
2266 if (ret != 0)
2267 return (errno);
2268 ret = ioctl(dev, DIOCXCOMMIT, &trans);
2269 if (ret != 0)
2270 return (errno);
2271
2272 return (0);
2273 }
2274
2275 int
pfctl_clear_eth_rules(int dev,const char * anchorname)2276 pfctl_clear_eth_rules(int dev, const char *anchorname)
2277 {
2278 struct pfioc_trans trans;
2279 struct pfioc_trans_e transe;
2280 int ret;
2281
2282 bzero(&trans, sizeof(trans));
2283 bzero(&transe, sizeof(transe));
2284
2285 transe.rs_num = PF_RULESET_ETH;
2286 if (strlcpy(transe.anchor, anchorname, sizeof(transe.anchor))
2287 >= sizeof(transe.anchor))
2288 return (E2BIG);
2289
2290 trans.size = 1;
2291 trans.esize = sizeof(transe);
2292 trans.array = &transe;
2293
2294 ret = ioctl(dev, DIOCXBEGIN, &trans);
2295 if (ret != 0)
2296 return (errno);
2297 ret = ioctl(dev, DIOCXCOMMIT, &trans);
2298 if (ret != 0)
2299 return (errno);
2300
2301 return (0);
2302 }
2303
2304 static int
_pfctl_get_limit(int dev,const int index,uint * limit)2305 _pfctl_get_limit(int dev, const int index, uint *limit)
2306 {
2307 struct pfioc_limit pl;
2308
2309 bzero(&pl, sizeof(pl));
2310 pl.index = index;
2311
2312 if (ioctl(dev, DIOCGETLIMIT, &pl) == -1)
2313 return (errno);
2314
2315 *limit = pl.limit;
2316
2317 return (0);
2318 }
2319
2320 int
pfctl_set_syncookies(int dev,const struct pfctl_syncookies * s)2321 pfctl_set_syncookies(int dev, const struct pfctl_syncookies *s)
2322 {
2323 struct pfioc_nv nv;
2324 nvlist_t *nvl;
2325 int ret;
2326 uint state_limit;
2327 uint64_t lim, hi, lo;
2328
2329 ret = _pfctl_get_limit(dev, PF_LIMIT_STATES, &state_limit);
2330 if (ret != 0)
2331 return (ret);
2332
2333 if (state_limit == 0)
2334 state_limit = INT_MAX;
2335
2336 lim = state_limit;
2337 hi = lim * s->highwater / 100;
2338 lo = lim * s->lowwater / 100;
2339
2340 if (lo == hi)
2341 hi++;
2342
2343 nvl = nvlist_create(0);
2344
2345 nvlist_add_bool(nvl, "enabled", s->mode != PFCTL_SYNCOOKIES_NEVER);
2346 nvlist_add_bool(nvl, "adaptive", s->mode == PFCTL_SYNCOOKIES_ADAPTIVE);
2347 nvlist_add_number(nvl, "highwater", hi);
2348 nvlist_add_number(nvl, "lowwater", lo);
2349
2350 nv.data = nvlist_pack(nvl, &nv.len);
2351 nv.size = nv.len;
2352 nvlist_destroy(nvl);
2353 nvl = NULL;
2354
2355 ret = ioctl(dev, DIOCSETSYNCOOKIES, &nv);
2356
2357 free(nv.data);
2358 if (ret != 0)
2359 return (errno);
2360
2361 return (0);
2362 }
2363
2364 int
pfctl_get_syncookies(int dev,struct pfctl_syncookies * s)2365 pfctl_get_syncookies(int dev, struct pfctl_syncookies *s)
2366 {
2367 nvlist_t *nvl;
2368 int ret;
2369 uint state_limit;
2370 bool enabled, adaptive;
2371
2372 ret = _pfctl_get_limit(dev, PF_LIMIT_STATES, &state_limit);
2373 if (ret != 0)
2374 return (ret);
2375
2376 if (state_limit == 0)
2377 state_limit = INT_MAX;
2378
2379 bzero(s, sizeof(*s));
2380
2381 nvl = nvlist_create(0);
2382
2383 if ((ret = pfctl_do_ioctl(dev, DIOCGETSYNCOOKIES, 256, &nvl)) != 0) {
2384 ret = errno;
2385 goto out;
2386 }
2387
2388 enabled = nvlist_get_bool(nvl, "enabled");
2389 adaptive = nvlist_get_bool(nvl, "adaptive");
2390
2391 if (enabled) {
2392 if (adaptive)
2393 s->mode = PFCTL_SYNCOOKIES_ADAPTIVE;
2394 else
2395 s->mode = PFCTL_SYNCOOKIES_ALWAYS;
2396 } else {
2397 s->mode = PFCTL_SYNCOOKIES_NEVER;
2398 }
2399
2400 s->highwater = nvlist_get_number(nvl, "highwater") * 100 / state_limit;
2401 s->lowwater = nvlist_get_number(nvl, "lowwater") * 100 / state_limit;
2402 s->halfopen_states = nvlist_get_number(nvl, "halfopen_states");
2403
2404 out:
2405 nvlist_destroy(nvl);
2406 return (ret);
2407 }
2408
2409 int
pfctl_table_add_addrs(int dev,struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nadd,int flags)2410 pfctl_table_add_addrs(int dev, struct pfr_table *tbl, struct pfr_addr
2411 *addr, int size, int *nadd, int flags)
2412 {
2413 struct pfioc_table io;
2414
2415 if (tbl == NULL || size < 0 || (size && addr == NULL)) {
2416 return (EINVAL);
2417 }
2418 bzero(&io, sizeof io);
2419 io.pfrio_flags = flags;
2420 io.pfrio_table = *tbl;
2421 io.pfrio_buffer = addr;
2422 io.pfrio_esize = sizeof(*addr);
2423 io.pfrio_size = size;
2424
2425 if (ioctl(dev, DIOCRADDADDRS, &io))
2426 return (errno);
2427 if (nadd != NULL)
2428 *nadd = io.pfrio_nadd;
2429 return (0);
2430 }
2431
2432 static void
snl_add_msg_attr_table(struct snl_writer * nw,uint32_t type,const struct pfr_table * tbl)2433 snl_add_msg_attr_table(struct snl_writer *nw, uint32_t type,
2434 const struct pfr_table *tbl)
2435 {
2436 int off;
2437
2438 off = snl_add_msg_attr_nested(nw, type);
2439
2440 snl_add_msg_attr_string(nw, PF_T_ANCHOR, tbl->pfrt_anchor);
2441 snl_add_msg_attr_string(nw, PF_T_NAME, tbl->pfrt_name);
2442 snl_add_msg_attr_u32(nw, PF_T_TABLE_FLAGS, tbl->pfrt_flags);
2443
2444 snl_end_attr_nested(nw, off);
2445 }
2446
2447 static void
snl_add_msg_attr_pfr_addr(struct snl_writer * nw,uint32_t type,const struct pfr_addr * addr)2448 snl_add_msg_attr_pfr_addr(struct snl_writer *nw, uint32_t type,
2449 const struct pfr_addr *addr)
2450 {
2451 int off;
2452
2453 off = snl_add_msg_attr_nested(nw, type);
2454
2455 snl_add_msg_attr_u8(nw, PFR_A_AF, addr->pfra_af);
2456 snl_add_msg_attr_u8(nw, PFR_A_NET, addr->pfra_net);
2457 snl_add_msg_attr_bool(nw, PFR_A_NOT, addr->pfra_not);
2458 snl_add_msg_attr_ip6(nw, PFR_A_ADDR, &addr->pfra_ip6addr);
2459
2460 snl_end_attr_nested(nw, off);
2461 }
2462
2463 static struct snl_attr_parser ap_table_add_addr[] = {
2464 { .type = PF_TA_NBR_ADDED, .off = 0, .cb = snl_attr_get_uint32 },
2465 };
2466 SNL_DECLARE_PARSER(table_add_addr_parser, struct genlmsghdr, snl_f_p_empty, ap_table_add_addr);
2467
2468 static int
_pfctl_table_add_addrs_h(struct pfctl_handle * h,struct pfr_table * tbl,struct pfr_addr * addrs,int size,int * nadd,int flags)2469 _pfctl_table_add_addrs_h(struct pfctl_handle *h, struct pfr_table *tbl, struct pfr_addr
2470 *addrs, int size, int *nadd, int flags)
2471 {
2472 struct snl_writer nw;
2473 struct snl_errmsg_data e = {};
2474 struct nlmsghdr *hdr;
2475 uint32_t seq_id;
2476 uint32_t added;
2477
2478 snl_init_writer(&h->ss, &nw);
2479 hdr = snl_create_genl_msg_request(&nw, h->family_id,
2480 PFNL_CMD_TABLE_ADD_ADDR);
2481
2482 snl_add_msg_attr_table(&nw, PF_TA_TABLE, tbl);
2483 snl_add_msg_attr_u32(&nw, PF_TA_FLAGS, flags);
2484 for (int i = 0; i < size; i++)
2485 snl_add_msg_attr_pfr_addr(&nw, PF_TA_ADDR, &addrs[i]);
2486
2487 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
2488 e.error = ENXIO;
2489 goto out;
2490 }
2491 seq_id = hdr->nlmsg_seq;
2492
2493 if (! snl_send_message(&h->ss, hdr)) {
2494 e.error = ENXIO;
2495 goto out;
2496 }
2497
2498 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
2499 if (! snl_parse_nlmsg(&h->ss, hdr, &table_add_addr_parser, &added))
2500 continue;
2501 }
2502
2503 if (nadd)
2504 *nadd = added;
2505
2506 out:
2507 snl_clear_lb(&h->ss);
2508 return (e.error);
2509 }
2510
2511 int
pfctl_table_add_addrs_h(struct pfctl_handle * h,struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nadd,int flags)2512 pfctl_table_add_addrs_h(struct pfctl_handle *h, struct pfr_table *tbl, struct pfr_addr
2513 *addr, int size, int *nadd, int flags)
2514 {
2515 int ret;
2516 int off = 0;
2517 int partial_added;
2518 int chunk_size;
2519
2520 do {
2521 chunk_size = MIN(size - off, 256);
2522 ret = _pfctl_table_add_addrs_h(h, tbl, &addr[off], chunk_size, &partial_added, flags);
2523 if (ret != 0)
2524 break;
2525 if (nadd)
2526 *nadd += partial_added;
2527 off += chunk_size;
2528 } while (off < size);
2529
2530 return (ret);
2531 }
2532
2533 static struct snl_attr_parser ap_table_del_addr[] = {
2534 { .type = PF_TA_NBR_DELETED, .off = 0, .cb = snl_attr_get_uint32 },
2535 };
2536 SNL_DECLARE_PARSER(table_del_addr_parser, struct genlmsghdr, snl_f_p_empty, ap_table_del_addr);
2537 static int
_pfctl_table_del_addrs_h(struct pfctl_handle * h,struct pfr_table * tbl,struct pfr_addr * addrs,int size,int * ndel,int flags)2538 _pfctl_table_del_addrs_h(struct pfctl_handle *h, struct pfr_table *tbl, struct pfr_addr
2539 *addrs, int size, int *ndel, int flags)
2540 {
2541 struct snl_writer nw;
2542 struct snl_errmsg_data e = {};
2543 struct nlmsghdr *hdr;
2544 uint32_t seq_id;
2545 uint32_t deleted;
2546
2547 snl_init_writer(&h->ss, &nw);
2548 hdr = snl_create_genl_msg_request(&nw, h->family_id,
2549 PFNL_CMD_TABLE_DEL_ADDR);
2550
2551 snl_add_msg_attr_table(&nw, PF_TA_TABLE, tbl);
2552 snl_add_msg_attr_u32(&nw, PF_TA_FLAGS, flags);
2553 for (int i = 0; i < size; i++)
2554 snl_add_msg_attr_pfr_addr(&nw, PF_TA_ADDR, &addrs[i]);
2555
2556 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
2557 e.error = ENXIO;
2558 goto out;
2559 }
2560 seq_id = hdr->nlmsg_seq;
2561
2562 if (! snl_send_message(&h->ss, hdr)) {
2563 e.error = ENXIO;
2564 goto out;
2565 }
2566
2567 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
2568 if (! snl_parse_nlmsg(&h->ss, hdr, &table_del_addr_parser, &deleted))
2569 continue;
2570 }
2571
2572 if (ndel)
2573 *ndel = deleted;
2574
2575 out:
2576 snl_clear_lb(&h->ss);
2577 return (e.error);
2578 }
2579
2580 int
pfctl_table_del_addrs(int dev,struct pfr_table * tbl,struct pfr_addr * addr,int size,int * ndel,int flags)2581 pfctl_table_del_addrs(int dev, struct pfr_table *tbl, struct pfr_addr
2582 *addr, int size, int *ndel, int flags)
2583 {
2584 struct pfioc_table io;
2585
2586 if (tbl == NULL || size < 0 || (size && addr == NULL)) {
2587 return (EINVAL);
2588 }
2589 bzero(&io, sizeof io);
2590 io.pfrio_flags = flags;
2591 io.pfrio_table = *tbl;
2592 io.pfrio_buffer = addr;
2593 io.pfrio_esize = sizeof(*addr);
2594 io.pfrio_size = size;
2595
2596 if (ioctl(dev, DIOCRDELADDRS, &io))
2597 return (errno);
2598 if (ndel != NULL)
2599 *ndel = io.pfrio_ndel;
2600 return (0);
2601 }
2602
2603 int
pfctl_table_del_addrs_h(struct pfctl_handle * h,struct pfr_table * tbl,struct pfr_addr * addr,int size,int * ndel,int flags)2604 pfctl_table_del_addrs_h(struct pfctl_handle *h, struct pfr_table *tbl, struct pfr_addr
2605 *addr, int size, int *ndel, int flags)
2606 {
2607 int ret;
2608 int off = 0;
2609 int partial_deleted;
2610 int chunk_size;
2611
2612 do {
2613 chunk_size = MIN(size - off, 256);
2614 ret = _pfctl_table_del_addrs_h(h, tbl, &addr[off], chunk_size,
2615 &partial_deleted, flags);
2616 if (ret != 0)
2617 break;
2618 if (ndel)
2619 *ndel += partial_deleted;
2620 off += chunk_size;
2621 } while (off < size);
2622
2623 return (ret);
2624 }
2625
2626 struct pfctl_change {
2627 int add;
2628 int del;
2629 int change;
2630 };
2631 #define _OUT(_field) offsetof(struct pfctl_change, _field)
2632 static struct snl_attr_parser ap_table_set_addr[] = {
2633 { .type = PF_TA_NBR_ADDED, .off = _OUT(add), .cb = snl_attr_get_uint32 },
2634 { .type = PF_TA_NBR_DELETED, .off = _OUT(del), .cb = snl_attr_get_uint32 },
2635 { .type = PF_TA_NBR_CHANGED, .off = _OUT(change), .cb = snl_attr_get_uint32 },
2636 };
2637 #undef _OUT
2638 SNL_DECLARE_PARSER(table_set_addr_parser, struct genlmsghdr, snl_f_p_empty, ap_table_set_addr);
2639
2640 static int
_pfctl_table_set_addrs_h(struct pfctl_handle * h,struct pfr_table * tbl,struct pfr_addr * addrs,int size,int * nadd,int * ndel,int * nchange,int flags)2641 _pfctl_table_set_addrs_h(struct pfctl_handle *h, struct pfr_table *tbl, struct pfr_addr
2642 *addrs, int size, int *nadd, int *ndel, int *nchange, int flags)
2643 {
2644 struct snl_writer nw;
2645 struct snl_errmsg_data e = {};
2646 struct nlmsghdr *hdr;
2647 struct pfctl_change change = { 0 };
2648 uint32_t seq_id;
2649
2650 snl_init_writer(&h->ss, &nw);
2651 hdr = snl_create_genl_msg_request(&nw, h->family_id,
2652 PFNL_CMD_TABLE_SET_ADDR);
2653
2654 snl_add_msg_attr_table(&nw, PF_TA_TABLE, tbl);
2655 snl_add_msg_attr_u32(&nw, PF_TA_FLAGS, flags);
2656 for (int i = 0; i < size; i++)
2657 snl_add_msg_attr_pfr_addr(&nw, PF_TA_ADDR, &addrs[i]);
2658
2659 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
2660 e.error = ENXIO;
2661 goto out;
2662 }
2663 seq_id = hdr->nlmsg_seq;
2664
2665 if (! snl_send_message(&h->ss, hdr)) {
2666 e.error = ENXIO;
2667 goto out;
2668 }
2669
2670 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
2671 if (! snl_parse_nlmsg(&h->ss, hdr, &table_set_addr_parser, &change))
2672 continue;
2673 }
2674
2675 if (nadd)
2676 *nadd = change.add;
2677 if (ndel)
2678 *ndel = change.del;
2679 if (nchange)
2680 *nchange = change.change;
2681
2682 out:
2683 snl_clear_lb(&h->ss);
2684 return (e.error);
2685 }
2686
2687 int
pfctl_table_set_addrs_h(struct pfctl_handle * h,struct pfr_table * tbl,struct pfr_addr * addr,int size,int * nadd,int * ndel,int * nchange,int flags)2688 pfctl_table_set_addrs_h(struct pfctl_handle *h, struct pfr_table *tbl,
2689 struct pfr_addr *addr, int size, int *nadd, int *ndel,
2690 int *nchange, int flags)
2691 {
2692 int ret;
2693 int off = 0;
2694 int partial_add, partial_del, partial_change;
2695 int chunk_size;
2696
2697 do {
2698 flags &= ~(PFR_FLAG_START | PFR_FLAG_DONE);
2699 if (off == 0)
2700 flags |= PFR_FLAG_START;
2701 chunk_size = MIN(size - off, 256);
2702 if ((chunk_size + off) == size)
2703 flags |= PFR_FLAG_DONE;
2704 ret = _pfctl_table_set_addrs_h(h, tbl, &addr[off], chunk_size,
2705 &partial_add, &partial_del, &partial_change, flags);
2706 if (ret != 0)
2707 break;
2708 if (! (flags & PFR_FLAG_DONE)) {
2709 assert(partial_del == 0);
2710 }
2711 if (nadd)
2712 *nadd += partial_add;
2713 if (ndel)
2714 *ndel += partial_del;
2715 if (nchange)
2716 *nchange += partial_change;
2717 off += chunk_size;
2718 } while (off < size);
2719
2720 return (ret);
2721 }
2722
2723 int
pfctl_table_set_addrs(int dev,struct pfr_table * tbl,struct pfr_addr * addr,int size,int * size2,int * nadd,int * ndel,int * nchange,int flags)2724 pfctl_table_set_addrs(int dev, struct pfr_table *tbl, struct pfr_addr
2725 *addr, int size, int *size2, int *nadd, int *ndel, int *nchange, int flags)
2726 {
2727 struct pfioc_table io;
2728
2729 if (tbl == NULL || size < 0 || (size && addr == NULL)) {
2730 return (EINVAL);
2731 }
2732 bzero(&io, sizeof io);
2733 io.pfrio_flags = flags;
2734 io.pfrio_table = *tbl;
2735 io.pfrio_buffer = addr;
2736 io.pfrio_esize = sizeof(*addr);
2737 io.pfrio_size = size;
2738 io.pfrio_size2 = (size2 != NULL) ? *size2 : 0;
2739 if (ioctl(dev, DIOCRSETADDRS, &io))
2740 return (errno);
2741 if (nadd != NULL)
2742 *nadd = io.pfrio_nadd;
2743 if (ndel != NULL)
2744 *ndel = io.pfrio_ndel;
2745 if (nchange != NULL)
2746 *nchange = io.pfrio_nchange;
2747 if (size2 != NULL)
2748 *size2 = io.pfrio_size2;
2749 return (0);
2750 }
2751
pfctl_table_get_addrs(int dev,struct pfr_table * tbl,struct pfr_addr * addr,int * size,int flags)2752 int pfctl_table_get_addrs(int dev, struct pfr_table *tbl, struct pfr_addr *addr,
2753 int *size, int flags)
2754 {
2755 struct pfioc_table io;
2756
2757 if (tbl == NULL || size == NULL || *size < 0 ||
2758 (*size && addr == NULL)) {
2759 return (EINVAL);
2760 }
2761 bzero(&io, sizeof io);
2762 io.pfrio_flags = flags;
2763 io.pfrio_table = *tbl;
2764 io.pfrio_buffer = addr;
2765 io.pfrio_esize = sizeof(*addr);
2766 io.pfrio_size = *size;
2767 if (ioctl(dev, DIOCRGETADDRS, &io))
2768 return (errno);
2769 *size = io.pfrio_size;
2770 return (0);
2771 }
2772
2773 struct nl_addrs {
2774 size_t max;
2775 struct pfr_addr *addrs;
2776 size_t count;
2777 size_t total_count;
2778 };
2779
2780 #define _OUT(_field) offsetof(struct pfr_addr, _field)
2781 static const struct snl_attr_parser ap_pfr_addr[] = {
2782 { .type = PFR_A_AF, .off = _OUT(pfra_af), .cb = snl_attr_get_uint32 },
2783 { .type = PFR_A_NET, .off = _OUT(pfra_net), .cb = snl_attr_get_uint8 },
2784 { .type = PFR_A_NOT, .off = _OUT(pfra_not), .cb = snl_attr_get_bool },
2785 { .type = PFR_A_ADDR, .off = _OUT(pfra_ip6addr), .cb = snl_attr_get_in6_addr },
2786 };
2787 #undef _OUT
2788 SNL_DECLARE_ATTR_PARSER(pfr_addr_parser, ap_pfr_addr);
2789
2790 static bool
snl_attr_get_pfr_addrs(struct snl_state * ss,struct nlattr * nla,const void * arg __unused,void * target)2791 snl_attr_get_pfr_addrs(struct snl_state *ss, struct nlattr *nla,
2792 const void *arg __unused, void *target)
2793 {
2794 struct nl_addrs *a = (struct nl_addrs *)target;
2795 bool ret;
2796
2797 if (a->count >= a->max)
2798 return (false);
2799
2800 ret = snl_parse_header(ss, NLA_DATA(nla), NLA_DATA_LEN(nla),
2801 &pfr_addr_parser, &a->addrs[a->count]);
2802 if (ret)
2803 a->count++;
2804
2805 return (ret);
2806 }
2807
2808 #define _OUT(_field) offsetof(struct nl_addrs, _field)
2809 static struct snl_attr_parser ap_table_get_addr[] = {
2810 { .type = PF_TA_ADDR, .off = 0, .cb = snl_attr_get_pfr_addrs },
2811 { .type = PF_TA_ADDR_COUNT, .off = _OUT(total_count), .cb = snl_attr_get_uint32 },
2812 };
2813 #undef _OUT
2814 SNL_DECLARE_PARSER(table_get_addr_parser, struct genlmsghdr, snl_f_p_empty, ap_table_get_addr);
2815 int
pfctl_table_get_addrs_h(struct pfctl_handle * h,struct pfr_table * tbl,struct pfr_addr * addr,int * size,int flags)2816 pfctl_table_get_addrs_h(struct pfctl_handle *h, struct pfr_table *tbl,
2817 struct pfr_addr *addr, int *size, int flags)
2818 {
2819 struct nl_addrs addrs = { 0 };
2820 struct snl_writer nw;
2821 struct snl_errmsg_data e = {};
2822 struct nlmsghdr *hdr;
2823 uint32_t seq_id;
2824
2825 snl_init_writer(&h->ss, &nw);
2826 hdr = snl_create_genl_msg_request(&nw, h->family_id,
2827 PFNL_CMD_TABLE_GET_ADDR);
2828
2829 snl_add_msg_attr_table(&nw, PF_TA_TABLE, tbl);
2830 snl_add_msg_attr_u32(&nw, PF_TA_FLAGS, flags);
2831
2832 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
2833 e.error = ENXIO;
2834 goto out;
2835 }
2836
2837 seq_id = hdr->nlmsg_seq;
2838 if (! snl_send_message(&h->ss, hdr)) {
2839 e.error = ENXIO;
2840 goto out;
2841 }
2842
2843 addrs.addrs = addr;
2844 addrs.max = *size;
2845 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
2846 if (! snl_parse_nlmsg(&h->ss, hdr, &table_get_addr_parser, &addrs))
2847 continue;
2848 }
2849
2850 *size = addrs.total_count;
2851
2852 out:
2853 snl_clear_lb(&h->ss);
2854 return (e.error);
2855 }
2856
2857 int
pfctl_set_statusif(struct pfctl_handle * h,const char * ifname)2858 pfctl_set_statusif(struct pfctl_handle *h, const char *ifname)
2859 {
2860 struct snl_writer nw;
2861 struct snl_errmsg_data e = {};
2862 struct nlmsghdr *hdr;
2863 uint32_t seq_id;
2864
2865 snl_init_writer(&h->ss, &nw);
2866 hdr = snl_create_genl_msg_request(&nw, h->family_id,
2867 PFNL_CMD_SET_STATUSIF);
2868
2869 snl_add_msg_attr_string(&nw, PF_SS_IFNAME, ifname);
2870
2871 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
2872 e.error = ENXIO;
2873 goto out;
2874 }
2875
2876 seq_id = hdr->nlmsg_seq;
2877
2878 if (! snl_send_message(&h->ss, hdr)) {
2879 e.error = ENXIO;
2880 goto out;
2881 }
2882
2883 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
2884 }
2885
2886 out:
2887 snl_clear_lb(&h->ss);
2888 return (e.error);
2889 }
2890
2891 #define _IN(_field) offsetof(struct genlmsghdr, _field)
2892 #define _OUT(_field) offsetof(struct pfctl_natlook, _field)
2893 static struct snl_attr_parser ap_natlook[] = {
2894 { .type = PF_NL_SRC_ADDR, .off = _OUT(saddr), .cb = snl_attr_get_in6_addr },
2895 { .type = PF_NL_DST_ADDR, .off = _OUT(daddr), .cb = snl_attr_get_in6_addr },
2896 { .type = PF_NL_SRC_PORT, .off = _OUT(sport), .cb = snl_attr_get_uint16 },
2897 { .type = PF_NL_DST_PORT, .off = _OUT(dport), .cb = snl_attr_get_uint16 },
2898 };
2899 #undef _IN
2900 #undef _OUT
2901 SNL_DECLARE_PARSER(natlook_parser, struct genlmsghdr, snl_f_p_empty, ap_natlook);
2902
2903 int
pfctl_natlook(struct pfctl_handle * h,const struct pfctl_natlook_key * k,struct pfctl_natlook * r)2904 pfctl_natlook(struct pfctl_handle *h, const struct pfctl_natlook_key *k,
2905 struct pfctl_natlook *r)
2906 {
2907 struct snl_writer nw;
2908 struct snl_errmsg_data e = {};
2909 struct nlmsghdr *hdr;
2910 uint32_t seq_id;
2911
2912 snl_init_writer(&h->ss, &nw);
2913 hdr = snl_create_genl_msg_request(&nw, h->family_id,
2914 PFNL_CMD_NATLOOK);
2915 hdr->nlmsg_flags |= NLM_F_DUMP;
2916
2917 snl_add_msg_attr_u8(&nw, PF_NL_AF, k->af);
2918 snl_add_msg_attr_u8(&nw, PF_NL_DIRECTION, k->direction);
2919 snl_add_msg_attr_u8(&nw, PF_NL_PROTO, k->proto);
2920 snl_add_msg_attr_ip6(&nw, PF_NL_SRC_ADDR, &k->saddr.v6);
2921 snl_add_msg_attr_ip6(&nw, PF_NL_DST_ADDR, &k->daddr.v6);
2922 snl_add_msg_attr_u16(&nw, PF_NL_SRC_PORT, k->sport);
2923 snl_add_msg_attr_u16(&nw, PF_NL_DST_PORT, k->dport);
2924
2925 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
2926 e.error = ENXIO;
2927 goto out;
2928 }
2929
2930 seq_id = hdr->nlmsg_seq;
2931
2932 if (! snl_send_message(&h->ss, hdr)) {
2933 e.error = ENXIO;
2934 goto out;
2935 }
2936
2937 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
2938 if (! snl_parse_nlmsg(&h->ss, hdr, &natlook_parser, r))
2939 continue;
2940 }
2941
2942 out:
2943 snl_clear_lb(&h->ss);
2944 return (e.error);
2945 }
2946
2947 int
pfctl_set_debug(struct pfctl_handle * h,uint32_t level)2948 pfctl_set_debug(struct pfctl_handle *h, uint32_t level)
2949 {
2950 struct snl_writer nw;
2951 struct snl_errmsg_data e = {};
2952 struct nlmsghdr *hdr;
2953 uint32_t seq_id;
2954
2955 snl_init_writer(&h->ss, &nw);
2956 hdr = snl_create_genl_msg_request(&nw, h->family_id,
2957 PFNL_CMD_SET_DEBUG);
2958
2959 snl_add_msg_attr_u32(&nw, PF_SD_LEVEL, level);
2960
2961 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
2962 e.error = ENXIO;
2963 goto out;
2964 }
2965
2966 seq_id = hdr->nlmsg_seq;
2967
2968 if (! snl_send_message(&h->ss, hdr)) {
2969 e.error = ENXIO;
2970 goto out;
2971 }
2972
2973 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
2974 }
2975
2976 out:
2977 snl_clear_lb(&h->ss);
2978 return (e.error);
2979 }
2980
2981 int
pfctl_set_timeout(struct pfctl_handle * h,uint32_t timeout,uint32_t seconds)2982 pfctl_set_timeout(struct pfctl_handle *h, uint32_t timeout, uint32_t seconds)
2983 {
2984 struct snl_writer nw;
2985 struct snl_errmsg_data e = {};
2986 struct nlmsghdr *hdr;
2987 uint32_t seq_id;
2988
2989 snl_init_writer(&h->ss, &nw);
2990 hdr = snl_create_genl_msg_request(&nw, h->family_id,
2991 PFNL_CMD_SET_TIMEOUT);
2992
2993 snl_add_msg_attr_u32(&nw, PF_TO_TIMEOUT, timeout);
2994 snl_add_msg_attr_u32(&nw, PF_TO_SECONDS, seconds);
2995
2996 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
2997 e.error = ENXIO;
2998 goto out;
2999 }
3000
3001 seq_id = hdr->nlmsg_seq;
3002
3003 if (! snl_send_message(&h->ss, hdr)) {
3004 e.error = ENXIO;
3005 goto out;
3006 }
3007
3008 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3009 }
3010
3011 out:
3012 snl_clear_lb(&h->ss);
3013 return (e.error);
3014 }
3015
3016 struct pfctl_nl_timeout {
3017 uint32_t seconds;
3018 };
3019 #define _OUT(_field) offsetof(struct pfctl_nl_timeout, _field)
3020 static struct snl_attr_parser ap_get_timeout[] = {
3021 { .type = PF_TO_SECONDS, .off = _OUT(seconds), .cb = snl_attr_get_uint32 },
3022 };
3023 #undef _OUT
3024 SNL_DECLARE_PARSER(get_timeout_parser, struct genlmsghdr, snl_f_p_empty, ap_get_timeout);
3025
3026 int
pfctl_get_timeout(struct pfctl_handle * h,uint32_t timeout,uint32_t * seconds)3027 pfctl_get_timeout(struct pfctl_handle *h, uint32_t timeout, uint32_t *seconds)
3028 {
3029 struct snl_writer nw;
3030 struct pfctl_nl_timeout to = {};
3031 struct snl_errmsg_data e = {};
3032 struct nlmsghdr *hdr;
3033 uint32_t seq_id;
3034
3035 snl_init_writer(&h->ss, &nw);
3036 hdr = snl_create_genl_msg_request(&nw, h->family_id,
3037 PFNL_CMD_GET_TIMEOUT);
3038 hdr->nlmsg_flags |= NLM_F_DUMP;
3039
3040 snl_add_msg_attr_u32(&nw, PF_TO_TIMEOUT, timeout);
3041
3042 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
3043 e.error = ENXIO;
3044 goto out;
3045 }
3046
3047 seq_id = hdr->nlmsg_seq;
3048
3049 if (! snl_send_message(&h->ss, hdr)) {
3050 e.error = ENXIO;
3051 goto out;
3052 }
3053
3054 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3055 if (! snl_parse_nlmsg(&h->ss, hdr, &get_timeout_parser, &to))
3056 continue;
3057 }
3058
3059 if (seconds != NULL)
3060 *seconds = to.seconds;
3061
3062 out:
3063 snl_clear_lb(&h->ss);
3064 return (e.error);
3065 }
3066
3067 int
pfctl_set_limit(struct pfctl_handle * h,const int index,const uint limit)3068 pfctl_set_limit(struct pfctl_handle *h, const int index, const uint limit)
3069 {
3070 struct snl_writer nw;
3071 struct snl_errmsg_data e = {};
3072 struct nlmsghdr *hdr;
3073 uint32_t seq_id;
3074
3075 snl_init_writer(&h->ss, &nw);
3076 hdr = snl_create_genl_msg_request(&nw, h->family_id,
3077 PFNL_CMD_SET_LIMIT);
3078
3079 snl_add_msg_attr_u32(&nw, PF_LI_INDEX, index);
3080 snl_add_msg_attr_u32(&nw, PF_LI_LIMIT, limit);
3081
3082 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
3083 e.error = ENXIO;
3084 goto out;
3085 }
3086
3087 seq_id = hdr->nlmsg_seq;
3088
3089 if (! snl_send_message(&h->ss, hdr)) {
3090 e.error = ENXIO;
3091 goto out;
3092 }
3093
3094 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3095 }
3096
3097 out:
3098 snl_clear_lb(&h->ss);
3099 return (e.error);
3100 }
3101
3102 struct pfctl_nl_limit {
3103 unsigned int limit;
3104 };
3105 #define _OUT(_field) offsetof(struct pfctl_nl_limit, _field)
3106 static struct snl_attr_parser ap_get_limit[] = {
3107 { .type = PF_LI_LIMIT, .off = _OUT(limit), .cb = snl_attr_get_uint32 },
3108 };
3109 #undef _OUT
3110 SNL_DECLARE_PARSER(get_limit_parser, struct genlmsghdr, snl_f_p_empty, ap_get_limit);
3111
3112 int
pfctl_get_limit(struct pfctl_handle * h,const int index,uint * limit)3113 pfctl_get_limit(struct pfctl_handle *h, const int index, uint *limit)
3114 {
3115 struct snl_writer nw;
3116 struct pfctl_nl_limit li = {};
3117 struct snl_errmsg_data e = {};
3118 struct nlmsghdr *hdr;
3119 uint32_t seq_id;
3120
3121 snl_init_writer(&h->ss, &nw);
3122 hdr = snl_create_genl_msg_request(&nw, h->family_id,
3123 PFNL_CMD_GET_LIMIT);
3124 hdr->nlmsg_flags |= NLM_F_DUMP;
3125
3126 snl_add_msg_attr_u32(&nw, PF_LI_INDEX, index);
3127
3128 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
3129 e.error = ENXIO;
3130 goto out;
3131 }
3132
3133 seq_id = hdr->nlmsg_seq;
3134
3135 if (! snl_send_message(&h->ss, hdr)) {
3136 e.error = ENXIO;
3137 goto out;
3138 }
3139
3140 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3141 if (! snl_parse_nlmsg(&h->ss, hdr, &get_limit_parser, &li))
3142 continue;
3143 }
3144
3145 if (limit != NULL)
3146 *limit = li.limit;
3147
3148 out:
3149 snl_clear_lb(&h->ss);
3150 return (e.error);
3151 }
3152
3153 struct pfctl_nl_begin_addrs {
3154 uint32_t ticket;
3155 };
3156 #define _OUT(_field) offsetof(struct pfctl_nl_begin_addrs, _field)
3157 static struct snl_attr_parser ap_begin_addrs[] = {
3158 { .type = PF_BA_TICKET, .off = _OUT(ticket), .cb = snl_attr_get_uint32 },
3159 };
3160 #undef _OUT
3161 SNL_DECLARE_PARSER(begin_addrs_parser, struct genlmsghdr, snl_f_p_empty, ap_begin_addrs);
3162
3163 int
pfctl_begin_addrs(struct pfctl_handle * h,uint32_t * ticket)3164 pfctl_begin_addrs(struct pfctl_handle *h, uint32_t *ticket)
3165 {
3166 struct snl_writer nw;
3167 struct pfctl_nl_begin_addrs attrs = {};
3168 struct snl_errmsg_data e = {};
3169 struct nlmsghdr *hdr;
3170 uint32_t seq_id;
3171
3172 snl_init_writer(&h->ss, &nw);
3173 hdr = snl_create_genl_msg_request(&nw, h->family_id,
3174 PFNL_CMD_BEGIN_ADDRS);
3175 hdr->nlmsg_flags |= NLM_F_DUMP;
3176
3177 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
3178 e.error = ENXIO;
3179 goto out;
3180 }
3181
3182 seq_id = hdr->nlmsg_seq;
3183
3184 if (! snl_send_message(&h->ss, hdr)) {
3185 e.error = ENXIO;
3186 goto out;
3187 }
3188
3189 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3190 if (! snl_parse_nlmsg(&h->ss, hdr, &begin_addrs_parser, &attrs))
3191 continue;
3192 }
3193
3194 if (ticket != NULL)
3195 *ticket = attrs.ticket;
3196
3197 out:
3198 snl_clear_lb(&h->ss);
3199 return (e.error);
3200 }
3201
3202 int
pfctl_add_addr(struct pfctl_handle * h,const struct pfioc_pooladdr * pa,int which)3203 pfctl_add_addr(struct pfctl_handle *h, const struct pfioc_pooladdr *pa, int which)
3204 {
3205 struct snl_writer nw;
3206 struct snl_errmsg_data e = {};
3207 struct nlmsghdr *hdr;
3208 uint32_t seq_id;
3209
3210 snl_init_writer(&h->ss, &nw);
3211 hdr = snl_create_genl_msg_request(&nw, h->family_id,
3212 PFNL_CMD_ADD_ADDR);
3213
3214 snl_add_msg_attr_u32(&nw, PF_AA_ACTION, pa->action);
3215 snl_add_msg_attr_u32(&nw, PF_AA_TICKET, pa->ticket);
3216 snl_add_msg_attr_u32(&nw, PF_AA_NR, pa->nr);
3217 snl_add_msg_attr_u32(&nw, PF_AA_R_NUM, pa->r_num);
3218 snl_add_msg_attr_u8(&nw, PF_AA_R_ACTION, pa->r_action);
3219 snl_add_msg_attr_u8(&nw, PF_AA_R_LAST, pa->r_last);
3220 snl_add_msg_attr_u8(&nw, PF_AA_AF, pa->af);
3221 snl_add_msg_attr_string(&nw, PF_AA_ANCHOR, pa->anchor);
3222 snl_add_msg_attr_pool_addr(&nw, PF_AA_ADDR, &pa->addr);
3223 snl_add_msg_attr_u32(&nw, PF_AA_WHICH, which);
3224
3225 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
3226 e.error = ENXIO;
3227 goto out;
3228 }
3229
3230 seq_id = hdr->nlmsg_seq;
3231
3232 if (! snl_send_message(&h->ss, hdr)) {
3233 e.error = ENXIO;
3234 goto out;
3235 }
3236
3237 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3238 }
3239
3240 out:
3241 snl_clear_lb(&h->ss);
3242 return (e.error);
3243 }
3244
3245 static const struct snl_attr_parser ap_get_addrs[] = {
3246 { .type = PF_AA_NR, .off = 0, .cb = snl_attr_get_uint32 },
3247 };
3248 SNL_DECLARE_PARSER(get_addrs_parser, struct genlmsghdr, snl_f_p_empty, ap_get_addrs);
3249
3250 int
pfctl_get_addrs(struct pfctl_handle * h,uint32_t ticket,uint32_t r_num,uint8_t r_action,const char * anchor,uint32_t * nr,int which)3251 pfctl_get_addrs(struct pfctl_handle *h, uint32_t ticket, uint32_t r_num,
3252 uint8_t r_action, const char *anchor, uint32_t *nr, int which)
3253 {
3254 struct snl_writer nw;
3255 struct snl_errmsg_data e = {};
3256 struct nlmsghdr *hdr;
3257 uint32_t seq_id;
3258
3259 snl_init_writer(&h->ss, &nw);
3260 hdr = snl_create_genl_msg_request(&nw, h->family_id,
3261 PFNL_CMD_GET_ADDRS);
3262
3263 snl_add_msg_attr_u32(&nw, PF_AA_TICKET, ticket);
3264 snl_add_msg_attr_u32(&nw, PF_AA_R_NUM, r_num);
3265 snl_add_msg_attr_u8(&nw, PF_AA_R_ACTION, r_action);
3266 snl_add_msg_attr_string(&nw, PF_AA_ANCHOR, anchor);
3267 snl_add_msg_attr_u32(&nw, PF_AA_WHICH, which);
3268
3269 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
3270 e.error = ENXIO;
3271 }
3272
3273 seq_id = hdr->nlmsg_seq;
3274
3275 if (! snl_send_message(&h->ss, hdr)) {
3276 e.error = ENXIO;
3277 goto out;
3278 }
3279
3280 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3281 if (! snl_parse_nlmsg(&h->ss, hdr, &get_addrs_parser, nr))
3282 continue;
3283 }
3284
3285 out:
3286 snl_clear_lb(&h->ss);
3287 return (e.error);
3288 }
3289
3290 #define _OUT(_field) offsetof(struct pf_pooladdr, _field)
3291 static const struct snl_attr_parser ap_pool_addr[] = {
3292 { .type = PF_PA_ADDR, .off = _OUT(addr), .arg = &addr_wrap_parser, .cb = snl_attr_get_nested },
3293 { .type = PF_PA_IFNAME, .off = _OUT(ifname), .arg_u32 = IFNAMSIZ, .cb = snl_attr_copy_string },
3294 };
3295 SNL_DECLARE_ATTR_PARSER(pool_addr_parser, ap_pool_addr);
3296 #undef _OUT
3297
3298 #define _OUT(_field) offsetof(struct pfioc_pooladdr, _field)
3299 static const struct snl_attr_parser ap_get_addr[] = {
3300 { .type = PF_AA_ACTION, .off = _OUT(action), .cb = snl_attr_get_uint32 },
3301 { .type = PF_AA_TICKET, .off = _OUT(ticket), .cb = snl_attr_get_uint32 },
3302 { .type = PF_AA_NR, .off = _OUT(nr), .cb = snl_attr_get_uint32 },
3303 { .type = PF_AA_R_NUM, .off = _OUT(r_num), .cb = snl_attr_get_uint32 },
3304 { .type = PF_AA_R_ACTION, .off = _OUT(r_action), .cb = snl_attr_get_uint8 },
3305 { .type = PF_AA_R_LAST, .off = _OUT(r_last), .cb = snl_attr_get_uint8 },
3306 { .type = PF_AA_AF, .off = _OUT(af), .cb = snl_attr_get_uint8 },
3307 { .type = PF_AA_ANCHOR, .off = _OUT(anchor), .arg_u32 = MAXPATHLEN, .cb = snl_attr_copy_string },
3308 { .type = PF_AA_ADDR, .off = _OUT(addr), .arg = &pool_addr_parser, .cb = snl_attr_get_nested },
3309 };
3310 SNL_DECLARE_PARSER(get_addr_parser, struct genlmsghdr, snl_f_p_empty, ap_get_addr);
3311 #undef _OUT
3312
3313 int
pfctl_get_addr(struct pfctl_handle * h,uint32_t ticket,uint32_t r_num,uint8_t r_action,const char * anchor,uint32_t nr,struct pfioc_pooladdr * pa,int which)3314 pfctl_get_addr(struct pfctl_handle *h, uint32_t ticket, uint32_t r_num,
3315 uint8_t r_action, const char *anchor, uint32_t nr, struct pfioc_pooladdr *pa,
3316 int which)
3317 {
3318 struct snl_writer nw;
3319 struct snl_errmsg_data e = {};
3320 struct nlmsghdr *hdr;
3321 uint32_t seq_id;
3322
3323 snl_init_writer(&h->ss, &nw);
3324 hdr = snl_create_genl_msg_request(&nw, h->family_id,
3325 PFNL_CMD_GET_ADDR);
3326
3327 snl_add_msg_attr_u32(&nw, PF_AA_TICKET, ticket);
3328 snl_add_msg_attr_u32(&nw, PF_AA_R_NUM, r_num);
3329 snl_add_msg_attr_u8(&nw, PF_AA_R_ACTION, r_action);
3330 snl_add_msg_attr_string(&nw, PF_AA_ANCHOR, anchor);
3331 snl_add_msg_attr_u32(&nw, PF_AA_NR, nr);
3332 snl_add_msg_attr_u32(&nw, PF_AA_WHICH, which);
3333
3334 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
3335 e.error = ENXIO;
3336 }
3337
3338 seq_id = hdr->nlmsg_seq;
3339
3340 if (! snl_send_message(&h->ss, hdr)) {
3341 e.error = ENXIO;
3342 goto out;
3343 }
3344
3345 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3346 if (! snl_parse_nlmsg(&h->ss, hdr, &get_addr_parser, pa))
3347 continue;
3348 }
3349
3350 out:
3351 snl_clear_lb(&h->ss);
3352 return (e.error);
3353 }
3354
3355 #define _OUT(_field) offsetof(struct pfioc_ruleset, _field)
3356 static const struct snl_attr_parser ap_ruleset[] = {
3357 { .type = PF_RS_NR, .off = _OUT(nr), .cb = snl_attr_get_uint32 },
3358 { .type = PF_RS_NAME, .off = _OUT(name), .arg = (void *)PF_ANCHOR_NAME_SIZE, .cb = snl_attr_copy_string },
3359 };
3360 SNL_DECLARE_PARSER(ruleset_parser, struct genlmsghdr, snl_f_p_empty, ap_ruleset);
3361 #undef _OUT
3362
3363 int
pfctl_get_rulesets(struct pfctl_handle * h,const char * path,uint32_t * nr)3364 pfctl_get_rulesets(struct pfctl_handle *h, const char *path, uint32_t *nr)
3365 {
3366 struct snl_writer nw;
3367 struct snl_errmsg_data e = {};
3368 struct nlmsghdr *hdr;
3369 struct pfioc_ruleset rs = {};
3370 uint32_t seq_id;
3371
3372 snl_init_writer(&h->ss, &nw);
3373 hdr = snl_create_genl_msg_request(&nw, h->family_id,
3374 PFNL_CMD_GET_RULESETS);
3375
3376 snl_add_msg_attr_string(&nw, PF_RS_PATH, path);
3377
3378 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
3379 e.error = ENXIO;
3380 goto out;
3381 }
3382
3383 seq_id = hdr->nlmsg_seq;
3384
3385 if (! snl_send_message(&h->ss, hdr)) {
3386 e.error = ENXIO;
3387 goto out;
3388 }
3389
3390 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3391 if (! snl_parse_nlmsg(&h->ss, hdr, &ruleset_parser, &rs))
3392 continue;
3393 }
3394
3395 *nr = rs.nr;
3396
3397 out:
3398 snl_clear_lb(&h->ss);
3399 return (e.error);
3400 }
3401
3402 int
pfctl_get_ruleset(struct pfctl_handle * h,const char * path,uint32_t nr,struct pfioc_ruleset * rs)3403 pfctl_get_ruleset(struct pfctl_handle *h, const char *path, uint32_t nr, struct pfioc_ruleset *rs)
3404 {
3405 struct snl_writer nw;
3406 struct snl_errmsg_data e = {};
3407 struct nlmsghdr *hdr;
3408 uint32_t seq_id;
3409
3410 snl_init_writer(&h->ss, &nw);
3411 hdr = snl_create_genl_msg_request(&nw, h->family_id,
3412 PFNL_CMD_GET_RULESET);
3413
3414 snl_add_msg_attr_string(&nw, PF_RS_PATH, path);
3415 snl_add_msg_attr_u32(&nw, PF_RS_NR, nr);
3416
3417 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
3418 e.error = ENXIO;
3419 }
3420
3421 seq_id = hdr->nlmsg_seq;
3422
3423 if (! snl_send_message(&h->ss, hdr)) {
3424 e.error = ENXIO;
3425 goto out;
3426 }
3427
3428 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3429 if (! snl_parse_nlmsg(&h->ss, hdr, &ruleset_parser, rs))
3430 continue;
3431 }
3432
3433 rs->nr = nr;
3434 strlcpy(rs->path, path, sizeof(rs->path));
3435
3436 out:
3437 snl_clear_lb(&h->ss);
3438 return (e.error);
3439 }
3440
3441 #define _OUT(_field) offsetof(struct pfctl_src_node, _field)
3442 static struct snl_attr_parser ap_srcnode[] = {
3443 { .type = PF_SN_ADDR, .off = _OUT(addr), .cb = snl_attr_get_in6_addr },
3444 { .type = PF_SN_RADDR, .off = _OUT(raddr), .cb = snl_attr_get_in6_addr },
3445 { .type = PF_SN_RULE_NR, .off = _OUT(rule), .cb = snl_attr_get_uint32 },
3446 { .type = PF_SN_BYTES_IN, .off = _OUT(bytes[0]), .cb = snl_attr_get_uint64 },
3447 { .type = PF_SN_BYTES_OUT, .off = _OUT(bytes[1]), .cb = snl_attr_get_uint64 },
3448 { .type = PF_SN_PACKETS_IN, .off = _OUT(packets[0]), .cb = snl_attr_get_uint64 },
3449 { .type = PF_SN_PACKETS_OUT, .off = _OUT(packets[1]), .cb = snl_attr_get_uint64 },
3450 { .type = PF_SN_STATES, .off = _OUT(states), .cb = snl_attr_get_uint32 },
3451 { .type = PF_SN_CONNECTIONS, .off = _OUT(conn), .cb = snl_attr_get_uint32 },
3452 { .type = PF_SN_AF, .off = _OUT(af), .cb = snl_attr_get_uint8 },
3453 { .type = PF_SN_RULE_TYPE, .off = _OUT(ruletype), .cb = snl_attr_get_uint8 },
3454 { .type = PF_SN_CREATION, .off = _OUT(creation), .cb = snl_attr_get_uint64 },
3455 { .type = PF_SN_EXPIRE, .off = _OUT(expire), .cb = snl_attr_get_uint64 },
3456 { .type = PF_SN_CONNECTION_RATE, .off = _OUT(conn_rate), .arg = &pfctl_threshold_parser, .cb = snl_attr_get_nested },
3457 { .type = PF_SN_RAF, .off = _OUT(raf), .cb = snl_attr_get_uint8 },
3458 { .type = PF_SN_NODE_TYPE, .off = _OUT(type), .cb = snl_attr_get_uint8 },
3459 };
3460 #undef _OUT
3461 SNL_DECLARE_PARSER(srcnode_parser, struct genlmsghdr, snl_f_p_empty, ap_srcnode);
3462
3463 int
pfctl_get_srcnodes(struct pfctl_handle * h,pfctl_get_srcnode_fn fn,void * arg)3464 pfctl_get_srcnodes(struct pfctl_handle *h, pfctl_get_srcnode_fn fn, void *arg)
3465 {
3466 struct snl_writer nw;
3467 struct pfctl_src_node sn;
3468 struct snl_errmsg_data e = {};
3469 struct nlmsghdr *hdr;
3470 uint32_t seq_id;
3471 int ret;
3472
3473 snl_init_writer(&h->ss, &nw);
3474 hdr = snl_create_genl_msg_request(&nw, h->family_id,
3475 PFNL_CMD_GET_SRCNODES);
3476
3477 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
3478 e.error = ENXIO;
3479 goto out;
3480 }
3481
3482 seq_id = hdr->nlmsg_seq;
3483
3484 if (!snl_send_message(&h->ss, hdr)) {
3485 e.error = ENXIO;
3486 goto out;
3487 }
3488
3489 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3490 bzero(&sn, sizeof(sn));
3491 if (!snl_parse_nlmsg(&h->ss, hdr, &srcnode_parser, &sn))
3492 continue;
3493
3494 ret = fn(&sn, arg);
3495 if (ret != 0)
3496 return (ret);
3497 }
3498
3499 out:
3500 snl_clear_lb(&h->ss);
3501 return (e.error);
3502 }
3503
3504 static struct snl_attr_parser ap_ndel[] = {
3505 { .type = PF_T_NBR_DELETED, .off = 0, .cb = snl_attr_get_uint32 },
3506 };
3507 SNL_DECLARE_PARSER(ndel_parser, struct genlmsghdr, snl_f_p_empty, ap_ndel);
3508
3509 int
pfctl_clear_tables(struct pfctl_handle * h,struct pfr_table * filter,int * ndel,int flags)3510 pfctl_clear_tables(struct pfctl_handle *h, struct pfr_table *filter,
3511 int *ndel, int flags)
3512 {
3513 struct snl_writer nw;
3514 struct snl_errmsg_data e = {};
3515 struct nlmsghdr *hdr;
3516 uint32_t seq_id;
3517
3518 snl_init_writer(&h->ss, &nw);
3519 hdr = snl_create_genl_msg_request(&nw, h->family_id,
3520 PFNL_CMD_CLEAR_TABLES);
3521
3522 snl_add_msg_attr_string(&nw, PF_T_ANCHOR, filter->pfrt_anchor);
3523 snl_add_msg_attr_string(&nw, PF_T_NAME, filter->pfrt_name);
3524 snl_add_msg_attr_u32(&nw, PF_T_TABLE_FLAGS, filter->pfrt_flags);
3525 snl_add_msg_attr_u32(&nw, PF_T_FLAGS, flags);
3526
3527 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
3528 e.error = ENXIO;
3529 goto out;
3530 }
3531
3532 seq_id = hdr->nlmsg_seq;
3533
3534 if (!snl_send_message(&h->ss, hdr)) {
3535 e.error = ENXIO;
3536 goto out;
3537 }
3538
3539 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3540 if (!snl_parse_nlmsg(&h->ss, hdr, &ndel_parser, ndel))
3541 continue;
3542 }
3543
3544 out:
3545 snl_clear_lb(&h->ss);
3546 return (e.error);
3547 }
3548
3549 static struct snl_attr_parser ap_nadd[] = {
3550 { .type = PF_T_NBR_ADDED, .off = 0, .cb = snl_attr_get_uint32 },
3551 };
3552 SNL_DECLARE_PARSER(nadd_parser, struct genlmsghdr, snl_f_p_empty, ap_nadd);
3553 int
pfctl_add_table(struct pfctl_handle * h,struct pfr_table * table,int * nadd,int flags)3554 pfctl_add_table(struct pfctl_handle *h, struct pfr_table *table,
3555 int *nadd, int flags)
3556 {
3557 struct snl_writer nw;
3558 struct snl_errmsg_data e = {};
3559 struct nlmsghdr *hdr;
3560 uint32_t seq_id;
3561
3562 snl_init_writer(&h->ss, &nw);
3563 hdr = snl_create_genl_msg_request(&nw, h->family_id,
3564 PFNL_CMD_ADD_TABLE);
3565
3566 snl_add_msg_attr_string(&nw, PF_T_ANCHOR, table->pfrt_anchor);
3567 snl_add_msg_attr_string(&nw, PF_T_NAME, table->pfrt_name);
3568 snl_add_msg_attr_u32(&nw, PF_T_TABLE_FLAGS, table->pfrt_flags);
3569 snl_add_msg_attr_u32(&nw, PF_T_FLAGS, flags);
3570
3571 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
3572 e.error = ENXIO;
3573 goto out;
3574 }
3575
3576 seq_id = hdr->nlmsg_seq;
3577
3578 if (!snl_send_message(&h->ss, hdr)) {
3579 e.error = ENXIO;
3580 goto out;
3581 }
3582
3583 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3584 if (!snl_parse_nlmsg(&h->ss, hdr, &nadd_parser, nadd))
3585 continue;
3586 }
3587
3588 out:
3589 snl_clear_lb(&h->ss);
3590 return (e.error);
3591 }
3592
3593 int
pfctl_del_table(struct pfctl_handle * h,struct pfr_table * table,int * ndel,int flags)3594 pfctl_del_table(struct pfctl_handle *h, struct pfr_table *table,
3595 int *ndel, int flags)
3596 {
3597 struct snl_writer nw;
3598 struct snl_errmsg_data e = {};
3599 struct nlmsghdr *hdr;
3600 uint32_t seq_id;
3601
3602 snl_init_writer(&h->ss, &nw);
3603 hdr = snl_create_genl_msg_request(&nw, h->family_id,
3604 PFNL_CMD_DEL_TABLE);
3605
3606 snl_add_msg_attr_string(&nw, PF_T_ANCHOR, table->pfrt_anchor);
3607 snl_add_msg_attr_string(&nw, PF_T_NAME, table->pfrt_name);
3608 snl_add_msg_attr_u32(&nw, PF_T_TABLE_FLAGS, table->pfrt_flags);
3609 snl_add_msg_attr_u32(&nw, PF_T_FLAGS, flags);
3610
3611 hdr = snl_finalize_msg(&nw);
3612 if (hdr == NULL) {
3613 e.error = ENXIO;
3614 goto out;
3615 }
3616
3617 seq_id = hdr->nlmsg_seq;
3618
3619 if (! snl_send_message(&h->ss, hdr)) {
3620 e.error = ENXIO;
3621 goto out;
3622 }
3623
3624 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3625 if (!snl_parse_nlmsg(&h->ss, hdr, &ndel_parser, ndel))
3626 continue;
3627 }
3628
3629 out:
3630 snl_clear_lb(&h->ss);
3631 return (e.error);
3632 }
3633
3634 static bool
snl_attr_get_uint64_into_int_array(struct snl_state * ss,struct nlattr * nla,const void * arg,void * target)3635 snl_attr_get_uint64_into_int_array(struct snl_state *ss, struct nlattr *nla,
3636 const void *arg, void *target)
3637 {
3638 uint64_t *u64target;
3639 struct snl_uint64_array a = {
3640 .count = 0,
3641 .max = (size_t)arg,
3642 };
3643 bool error;
3644
3645 u64target = malloc(a.max * sizeof(uint64_t));
3646 a.array = u64target;
3647
3648 error = snl_parse_header(ss, NLA_DATA(nla), NLA_DATA_LEN(nla), &array_parser, &a);
3649 if (! error)
3650 return (error);
3651
3652 for (size_t i = 0; i < a.count; i++)
3653 ((int *)target)[i] = (int)u64target[i];
3654
3655 free(u64target);
3656
3657 return (true);
3658 }
3659
3660 #define _OUT(_field) offsetof(struct pfr_table, _field)
3661 static const struct snl_attr_parser ap_table[] = {
3662 { .type = PF_T_ANCHOR, .off = _OUT(pfrt_anchor), .arg = (void *)MAXPATHLEN, .cb = snl_attr_copy_string },
3663 { .type = PF_T_NAME, .off = _OUT(pfrt_name), .arg = (void *)PF_TABLE_NAME_SIZE, .cb =snl_attr_copy_string },
3664 { .type = PF_T_TABLE_FLAGS, .off = _OUT(pfrt_flags), .cb = snl_attr_get_uint32 },
3665 };
3666 #undef _OUT
3667 SNL_DECLARE_ATTR_PARSER(table_parser, ap_table);
3668 #define _OUT(_field) offsetof(struct pfr_tstats, _field)
3669 static struct snl_attr_parser ap_tstats[] = {
3670 { .type = PF_TS_TABLE, .off = _OUT(pfrts_t), .arg = &table_parser, .cb = snl_attr_get_nested },
3671 { .type = PF_TS_PACKETS, .off = _OUT(pfrts_packets), .arg = (void *)(PFR_DIR_MAX * PFR_OP_TABLE_MAX), .cb = snl_attr_get_uint64_array},
3672 { .type = PF_TS_BYTES, .off = _OUT(pfrts_bytes), .arg = (void *)(PFR_DIR_MAX * PFR_OP_TABLE_MAX), .cb = snl_attr_get_uint64_array },
3673 { .type = PF_TS_MATCH, .off = _OUT(pfrts_match), .cb = snl_attr_get_uint64 },
3674 {. type = PF_TS_NOMATCH, .off = _OUT(pfrts_nomatch), .cb = snl_attr_get_uint64 },
3675 { .type = PF_TS_TZERO, .off = _OUT(pfrts_tzero), .cb = snl_attr_get_uint64 },
3676 { .type = PF_TS_CNT, .off = _OUT(pfrts_cnt), .cb = snl_attr_get_uint64 },
3677 { .type = PF_TS_REFCNT, .off = _OUT(pfrts_refcnt), . arg = (void *)PFR_REFCNT_MAX, .cb = snl_attr_get_uint64_into_int_array },
3678 };
3679 #undef _OUT
3680 SNL_DECLARE_PARSER(tstats_parser, struct genlmsghdr, snl_f_p_empty, ap_tstats);
3681
3682 int
pfctl_get_tstats(struct pfctl_handle * h,const struct pfr_table * filter,pfctl_get_tstats_fn fn,void * arg)3683 pfctl_get_tstats(struct pfctl_handle *h, const struct pfr_table *filter,
3684 pfctl_get_tstats_fn fn, void *arg)
3685 {
3686 struct snl_writer nw;
3687 struct snl_errmsg_data e = {};
3688 struct nlmsghdr *hdr;
3689 uint32_t seq_id;
3690 int ret;
3691
3692 snl_init_writer(&h->ss, &nw);
3693 hdr = snl_create_genl_msg_request(&nw, h->family_id,
3694 PFNL_CMD_GET_TSTATS);
3695
3696 snl_add_msg_attr_string(&nw, PF_T_ANCHOR, filter->pfrt_anchor);
3697 snl_add_msg_attr_string(&nw, PF_T_NAME, filter->pfrt_name);
3698 snl_add_msg_attr_u32(&nw, PF_T_TABLE_FLAGS, filter->pfrt_flags);
3699
3700 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
3701 e.error = ENXIO;
3702 goto out;
3703 }
3704
3705 seq_id = hdr->nlmsg_seq;
3706
3707 if (! snl_send_message(&h->ss, hdr)) {
3708 e.error = ENXIO;
3709 goto out;
3710 }
3711
3712 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3713 struct pfr_tstats tstats = {};
3714
3715 if (!snl_parse_nlmsg(&h->ss, hdr, &tstats_parser, &tstats))
3716 continue;
3717
3718 ret = fn(&tstats, arg);
3719 if (ret != 0)
3720 break;
3721 }
3722
3723 out:
3724 snl_clear_lb(&h->ss);
3725 return (e.error);
3726 }
3727
3728 static struct snl_attr_parser ap_tstats_clr[] = {
3729 { .type = PF_TS_NZERO, .off = 0, .cb = snl_attr_get_uint64 },
3730 };
3731 SNL_DECLARE_PARSER(tstats_clr_parser, struct genlmsghdr, snl_f_p_empty, ap_tstats_clr);
3732
3733 int
pfctl_clear_tstats(struct pfctl_handle * h,const struct pfr_table * filter,int * nzero,int flags)3734 pfctl_clear_tstats(struct pfctl_handle *h, const struct pfr_table *filter,
3735 int *nzero, int flags)
3736 {
3737 struct snl_writer nw;
3738 struct snl_errmsg_data e = {};
3739 struct nlmsghdr *hdr;
3740 uint64_t zero;
3741 uint32_t seq_id;
3742
3743 snl_init_writer(&h->ss, &nw);
3744 hdr = snl_create_genl_msg_request(&nw, h->family_id,
3745 PFNL_CMD_CLR_TSTATS);
3746
3747 snl_add_msg_attr_string(&nw, PF_T_ANCHOR, filter->pfrt_anchor);
3748 snl_add_msg_attr_string(&nw, PF_T_NAME, filter->pfrt_name);
3749 snl_add_msg_attr_u32(&nw, PF_T_TABLE_FLAGS, filter->pfrt_flags);
3750 snl_add_msg_attr_u32(&nw, PF_T_FLAGS, flags);
3751
3752 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
3753 e.error = ENXIO;
3754 goto out;
3755 }
3756
3757 seq_id = hdr->nlmsg_seq;
3758
3759 if (! snl_send_message(&h->ss, hdr)) {
3760 e.error = ENXIO;
3761 goto out;
3762 }
3763
3764 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3765 if (!snl_parse_nlmsg(&h->ss, hdr, &tstats_clr_parser, &zero))
3766 continue;
3767 if (nzero)
3768 *nzero = (uint32_t)zero;
3769 }
3770
3771 out:
3772 snl_clear_lb(&h->ss);
3773 return (e.error);
3774 }
3775
3776 static struct snl_attr_parser ap_clr_addrs[] = {
3777 { .type = PF_T_NBR_DELETED, .off = 0, .cb = snl_attr_get_uint64 },
3778 };
3779 SNL_DECLARE_PARSER(clr_addrs_parser, struct genlmsghdr, snl_f_p_empty, ap_clr_addrs);
3780
3781 int
pfctl_clear_addrs(struct pfctl_handle * h,const struct pfr_table * filter,int * ndel,int flags)3782 pfctl_clear_addrs(struct pfctl_handle *h, const struct pfr_table *filter,
3783 int *ndel, int flags)
3784 {
3785 struct snl_writer nw;
3786 struct snl_errmsg_data e = {};
3787 struct nlmsghdr *hdr;
3788 uint64_t del;
3789 uint32_t seq_id;
3790
3791 snl_init_writer(&h->ss, &nw);
3792 hdr = snl_create_genl_msg_request(&nw, h->family_id,
3793 PFNL_CMD_CLR_ADDRS);
3794
3795 snl_add_msg_attr_string(&nw, PF_T_ANCHOR, filter->pfrt_anchor);
3796 snl_add_msg_attr_string(&nw, PF_T_NAME, filter->pfrt_name);
3797 snl_add_msg_attr_u32(&nw, PF_T_TABLE_FLAGS, filter->pfrt_flags);
3798 snl_add_msg_attr_u32(&nw, PF_T_FLAGS, flags);
3799
3800 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
3801 e.error = ENXIO;
3802 goto out;
3803 }
3804
3805 seq_id = hdr->nlmsg_seq;
3806
3807 if (! snl_send_message(&h->ss, hdr)) {
3808 e.error = ENXIO;
3809 goto out;
3810 }
3811
3812 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3813 if (!snl_parse_nlmsg(&h->ss, hdr, &clr_addrs_parser, &del))
3814 continue;
3815 if (ndel)
3816 *ndel = (uint32_t)del;
3817 }
3818
3819 out:
3820 snl_clear_lb(&h->ss);
3821 return (e.error);
3822 }
3823
3824 struct nl_astats {
3825 struct pfr_astats *a;
3826 size_t max;
3827 size_t count;
3828 uint32_t total_count;
3829 uint32_t zeroed;
3830 };
3831
3832 #define _OUT(_field) offsetof(struct pfr_astats, _field)
3833 static const struct snl_attr_parser ap_pfr_astats[] = {
3834 { .type = PF_AS_ADDR , .off = _OUT(pfras_a), .arg = &pfr_addr_parser, .cb = snl_attr_get_nested },
3835 { .type = PF_AS_PACKETS, .off = _OUT(pfras_packets), .arg = (void *)(PFR_DIR_MAX * PFR_OP_ADDR_MAX), .cb = snl_attr_get_uint64_array },
3836 { .type = PF_AS_BYTES, .off = _OUT(pfras_bytes), .arg = (void *)(PFR_DIR_MAX * PFR_OP_ADDR_MAX), .cb = snl_attr_get_uint64_array },
3837 { .type = PF_AS_TZERO, .off = _OUT(pfras_tzero), .cb = snl_attr_get_time_t },
3838 };
3839 #undef _OUT
3840 SNL_DECLARE_ATTR_PARSER(pfr_astats_parser, ap_pfr_astats);
3841
3842 static bool
snl_attr_get_pfr_astats(struct snl_state * ss,struct nlattr * nla,const void * arg __unused,void * target)3843 snl_attr_get_pfr_astats(struct snl_state *ss, struct nlattr *nla,
3844 const void *arg __unused, void *target)
3845 {
3846 struct nl_astats *a = (struct nl_astats *)target;
3847 bool ret;
3848
3849 if (a->count >= a->max)
3850 return (false);
3851
3852 ret = snl_parse_header(ss, NLA_DATA(nla), NLA_DATA_LEN(nla),
3853 &pfr_astats_parser, &a->a[a->count]);
3854 if (ret)
3855 a->count++;
3856
3857 return (ret);
3858 }
3859
3860 #define _OUT(_field) offsetof(struct nl_astats, _field)
3861 static struct snl_attr_parser ap_table_get_astats[] = {
3862 { .type = PF_TAS_ASTATS, .off = 0, .cb = snl_attr_get_pfr_astats },
3863 { .type = PF_TAS_ASTATS_COUNT, .off = _OUT(total_count), .cb = snl_attr_get_uint32 },
3864 { .type = PF_TAS_ASTATS_ZEROED, .off = _OUT(zeroed), .cb = snl_attr_get_uint32 },
3865 };
3866 #undef _OUT
3867 SNL_DECLARE_PARSER(table_astats_parser, struct genlmsghdr, snl_f_p_empty, ap_table_get_astats);
3868
3869 int
pfctl_get_astats(struct pfctl_handle * h,const struct pfr_table * tbl,struct pfr_astats * as,int * size,int flags)3870 pfctl_get_astats(struct pfctl_handle *h, const struct pfr_table *tbl,
3871 struct pfr_astats *as, int *size, int flags)
3872 {
3873 struct snl_writer nw;
3874 struct snl_errmsg_data e = {};
3875 struct nlmsghdr *hdr;
3876 struct nl_astats out = { 0 };
3877 uint32_t seq_id;
3878
3879 if (tbl == NULL || size == NULL || *size < 0 ||
3880 (*size && as == NULL))
3881 return (EINVAL);
3882
3883 snl_init_writer(&h->ss, &nw);
3884 hdr = snl_create_genl_msg_request(&nw, h->family_id,
3885 PFNL_CMD_TABLE_GET_ASTATS);
3886
3887 snl_add_msg_attr_table(&nw, PF_TAS_TABLE, tbl);
3888 snl_add_msg_attr_u32(&nw, PF_TAS_FLAGS, flags);
3889
3890 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
3891 e.error = ENXIO;
3892 goto out;
3893 }
3894
3895 seq_id = hdr->nlmsg_seq;
3896
3897 if (! snl_send_message(&h->ss, hdr)) {
3898 e.error = ENXIO;
3899 goto out;
3900 }
3901
3902 out.a = as;
3903 out.max = *size;
3904
3905 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3906 if (! snl_parse_nlmsg(&h->ss, hdr, &table_astats_parser, &out))
3907 continue;
3908 }
3909
3910 *size = out.total_count;
3911
3912 out:
3913 snl_clear_lb(&h->ss);
3914 return (e.error);
3915 }
3916
3917 static int
_pfctl_clr_astats(struct pfctl_handle * h,const struct pfr_table * tbl,struct pfr_addr * addrs,int size,int * nzero,int flags)3918 _pfctl_clr_astats(struct pfctl_handle *h, const struct pfr_table *tbl,
3919 struct pfr_addr *addrs, int size, int *nzero, int flags)
3920 {
3921 struct snl_writer nw;
3922 struct snl_errmsg_data e = {};
3923 struct nlmsghdr *hdr;
3924 uint32_t seq_id;
3925 struct nl_astats attrs;
3926
3927 snl_init_writer(&h->ss, &nw);
3928 hdr = snl_create_genl_msg_request(&nw, h->family_id,
3929 PFNL_CMD_TABLE_CLEAR_ASTATS);
3930
3931 snl_add_msg_attr_table(&nw, PF_TA_TABLE, tbl);
3932 snl_add_msg_attr_u32(&nw, PF_TA_FLAGS, flags);
3933 for (int i = 0; i < size; i++)
3934 snl_add_msg_attr_pfr_addr(&nw, PF_TA_ADDR, &addrs[i]);
3935
3936 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
3937 e.error = ENXIO;
3938 goto out;
3939 }
3940
3941 seq_id = hdr->nlmsg_seq;
3942
3943 if (! snl_send_message(&h->ss, hdr)) {
3944 e.error = ENXIO;
3945 goto out;
3946 }
3947
3948 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
3949 if (! snl_parse_nlmsg(&h->ss, hdr, &table_astats_parser, &attrs))
3950 continue;
3951 }
3952
3953 if (nzero)
3954 *nzero = attrs.zeroed;
3955
3956 out:
3957 snl_clear_lb(&h->ss);
3958 return (e.error);
3959 }
3960
3961 int
pfctl_clr_astats(struct pfctl_handle * h,const struct pfr_table * tbl,struct pfr_addr * addrs,int size,int * nzero,int flags)3962 pfctl_clr_astats(struct pfctl_handle *h, const struct pfr_table *tbl,
3963 struct pfr_addr *addrs, int size, int *nzero, int flags)
3964 {
3965 int ret;
3966 int off = 0;
3967 int partial_zeroed;
3968 int chunk_size;
3969
3970 do {
3971 chunk_size = MIN(size - off, 256);
3972 ret = _pfctl_clr_astats(h, tbl, &addrs[off], chunk_size,
3973 &partial_zeroed, flags);
3974 if (ret != 0)
3975 break;
3976 if (nzero)
3977 *nzero += partial_zeroed;
3978 off += chunk_size;
3979 } while (off < size);
3980
3981 return (ret);
3982 }
3983
3984 static int
_pfctl_test_addrs(struct pfctl_handle * h,const struct pfr_table * tbl,struct pfr_addr * addrs,int size,int * nmatch,int flags)3985 _pfctl_test_addrs(struct pfctl_handle *h, const struct pfr_table *tbl,
3986 struct pfr_addr *addrs, int size, int *nmatch, int flags)
3987 {
3988 struct snl_writer nw;
3989 struct snl_errmsg_data e = {};
3990 struct nlmsghdr *hdr;
3991 uint32_t seq_id;
3992 struct nl_astats attrs;
3993
3994 snl_init_writer(&h->ss, &nw);
3995 hdr = snl_create_genl_msg_request(&nw, h->family_id,
3996 PFNL_CMD_TABLE_TEST_ADDRS);
3997
3998 snl_add_msg_attr_table(&nw, PF_TA_TABLE, tbl);
3999 snl_add_msg_attr_u32(&nw, PF_TA_FLAGS, flags);
4000 for (int i = 0; i < size; i++)
4001 snl_add_msg_attr_pfr_addr(&nw, PF_TA_ADDR, &addrs[i]);
4002
4003 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
4004 e.error = ENXIO;
4005 goto out;
4006 }
4007
4008 seq_id = hdr->nlmsg_seq;
4009
4010 if (! snl_send_message(&h->ss, hdr)) {
4011 e.error = ENXIO;
4012 goto out;
4013 }
4014
4015 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
4016 if (! snl_parse_nlmsg(&h->ss, hdr, &table_astats_parser, &attrs))
4017 continue;
4018 }
4019
4020 if (nmatch)
4021 *nmatch = attrs.total_count;
4022
4023 out:
4024 snl_clear_lb(&h->ss);
4025 return (e.error);
4026 }
4027
4028 int
pfctl_test_addrs(struct pfctl_handle * h,const struct pfr_table * tbl,struct pfr_addr * addrs,int size,int * nmatch,int flags)4029 pfctl_test_addrs(struct pfctl_handle *h, const struct pfr_table *tbl,
4030 struct pfr_addr *addrs, int size, int *nmatch, int flags)
4031 {
4032 int ret;
4033 int off = 0;
4034 int partial_match;
4035 int chunk_size;
4036
4037 if (nmatch)
4038 *nmatch = 0;
4039
4040 do {
4041 chunk_size = MIN(size - off, 256);
4042 ret = _pfctl_test_addrs(h, tbl, &addrs[off], chunk_size,
4043 &partial_match, flags);
4044 if (ret != 0)
4045 break;
4046 if (nmatch)
4047 *nmatch += partial_match;
4048 off += chunk_size;
4049 } while (off < size);
4050
4051 return (ret);
4052 }
4053
4054 static void
snl_add_msg_attr_limit_rate(struct snl_writer * nw,uint32_t type,const struct pfctl_limit_rate * rate)4055 snl_add_msg_attr_limit_rate(struct snl_writer *nw, uint32_t type,
4056 const struct pfctl_limit_rate *rate)
4057 {
4058 int off;
4059
4060 off = snl_add_msg_attr_nested(nw, type);
4061
4062 snl_add_msg_attr_u32(nw, PF_LR_LIMIT, rate->limit);
4063 snl_add_msg_attr_u32(nw, PF_LR_SECONDS, rate->seconds);
4064
4065 snl_end_attr_nested(nw, off);
4066 }
4067
4068 #define _OUT(_field) offsetof(struct pfctl_limit_rate, _field)
4069 static const struct snl_attr_parser ap_limit_rate[] = {
4070 { .type = PF_LR_LIMIT, .off = _OUT(limit), .cb = snl_attr_get_uint32 },
4071 { .type = PF_LR_SECONDS, .off = _OUT(seconds), .cb = snl_attr_get_uint32 },
4072 };
4073 SNL_DECLARE_ATTR_PARSER(limit_rate_parser, ap_limit_rate);
4074 #undef _OUT
4075
4076 #define _OUT(_field) offsetof(struct pfctl_state_lim, _field)
4077 static struct snl_attr_parser ap_statelim[] = {
4078 { .type = PF_SL_NAME, .off = _OUT(name), .arg_u32 = PF_STATELIM_NAME_LEN, .cb = snl_attr_copy_string },
4079 { .type = PF_SL_ID, .off = _OUT(id), .cb = snl_attr_get_uint32 },
4080 { .type = PF_SL_LIMIT, .off = _OUT(limit), .cb = snl_attr_get_uint32 },
4081 { .type = PF_SL_RATE, .off = _OUT(rate), .arg = &limit_rate_parser, .cb = snl_attr_get_nested },
4082 { .type = PF_SL_DESCR, .off = _OUT(description), .arg_u32 = PF_STATELIM_DESCR_LEN, .cb = snl_attr_copy_string },
4083 { .type = PF_SL_INUSE, .off = _OUT(inuse), .cb = snl_attr_get_uint32 },
4084 { .type = PF_SL_ADMITTED, .off = _OUT(admitted), .cb = snl_attr_get_uint64 },
4085 { .type = PF_SL_HARDLIMITED, .off = _OUT(hardlimited), .cb = snl_attr_get_uint64 },
4086 { .type = PF_SL_RATELIMITED, .off = _OUT(ratelimited), .cb = snl_attr_get_uint64 },
4087 };
4088 #undef _OUT
4089 SNL_DECLARE_PARSER(statelim_parser, struct genlmsghdr, snl_f_p_empty, ap_statelim);
4090
4091 int
pfctl_state_limiter_nget(struct pfctl_handle * h,struct pfctl_state_lim * lim)4092 pfctl_state_limiter_nget(struct pfctl_handle *h, struct pfctl_state_lim *lim)
4093 {
4094 struct snl_writer nw;
4095 struct snl_errmsg_data e = {};
4096 struct nlmsghdr *hdr;
4097 uint32_t seq_id;
4098
4099 snl_init_writer(&h->ss, &nw);
4100 hdr = snl_create_genl_msg_request(&nw, h->family_id,
4101 PFNL_CMD_STATE_LIMITER_NGET);
4102
4103 snl_add_msg_attr_u32(&nw, PF_SL_ID, lim->id);
4104
4105 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
4106 e.error = ENXIO;
4107 goto out;
4108 }
4109
4110 seq_id = hdr->nlmsg_seq;
4111
4112 if (! snl_send_message(&h->ss, hdr)) {
4113 e.error = ENXIO;
4114 goto out;
4115 }
4116
4117 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
4118 if (! snl_parse_nlmsg(&h->ss, hdr, &statelim_parser, lim))
4119 continue;
4120 }
4121
4122 out:
4123 snl_clear_lb(&h->ss);
4124 return (e.error);
4125 }
4126
4127 int
pfctl_state_limiter_add(struct pfctl_handle * h,struct pfctl_state_lim * lim)4128 pfctl_state_limiter_add(struct pfctl_handle *h, struct pfctl_state_lim *lim)
4129 {
4130 struct snl_writer nw;
4131 struct snl_errmsg_data e = {};
4132 struct nlmsghdr *hdr;
4133 uint32_t seq_id;
4134
4135 snl_init_writer(&h->ss, &nw);
4136 hdr = snl_create_genl_msg_request(&nw, h->family_id,
4137 PFNL_CMD_STATE_LIMITER_ADD);
4138
4139 snl_add_msg_attr_u32(&nw, PF_SL_ID, lim->id);
4140 snl_add_msg_attr_u32(&nw, PF_SL_TICKET, lim->ticket);
4141 snl_add_msg_attr_string(&nw, PF_SL_NAME, lim->name);
4142 snl_add_msg_attr_u32(&nw, PF_SL_LIMIT, lim->limit);
4143 snl_add_msg_attr_limit_rate(&nw, PF_SL_RATE, &lim->rate);
4144 snl_add_msg_attr_string(&nw, PF_SL_DESCR, lim->description);
4145
4146 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
4147 e.error = ENXIO;
4148 goto out;
4149 }
4150
4151 seq_id = hdr->nlmsg_seq;
4152
4153 if (! snl_send_message(&h->ss, hdr)) {
4154 e.error = ENXIO;
4155 goto out;
4156 }
4157
4158 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
4159 if (! snl_parse_nlmsg(&h->ss, hdr, &statelim_parser, lim))
4160 continue;
4161 }
4162
4163 out:
4164 snl_clear_lb(&h->ss);
4165 return (e.error);
4166 }
4167
4168 #define _OUT(_field) offsetof(struct pfctl_source_lim, _field)
4169 static struct snl_attr_parser ap_sourcelim[] = {
4170 { .type = PF_SCL_NAME, .off = _OUT(name), .arg_u32 = PF_SOURCELIM_NAME_LEN, .cb = snl_attr_copy_string },
4171 { .type = PF_SCL_ID, .off = _OUT(id), .cb = snl_attr_get_uint32 },
4172 { .type = PF_SCL_ENTRIES, .off = _OUT(entries), .cb = snl_attr_get_uint32 },
4173 { .type = PF_SCL_LIMIT, .off = _OUT(limit), .cb = snl_attr_get_uint32 },
4174 { .type = PF_SCL_RATE, .off = _OUT(rate), .arg = &limit_rate_parser, .cb = snl_attr_get_nested },
4175 { .type = PF_SCL_OVERLOAD_TBL_NAME, .off = _OUT(overload_tblname), .arg_u32 = PF_TABLE_NAME_SIZE, .cb = snl_attr_copy_string },
4176 { .type = PF_SCL_OVERLOAD_HIGH_WM, .off = _OUT(overload_hwm), .cb = snl_attr_get_uint32 },
4177 { .type = PF_SCL_OVERLOAD_LOW_WM, .off = _OUT(overload_lwm), .cb = snl_attr_get_uint32 },
4178 { .type = PF_SCL_INET_PREFIX, .off = _OUT(inet_prefix), .cb = snl_attr_get_uint32 },
4179 { .type = PF_SCL_INET6_PREFIX, .off = _OUT(inet6_prefix), .cb = snl_attr_get_uint32 },
4180 { .type = PF_SCL_DESCR, .off = _OUT(description), .arg_u32 = PF_SOURCELIM_DESCR_LEN, .cb = snl_attr_copy_string },
4181 { .type = PF_SCL_NENTRIES, .off = _OUT(nentries), .cb = snl_attr_get_uint32 },
4182 { .type = PF_SCL_INUSE, .off = _OUT(inuse), .cb = snl_attr_get_uint32 },
4183 { .type = PF_SCL_ADDR_ALLOCS, .off = _OUT(addrallocs), .cb = snl_attr_get_uint64 },
4184 { .type = PF_SCL_ADDR_NOMEM, .off = _OUT(addrnomem), .cb = snl_attr_get_uint64 },
4185 { .type = PF_SCL_ADMITTED, .off = _OUT(admitted), .cb = snl_attr_get_uint64 },
4186 { .type = PF_SCL_ADDRLIMITED, .off = _OUT(addrlimited), .cb = snl_attr_get_uint64 },
4187 { .type = PF_SCL_HARDLIMITED, .off = _OUT(hardlimited), .cb = snl_attr_get_uint64 },
4188 { .type = PF_SCL_RATELIMITED, .off = _OUT(ratelimited), .cb = snl_attr_get_uint64 },
4189 };
4190 #undef _OUT
4191 SNL_DECLARE_PARSER(sourcelim_parser, struct genlmsghdr, snl_f_p_empty, ap_sourcelim);
4192
4193 int
pfctl_source_limiter_add(struct pfctl_handle * h,struct pfctl_source_lim * lim)4194 pfctl_source_limiter_add(struct pfctl_handle *h, struct pfctl_source_lim *lim)
4195 {
4196 struct snl_writer nw;
4197 struct snl_errmsg_data e = {};
4198 struct nlmsghdr *hdr;
4199 uint32_t seq_id;
4200
4201 snl_init_writer(&h->ss, &nw);
4202 hdr = snl_create_genl_msg_request(&nw, h->family_id,
4203 PFNL_CMD_SOURCE_LIMITER_ADD);
4204
4205 snl_add_msg_attr_u32(&nw, PF_SCL_TICKET, lim->ticket);
4206 snl_add_msg_attr_string(&nw, PF_SCL_NAME, lim->name);
4207 snl_add_msg_attr_u32(&nw, PF_SCL_ID, lim->id);
4208 snl_add_msg_attr_u32(&nw, PF_SCL_ENTRIES, lim->entries);
4209 snl_add_msg_attr_u32(&nw, PF_SCL_LIMIT, lim->limit);
4210 snl_add_msg_attr_limit_rate(&nw, PF_SCL_RATE, &lim->rate);
4211 snl_add_msg_attr_string(&nw, PF_SCL_OVERLOAD_TBL_NAME, lim->overload_tblname);
4212 snl_add_msg_attr_u32(&nw, PF_SCL_OVERLOAD_HIGH_WM, lim->overload_hwm);
4213 snl_add_msg_attr_u32(&nw, PF_SCL_OVERLOAD_LOW_WM, lim->overload_lwm);
4214 snl_add_msg_attr_u32(&nw, PF_SCL_INET_PREFIX, lim->inet_prefix);
4215 snl_add_msg_attr_u32(&nw, PF_SCL_INET6_PREFIX, lim->inet6_prefix);
4216 snl_add_msg_attr_string(&nw, PF_SCL_DESCR, lim->description);
4217
4218 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
4219 e.error = ENXIO;
4220 goto out;
4221 }
4222
4223 seq_id = hdr->nlmsg_seq;
4224
4225 if (! snl_send_message(&h->ss, hdr)) {
4226 e.error = ENXIO;
4227 goto out;
4228 }
4229
4230 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
4231 if (! snl_parse_nlmsg(&h->ss, hdr, &sourcelim_parser, lim))
4232 continue;
4233 }
4234
4235 out:
4236 snl_clear_lb(&h->ss);
4237 return (e.error);
4238 }
4239
4240 static int
_pfctl_source_limiter_get(struct pfctl_handle * h,int cmd,struct pfctl_source_lim * lim)4241 _pfctl_source_limiter_get(struct pfctl_handle *h, int cmd, struct pfctl_source_lim *lim)
4242 {
4243 struct snl_writer nw;
4244 struct snl_errmsg_data e = {};
4245 struct nlmsghdr *hdr;
4246 uint32_t seq_id;
4247
4248 snl_init_writer(&h->ss, &nw);
4249 hdr = snl_create_genl_msg_request(&nw, h->family_id, cmd);
4250
4251 snl_add_msg_attr_u32(&nw, PF_SCL_ID, lim->id);
4252
4253 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
4254 e.error = ENXIO;
4255 goto out;
4256 }
4257
4258 seq_id = hdr->nlmsg_seq;
4259
4260 if (! snl_send_message(&h->ss, hdr)) {
4261 e.error = ENXIO;
4262 goto out;
4263 }
4264
4265 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
4266 if (! snl_parse_nlmsg(&h->ss, hdr, &sourcelim_parser, lim))
4267 continue;
4268 }
4269
4270 out:
4271 snl_clear_lb(&h->ss);
4272 return (e.error);
4273 }
4274
4275 int
pfctl_source_limiter_get(struct pfctl_handle * h,struct pfctl_source_lim * lim)4276 pfctl_source_limiter_get(struct pfctl_handle *h, struct pfctl_source_lim *lim)
4277 {
4278 return (_pfctl_source_limiter_get(h, PFNL_CMD_SOURCE_LIMITER_GET, lim));
4279 }
4280
4281 int
pfctl_source_limiter_nget(struct pfctl_handle * h,struct pfctl_source_lim * lim)4282 pfctl_source_limiter_nget(struct pfctl_handle *h, struct pfctl_source_lim *lim)
4283 {
4284 return (_pfctl_source_limiter_get(h, PFNL_CMD_SOURCE_LIMITER_NGET, lim));
4285 }
4286
4287 #define _OUT(_field) offsetof(struct pfctl_source, _field)
4288 static struct snl_attr_parser ap_source[] = {
4289 { .type = PF_SRC_AF, .off = _OUT(af), .cb = snl_attr_get_uint8 },
4290 { .type = PF_SRC_RDOMAIN, .off = _OUT(rdomain), .cb = snl_attr_get_uint32 },
4291 { .type = PF_SRC_ADDR, .off = _OUT(addr), .cb = snl_attr_get_in6_addr },
4292 { .type = PF_SRC_INUSE, .off = _OUT(inuse), .cb = snl_attr_get_uint32 },
4293 { .type = PF_SRC_ADMITTED, .off = _OUT(admitted), .cb = snl_attr_get_uint64 },
4294 { .type = PF_SRC_HARDLIMITED, .off = _OUT(hardlimited), .cb = snl_attr_get_uint64 },
4295 { .type = PF_SRC_RATELIMITED, .off = _OUT(ratelimited), .cb = snl_attr_get_uint64 },
4296 { .type = PF_SRC_LIMIT, .off = _OUT(limit), .cb = snl_attr_get_uint32 },
4297 { .type = PF_SRC_INET_PREFIX, .off = _OUT(inet_prefix), .cb = snl_attr_get_uint32 },
4298 {. type = PF_SRC_INET6_PREFIX, .off = _OUT(inet6_prefix), .cb = snl_attr_get_uint32 },
4299 };
4300 #undef _OUT
4301 SNL_DECLARE_PARSER(source_parser, struct genlmsghdr, snl_f_p_empty, ap_source);
4302
4303 int
pfctl_source_get(struct pfctl_handle * h,int id,pfctl_get_source_fn fn,void * arg)4304 pfctl_source_get(struct pfctl_handle *h, int id, pfctl_get_source_fn fn, void *arg)
4305 {
4306 struct snl_writer nw;
4307 struct snl_errmsg_data e = {};
4308 struct nlmsghdr *hdr;
4309 uint32_t seq_id;
4310 int error;
4311
4312 snl_init_writer(&h->ss, &nw);
4313 hdr = snl_create_genl_msg_request(&nw, h->family_id,
4314 PFNL_CMD_SOURCE_NGET);
4315
4316 snl_add_msg_attr_u32(&nw, PF_SRC_ID, id);
4317
4318 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
4319 e.error = ENXIO;
4320 goto out;
4321 }
4322
4323 seq_id = hdr->nlmsg_seq;
4324
4325 if (! snl_send_message(&h->ss, hdr)) {
4326 e.error = ENXIO;
4327 goto out;
4328 }
4329
4330 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
4331 struct pfctl_source src;
4332
4333 if (! snl_parse_nlmsg(&h->ss, hdr, &source_parser, &src))
4334 continue;
4335
4336 error = fn(&src, arg);
4337 if (error != 0) {
4338 e.error = error;
4339 break;
4340 }
4341 }
4342
4343 out:
4344 snl_clear_lb(&h->ss);
4345 return (e.error);
4346 }
4347
4348 int
pfctl_source_clear(struct pfctl_handle * h,struct pfctl_source_clear * kill)4349 pfctl_source_clear(struct pfctl_handle *h, struct pfctl_source_clear *kill)
4350 {
4351 struct snl_writer nw;
4352 struct snl_errmsg_data e = {};
4353 struct nlmsghdr *hdr;
4354 uint32_t seq_id;
4355
4356 snl_init_writer(&h->ss, &nw);
4357 hdr = snl_create_genl_msg_request(&nw, h->family_id,
4358 PFNL_CMD_SOURCE_CLEAR);
4359
4360 snl_add_msg_attr_string(&nw, PF_SC_NAME, kill->name);
4361 snl_add_msg_attr_u32(&nw, PF_SC_ID, kill->id);
4362 snl_add_msg_attr_u32(&nw, PF_SC_RDOMAIN, kill->rdomain);
4363 snl_add_msg_attr_u8(&nw, PF_SC_AF, kill->af);
4364 snl_add_msg_attr_ip6(&nw, PF_SC_ADDR, &kill->addr.v6);
4365
4366 if ((hdr = snl_finalize_msg(&nw)) == NULL) {
4367 e.error = ENXIO;
4368 goto out;
4369 }
4370
4371 seq_id = hdr->nlmsg_seq;
4372
4373 if (! snl_send_message(&h->ss, hdr)) {
4374 e.error = ENXIO;
4375 goto out;
4376 }
4377
4378 while ((hdr = snl_read_reply_multi(&h->ss, seq_id, &e)) != NULL) {
4379 }
4380
4381 out:
4382 snl_clear_lb(&h->ss);
4383 return (e.error);
4384 }
4385
4386 static const struct snl_hdr_parser *all_parsers[] = {
4387 &begin_addrs_parser,
4388 &clear_states_parser,
4389 &clr_addrs_parser,
4390 &creator_parser,
4391 &get_addr_parser,
4392 &get_addrs_parser,
4393 &get_limit_parser,
4394 &get_timeout_parser,
4395 &getrule_parser,
4396 &getrules_parser,
4397 &getstatus_parser,
4398 &nadd_parser,
4399 &natlook_parser,
4400 &ndel_parser,
4401 &ruleset_parser,
4402 &skey_parser,
4403 &source_parser,
4404 &sourcelim_parser,
4405 &speer_parser,
4406 &srcnode_parser,
4407 &state_parser,
4408 &statelim_parser,
4409 &table_add_addr_parser,
4410 &table_astats_parser,
4411 &table_del_addr_parser,
4412 &table_get_addr_parser,
4413 &table_set_addr_parser,
4414 &tstats_clr_parser,
4415 &tstats_parser,
4416 };
4417
4418 static void
_pfctl_verify_parsers(void)4419 _pfctl_verify_parsers(void)
4420 {
4421 SNL_VERIFY_PARSERS(all_parsers);
4422 }
4423