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