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