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 <stdlib.h> 54 #include <string.h> 55 56 #include "libpfctl.h" 57 58 const char* PFCTL_SYNCOOKIES_MODE_NAMES[] = { 59 "never", 60 "always", 61 "adaptive" 62 }; 63 64 static int _pfctl_clear_states(int , const struct pfctl_kill *, 65 unsigned int *, uint64_t); 66 67 static int 68 pfctl_do_ioctl(int dev, uint cmd, size_t size, nvlist_t **nvl) 69 { 70 struct pfioc_nv nv; 71 void *data; 72 size_t nvlen; 73 int ret; 74 75 data = nvlist_pack(*nvl, &nvlen); 76 if (nvlen > size) 77 size = nvlen; 78 79 retry: 80 nv.data = malloc(size); 81 memcpy(nv.data, data, nvlen); 82 83 nv.len = nvlen; 84 nv.size = size; 85 86 ret = ioctl(dev, cmd, &nv); 87 if (ret == -1 && errno == ENOSPC) { 88 size *= 2; 89 free(nv.data); 90 goto retry; 91 } 92 93 nvlist_destroy(*nvl); 94 *nvl = NULL; 95 96 if (ret == 0) { 97 *nvl = nvlist_unpack(nv.data, nv.len, 0); 98 if (*nvl == NULL) { 99 ret = EIO; 100 goto out; 101 } 102 } else { 103 ret = errno; 104 } 105 106 out: 107 free(data); 108 free(nv.data); 109 110 return (ret); 111 } 112 113 static void 114 pf_nvuint_8_array(const nvlist_t *nvl, const char *name, size_t maxelems, 115 uint8_t *numbers, size_t *nelems) 116 { 117 const uint64_t *tmp; 118 size_t elems; 119 120 tmp = nvlist_get_number_array(nvl, name, &elems); 121 assert(elems <= maxelems); 122 123 for (size_t i = 0; i < elems; i++) 124 numbers[i] = tmp[i]; 125 126 if (nelems) 127 *nelems = elems; 128 } 129 130 static void 131 pf_nvuint_16_array(const nvlist_t *nvl, const char *name, size_t maxelems, 132 uint16_t *numbers, size_t *nelems) 133 { 134 const uint64_t *tmp; 135 size_t elems; 136 137 tmp = nvlist_get_number_array(nvl, name, &elems); 138 assert(elems <= maxelems); 139 140 for (size_t i = 0; i < elems; i++) 141 numbers[i] = tmp[i]; 142 143 if (nelems) 144 *nelems = elems; 145 } 146 147 static void 148 pf_nvuint_32_array(const nvlist_t *nvl, const char *name, size_t maxelems, 149 uint32_t *numbers, size_t *nelems) 150 { 151 const uint64_t *tmp; 152 size_t elems; 153 154 tmp = nvlist_get_number_array(nvl, name, &elems); 155 assert(elems <= maxelems); 156 157 for (size_t i = 0; i < elems; i++) 158 numbers[i] = tmp[i]; 159 160 if (nelems) 161 *nelems = elems; 162 } 163 164 static void 165 pf_nvuint_64_array(const nvlist_t *nvl, const char *name, size_t maxelems, 166 uint64_t *numbers, size_t *nelems) 167 { 168 const uint64_t *tmp; 169 size_t elems; 170 171 tmp = nvlist_get_number_array(nvl, name, &elems); 172 assert(elems <= maxelems); 173 174 for (size_t i = 0; i < elems; i++) 175 numbers[i] = tmp[i]; 176 177 if (nelems) 178 *nelems = elems; 179 } 180 181 int 182 pfctl_startstop(int start) 183 { 184 struct snl_state ss = {}; 185 struct snl_errmsg_data e = {}; 186 struct snl_writer nw; 187 struct nlmsghdr *hdr; 188 uint32_t seq_id; 189 int family_id; 190 191 snl_init(&ss, NETLINK_GENERIC); 192 family_id = snl_get_genl_family(&ss, PFNL_FAMILY_NAME); 193 194 snl_init_writer(&ss, &nw); 195 hdr = snl_create_genl_msg_request(&nw, family_id, 196 start ? PFNL_CMD_START : PFNL_CMD_STOP); 197 198 hdr = snl_finalize_msg(&nw); 199 if (hdr == NULL) 200 return (ENOMEM); 201 seq_id = hdr->nlmsg_seq; 202 203 snl_send_message(&ss, hdr); 204 205 while ((hdr = snl_read_reply_multi(&ss, seq_id, &e)) != NULL) { 206 } 207 208 return (e.error); 209 } 210 211 static void 212 _pfctl_get_status_counters(const nvlist_t *nvl, 213 struct pfctl_status_counters *counters) 214 { 215 const uint64_t *ids, *counts; 216 const char *const *names; 217 size_t id_len, counter_len, names_len; 218 219 ids = nvlist_get_number_array(nvl, "ids", &id_len); 220 counts = nvlist_get_number_array(nvl, "counters", &counter_len); 221 names = nvlist_get_string_array(nvl, "names", &names_len); 222 assert(id_len == counter_len); 223 assert(counter_len == names_len); 224 225 TAILQ_INIT(counters); 226 227 for (size_t i = 0; i < id_len; i++) { 228 struct pfctl_status_counter *c; 229 230 c = malloc(sizeof(*c)); 231 232 c->id = ids[i]; 233 c->counter = counts[i]; 234 c->name = strdup(names[i]); 235 236 TAILQ_INSERT_TAIL(counters, c, entry); 237 } 238 } 239 240 struct pfctl_status * 241 pfctl_get_status(int dev) 242 { 243 struct pfctl_status *status; 244 nvlist_t *nvl; 245 size_t len; 246 const void *chksum; 247 248 status = calloc(1, sizeof(*status)); 249 if (status == NULL) 250 return (NULL); 251 252 nvl = nvlist_create(0); 253 254 if (pfctl_do_ioctl(dev, DIOCGETSTATUSNV, 4096, &nvl)) { 255 free(status); 256 return (NULL); 257 } 258 259 status->running = nvlist_get_bool(nvl, "running"); 260 status->since = nvlist_get_number(nvl, "since"); 261 status->debug = nvlist_get_number(nvl, "debug"); 262 status->hostid = ntohl(nvlist_get_number(nvl, "hostid")); 263 status->states = nvlist_get_number(nvl, "states"); 264 status->src_nodes = nvlist_get_number(nvl, "src_nodes"); 265 status->syncookies_active = nvlist_get_bool(nvl, "syncookies_active"); 266 status->reass = nvlist_get_number(nvl, "reass"); 267 268 strlcpy(status->ifname, nvlist_get_string(nvl, "ifname"), 269 IFNAMSIZ); 270 chksum = nvlist_get_binary(nvl, "chksum", &len); 271 assert(len == PF_MD5_DIGEST_LENGTH); 272 memcpy(status->pf_chksum, chksum, len); 273 274 _pfctl_get_status_counters(nvlist_get_nvlist(nvl, "counters"), 275 &status->counters); 276 _pfctl_get_status_counters(nvlist_get_nvlist(nvl, "lcounters"), 277 &status->lcounters); 278 _pfctl_get_status_counters(nvlist_get_nvlist(nvl, "fcounters"), 279 &status->fcounters); 280 _pfctl_get_status_counters(nvlist_get_nvlist(nvl, "scounters"), 281 &status->scounters); 282 283 pf_nvuint_64_array(nvl, "pcounters", 2 * 2 * 3, 284 (uint64_t *)status->pcounters, NULL); 285 pf_nvuint_64_array(nvl, "bcounters", 2 * 2, 286 (uint64_t *)status->bcounters, NULL); 287 288 nvlist_destroy(nvl); 289 290 return (status); 291 } 292 293 static uint64_t 294 _pfctl_status_counter(struct pfctl_status_counters *counters, uint64_t id) 295 { 296 struct pfctl_status_counter *c; 297 298 TAILQ_FOREACH(c, counters, entry) { 299 if (c->id == id) 300 return (c->counter); 301 } 302 303 return (0); 304 } 305 306 uint64_t 307 pfctl_status_counter(struct pfctl_status *status, int id) 308 { 309 return (_pfctl_status_counter(&status->counters, id)); 310 } 311 312 uint64_t 313 pfctl_status_fcounter(struct pfctl_status *status, int id) 314 { 315 return (_pfctl_status_counter(&status->fcounters, id)); 316 } 317 318 uint64_t 319 pfctl_status_scounter(struct pfctl_status *status, int id) 320 { 321 return (_pfctl_status_counter(&status->scounters, id)); 322 } 323 324 void 325 pfctl_free_status(struct pfctl_status *status) 326 { 327 struct pfctl_status_counter *c, *tmp; 328 329 if (status == NULL) 330 return; 331 332 TAILQ_FOREACH_SAFE(c, &status->counters, entry, tmp) { 333 free(c->name); 334 free(c); 335 } 336 TAILQ_FOREACH_SAFE(c, &status->lcounters, entry, tmp) { 337 free(c->name); 338 free(c); 339 } 340 TAILQ_FOREACH_SAFE(c, &status->fcounters, entry, tmp) { 341 free(c->name); 342 free(c); 343 } 344 TAILQ_FOREACH_SAFE(c, &status->scounters, entry, tmp) { 345 free(c->name); 346 free(c); 347 } 348 349 free(status); 350 } 351 352 static void 353 pfctl_nv_add_addr(nvlist_t *nvparent, const char *name, 354 const struct pf_addr *addr) 355 { 356 nvlist_t *nvl = nvlist_create(0); 357 358 nvlist_add_binary(nvl, "addr", addr, sizeof(*addr)); 359 360 nvlist_add_nvlist(nvparent, name, nvl); 361 nvlist_destroy(nvl); 362 } 363 364 static void 365 pf_nvaddr_to_addr(const nvlist_t *nvl, struct pf_addr *addr) 366 { 367 size_t len; 368 const void *data; 369 370 data = nvlist_get_binary(nvl, "addr", &len); 371 assert(len == sizeof(struct pf_addr)); 372 memcpy(addr, data, len); 373 } 374 375 static void 376 pfctl_nv_add_addr_wrap(nvlist_t *nvparent, const char *name, 377 const struct pf_addr_wrap *addr) 378 { 379 nvlist_t *nvl = nvlist_create(0); 380 381 nvlist_add_number(nvl, "type", addr->type); 382 nvlist_add_number(nvl, "iflags", addr->iflags); 383 if (addr->type == PF_ADDR_DYNIFTL) 384 nvlist_add_string(nvl, "ifname", addr->v.ifname); 385 if (addr->type == PF_ADDR_TABLE) 386 nvlist_add_string(nvl, "tblname", addr->v.tblname); 387 pfctl_nv_add_addr(nvl, "addr", &addr->v.a.addr); 388 pfctl_nv_add_addr(nvl, "mask", &addr->v.a.mask); 389 390 nvlist_add_nvlist(nvparent, name, nvl); 391 nvlist_destroy(nvl); 392 } 393 394 static void 395 pf_nvaddr_wrap_to_addr_wrap(const nvlist_t *nvl, struct pf_addr_wrap *addr) 396 { 397 bzero(addr, sizeof(*addr)); 398 399 addr->type = nvlist_get_number(nvl, "type"); 400 addr->iflags = nvlist_get_number(nvl, "iflags"); 401 if (addr->type == PF_ADDR_DYNIFTL) { 402 strlcpy(addr->v.ifname, nvlist_get_string(nvl, "ifname"), 403 IFNAMSIZ); 404 addr->p.dyncnt = nvlist_get_number(nvl, "dyncnt"); 405 } 406 if (addr->type == PF_ADDR_TABLE) { 407 strlcpy(addr->v.tblname, nvlist_get_string(nvl, "tblname"), 408 PF_TABLE_NAME_SIZE); 409 addr->p.tblcnt = nvlist_get_number(nvl, "tblcnt"); 410 } 411 412 pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "addr"), &addr->v.a.addr); 413 pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "mask"), &addr->v.a.mask); 414 } 415 416 static void 417 pfctl_nv_add_rule_addr(nvlist_t *nvparent, const char *name, 418 const struct pf_rule_addr *addr) 419 { 420 uint64_t ports[2]; 421 nvlist_t *nvl = nvlist_create(0); 422 423 pfctl_nv_add_addr_wrap(nvl, "addr", &addr->addr); 424 ports[0] = addr->port[0]; 425 ports[1] = addr->port[1]; 426 nvlist_add_number_array(nvl, "port", ports, 2); 427 nvlist_add_number(nvl, "neg", addr->neg); 428 nvlist_add_number(nvl, "port_op", addr->port_op); 429 430 nvlist_add_nvlist(nvparent, name, nvl); 431 nvlist_destroy(nvl); 432 } 433 434 static void 435 pf_nvrule_addr_to_rule_addr(const nvlist_t *nvl, struct pf_rule_addr *addr) 436 { 437 pf_nvaddr_wrap_to_addr_wrap(nvlist_get_nvlist(nvl, "addr"), &addr->addr); 438 439 pf_nvuint_16_array(nvl, "port", 2, addr->port, NULL); 440 addr->neg = nvlist_get_number(nvl, "neg"); 441 addr->port_op = nvlist_get_number(nvl, "port_op"); 442 } 443 444 static void 445 pf_nvmape_to_mape(const nvlist_t *nvl, struct pf_mape_portset *mape) 446 { 447 mape->offset = nvlist_get_number(nvl, "offset"); 448 mape->psidlen = nvlist_get_number(nvl, "psidlen"); 449 mape->psid = nvlist_get_number(nvl, "psid"); 450 } 451 452 static void 453 pf_nvpool_to_pool(const nvlist_t *nvl, struct pfctl_pool *pool) 454 { 455 size_t len; 456 const void *data; 457 458 data = nvlist_get_binary(nvl, "key", &len); 459 assert(len == sizeof(pool->key)); 460 memcpy(&pool->key, data, len); 461 462 pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "counter"), &pool->counter); 463 464 pool->tblidx = nvlist_get_number(nvl, "tblidx"); 465 pf_nvuint_16_array(nvl, "proxy_port", 2, pool->proxy_port, NULL); 466 pool->opts = nvlist_get_number(nvl, "opts"); 467 468 if (nvlist_exists_nvlist(nvl, "mape")) 469 pf_nvmape_to_mape(nvlist_get_nvlist(nvl, "mape"), &pool->mape); 470 } 471 472 static void 473 pf_nvrule_uid_to_rule_uid(const nvlist_t *nvl, struct pf_rule_uid *uid) 474 { 475 pf_nvuint_32_array(nvl, "uid", 2, uid->uid, NULL); 476 uid->op = nvlist_get_number(nvl, "op"); 477 } 478 479 static void 480 pf_nvdivert_to_divert(const nvlist_t *nvl, struct pfctl_rule *rule) 481 { 482 pf_nvaddr_to_addr(nvlist_get_nvlist(nvl, "addr"), &rule->divert.addr); 483 rule->divert.port = nvlist_get_number(nvl, "port"); 484 } 485 486 static void 487 pf_nvrule_to_rule(const nvlist_t *nvl, struct pfctl_rule *rule) 488 { 489 const uint64_t *skip; 490 const char *const *labels; 491 size_t skipcount, labelcount; 492 493 rule->nr = nvlist_get_number(nvl, "nr"); 494 495 pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "src"), &rule->src); 496 pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "dst"), &rule->dst); 497 498 skip = nvlist_get_number_array(nvl, "skip", &skipcount); 499 assert(skip); 500 assert(skipcount == PF_SKIP_COUNT); 501 for (int i = 0; i < PF_SKIP_COUNT; i++) 502 rule->skip[i].nr = skip[i]; 503 504 labels = nvlist_get_string_array(nvl, "labels", &labelcount); 505 assert(labelcount <= PF_RULE_MAX_LABEL_COUNT); 506 for (size_t i = 0; i < labelcount; i++) 507 strlcpy(rule->label[i], labels[i], PF_RULE_LABEL_SIZE); 508 rule->ridentifier = nvlist_get_number(nvl, "ridentifier"); 509 strlcpy(rule->ifname, nvlist_get_string(nvl, "ifname"), IFNAMSIZ); 510 strlcpy(rule->qname, nvlist_get_string(nvl, "qname"), PF_QNAME_SIZE); 511 strlcpy(rule->pqname, nvlist_get_string(nvl, "pqname"), PF_QNAME_SIZE); 512 strlcpy(rule->tagname, nvlist_get_string(nvl, "tagname"), 513 PF_TAG_NAME_SIZE); 514 strlcpy(rule->match_tagname, nvlist_get_string(nvl, "match_tagname"), 515 PF_TAG_NAME_SIZE); 516 517 strlcpy(rule->overload_tblname, nvlist_get_string(nvl, "overload_tblname"), 518 PF_TABLE_NAME_SIZE); 519 520 pf_nvpool_to_pool(nvlist_get_nvlist(nvl, "rpool"), &rule->rpool); 521 522 rule->evaluations = nvlist_get_number(nvl, "evaluations"); 523 pf_nvuint_64_array(nvl, "packets", 2, rule->packets, NULL); 524 pf_nvuint_64_array(nvl, "bytes", 2, rule->bytes, NULL); 525 526 if (nvlist_exists_number(nvl, "timestamp")) { 527 rule->last_active_timestamp = nvlist_get_number(nvl, "timestamp"); 528 } 529 530 rule->os_fingerprint = nvlist_get_number(nvl, "os_fingerprint"); 531 532 rule->rtableid = nvlist_get_number(nvl, "rtableid"); 533 pf_nvuint_32_array(nvl, "timeout", PFTM_MAX, rule->timeout, NULL); 534 rule->max_states = nvlist_get_number(nvl, "max_states"); 535 rule->max_src_nodes = nvlist_get_number(nvl, "max_src_nodes"); 536 rule->max_src_states = nvlist_get_number(nvl, "max_src_states"); 537 rule->max_src_conn = nvlist_get_number(nvl, "max_src_conn"); 538 rule->max_src_conn_rate.limit = 539 nvlist_get_number(nvl, "max_src_conn_rate.limit"); 540 rule->max_src_conn_rate.seconds = 541 nvlist_get_number(nvl, "max_src_conn_rate.seconds"); 542 rule->qid = nvlist_get_number(nvl, "qid"); 543 rule->pqid = nvlist_get_number(nvl, "pqid"); 544 rule->dnpipe = nvlist_get_number(nvl, "dnpipe"); 545 rule->dnrpipe = nvlist_get_number(nvl, "dnrpipe"); 546 rule->free_flags = nvlist_get_number(nvl, "dnflags"); 547 rule->prob = nvlist_get_number(nvl, "prob"); 548 rule->cuid = nvlist_get_number(nvl, "cuid"); 549 rule->cpid = nvlist_get_number(nvl, "cpid"); 550 551 rule->return_icmp = nvlist_get_number(nvl, "return_icmp"); 552 rule->return_icmp6 = nvlist_get_number(nvl, "return_icmp6"); 553 rule->max_mss = nvlist_get_number(nvl, "max_mss"); 554 rule->scrub_flags = nvlist_get_number(nvl, "scrub_flags"); 555 556 pf_nvrule_uid_to_rule_uid(nvlist_get_nvlist(nvl, "uid"), &rule->uid); 557 pf_nvrule_uid_to_rule_uid(nvlist_get_nvlist(nvl, "gid"), 558 (struct pf_rule_uid *)&rule->gid); 559 560 rule->rule_flag = nvlist_get_number(nvl, "rule_flag"); 561 rule->action = nvlist_get_number(nvl, "action"); 562 rule->direction = nvlist_get_number(nvl, "direction"); 563 rule->log = nvlist_get_number(nvl, "log"); 564 rule->logif = nvlist_get_number(nvl, "logif"); 565 rule->quick = nvlist_get_number(nvl, "quick"); 566 rule->ifnot = nvlist_get_number(nvl, "ifnot"); 567 rule->match_tag_not = nvlist_get_number(nvl, "match_tag_not"); 568 rule->natpass = nvlist_get_number(nvl, "natpass"); 569 570 rule->keep_state = nvlist_get_number(nvl, "keep_state"); 571 rule->af = nvlist_get_number(nvl, "af"); 572 rule->proto = nvlist_get_number(nvl, "proto"); 573 rule->type = nvlist_get_number(nvl, "type"); 574 rule->code = nvlist_get_number(nvl, "code"); 575 rule->flags = nvlist_get_number(nvl, "flags"); 576 rule->flagset = nvlist_get_number(nvl, "flagset"); 577 rule->min_ttl = nvlist_get_number(nvl, "min_ttl"); 578 rule->allow_opts = nvlist_get_number(nvl, "allow_opts"); 579 rule->rt = nvlist_get_number(nvl, "rt"); 580 rule->return_ttl = nvlist_get_number(nvl, "return_ttl"); 581 rule->tos = nvlist_get_number(nvl, "tos"); 582 rule->set_tos = nvlist_get_number(nvl, "set_tos"); 583 rule->anchor_relative = nvlist_get_number(nvl, "anchor_relative"); 584 rule->anchor_wildcard = nvlist_get_number(nvl, "anchor_wildcard"); 585 586 rule->flush = nvlist_get_number(nvl, "flush"); 587 rule->prio = nvlist_get_number(nvl, "prio"); 588 pf_nvuint_8_array(nvl, "set_prio", 2, rule->set_prio, NULL); 589 590 pf_nvdivert_to_divert(nvlist_get_nvlist(nvl, "divert"), rule); 591 592 rule->states_cur = nvlist_get_number(nvl, "states_cur"); 593 rule->states_tot = nvlist_get_number(nvl, "states_tot"); 594 rule->src_nodes = nvlist_get_number(nvl, "src_nodes"); 595 } 596 597 static void 598 pfctl_nveth_addr_to_eth_addr(const nvlist_t *nvl, struct pfctl_eth_addr *addr) 599 { 600 static const u_int8_t EMPTY_MAC[ETHER_ADDR_LEN] = { 0 }; 601 size_t len; 602 const void *data; 603 604 data = nvlist_get_binary(nvl, "addr", &len); 605 assert(len == sizeof(addr->addr)); 606 memcpy(addr->addr, data, sizeof(addr->addr)); 607 608 data = nvlist_get_binary(nvl, "mask", &len); 609 assert(len == sizeof(addr->mask)); 610 memcpy(addr->mask, data, sizeof(addr->mask)); 611 612 addr->neg = nvlist_get_bool(nvl, "neg"); 613 614 /* To make checks for 'is this address set?' easier. */ 615 addr->isset = memcmp(addr->addr, EMPTY_MAC, ETHER_ADDR_LEN) != 0; 616 } 617 618 static nvlist_t * 619 pfctl_eth_addr_to_nveth_addr(const struct pfctl_eth_addr *addr) 620 { 621 nvlist_t *nvl; 622 623 nvl = nvlist_create(0); 624 if (nvl == NULL) 625 return (NULL); 626 627 nvlist_add_bool(nvl, "neg", addr->neg); 628 nvlist_add_binary(nvl, "addr", &addr->addr, ETHER_ADDR_LEN); 629 nvlist_add_binary(nvl, "mask", &addr->mask, ETHER_ADDR_LEN); 630 631 return (nvl); 632 } 633 634 static void 635 pfctl_nveth_rule_to_eth_rule(const nvlist_t *nvl, struct pfctl_eth_rule *rule) 636 { 637 const char *const *labels; 638 size_t labelcount, i; 639 640 rule->nr = nvlist_get_number(nvl, "nr"); 641 rule->quick = nvlist_get_bool(nvl, "quick"); 642 strlcpy(rule->ifname, nvlist_get_string(nvl, "ifname"), IFNAMSIZ); 643 rule->ifnot = nvlist_get_bool(nvl, "ifnot"); 644 rule->direction = nvlist_get_number(nvl, "direction"); 645 rule->proto = nvlist_get_number(nvl, "proto"); 646 strlcpy(rule->match_tagname, nvlist_get_string(nvl, "match_tagname"), 647 PF_TAG_NAME_SIZE); 648 rule->match_tag = nvlist_get_number(nvl, "match_tag"); 649 rule->match_tag_not = nvlist_get_bool(nvl, "match_tag_not"); 650 651 labels = nvlist_get_string_array(nvl, "labels", &labelcount); 652 assert(labelcount <= PF_RULE_MAX_LABEL_COUNT); 653 for (i = 0; i < labelcount; i++) 654 strlcpy(rule->label[i], labels[i], PF_RULE_LABEL_SIZE); 655 rule->ridentifier = nvlist_get_number(nvl, "ridentifier"); 656 657 pfctl_nveth_addr_to_eth_addr(nvlist_get_nvlist(nvl, "src"), 658 &rule->src); 659 pfctl_nveth_addr_to_eth_addr(nvlist_get_nvlist(nvl, "dst"), 660 &rule->dst); 661 662 pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "ipsrc"), 663 &rule->ipsrc); 664 pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "ipdst"), 665 &rule->ipdst); 666 667 rule->evaluations = nvlist_get_number(nvl, "evaluations"); 668 rule->packets[0] = nvlist_get_number(nvl, "packets-in"); 669 rule->packets[1] = nvlist_get_number(nvl, "packets-out"); 670 rule->bytes[0] = nvlist_get_number(nvl, "bytes-in"); 671 rule->bytes[1] = nvlist_get_number(nvl, "bytes-out"); 672 673 if (nvlist_exists_number(nvl, "timestamp")) { 674 rule->last_active_timestamp = nvlist_get_number(nvl, "timestamp"); 675 } 676 677 strlcpy(rule->qname, nvlist_get_string(nvl, "qname"), PF_QNAME_SIZE); 678 strlcpy(rule->tagname, nvlist_get_string(nvl, "tagname"), 679 PF_TAG_NAME_SIZE); 680 681 rule->dnpipe = nvlist_get_number(nvl, "dnpipe"); 682 rule->dnflags = nvlist_get_number(nvl, "dnflags"); 683 684 rule->anchor_relative = nvlist_get_number(nvl, "anchor_relative"); 685 rule->anchor_wildcard = nvlist_get_number(nvl, "anchor_wildcard"); 686 687 strlcpy(rule->bridge_to, nvlist_get_string(nvl, "bridge_to"), 688 IFNAMSIZ); 689 690 rule->action = nvlist_get_number(nvl, "action"); 691 } 692 693 int 694 pfctl_get_eth_rulesets_info(int dev, struct pfctl_eth_rulesets_info *ri, 695 const char *path) 696 { 697 nvlist_t *nvl; 698 int ret; 699 700 bzero(ri, sizeof(*ri)); 701 702 nvl = nvlist_create(0); 703 nvlist_add_string(nvl, "path", path); 704 705 if ((ret = pfctl_do_ioctl(dev, DIOCGETETHRULESETS, 256, &nvl)) != 0) 706 return (ret); 707 708 ri->nr = nvlist_get_number(nvl, "nr"); 709 710 nvlist_destroy(nvl); 711 return (0); 712 } 713 714 int 715 pfctl_get_eth_ruleset(int dev, const char *path, int nr, 716 struct pfctl_eth_ruleset_info *ri) 717 { 718 nvlist_t *nvl; 719 int ret; 720 721 bzero(ri, sizeof(*ri)); 722 723 nvl = nvlist_create(0); 724 nvlist_add_string(nvl, "path", path); 725 nvlist_add_number(nvl, "nr", nr); 726 727 if ((ret = pfctl_do_ioctl(dev, DIOCGETETHRULESET, 1024, &nvl)) != 0) 728 return (ret); 729 730 ri->nr = nvlist_get_number(nvl, "nr"); 731 strlcpy(ri->path, nvlist_get_string(nvl, "path"), MAXPATHLEN); 732 strlcpy(ri->name, nvlist_get_string(nvl, "name"), 733 PF_ANCHOR_NAME_SIZE); 734 735 nvlist_destroy(nvl); 736 737 return (0); 738 } 739 740 int 741 pfctl_get_eth_rules_info(int dev, struct pfctl_eth_rules_info *rules, 742 const char *path) 743 { 744 nvlist_t *nvl; 745 int ret; 746 747 bzero(rules, sizeof(*rules)); 748 749 nvl = nvlist_create(0); 750 nvlist_add_string(nvl, "anchor", path); 751 752 if ((ret = pfctl_do_ioctl(dev, DIOCGETETHRULES, 1024, &nvl)) != 0) 753 return (ret); 754 755 rules->nr = nvlist_get_number(nvl, "nr"); 756 rules->ticket = nvlist_get_number(nvl, "ticket"); 757 758 nvlist_destroy(nvl); 759 return (0); 760 } 761 762 int 763 pfctl_get_eth_rule(int dev, uint32_t nr, uint32_t ticket, 764 const char *path, struct pfctl_eth_rule *rule, bool clear, 765 char *anchor_call) 766 { 767 nvlist_t *nvl; 768 int ret; 769 770 nvl = nvlist_create(0); 771 772 nvlist_add_string(nvl, "anchor", path); 773 nvlist_add_number(nvl, "ticket", ticket); 774 nvlist_add_number(nvl, "nr", nr); 775 nvlist_add_bool(nvl, "clear", clear); 776 777 if ((ret = pfctl_do_ioctl(dev, DIOCGETETHRULE, 4096, &nvl)) != 0) 778 return (ret); 779 780 pfctl_nveth_rule_to_eth_rule(nvl, rule); 781 782 if (anchor_call) 783 strlcpy(anchor_call, nvlist_get_string(nvl, "anchor_call"), 784 MAXPATHLEN); 785 786 nvlist_destroy(nvl); 787 return (0); 788 } 789 790 int 791 pfctl_add_eth_rule(int dev, const struct pfctl_eth_rule *r, const char *anchor, 792 const char *anchor_call, uint32_t ticket) 793 { 794 struct pfioc_nv nv; 795 nvlist_t *nvl, *addr; 796 void *packed; 797 int error = 0; 798 size_t labelcount, size; 799 800 nvl = nvlist_create(0); 801 802 nvlist_add_number(nvl, "ticket", ticket); 803 nvlist_add_string(nvl, "anchor", anchor); 804 nvlist_add_string(nvl, "anchor_call", anchor_call); 805 806 nvlist_add_number(nvl, "nr", r->nr); 807 nvlist_add_bool(nvl, "quick", r->quick); 808 nvlist_add_string(nvl, "ifname", r->ifname); 809 nvlist_add_bool(nvl, "ifnot", r->ifnot); 810 nvlist_add_number(nvl, "direction", r->direction); 811 nvlist_add_number(nvl, "proto", r->proto); 812 nvlist_add_string(nvl, "match_tagname", r->match_tagname); 813 nvlist_add_bool(nvl, "match_tag_not", r->match_tag_not); 814 815 addr = pfctl_eth_addr_to_nveth_addr(&r->src); 816 if (addr == NULL) { 817 nvlist_destroy(nvl); 818 return (ENOMEM); 819 } 820 nvlist_add_nvlist(nvl, "src", addr); 821 nvlist_destroy(addr); 822 823 addr = pfctl_eth_addr_to_nveth_addr(&r->dst); 824 if (addr == NULL) { 825 nvlist_destroy(nvl); 826 return (ENOMEM); 827 } 828 nvlist_add_nvlist(nvl, "dst", addr); 829 nvlist_destroy(addr); 830 831 pfctl_nv_add_rule_addr(nvl, "ipsrc", &r->ipsrc); 832 pfctl_nv_add_rule_addr(nvl, "ipdst", &r->ipdst); 833 834 labelcount = 0; 835 while (labelcount < PF_RULE_MAX_LABEL_COUNT && 836 r->label[labelcount][0] != 0) { 837 nvlist_append_string_array(nvl, "labels", 838 r->label[labelcount]); 839 labelcount++; 840 } 841 nvlist_add_number(nvl, "ridentifier", r->ridentifier); 842 843 nvlist_add_string(nvl, "qname", r->qname); 844 nvlist_add_string(nvl, "tagname", r->tagname); 845 nvlist_add_number(nvl, "dnpipe", r->dnpipe); 846 nvlist_add_number(nvl, "dnflags", r->dnflags); 847 848 nvlist_add_string(nvl, "bridge_to", r->bridge_to); 849 850 nvlist_add_number(nvl, "action", r->action); 851 852 packed = nvlist_pack(nvl, &size); 853 if (packed == NULL) { 854 nvlist_destroy(nvl); 855 return (ENOMEM); 856 } 857 858 nv.len = size; 859 nv.size = size; 860 nv.data = packed; 861 862 if (ioctl(dev, DIOCADDETHRULE, &nv) != 0) 863 error = errno; 864 865 free(packed); 866 nvlist_destroy(nvl); 867 868 return (error); 869 } 870 871 static void 872 snl_add_msg_attr_addr_wrap(struct snl_writer *nw, uint32_t type, const struct pf_addr_wrap *addr) 873 { 874 int off; 875 876 off = snl_add_msg_attr_nested(nw, type); 877 878 snl_add_msg_attr_ip6(nw, PF_AT_ADDR, &addr->v.a.addr.v6); 879 snl_add_msg_attr_ip6(nw, PF_AT_MASK, &addr->v.a.mask.v6); 880 881 if (addr->type == PF_ADDR_DYNIFTL) 882 snl_add_msg_attr_string(nw, PF_AT_IFNAME, addr->v.ifname); 883 if (addr->type == PF_ADDR_TABLE) 884 snl_add_msg_attr_string(nw, PF_AT_TABLENAME, addr->v.tblname); 885 snl_add_msg_attr_u8(nw, PF_AT_TYPE, addr->type); 886 snl_add_msg_attr_u8(nw, PF_AT_IFLAGS, addr->iflags); 887 888 snl_end_attr_nested(nw, off); 889 } 890 891 static void 892 snl_add_msg_attr_rule_addr(struct snl_writer *nw, uint32_t type, const struct pf_rule_addr *addr) 893 { 894 int off; 895 896 off = snl_add_msg_attr_nested(nw, type); 897 898 snl_add_msg_attr_addr_wrap(nw, PF_RAT_ADDR, &addr->addr); 899 snl_add_msg_attr_u16(nw, PF_RAT_SRC_PORT, addr->port[0]); 900 snl_add_msg_attr_u16(nw, PF_RAT_DST_PORT, addr->port[1]); 901 snl_add_msg_attr_u8(nw, PF_RAT_NEG, addr->neg); 902 snl_add_msg_attr_u8(nw, PF_RAT_OP, addr->port_op); 903 904 snl_end_attr_nested(nw, off); 905 } 906 907 static void 908 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]) 909 { 910 int off, i = 0; 911 912 off = snl_add_msg_attr_nested(nw, type); 913 914 while (labels[i][0] != 0 && 915 i < PF_RULE_MAX_LABEL_COUNT) { 916 snl_add_msg_attr_string(nw, PF_LT_LABEL, labels[i]); 917 i++; 918 } 919 920 snl_end_attr_nested(nw, off); 921 } 922 923 static void 924 snl_add_msg_attr_mape(struct snl_writer *nw, uint32_t type, const struct pf_mape_portset *me) 925 { 926 int off; 927 928 off = snl_add_msg_attr_nested(nw, type); 929 930 snl_add_msg_attr_u8(nw, PF_MET_OFFSET, me->offset); 931 snl_add_msg_attr_u8(nw, PF_MET_PSID_LEN, me->psidlen); 932 snl_add_msg_attr_u16(nw, PF_MET_PSID, me->psid); 933 934 snl_end_attr_nested(nw, off); 935 } 936 937 static void 938 snl_add_msg_attr_rpool(struct snl_writer *nw, uint32_t type, const struct pfctl_pool *pool) 939 { 940 int off; 941 942 off = snl_add_msg_attr_nested(nw, type); 943 944 snl_add_msg_attr(nw, PF_PT_KEY, sizeof(pool->key), &pool->key); 945 snl_add_msg_attr_ip6(nw, PF_PT_COUNTER, &pool->counter.v6); 946 snl_add_msg_attr_u32(nw, PF_PT_TBLIDX, pool->tblidx); 947 snl_add_msg_attr_u16(nw, PF_PT_PROXY_SRC_PORT, pool->proxy_port[0]); 948 snl_add_msg_attr_u16(nw, PF_PT_PROXY_DST_PORT, pool->proxy_port[1]); 949 snl_add_msg_attr_u8(nw, PF_PT_OPTS, pool->opts); 950 snl_add_msg_attr_mape(nw, PF_PT_MAPE, &pool->mape); 951 952 snl_end_attr_nested(nw, off); 953 } 954 955 static void 956 snl_add_msg_attr_timeouts(struct snl_writer *nw, uint32_t type, const uint32_t *timeouts) 957 { 958 int off; 959 960 off = snl_add_msg_attr_nested(nw, type); 961 962 for (int i = 0; i < PFTM_MAX; i++) 963 snl_add_msg_attr_u32(nw, PF_TT_TIMEOUT, timeouts[i]); 964 965 snl_end_attr_nested(nw, off); 966 } 967 968 static void 969 snl_add_msg_attr_uid(struct snl_writer *nw, uint32_t type, const struct pf_rule_uid *uid) 970 { 971 int off; 972 973 off = snl_add_msg_attr_nested(nw, type); 974 975 snl_add_msg_attr_u32(nw, PF_RUT_UID_LOW, uid->uid[0]); 976 snl_add_msg_attr_u32(nw, PF_RUT_UID_HIGH, uid->uid[1]); 977 snl_add_msg_attr_u8(nw, PF_RUT_OP, uid->op); 978 979 snl_end_attr_nested(nw, off); 980 } 981 982 static void 983 snl_add_msg_attr_pf_rule(struct snl_writer *nw, uint32_t type, const struct pfctl_rule *r) 984 { 985 int off; 986 987 off = snl_add_msg_attr_nested(nw, type); 988 989 snl_add_msg_attr_rule_addr(nw, PF_RT_SRC, &r->src); 990 snl_add_msg_attr_rule_addr(nw, PF_RT_DST, &r->dst); 991 snl_add_msg_attr_rule_labels(nw, PF_RT_LABELS, r->label); 992 snl_add_msg_attr_u32(nw, PF_RT_RIDENTIFIER, r->ridentifier); 993 snl_add_msg_attr_string(nw, PF_RT_IFNAME, r->ifname); 994 snl_add_msg_attr_string(nw, PF_RT_QNAME, r->qname); 995 snl_add_msg_attr_string(nw, PF_RT_PQNAME, r->pqname); 996 snl_add_msg_attr_string(nw, PF_RT_TAGNAME, r->tagname); 997 snl_add_msg_attr_string(nw, PF_RT_MATCH_TAGNAME, r->match_tagname); 998 snl_add_msg_attr_string(nw, PF_RT_OVERLOAD_TBLNAME, r->overload_tblname); 999 snl_add_msg_attr_rpool(nw, PF_RT_RPOOL, &r->rpool); 1000 snl_add_msg_attr_u32(nw, PF_RT_OS_FINGERPRINT, r->os_fingerprint); 1001 snl_add_msg_attr_u32(nw, PF_RT_RTABLEID, r->rtableid); 1002 snl_add_msg_attr_timeouts(nw, PF_RT_TIMEOUT, r->timeout); 1003 snl_add_msg_attr_u32(nw, PF_RT_MAX_STATES, r->max_states); 1004 snl_add_msg_attr_u32(nw, PF_RT_MAX_SRC_NODES, r->max_src_nodes); 1005 snl_add_msg_attr_u32(nw, PF_RT_MAX_SRC_STATES, r->max_src_states); 1006 snl_add_msg_attr_u32(nw, PF_RT_MAX_SRC_CONN_RATE_LIMIT, r->max_src_conn_rate.limit); 1007 snl_add_msg_attr_u32(nw, PF_RT_MAX_SRC_CONN_RATE_SECS, r->max_src_conn_rate.seconds); 1008 1009 snl_add_msg_attr_u16(nw, PF_RT_DNPIPE, r->dnpipe); 1010 snl_add_msg_attr_u16(nw, PF_RT_DNRPIPE, r->dnrpipe); 1011 snl_add_msg_attr_u32(nw, PF_RT_DNFLAGS, r->free_flags); 1012 1013 snl_add_msg_attr_u32(nw, PF_RT_NR, r->nr); 1014 snl_add_msg_attr_u32(nw, PF_RT_PROB, r->prob); 1015 snl_add_msg_attr_u32(nw, PF_RT_CUID, r->cuid); 1016 snl_add_msg_attr_u32(nw, PF_RT_CPID, r->cpid); 1017 1018 snl_add_msg_attr_u16(nw, PF_RT_RETURN_ICMP, r->return_icmp); 1019 snl_add_msg_attr_u16(nw, PF_RT_RETURN_ICMP6, r->return_icmp6); 1020 snl_add_msg_attr_u16(nw, PF_RT_MAX_MSS, r->max_mss); 1021 snl_add_msg_attr_u16(nw, PF_RT_SCRUB_FLAGS, r->scrub_flags); 1022 1023 snl_add_msg_attr_uid(nw, PF_RT_UID, &r->uid); 1024 snl_add_msg_attr_uid(nw, PF_RT_GID, (const struct pf_rule_uid *)&r->gid); 1025 1026 snl_add_msg_attr_u32(nw, PF_RT_RULE_FLAG, r->rule_flag); 1027 snl_add_msg_attr_u8(nw, PF_RT_ACTION, r->action); 1028 snl_add_msg_attr_u8(nw, PF_RT_DIRECTION, r->direction); 1029 snl_add_msg_attr_u8(nw, PF_RT_LOG, r->log); 1030 snl_add_msg_attr_u8(nw, PF_RT_LOGIF, r->logif); 1031 snl_add_msg_attr_u8(nw, PF_RT_QUICK, r->quick); 1032 snl_add_msg_attr_u8(nw, PF_RT_IF_NOT, r->ifnot); 1033 snl_add_msg_attr_u8(nw, PF_RT_MATCH_TAG_NOT, r->match_tag_not); 1034 snl_add_msg_attr_u8(nw, PF_RT_NATPASS, r->natpass); 1035 snl_add_msg_attr_u8(nw, PF_RT_KEEP_STATE, r->keep_state); 1036 snl_add_msg_attr_u8(nw, PF_RT_AF, r->af); 1037 snl_add_msg_attr_u8(nw, PF_RT_PROTO, r->proto); 1038 snl_add_msg_attr_u8(nw, PF_RT_TYPE, r->type); 1039 snl_add_msg_attr_u8(nw, PF_RT_CODE, r->code); 1040 snl_add_msg_attr_u8(nw, PF_RT_FLAGS, r->flags); 1041 snl_add_msg_attr_u8(nw, PF_RT_FLAGSET, r->flagset); 1042 snl_add_msg_attr_u8(nw, PF_RT_MIN_TTL, r->min_ttl); 1043 snl_add_msg_attr_u8(nw, PF_RT_ALLOW_OPTS, r->allow_opts); 1044 snl_add_msg_attr_u8(nw, PF_RT_RT, r->rt); 1045 snl_add_msg_attr_u8(nw, PF_RT_RETURN_TTL, r->return_ttl); 1046 snl_add_msg_attr_u8(nw, PF_RT_TOS, r->tos); 1047 snl_add_msg_attr_u8(nw, PF_RT_SET_TOS, r->set_tos); 1048 1049 snl_add_msg_attr_u8(nw, PF_RT_ANCHOR_RELATIVE, r->anchor_relative); 1050 snl_add_msg_attr_u8(nw, PF_RT_ANCHOR_WILDCARD, r->anchor_wildcard); 1051 snl_add_msg_attr_u8(nw, PF_RT_FLUSH, r->flush); 1052 snl_add_msg_attr_u8(nw, PF_RT_PRIO, r->prio); 1053 snl_add_msg_attr_u8(nw, PF_RT_SET_PRIO, r->set_prio[0]); 1054 snl_add_msg_attr_u8(nw, PF_RT_SET_PRIO_REPLY, r->set_prio[1]); 1055 1056 snl_add_msg_attr_ip6(nw, PF_RT_DIVERT_ADDRESS, &r->divert.addr.v6); 1057 snl_add_msg_attr_u16(nw, PF_RT_DIVERT_PORT, r->divert.port); 1058 1059 snl_end_attr_nested(nw, off); 1060 } 1061 1062 int 1063 pfctl_add_rule(int dev __unused, const struct pfctl_rule *r, const char *anchor, 1064 const char *anchor_call, uint32_t ticket, uint32_t pool_ticket) 1065 { 1066 struct snl_writer nw; 1067 struct snl_state ss = {}; 1068 struct snl_errmsg_data e = {}; 1069 struct nlmsghdr *hdr; 1070 uint32_t seq_id; 1071 int family_id; 1072 1073 snl_init(&ss, NETLINK_GENERIC); 1074 family_id = snl_get_genl_family(&ss, PFNL_FAMILY_NAME); 1075 1076 snl_init_writer(&ss, &nw); 1077 hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_ADDRULE); 1078 hdr->nlmsg_flags |= NLM_F_DUMP; 1079 snl_add_msg_attr_u32(&nw, PF_ART_TICKET, ticket); 1080 snl_add_msg_attr_u32(&nw, PF_ART_POOL_TICKET, pool_ticket); 1081 snl_add_msg_attr_string(&nw, PF_ART_ANCHOR, anchor); 1082 snl_add_msg_attr_string(&nw, PF_ART_ANCHOR_CALL, anchor_call); 1083 1084 snl_add_msg_attr_pf_rule(&nw, PF_ART_RULE, r); 1085 1086 if ((hdr = snl_finalize_msg(&nw)) == NULL) 1087 return (ENXIO); 1088 1089 seq_id = hdr->nlmsg_seq; 1090 1091 if (! snl_send_message(&ss, hdr)) { 1092 printf("Send failed\n"); 1093 return (ENXIO); 1094 } 1095 1096 while ((hdr = snl_read_reply_multi(&ss, seq_id, &e)) != NULL) { 1097 } 1098 1099 return (e.error); 1100 } 1101 1102 int 1103 pfctl_get_rules_info(int dev, struct pfctl_rules_info *rules, uint32_t ruleset, 1104 const char *path) 1105 { 1106 struct pfioc_rule pr; 1107 int ret; 1108 1109 bzero(&pr, sizeof(pr)); 1110 if (strlcpy(pr.anchor, path, sizeof(pr.anchor)) >= sizeof(pr.anchor)) 1111 return (E2BIG); 1112 1113 pr.rule.action = ruleset; 1114 ret = ioctl(dev, DIOCGETRULES, &pr); 1115 if (ret != 0) 1116 return (ret); 1117 1118 rules->nr = pr.nr; 1119 rules->ticket = pr.ticket; 1120 1121 return (0); 1122 } 1123 1124 int 1125 pfctl_get_rule(int dev, uint32_t nr, uint32_t ticket, const char *anchor, 1126 uint32_t ruleset, struct pfctl_rule *rule, char *anchor_call) 1127 { 1128 return (pfctl_get_clear_rule(dev, nr, ticket, anchor, ruleset, rule, 1129 anchor_call, false)); 1130 } 1131 1132 int pfctl_get_clear_rule(int dev, uint32_t nr, uint32_t ticket, 1133 const char *anchor, uint32_t ruleset, struct pfctl_rule *rule, 1134 char *anchor_call, bool clear) 1135 { 1136 nvlist_t *nvl; 1137 int ret; 1138 1139 nvl = nvlist_create(0); 1140 if (nvl == 0) 1141 return (ENOMEM); 1142 1143 nvlist_add_number(nvl, "nr", nr); 1144 nvlist_add_number(nvl, "ticket", ticket); 1145 nvlist_add_string(nvl, "anchor", anchor); 1146 nvlist_add_number(nvl, "ruleset", ruleset); 1147 1148 if (clear) 1149 nvlist_add_bool(nvl, "clear_counter", true); 1150 1151 if ((ret = pfctl_do_ioctl(dev, DIOCGETRULENV, 8192, &nvl)) != 0) 1152 return (ret); 1153 1154 pf_nvrule_to_rule(nvlist_get_nvlist(nvl, "rule"), rule); 1155 1156 if (anchor_call) 1157 strlcpy(anchor_call, nvlist_get_string(nvl, "anchor_call"), 1158 MAXPATHLEN); 1159 1160 nvlist_destroy(nvl); 1161 1162 return (0); 1163 } 1164 1165 int 1166 pfctl_set_keepcounters(int dev, bool keep) 1167 { 1168 struct pfioc_nv nv; 1169 nvlist_t *nvl; 1170 int ret; 1171 1172 nvl = nvlist_create(0); 1173 1174 nvlist_add_bool(nvl, "keep_counters", keep); 1175 1176 nv.data = nvlist_pack(nvl, &nv.len); 1177 nv.size = nv.len; 1178 1179 nvlist_destroy(nvl); 1180 1181 ret = ioctl(dev, DIOCKEEPCOUNTERS, &nv); 1182 1183 free(nv.data); 1184 return (ret); 1185 } 1186 1187 struct pfctl_creator { 1188 uint32_t id; 1189 }; 1190 #define _IN(_field) offsetof(struct genlmsghdr, _field) 1191 #define _OUT(_field) offsetof(struct pfctl_creator, _field) 1192 static struct snl_attr_parser ap_creators[] = { 1193 { .type = PF_ST_CREATORID, .off = _OUT(id), .cb = snl_attr_get_uint32 }, 1194 }; 1195 static struct snl_field_parser fp_creators[] = { 1196 }; 1197 #undef _IN 1198 #undef _OUT 1199 SNL_DECLARE_PARSER(creator_parser, struct genlmsghdr, fp_creators, ap_creators); 1200 1201 static int 1202 pfctl_get_creators_nl(struct snl_state *ss, uint32_t *creators, size_t *len) 1203 { 1204 1205 int family_id = snl_get_genl_family(ss, PFNL_FAMILY_NAME); 1206 size_t i = 0; 1207 1208 struct nlmsghdr *hdr; 1209 struct snl_writer nw; 1210 1211 snl_init_writer(ss, &nw); 1212 hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GETCREATORS); 1213 hdr->nlmsg_flags |= NLM_F_DUMP; 1214 hdr = snl_finalize_msg(&nw); 1215 if (hdr == NULL) 1216 return (ENOMEM); 1217 uint32_t seq_id = hdr->nlmsg_seq; 1218 1219 snl_send_message(ss, hdr); 1220 1221 struct snl_errmsg_data e = {}; 1222 while ((hdr = snl_read_reply_multi(ss, seq_id, &e)) != NULL) { 1223 struct pfctl_creator c; 1224 bzero(&c, sizeof(c)); 1225 1226 if (!snl_parse_nlmsg(ss, hdr, &creator_parser, &c)) 1227 continue; 1228 1229 creators[i] = c.id; 1230 i++; 1231 if (i > *len) 1232 return (E2BIG); 1233 } 1234 1235 *len = i; 1236 1237 return (0); 1238 } 1239 1240 int 1241 pfctl_get_creatorids(uint32_t *creators, size_t *len) 1242 { 1243 struct snl_state ss = {}; 1244 int error; 1245 1246 snl_init(&ss, NETLINK_GENERIC); 1247 error = pfctl_get_creators_nl(&ss, creators, len); 1248 snl_free(&ss); 1249 1250 return (error); 1251 1252 } 1253 1254 static void 1255 pfctl_nv_add_state_cmp(nvlist_t *nvl, const char *name, 1256 const struct pfctl_state_cmp *cmp) 1257 { 1258 nvlist_t *nv; 1259 1260 nv = nvlist_create(0); 1261 1262 nvlist_add_number(nv, "id", cmp->id); 1263 nvlist_add_number(nv, "creatorid", htonl(cmp->creatorid)); 1264 nvlist_add_number(nv, "direction", cmp->direction); 1265 1266 nvlist_add_nvlist(nvl, name, nv); 1267 nvlist_destroy(nv); 1268 } 1269 1270 static inline bool 1271 snl_attr_get_pfaddr(struct snl_state *ss __unused, struct nlattr *nla, 1272 const void *arg __unused, void *target) 1273 { 1274 memcpy(target, NLA_DATA(nla), NLA_DATA_LEN(nla)); 1275 return (true); 1276 } 1277 1278 static inline bool 1279 snl_attr_store_ifname(struct snl_state *ss __unused, struct nlattr *nla, 1280 const void *arg __unused, void *target) 1281 { 1282 size_t maxlen = NLA_DATA_LEN(nla); 1283 1284 if (strnlen((char *)NLA_DATA(nla), maxlen) < maxlen) { 1285 strlcpy(target, (char *)NLA_DATA(nla), maxlen); 1286 return (true); 1287 } 1288 return (false); 1289 } 1290 1291 #define _OUT(_field) offsetof(struct pfctl_state_peer, _field) 1292 static const struct snl_attr_parser nla_p_speer[] = { 1293 { .type = PF_STP_SEQLO, .off = _OUT(seqlo), .cb = snl_attr_get_uint32 }, 1294 { .type = PF_STP_SEQHI, .off = _OUT(seqhi), .cb = snl_attr_get_uint32 }, 1295 { .type = PF_STP_SEQDIFF, .off = _OUT(seqdiff), .cb = snl_attr_get_uint32 }, 1296 { .type = PF_STP_STATE, .off = _OUT(state), .cb = snl_attr_get_uint8 }, 1297 { .type = PF_STP_WSCALE, .off = _OUT(wscale), .cb = snl_attr_get_uint8 }, 1298 }; 1299 SNL_DECLARE_ATTR_PARSER(speer_parser, nla_p_speer); 1300 #undef _OUT 1301 1302 #define _OUT(_field) offsetof(struct pf_state_key_export, _field) 1303 static const struct snl_attr_parser nla_p_skey[] = { 1304 { .type = PF_STK_ADDR0, .off = _OUT(addr[0]), .cb = snl_attr_get_pfaddr }, 1305 { .type = PF_STK_ADDR1, .off = _OUT(addr[1]), .cb = snl_attr_get_pfaddr }, 1306 { .type = PF_STK_PORT0, .off = _OUT(port[0]), .cb = snl_attr_get_uint16 }, 1307 { .type = PF_STK_PORT1, .off = _OUT(port[1]), .cb = snl_attr_get_uint16 }, 1308 }; 1309 SNL_DECLARE_ATTR_PARSER(skey_parser, nla_p_skey); 1310 #undef _OUT 1311 1312 #define _IN(_field) offsetof(struct genlmsghdr, _field) 1313 #define _OUT(_field) offsetof(struct pfctl_state, _field) 1314 static struct snl_attr_parser ap_state[] = { 1315 { .type = PF_ST_ID, .off = _OUT(id), .cb = snl_attr_get_uint64 }, 1316 { .type = PF_ST_CREATORID, .off = _OUT(creatorid), .cb = snl_attr_get_uint32 }, 1317 { .type = PF_ST_IFNAME, .off = _OUT(ifname), .cb = snl_attr_store_ifname }, 1318 { .type = PF_ST_ORIG_IFNAME, .off = _OUT(orig_ifname), .cb = snl_attr_store_ifname }, 1319 { .type = PF_ST_KEY_WIRE, .off = _OUT(key[0]), .arg = &skey_parser, .cb = snl_attr_get_nested }, 1320 { .type = PF_ST_KEY_STACK, .off = _OUT(key[1]), .arg = &skey_parser, .cb = snl_attr_get_nested }, 1321 { .type = PF_ST_PEER_SRC, .off = _OUT(src), .arg = &speer_parser, .cb = snl_attr_get_nested }, 1322 { .type = PF_ST_PEER_DST, .off = _OUT(dst), .arg = &speer_parser, .cb = snl_attr_get_nested }, 1323 { .type = PF_ST_RT_ADDR, .off = _OUT(rt_addr), .cb = snl_attr_get_pfaddr }, 1324 { .type = PF_ST_RULE, .off = _OUT(rule), .cb = snl_attr_get_uint32 }, 1325 { .type = PF_ST_ANCHOR, .off = _OUT(anchor), .cb = snl_attr_get_uint32 }, 1326 { .type = PF_ST_NAT_RULE, .off = _OUT(nat_rule), .cb = snl_attr_get_uint32 }, 1327 { .type = PF_ST_CREATION, .off = _OUT(creation), .cb = snl_attr_get_uint32 }, 1328 { .type = PF_ST_EXPIRE, .off = _OUT(expire), .cb = snl_attr_get_uint32 }, 1329 { .type = PF_ST_PACKETS0, .off = _OUT(packets[0]), .cb = snl_attr_get_uint64 }, 1330 { .type = PF_ST_PACKETS1, .off = _OUT(packets[1]), .cb = snl_attr_get_uint64 }, 1331 { .type = PF_ST_BYTES0, .off = _OUT(bytes[0]), .cb = snl_attr_get_uint64 }, 1332 { .type = PF_ST_BYTES1, .off = _OUT(bytes[1]), .cb = snl_attr_get_uint64 }, 1333 { .type = PF_ST_AF, .off = _OUT(key[0].af), .cb = snl_attr_get_uint8 }, 1334 { .type = PF_ST_PROTO, .off = _OUT(key[0].proto), .cb = snl_attr_get_uint8 }, 1335 { .type = PF_ST_DIRECTION, .off = _OUT(direction), .cb = snl_attr_get_uint8 }, 1336 { .type = PF_ST_LOG, .off = _OUT(log), .cb = snl_attr_get_uint8 }, 1337 { .type = PF_ST_STATE_FLAGS, .off = _OUT(state_flags), .cb = snl_attr_get_uint16 }, 1338 { .type = PF_ST_SYNC_FLAGS, .off = _OUT(sync_flags), .cb = snl_attr_get_uint8 }, 1339 }; 1340 static struct snl_field_parser fp_state[] = { 1341 }; 1342 #undef _IN 1343 #undef _OUT 1344 SNL_DECLARE_PARSER(state_parser, struct genlmsghdr, fp_state, ap_state); 1345 1346 static const struct snl_hdr_parser *all_parsers[] = { 1347 &state_parser, &skey_parser, &speer_parser, 1348 &creator_parser, 1349 }; 1350 1351 static int 1352 pfctl_get_states_nl(struct pfctl_state_filter *filter, struct snl_state *ss, pfctl_get_state_fn f, void *arg) 1353 { 1354 SNL_VERIFY_PARSERS(all_parsers); 1355 int family_id = snl_get_genl_family(ss, PFNL_FAMILY_NAME); 1356 int ret; 1357 1358 struct nlmsghdr *hdr; 1359 struct snl_writer nw; 1360 1361 snl_init_writer(ss, &nw); 1362 hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GETSTATES); 1363 hdr->nlmsg_flags |= NLM_F_DUMP; 1364 snl_add_msg_attr_string(&nw, PF_ST_IFNAME, filter->ifname); 1365 snl_add_msg_attr_u16(&nw, PF_ST_PROTO, filter->proto); 1366 snl_add_msg_attr_u8(&nw, PF_ST_AF, filter->af); 1367 snl_add_msg_attr_ip6(&nw, PF_ST_FILTER_ADDR, &filter->addr.v6); 1368 snl_add_msg_attr_ip6(&nw, PF_ST_FILTER_MASK, &filter->mask.v6); 1369 1370 hdr = snl_finalize_msg(&nw); 1371 if (hdr == NULL) 1372 return (ENOMEM); 1373 1374 uint32_t seq_id = hdr->nlmsg_seq; 1375 1376 snl_send_message(ss, hdr); 1377 1378 struct snl_errmsg_data e = {}; 1379 while ((hdr = snl_read_reply_multi(ss, seq_id, &e)) != NULL) { 1380 struct pfctl_state s; 1381 bzero(&s, sizeof(s)); 1382 if (!snl_parse_nlmsg(ss, hdr, &state_parser, &s)) 1383 continue; 1384 1385 s.key[1].af = s.key[0].af; 1386 s.key[1].proto = s.key[0].proto; 1387 1388 ret = f(&s, arg); 1389 if (ret != 0) 1390 return (ret); 1391 } 1392 1393 return (0); 1394 } 1395 1396 int 1397 pfctl_get_states_iter(pfctl_get_state_fn f, void *arg) 1398 { 1399 struct pfctl_state_filter filter = {}; 1400 return (pfctl_get_filtered_states_iter(&filter, f, arg)); 1401 } 1402 1403 int 1404 pfctl_get_filtered_states_iter(struct pfctl_state_filter *filter, pfctl_get_state_fn f, void *arg) 1405 { 1406 struct snl_state ss = {}; 1407 int error; 1408 1409 snl_init(&ss, NETLINK_GENERIC); 1410 error = pfctl_get_states_nl(filter, &ss, f, arg); 1411 snl_free(&ss); 1412 1413 return (error); 1414 } 1415 1416 static int 1417 pfctl_append_states(struct pfctl_state *s, void *arg) 1418 { 1419 struct pfctl_state *new; 1420 struct pfctl_states *states = (struct pfctl_states *)arg; 1421 1422 new = malloc(sizeof(*s)); 1423 if (new == NULL) 1424 return (ENOMEM); 1425 1426 memcpy(new, s, sizeof(*s)); 1427 1428 TAILQ_INSERT_TAIL(&states->states, new, entry); 1429 1430 return (0); 1431 } 1432 1433 int 1434 pfctl_get_states(int dev __unused, struct pfctl_states *states) 1435 { 1436 int ret; 1437 1438 bzero(states, sizeof(*states)); 1439 TAILQ_INIT(&states->states); 1440 1441 ret = pfctl_get_states_iter(pfctl_append_states, states); 1442 if (ret != 0) { 1443 pfctl_free_states(states); 1444 return (ret); 1445 } 1446 1447 return (0); 1448 } 1449 1450 void 1451 pfctl_free_states(struct pfctl_states *states) 1452 { 1453 struct pfctl_state *s, *tmp; 1454 1455 TAILQ_FOREACH_SAFE(s, &states->states, entry, tmp) { 1456 free(s); 1457 } 1458 1459 bzero(states, sizeof(*states)); 1460 } 1461 1462 static int 1463 _pfctl_clear_states(int dev, const struct pfctl_kill *kill, 1464 unsigned int *killed, uint64_t ioctlval) 1465 { 1466 nvlist_t *nvl; 1467 int ret; 1468 1469 nvl = nvlist_create(0); 1470 1471 pfctl_nv_add_state_cmp(nvl, "cmp", &kill->cmp); 1472 nvlist_add_number(nvl, "af", kill->af); 1473 nvlist_add_number(nvl, "proto", kill->proto); 1474 pfctl_nv_add_rule_addr(nvl, "src", &kill->src); 1475 pfctl_nv_add_rule_addr(nvl, "dst", &kill->dst); 1476 pfctl_nv_add_rule_addr(nvl, "rt_addr", &kill->rt_addr); 1477 nvlist_add_string(nvl, "ifname", kill->ifname); 1478 nvlist_add_string(nvl, "label", kill->label); 1479 nvlist_add_bool(nvl, "kill_match", kill->kill_match); 1480 nvlist_add_bool(nvl, "nat", kill->nat); 1481 1482 if ((ret = pfctl_do_ioctl(dev, ioctlval, 1024, &nvl)) != 0) 1483 return (ret); 1484 1485 if (killed) 1486 *killed = nvlist_get_number(nvl, "killed"); 1487 1488 nvlist_destroy(nvl); 1489 1490 return (ret); 1491 } 1492 1493 int 1494 pfctl_clear_states(int dev, const struct pfctl_kill *kill, 1495 unsigned int *killed) 1496 { 1497 return (_pfctl_clear_states(dev, kill, killed, DIOCCLRSTATESNV)); 1498 } 1499 1500 int 1501 pfctl_kill_states(int dev, const struct pfctl_kill *kill, unsigned int *killed) 1502 { 1503 return (_pfctl_clear_states(dev, kill, killed, DIOCKILLSTATESNV)); 1504 } 1505 1506 int 1507 pfctl_clear_rules(int dev, const char *anchorname) 1508 { 1509 struct pfioc_trans trans; 1510 struct pfioc_trans_e transe[2]; 1511 int ret; 1512 1513 bzero(&trans, sizeof(trans)); 1514 bzero(&transe, sizeof(transe)); 1515 1516 transe[0].rs_num = PF_RULESET_SCRUB; 1517 if (strlcpy(transe[0].anchor, anchorname, sizeof(transe[0].anchor)) 1518 >= sizeof(transe[0].anchor)) 1519 return (E2BIG); 1520 1521 transe[1].rs_num = PF_RULESET_FILTER; 1522 if (strlcpy(transe[1].anchor, anchorname, sizeof(transe[1].anchor)) 1523 >= sizeof(transe[1].anchor)) 1524 return (E2BIG); 1525 1526 trans.size = 2; 1527 trans.esize = sizeof(transe[0]); 1528 trans.array = transe; 1529 1530 ret = ioctl(dev, DIOCXBEGIN, &trans); 1531 if (ret != 0) 1532 return (ret); 1533 return ioctl(dev, DIOCXCOMMIT, &trans); 1534 } 1535 1536 int 1537 pfctl_clear_nat(int dev, const char *anchorname) 1538 { 1539 struct pfioc_trans trans; 1540 struct pfioc_trans_e transe[3]; 1541 int ret; 1542 1543 bzero(&trans, sizeof(trans)); 1544 bzero(&transe, sizeof(transe)); 1545 1546 transe[0].rs_num = PF_RULESET_NAT; 1547 if (strlcpy(transe[0].anchor, anchorname, sizeof(transe[0].anchor)) 1548 >= sizeof(transe[0].anchor)) 1549 return (E2BIG); 1550 1551 transe[1].rs_num = PF_RULESET_BINAT; 1552 if (strlcpy(transe[1].anchor, anchorname, sizeof(transe[1].anchor)) 1553 >= sizeof(transe[0].anchor)) 1554 return (E2BIG); 1555 1556 transe[2].rs_num = PF_RULESET_RDR; 1557 if (strlcpy(transe[2].anchor, anchorname, sizeof(transe[2].anchor)) 1558 >= sizeof(transe[2].anchor)) 1559 return (E2BIG); 1560 1561 trans.size = 3; 1562 trans.esize = sizeof(transe[0]); 1563 trans.array = transe; 1564 1565 ret = ioctl(dev, DIOCXBEGIN, &trans); 1566 if (ret != 0) 1567 return (ret); 1568 return ioctl(dev, DIOCXCOMMIT, &trans); 1569 } 1570 int 1571 pfctl_clear_eth_rules(int dev, const char *anchorname) 1572 { 1573 struct pfioc_trans trans; 1574 struct pfioc_trans_e transe; 1575 int ret; 1576 1577 bzero(&trans, sizeof(trans)); 1578 bzero(&transe, sizeof(transe)); 1579 1580 transe.rs_num = PF_RULESET_ETH; 1581 if (strlcpy(transe.anchor, anchorname, sizeof(transe.anchor)) 1582 >= sizeof(transe.anchor)) 1583 return (E2BIG); 1584 1585 trans.size = 1; 1586 trans.esize = sizeof(transe); 1587 trans.array = &transe; 1588 1589 ret = ioctl(dev, DIOCXBEGIN, &trans); 1590 if (ret != 0) 1591 return (ret); 1592 return ioctl(dev, DIOCXCOMMIT, &trans); 1593 } 1594 1595 static int 1596 pfctl_get_limit(int dev, const int index, uint *limit) 1597 { 1598 struct pfioc_limit pl; 1599 1600 bzero(&pl, sizeof(pl)); 1601 pl.index = index; 1602 1603 if (ioctl(dev, DIOCGETLIMIT, &pl) == -1) 1604 return (errno); 1605 1606 *limit = pl.limit; 1607 1608 return (0); 1609 } 1610 1611 int 1612 pfctl_set_syncookies(int dev, const struct pfctl_syncookies *s) 1613 { 1614 struct pfioc_nv nv; 1615 nvlist_t *nvl; 1616 int ret; 1617 uint state_limit; 1618 uint64_t lim, hi, lo; 1619 1620 ret = pfctl_get_limit(dev, PF_LIMIT_STATES, &state_limit); 1621 if (ret != 0) 1622 return (ret); 1623 1624 lim = state_limit; 1625 hi = lim * s->highwater / 100; 1626 lo = lim * s->lowwater / 100; 1627 1628 if (lo == hi) 1629 hi++; 1630 1631 nvl = nvlist_create(0); 1632 1633 nvlist_add_bool(nvl, "enabled", s->mode != PFCTL_SYNCOOKIES_NEVER); 1634 nvlist_add_bool(nvl, "adaptive", s->mode == PFCTL_SYNCOOKIES_ADAPTIVE); 1635 nvlist_add_number(nvl, "highwater", hi); 1636 nvlist_add_number(nvl, "lowwater", lo); 1637 1638 nv.data = nvlist_pack(nvl, &nv.len); 1639 nv.size = nv.len; 1640 nvlist_destroy(nvl); 1641 nvl = NULL; 1642 1643 ret = ioctl(dev, DIOCSETSYNCOOKIES, &nv); 1644 1645 free(nv.data); 1646 return (ret); 1647 } 1648 1649 int 1650 pfctl_get_syncookies(int dev, struct pfctl_syncookies *s) 1651 { 1652 nvlist_t *nvl; 1653 int ret; 1654 uint state_limit; 1655 bool enabled, adaptive; 1656 1657 ret = pfctl_get_limit(dev, PF_LIMIT_STATES, &state_limit); 1658 if (ret != 0) 1659 return (ret); 1660 1661 bzero(s, sizeof(*s)); 1662 1663 nvl = nvlist_create(0); 1664 1665 if ((ret = pfctl_do_ioctl(dev, DIOCGETSYNCOOKIES, 256, &nvl)) != 0) 1666 return (errno); 1667 1668 enabled = nvlist_get_bool(nvl, "enabled"); 1669 adaptive = nvlist_get_bool(nvl, "adaptive"); 1670 1671 if (enabled) { 1672 if (adaptive) 1673 s->mode = PFCTL_SYNCOOKIES_ADAPTIVE; 1674 else 1675 s->mode = PFCTL_SYNCOOKIES_ALWAYS; 1676 } else { 1677 s->mode = PFCTL_SYNCOOKIES_NEVER; 1678 } 1679 1680 s->highwater = nvlist_get_number(nvl, "highwater") * 100 / state_limit; 1681 s->lowwater = nvlist_get_number(nvl, "lowwater") * 100 / state_limit; 1682 1683 nvlist_destroy(nvl); 1684 1685 return (0); 1686 } 1687 1688 int 1689 pfctl_table_add_addrs(int dev, struct pfr_table *tbl, struct pfr_addr 1690 *addr, int size, int *nadd, int flags) 1691 { 1692 struct pfioc_table io; 1693 1694 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 1695 return (EINVAL); 1696 } 1697 bzero(&io, sizeof io); 1698 io.pfrio_flags = flags; 1699 io.pfrio_table = *tbl; 1700 io.pfrio_buffer = addr; 1701 io.pfrio_esize = sizeof(*addr); 1702 io.pfrio_size = size; 1703 1704 if (ioctl(dev, DIOCRADDADDRS, &io)) 1705 return (errno); 1706 if (nadd != NULL) 1707 *nadd = io.pfrio_nadd; 1708 return (0); 1709 } 1710 1711 int 1712 pfctl_table_del_addrs(int dev, struct pfr_table *tbl, struct pfr_addr 1713 *addr, int size, int *ndel, int flags) 1714 { 1715 struct pfioc_table io; 1716 1717 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 1718 return (EINVAL); 1719 } 1720 bzero(&io, sizeof io); 1721 io.pfrio_flags = flags; 1722 io.pfrio_table = *tbl; 1723 io.pfrio_buffer = addr; 1724 io.pfrio_esize = sizeof(*addr); 1725 io.pfrio_size = size; 1726 1727 if (ioctl(dev, DIOCRDELADDRS, &io)) 1728 return (errno); 1729 if (ndel != NULL) 1730 *ndel = io.pfrio_ndel; 1731 return (0); 1732 } 1733 1734 int 1735 pfctl_table_set_addrs(int dev, struct pfr_table *tbl, struct pfr_addr 1736 *addr, int size, int *size2, int *nadd, int *ndel, int *nchange, int flags) 1737 { 1738 struct pfioc_table io; 1739 1740 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 1741 return (EINVAL); 1742 } 1743 bzero(&io, sizeof io); 1744 io.pfrio_flags = flags; 1745 io.pfrio_table = *tbl; 1746 io.pfrio_buffer = addr; 1747 io.pfrio_esize = sizeof(*addr); 1748 io.pfrio_size = size; 1749 io.pfrio_size2 = (size2 != NULL) ? *size2 : 0; 1750 if (ioctl(dev, DIOCRSETADDRS, &io)) 1751 return (-1); 1752 if (nadd != NULL) 1753 *nadd = io.pfrio_nadd; 1754 if (ndel != NULL) 1755 *ndel = io.pfrio_ndel; 1756 if (nchange != NULL) 1757 *nchange = io.pfrio_nchange; 1758 if (size2 != NULL) 1759 *size2 = io.pfrio_size2; 1760 return (0); 1761 } 1762 1763 int pfctl_table_get_addrs(int dev, struct pfr_table *tbl, struct pfr_addr *addr, 1764 int *size, int flags) 1765 { 1766 struct pfioc_table io; 1767 1768 if (tbl == NULL || size == NULL || *size < 0 || 1769 (*size && addr == NULL)) { 1770 return (EINVAL); 1771 } 1772 bzero(&io, sizeof io); 1773 io.pfrio_flags = flags; 1774 io.pfrio_table = *tbl; 1775 io.pfrio_buffer = addr; 1776 io.pfrio_esize = sizeof(*addr); 1777 io.pfrio_size = *size; 1778 if (ioctl(dev, DIOCRGETADDRS, &io)) 1779 return (-1); 1780 *size = io.pfrio_size; 1781 return (0); 1782 } 1783