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