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 return (ENXIO); 1113 1114 while ((hdr = snl_read_reply_multi(&ss, seq_id, &e)) != NULL) { 1115 } 1116 1117 return (e.error); 1118 } 1119 1120 #define _IN(_field) offsetof(struct genlmsghdr, _field) 1121 #define _OUT(_field) offsetof(struct pfctl_rules_info, _field) 1122 static struct snl_attr_parser ap_getrules[] = { 1123 { .type = PF_GR_NR, .off = _OUT(nr), .cb = snl_attr_get_uint32 }, 1124 { .type = PF_GR_TICKET, .off = _OUT(ticket), .cb = snl_attr_get_uint32 }, 1125 }; 1126 static struct snl_field_parser fp_getrules[] = { 1127 }; 1128 #undef _IN 1129 #undef _OUT 1130 SNL_DECLARE_PARSER(getrules_parser, struct genlmsghdr, fp_getrules, ap_getrules); 1131 1132 int 1133 pfctl_get_rules_info(int dev __unused, struct pfctl_rules_info *rules, uint32_t ruleset, 1134 const char *path) 1135 { 1136 struct snl_state ss = {}; 1137 struct snl_errmsg_data e = {}; 1138 struct nlmsghdr *hdr; 1139 struct snl_writer nw; 1140 uint32_t seq_id; 1141 int family_id; 1142 1143 snl_init(&ss, NETLINK_GENERIC); 1144 family_id = snl_get_genl_family(&ss, PFNL_FAMILY_NAME); 1145 if (family_id == 0) 1146 return (ENOTSUP); 1147 1148 snl_init_writer(&ss, &nw); 1149 hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GETRULES); 1150 hdr->nlmsg_flags |= NLM_F_DUMP; 1151 1152 snl_add_msg_attr_string(&nw, PF_GR_ANCHOR, path); 1153 snl_add_msg_attr_u8(&nw, PF_GR_ACTION, ruleset); 1154 1155 hdr = snl_finalize_msg(&nw); 1156 if (hdr == NULL) 1157 return (ENOMEM); 1158 1159 seq_id = hdr->nlmsg_seq; 1160 if (! snl_send_message(&ss, hdr)) 1161 return (ENXIO); 1162 1163 while ((hdr = snl_read_reply_multi(&ss, seq_id, &e)) != NULL) { 1164 if (! snl_parse_nlmsg(&ss, hdr, &getrules_parser, rules)) 1165 continue; 1166 } 1167 1168 return (e.error); 1169 } 1170 1171 int 1172 pfctl_get_rule(int dev, uint32_t nr, uint32_t ticket, const char *anchor, 1173 uint32_t ruleset, struct pfctl_rule *rule, char *anchor_call) 1174 { 1175 return (pfctl_get_clear_rule(dev, nr, ticket, anchor, ruleset, rule, 1176 anchor_call, false)); 1177 } 1178 1179 int pfctl_get_clear_rule(int dev, uint32_t nr, uint32_t ticket, 1180 const char *anchor, uint32_t ruleset, struct pfctl_rule *rule, 1181 char *anchor_call, bool clear) 1182 { 1183 nvlist_t *nvl; 1184 int ret; 1185 1186 nvl = nvlist_create(0); 1187 if (nvl == 0) 1188 return (ENOMEM); 1189 1190 nvlist_add_number(nvl, "nr", nr); 1191 nvlist_add_number(nvl, "ticket", ticket); 1192 nvlist_add_string(nvl, "anchor", anchor); 1193 nvlist_add_number(nvl, "ruleset", ruleset); 1194 1195 if (clear) 1196 nvlist_add_bool(nvl, "clear_counter", true); 1197 1198 if ((ret = pfctl_do_ioctl(dev, DIOCGETRULENV, 8192, &nvl)) != 0) 1199 goto out; 1200 1201 pf_nvrule_to_rule(nvlist_get_nvlist(nvl, "rule"), rule); 1202 1203 if (anchor_call) 1204 strlcpy(anchor_call, nvlist_get_string(nvl, "anchor_call"), 1205 MAXPATHLEN); 1206 1207 out: 1208 nvlist_destroy(nvl); 1209 return (ret); 1210 } 1211 1212 int 1213 pfctl_set_keepcounters(int dev, bool keep) 1214 { 1215 struct pfioc_nv nv; 1216 nvlist_t *nvl; 1217 int ret; 1218 1219 nvl = nvlist_create(0); 1220 1221 nvlist_add_bool(nvl, "keep_counters", keep); 1222 1223 nv.data = nvlist_pack(nvl, &nv.len); 1224 nv.size = nv.len; 1225 1226 nvlist_destroy(nvl); 1227 1228 ret = ioctl(dev, DIOCKEEPCOUNTERS, &nv); 1229 1230 free(nv.data); 1231 return (ret); 1232 } 1233 1234 struct pfctl_creator { 1235 uint32_t id; 1236 }; 1237 #define _IN(_field) offsetof(struct genlmsghdr, _field) 1238 #define _OUT(_field) offsetof(struct pfctl_creator, _field) 1239 static struct snl_attr_parser ap_creators[] = { 1240 { .type = PF_ST_CREATORID, .off = _OUT(id), .cb = snl_attr_get_uint32 }, 1241 }; 1242 static struct snl_field_parser fp_creators[] = { 1243 }; 1244 #undef _IN 1245 #undef _OUT 1246 SNL_DECLARE_PARSER(creator_parser, struct genlmsghdr, fp_creators, ap_creators); 1247 1248 static int 1249 pfctl_get_creators_nl(struct snl_state *ss, uint32_t *creators, size_t *len) 1250 { 1251 1252 int family_id = snl_get_genl_family(ss, PFNL_FAMILY_NAME); 1253 size_t i = 0; 1254 1255 struct nlmsghdr *hdr; 1256 struct snl_writer nw; 1257 1258 if (family_id == 0) 1259 return (ENOTSUP); 1260 1261 snl_init_writer(ss, &nw); 1262 hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GETCREATORS); 1263 hdr->nlmsg_flags |= NLM_F_DUMP; 1264 hdr = snl_finalize_msg(&nw); 1265 if (hdr == NULL) 1266 return (ENOMEM); 1267 uint32_t seq_id = hdr->nlmsg_seq; 1268 1269 snl_send_message(ss, hdr); 1270 1271 struct snl_errmsg_data e = {}; 1272 while ((hdr = snl_read_reply_multi(ss, seq_id, &e)) != NULL) { 1273 struct pfctl_creator c; 1274 bzero(&c, sizeof(c)); 1275 1276 if (!snl_parse_nlmsg(ss, hdr, &creator_parser, &c)) 1277 continue; 1278 1279 creators[i] = c.id; 1280 i++; 1281 if (i > *len) 1282 return (E2BIG); 1283 } 1284 1285 *len = i; 1286 1287 return (0); 1288 } 1289 1290 int 1291 pfctl_get_creatorids(uint32_t *creators, size_t *len) 1292 { 1293 struct snl_state ss = {}; 1294 int error; 1295 1296 snl_init(&ss, NETLINK_GENERIC); 1297 error = pfctl_get_creators_nl(&ss, creators, len); 1298 snl_free(&ss); 1299 1300 return (error); 1301 1302 } 1303 1304 static void 1305 pfctl_nv_add_state_cmp(nvlist_t *nvl, const char *name, 1306 const struct pfctl_state_cmp *cmp) 1307 { 1308 nvlist_t *nv; 1309 1310 nv = nvlist_create(0); 1311 1312 nvlist_add_number(nv, "id", cmp->id); 1313 nvlist_add_number(nv, "creatorid", htonl(cmp->creatorid)); 1314 nvlist_add_number(nv, "direction", cmp->direction); 1315 1316 nvlist_add_nvlist(nvl, name, nv); 1317 nvlist_destroy(nv); 1318 } 1319 1320 static inline bool 1321 snl_attr_get_pfaddr(struct snl_state *ss __unused, struct nlattr *nla, 1322 const void *arg __unused, void *target) 1323 { 1324 memcpy(target, NLA_DATA(nla), NLA_DATA_LEN(nla)); 1325 return (true); 1326 } 1327 1328 static inline bool 1329 snl_attr_store_ifname(struct snl_state *ss __unused, struct nlattr *nla, 1330 const void *arg __unused, void *target) 1331 { 1332 size_t maxlen = NLA_DATA_LEN(nla); 1333 1334 if (strnlen((char *)NLA_DATA(nla), maxlen) < maxlen) { 1335 strlcpy(target, (char *)NLA_DATA(nla), maxlen); 1336 return (true); 1337 } 1338 return (false); 1339 } 1340 1341 #define _OUT(_field) offsetof(struct pfctl_state_peer, _field) 1342 static const struct snl_attr_parser nla_p_speer[] = { 1343 { .type = PF_STP_SEQLO, .off = _OUT(seqlo), .cb = snl_attr_get_uint32 }, 1344 { .type = PF_STP_SEQHI, .off = _OUT(seqhi), .cb = snl_attr_get_uint32 }, 1345 { .type = PF_STP_SEQDIFF, .off = _OUT(seqdiff), .cb = snl_attr_get_uint32 }, 1346 { .type = PF_STP_STATE, .off = _OUT(state), .cb = snl_attr_get_uint8 }, 1347 { .type = PF_STP_WSCALE, .off = _OUT(wscale), .cb = snl_attr_get_uint8 }, 1348 }; 1349 SNL_DECLARE_ATTR_PARSER(speer_parser, nla_p_speer); 1350 #undef _OUT 1351 1352 #define _OUT(_field) offsetof(struct pf_state_key_export, _field) 1353 static const struct snl_attr_parser nla_p_skey[] = { 1354 { .type = PF_STK_ADDR0, .off = _OUT(addr[0]), .cb = snl_attr_get_pfaddr }, 1355 { .type = PF_STK_ADDR1, .off = _OUT(addr[1]), .cb = snl_attr_get_pfaddr }, 1356 { .type = PF_STK_PORT0, .off = _OUT(port[0]), .cb = snl_attr_get_uint16 }, 1357 { .type = PF_STK_PORT1, .off = _OUT(port[1]), .cb = snl_attr_get_uint16 }, 1358 }; 1359 SNL_DECLARE_ATTR_PARSER(skey_parser, nla_p_skey); 1360 #undef _OUT 1361 1362 #define _IN(_field) offsetof(struct genlmsghdr, _field) 1363 #define _OUT(_field) offsetof(struct pfctl_state, _field) 1364 static struct snl_attr_parser ap_state[] = { 1365 { .type = PF_ST_ID, .off = _OUT(id), .cb = snl_attr_get_uint64 }, 1366 { .type = PF_ST_CREATORID, .off = _OUT(creatorid), .cb = snl_attr_get_uint32 }, 1367 { .type = PF_ST_IFNAME, .off = _OUT(ifname), .cb = snl_attr_store_ifname }, 1368 { .type = PF_ST_ORIG_IFNAME, .off = _OUT(orig_ifname), .cb = snl_attr_store_ifname }, 1369 { .type = PF_ST_KEY_WIRE, .off = _OUT(key[0]), .arg = &skey_parser, .cb = snl_attr_get_nested }, 1370 { .type = PF_ST_KEY_STACK, .off = _OUT(key[1]), .arg = &skey_parser, .cb = snl_attr_get_nested }, 1371 { .type = PF_ST_PEER_SRC, .off = _OUT(src), .arg = &speer_parser, .cb = snl_attr_get_nested }, 1372 { .type = PF_ST_PEER_DST, .off = _OUT(dst), .arg = &speer_parser, .cb = snl_attr_get_nested }, 1373 { .type = PF_ST_RT_ADDR, .off = _OUT(rt_addr), .cb = snl_attr_get_pfaddr }, 1374 { .type = PF_ST_RULE, .off = _OUT(rule), .cb = snl_attr_get_uint32 }, 1375 { .type = PF_ST_ANCHOR, .off = _OUT(anchor), .cb = snl_attr_get_uint32 }, 1376 { .type = PF_ST_NAT_RULE, .off = _OUT(nat_rule), .cb = snl_attr_get_uint32 }, 1377 { .type = PF_ST_CREATION, .off = _OUT(creation), .cb = snl_attr_get_uint32 }, 1378 { .type = PF_ST_EXPIRE, .off = _OUT(expire), .cb = snl_attr_get_uint32 }, 1379 { .type = PF_ST_PACKETS0, .off = _OUT(packets[0]), .cb = snl_attr_get_uint64 }, 1380 { .type = PF_ST_PACKETS1, .off = _OUT(packets[1]), .cb = snl_attr_get_uint64 }, 1381 { .type = PF_ST_BYTES0, .off = _OUT(bytes[0]), .cb = snl_attr_get_uint64 }, 1382 { .type = PF_ST_BYTES1, .off = _OUT(bytes[1]), .cb = snl_attr_get_uint64 }, 1383 { .type = PF_ST_AF, .off = _OUT(key[0].af), .cb = snl_attr_get_uint8 }, 1384 { .type = PF_ST_PROTO, .off = _OUT(key[0].proto), .cb = snl_attr_get_uint8 }, 1385 { .type = PF_ST_DIRECTION, .off = _OUT(direction), .cb = snl_attr_get_uint8 }, 1386 { .type = PF_ST_LOG, .off = _OUT(log), .cb = snl_attr_get_uint8 }, 1387 { .type = PF_ST_STATE_FLAGS, .off = _OUT(state_flags), .cb = snl_attr_get_uint16 }, 1388 { .type = PF_ST_SYNC_FLAGS, .off = _OUT(sync_flags), .cb = snl_attr_get_uint8 }, 1389 }; 1390 static struct snl_field_parser fp_state[] = { 1391 }; 1392 #undef _IN 1393 #undef _OUT 1394 SNL_DECLARE_PARSER(state_parser, struct genlmsghdr, fp_state, ap_state); 1395 1396 static const struct snl_hdr_parser *all_parsers[] = { 1397 &state_parser, &skey_parser, &speer_parser, 1398 &creator_parser, &getrules_parser 1399 }; 1400 1401 static int 1402 pfctl_get_states_nl(struct pfctl_state_filter *filter, struct snl_state *ss, pfctl_get_state_fn f, void *arg) 1403 { 1404 SNL_VERIFY_PARSERS(all_parsers); 1405 int family_id = snl_get_genl_family(ss, PFNL_FAMILY_NAME); 1406 int ret; 1407 1408 struct nlmsghdr *hdr; 1409 struct snl_writer nw; 1410 1411 if (family_id == 0) 1412 return (ENOTSUP); 1413 1414 snl_init_writer(ss, &nw); 1415 hdr = snl_create_genl_msg_request(&nw, family_id, PFNL_CMD_GETSTATES); 1416 hdr->nlmsg_flags |= NLM_F_DUMP; 1417 snl_add_msg_attr_string(&nw, PF_ST_IFNAME, filter->ifname); 1418 snl_add_msg_attr_u16(&nw, PF_ST_PROTO, filter->proto); 1419 snl_add_msg_attr_u8(&nw, PF_ST_AF, filter->af); 1420 snl_add_msg_attr_ip6(&nw, PF_ST_FILTER_ADDR, &filter->addr.v6); 1421 snl_add_msg_attr_ip6(&nw, PF_ST_FILTER_MASK, &filter->mask.v6); 1422 1423 hdr = snl_finalize_msg(&nw); 1424 if (hdr == NULL) 1425 return (ENOMEM); 1426 1427 uint32_t seq_id = hdr->nlmsg_seq; 1428 1429 snl_send_message(ss, hdr); 1430 1431 struct snl_errmsg_data e = {}; 1432 while ((hdr = snl_read_reply_multi(ss, seq_id, &e)) != NULL) { 1433 struct pfctl_state s; 1434 bzero(&s, sizeof(s)); 1435 if (!snl_parse_nlmsg(ss, hdr, &state_parser, &s)) 1436 continue; 1437 1438 s.key[1].af = s.key[0].af; 1439 s.key[1].proto = s.key[0].proto; 1440 1441 ret = f(&s, arg); 1442 if (ret != 0) 1443 return (ret); 1444 } 1445 1446 return (0); 1447 } 1448 1449 int 1450 pfctl_get_states_iter(pfctl_get_state_fn f, void *arg) 1451 { 1452 struct pfctl_state_filter filter = {}; 1453 return (pfctl_get_filtered_states_iter(&filter, f, arg)); 1454 } 1455 1456 int 1457 pfctl_get_filtered_states_iter(struct pfctl_state_filter *filter, pfctl_get_state_fn f, void *arg) 1458 { 1459 struct snl_state ss = {}; 1460 int error; 1461 1462 snl_init(&ss, NETLINK_GENERIC); 1463 error = pfctl_get_states_nl(filter, &ss, f, arg); 1464 snl_free(&ss); 1465 1466 return (error); 1467 } 1468 1469 static int 1470 pfctl_append_states(struct pfctl_state *s, void *arg) 1471 { 1472 struct pfctl_state *new; 1473 struct pfctl_states *states = (struct pfctl_states *)arg; 1474 1475 new = malloc(sizeof(*s)); 1476 if (new == NULL) 1477 return (ENOMEM); 1478 1479 memcpy(new, s, sizeof(*s)); 1480 1481 TAILQ_INSERT_TAIL(&states->states, new, entry); 1482 1483 return (0); 1484 } 1485 1486 int 1487 pfctl_get_states(int dev __unused, struct pfctl_states *states) 1488 { 1489 int ret; 1490 1491 bzero(states, sizeof(*states)); 1492 TAILQ_INIT(&states->states); 1493 1494 ret = pfctl_get_states_iter(pfctl_append_states, states); 1495 if (ret != 0) { 1496 pfctl_free_states(states); 1497 return (ret); 1498 } 1499 1500 return (0); 1501 } 1502 1503 void 1504 pfctl_free_states(struct pfctl_states *states) 1505 { 1506 struct pfctl_state *s, *tmp; 1507 1508 TAILQ_FOREACH_SAFE(s, &states->states, entry, tmp) { 1509 free(s); 1510 } 1511 1512 bzero(states, sizeof(*states)); 1513 } 1514 1515 static int 1516 _pfctl_clear_states(int dev, const struct pfctl_kill *kill, 1517 unsigned int *killed, uint64_t ioctlval) 1518 { 1519 nvlist_t *nvl; 1520 int ret; 1521 1522 nvl = nvlist_create(0); 1523 1524 pfctl_nv_add_state_cmp(nvl, "cmp", &kill->cmp); 1525 nvlist_add_number(nvl, "af", kill->af); 1526 nvlist_add_number(nvl, "proto", kill->proto); 1527 pfctl_nv_add_rule_addr(nvl, "src", &kill->src); 1528 pfctl_nv_add_rule_addr(nvl, "dst", &kill->dst); 1529 pfctl_nv_add_rule_addr(nvl, "rt_addr", &kill->rt_addr); 1530 nvlist_add_string(nvl, "ifname", kill->ifname); 1531 nvlist_add_string(nvl, "label", kill->label); 1532 nvlist_add_bool(nvl, "kill_match", kill->kill_match); 1533 nvlist_add_bool(nvl, "nat", kill->nat); 1534 1535 if ((ret = pfctl_do_ioctl(dev, ioctlval, 1024, &nvl)) != 0) 1536 goto out; 1537 1538 if (killed) 1539 *killed = nvlist_get_number(nvl, "killed"); 1540 1541 out: 1542 nvlist_destroy(nvl); 1543 return (ret); 1544 } 1545 1546 int 1547 pfctl_clear_states(int dev, const struct pfctl_kill *kill, 1548 unsigned int *killed) 1549 { 1550 return (_pfctl_clear_states(dev, kill, killed, DIOCCLRSTATESNV)); 1551 } 1552 1553 int 1554 pfctl_kill_states(int dev, const struct pfctl_kill *kill, unsigned int *killed) 1555 { 1556 return (_pfctl_clear_states(dev, kill, killed, DIOCKILLSTATESNV)); 1557 } 1558 1559 int 1560 pfctl_clear_rules(int dev, const char *anchorname) 1561 { 1562 struct pfioc_trans trans; 1563 struct pfioc_trans_e transe[2]; 1564 int ret; 1565 1566 bzero(&trans, sizeof(trans)); 1567 bzero(&transe, sizeof(transe)); 1568 1569 transe[0].rs_num = PF_RULESET_SCRUB; 1570 if (strlcpy(transe[0].anchor, anchorname, sizeof(transe[0].anchor)) 1571 >= sizeof(transe[0].anchor)) 1572 return (E2BIG); 1573 1574 transe[1].rs_num = PF_RULESET_FILTER; 1575 if (strlcpy(transe[1].anchor, anchorname, sizeof(transe[1].anchor)) 1576 >= sizeof(transe[1].anchor)) 1577 return (E2BIG); 1578 1579 trans.size = 2; 1580 trans.esize = sizeof(transe[0]); 1581 trans.array = transe; 1582 1583 ret = ioctl(dev, DIOCXBEGIN, &trans); 1584 if (ret != 0) 1585 return (ret); 1586 return ioctl(dev, DIOCXCOMMIT, &trans); 1587 } 1588 1589 int 1590 pfctl_clear_nat(int dev, const char *anchorname) 1591 { 1592 struct pfioc_trans trans; 1593 struct pfioc_trans_e transe[3]; 1594 int ret; 1595 1596 bzero(&trans, sizeof(trans)); 1597 bzero(&transe, sizeof(transe)); 1598 1599 transe[0].rs_num = PF_RULESET_NAT; 1600 if (strlcpy(transe[0].anchor, anchorname, sizeof(transe[0].anchor)) 1601 >= sizeof(transe[0].anchor)) 1602 return (E2BIG); 1603 1604 transe[1].rs_num = PF_RULESET_BINAT; 1605 if (strlcpy(transe[1].anchor, anchorname, sizeof(transe[1].anchor)) 1606 >= sizeof(transe[0].anchor)) 1607 return (E2BIG); 1608 1609 transe[2].rs_num = PF_RULESET_RDR; 1610 if (strlcpy(transe[2].anchor, anchorname, sizeof(transe[2].anchor)) 1611 >= sizeof(transe[2].anchor)) 1612 return (E2BIG); 1613 1614 trans.size = 3; 1615 trans.esize = sizeof(transe[0]); 1616 trans.array = transe; 1617 1618 ret = ioctl(dev, DIOCXBEGIN, &trans); 1619 if (ret != 0) 1620 return (ret); 1621 return ioctl(dev, DIOCXCOMMIT, &trans); 1622 } 1623 int 1624 pfctl_clear_eth_rules(int dev, const char *anchorname) 1625 { 1626 struct pfioc_trans trans; 1627 struct pfioc_trans_e transe; 1628 int ret; 1629 1630 bzero(&trans, sizeof(trans)); 1631 bzero(&transe, sizeof(transe)); 1632 1633 transe.rs_num = PF_RULESET_ETH; 1634 if (strlcpy(transe.anchor, anchorname, sizeof(transe.anchor)) 1635 >= sizeof(transe.anchor)) 1636 return (E2BIG); 1637 1638 trans.size = 1; 1639 trans.esize = sizeof(transe); 1640 trans.array = &transe; 1641 1642 ret = ioctl(dev, DIOCXBEGIN, &trans); 1643 if (ret != 0) 1644 return (ret); 1645 return ioctl(dev, DIOCXCOMMIT, &trans); 1646 } 1647 1648 static int 1649 pfctl_get_limit(int dev, const int index, uint *limit) 1650 { 1651 struct pfioc_limit pl; 1652 1653 bzero(&pl, sizeof(pl)); 1654 pl.index = index; 1655 1656 if (ioctl(dev, DIOCGETLIMIT, &pl) == -1) 1657 return (errno); 1658 1659 *limit = pl.limit; 1660 1661 return (0); 1662 } 1663 1664 int 1665 pfctl_set_syncookies(int dev, const struct pfctl_syncookies *s) 1666 { 1667 struct pfioc_nv nv; 1668 nvlist_t *nvl; 1669 int ret; 1670 uint state_limit; 1671 uint64_t lim, hi, lo; 1672 1673 ret = pfctl_get_limit(dev, PF_LIMIT_STATES, &state_limit); 1674 if (ret != 0) 1675 return (ret); 1676 1677 lim = state_limit; 1678 hi = lim * s->highwater / 100; 1679 lo = lim * s->lowwater / 100; 1680 1681 if (lo == hi) 1682 hi++; 1683 1684 nvl = nvlist_create(0); 1685 1686 nvlist_add_bool(nvl, "enabled", s->mode != PFCTL_SYNCOOKIES_NEVER); 1687 nvlist_add_bool(nvl, "adaptive", s->mode == PFCTL_SYNCOOKIES_ADAPTIVE); 1688 nvlist_add_number(nvl, "highwater", hi); 1689 nvlist_add_number(nvl, "lowwater", lo); 1690 1691 nv.data = nvlist_pack(nvl, &nv.len); 1692 nv.size = nv.len; 1693 nvlist_destroy(nvl); 1694 nvl = NULL; 1695 1696 ret = ioctl(dev, DIOCSETSYNCOOKIES, &nv); 1697 1698 free(nv.data); 1699 return (ret); 1700 } 1701 1702 int 1703 pfctl_get_syncookies(int dev, struct pfctl_syncookies *s) 1704 { 1705 nvlist_t *nvl; 1706 int ret; 1707 uint state_limit; 1708 bool enabled, adaptive; 1709 1710 ret = pfctl_get_limit(dev, PF_LIMIT_STATES, &state_limit); 1711 if (ret != 0) 1712 return (ret); 1713 1714 bzero(s, sizeof(*s)); 1715 1716 nvl = nvlist_create(0); 1717 1718 if ((ret = pfctl_do_ioctl(dev, DIOCGETSYNCOOKIES, 256, &nvl)) != 0) { 1719 ret = errno; 1720 goto out; 1721 } 1722 1723 enabled = nvlist_get_bool(nvl, "enabled"); 1724 adaptive = nvlist_get_bool(nvl, "adaptive"); 1725 1726 if (enabled) { 1727 if (adaptive) 1728 s->mode = PFCTL_SYNCOOKIES_ADAPTIVE; 1729 else 1730 s->mode = PFCTL_SYNCOOKIES_ALWAYS; 1731 } else { 1732 s->mode = PFCTL_SYNCOOKIES_NEVER; 1733 } 1734 1735 s->highwater = nvlist_get_number(nvl, "highwater") * 100 / state_limit; 1736 s->lowwater = nvlist_get_number(nvl, "lowwater") * 100 / state_limit; 1737 s->halfopen_states = nvlist_get_number(nvl, "halfopen_states"); 1738 1739 out: 1740 nvlist_destroy(nvl); 1741 return (ret); 1742 } 1743 1744 int 1745 pfctl_table_add_addrs(int dev, struct pfr_table *tbl, struct pfr_addr 1746 *addr, int size, int *nadd, int flags) 1747 { 1748 struct pfioc_table io; 1749 1750 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 1751 return (EINVAL); 1752 } 1753 bzero(&io, sizeof io); 1754 io.pfrio_flags = flags; 1755 io.pfrio_table = *tbl; 1756 io.pfrio_buffer = addr; 1757 io.pfrio_esize = sizeof(*addr); 1758 io.pfrio_size = size; 1759 1760 if (ioctl(dev, DIOCRADDADDRS, &io)) 1761 return (errno); 1762 if (nadd != NULL) 1763 *nadd = io.pfrio_nadd; 1764 return (0); 1765 } 1766 1767 int 1768 pfctl_table_del_addrs(int dev, struct pfr_table *tbl, struct pfr_addr 1769 *addr, int size, int *ndel, int flags) 1770 { 1771 struct pfioc_table io; 1772 1773 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 1774 return (EINVAL); 1775 } 1776 bzero(&io, sizeof io); 1777 io.pfrio_flags = flags; 1778 io.pfrio_table = *tbl; 1779 io.pfrio_buffer = addr; 1780 io.pfrio_esize = sizeof(*addr); 1781 io.pfrio_size = size; 1782 1783 if (ioctl(dev, DIOCRDELADDRS, &io)) 1784 return (errno); 1785 if (ndel != NULL) 1786 *ndel = io.pfrio_ndel; 1787 return (0); 1788 } 1789 1790 int 1791 pfctl_table_set_addrs(int dev, struct pfr_table *tbl, struct pfr_addr 1792 *addr, int size, int *size2, int *nadd, int *ndel, int *nchange, int flags) 1793 { 1794 struct pfioc_table io; 1795 1796 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 1797 return (EINVAL); 1798 } 1799 bzero(&io, sizeof io); 1800 io.pfrio_flags = flags; 1801 io.pfrio_table = *tbl; 1802 io.pfrio_buffer = addr; 1803 io.pfrio_esize = sizeof(*addr); 1804 io.pfrio_size = size; 1805 io.pfrio_size2 = (size2 != NULL) ? *size2 : 0; 1806 if (ioctl(dev, DIOCRSETADDRS, &io)) 1807 return (-1); 1808 if (nadd != NULL) 1809 *nadd = io.pfrio_nadd; 1810 if (ndel != NULL) 1811 *ndel = io.pfrio_ndel; 1812 if (nchange != NULL) 1813 *nchange = io.pfrio_nchange; 1814 if (size2 != NULL) 1815 *size2 = io.pfrio_size2; 1816 return (0); 1817 } 1818 1819 int pfctl_table_get_addrs(int dev, struct pfr_table *tbl, struct pfr_addr *addr, 1820 int *size, int flags) 1821 { 1822 struct pfioc_table io; 1823 1824 if (tbl == NULL || size == NULL || *size < 0 || 1825 (*size && addr == NULL)) { 1826 return (EINVAL); 1827 } 1828 bzero(&io, sizeof io); 1829 io.pfrio_flags = flags; 1830 io.pfrio_table = *tbl; 1831 io.pfrio_buffer = addr; 1832 io.pfrio_esize = sizeof(*addr); 1833 io.pfrio_size = *size; 1834 if (ioctl(dev, DIOCRGETADDRS, &io)) 1835 return (-1); 1836 *size = io.pfrio_size; 1837 return (0); 1838 } 1839