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