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