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