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 <assert.h> 44 #include <err.h> 45 #include <errno.h> 46 #include <stdlib.h> 47 #include <string.h> 48 49 #include "libpfctl.h" 50 51 const char* PFCTL_SYNCOOKIES_MODE_NAMES[] = { 52 "never", 53 "always", 54 "adaptive" 55 }; 56 57 static int _pfctl_clear_states(int , const struct pfctl_kill *, 58 unsigned int *, uint64_t); 59 60 static int 61 pfctl_do_ioctl(int dev, uint cmd, size_t size, nvlist_t **nvl) 62 { 63 struct pfioc_nv nv; 64 void *data; 65 size_t nvlen; 66 int ret; 67 68 data = nvlist_pack(*nvl, &nvlen); 69 if (nvlen > size) 70 size = nvlen; 71 72 retry: 73 nv.data = malloc(size); 74 memcpy(nv.data, data, nvlen); 75 76 nv.len = nvlen; 77 nv.size = size; 78 79 ret = ioctl(dev, cmd, &nv); 80 if (ret == -1 && errno == ENOSPC) { 81 size *= 2; 82 free(nv.data); 83 goto retry; 84 } 85 86 nvlist_destroy(*nvl); 87 *nvl = NULL; 88 89 if (ret == 0) { 90 *nvl = nvlist_unpack(nv.data, nv.len, 0); 91 if (*nvl == NULL) { 92 ret = EIO; 93 goto out; 94 } 95 } else { 96 ret = errno; 97 } 98 99 out: 100 free(data); 101 free(nv.data); 102 103 return (ret); 104 } 105 106 static void 107 pf_nvuint_8_array(const nvlist_t *nvl, const char *name, size_t maxelems, 108 uint8_t *numbers, size_t *nelems) 109 { 110 const uint64_t *tmp; 111 size_t elems; 112 113 tmp = nvlist_get_number_array(nvl, name, &elems); 114 assert(elems <= maxelems); 115 116 for (size_t i = 0; i < elems; i++) 117 numbers[i] = tmp[i]; 118 119 if (nelems) 120 *nelems = elems; 121 } 122 123 static void 124 pf_nvuint_16_array(const nvlist_t *nvl, const char *name, size_t maxelems, 125 uint16_t *numbers, size_t *nelems) 126 { 127 const uint64_t *tmp; 128 size_t elems; 129 130 tmp = nvlist_get_number_array(nvl, name, &elems); 131 assert(elems <= maxelems); 132 133 for (size_t i = 0; i < elems; i++) 134 numbers[i] = tmp[i]; 135 136 if (nelems) 137 *nelems = elems; 138 } 139 140 static void 141 pf_nvuint_32_array(const nvlist_t *nvl, const char *name, size_t maxelems, 142 uint32_t *numbers, size_t *nelems) 143 { 144 const uint64_t *tmp; 145 size_t elems; 146 147 tmp = nvlist_get_number_array(nvl, name, &elems); 148 assert(elems <= maxelems); 149 150 for (size_t i = 0; i < elems; i++) 151 numbers[i] = tmp[i]; 152 153 if (nelems) 154 *nelems = elems; 155 } 156 157 static void 158 pf_nvuint_64_array(const nvlist_t *nvl, const char *name, size_t maxelems, 159 uint64_t *numbers, size_t *nelems) 160 { 161 const uint64_t *tmp; 162 size_t elems; 163 164 tmp = nvlist_get_number_array(nvl, name, &elems); 165 assert(elems <= maxelems); 166 167 for (size_t i = 0; i < elems; i++) 168 numbers[i] = tmp[i]; 169 170 if (nelems) 171 *nelems = elems; 172 } 173 174 static void 175 _pfctl_get_status_counters(const nvlist_t *nvl, 176 struct pfctl_status_counters *counters) 177 { 178 const uint64_t *ids, *counts; 179 const char *const *names; 180 size_t id_len, counter_len, names_len; 181 182 ids = nvlist_get_number_array(nvl, "ids", &id_len); 183 counts = nvlist_get_number_array(nvl, "counters", &counter_len); 184 names = nvlist_get_string_array(nvl, "names", &names_len); 185 assert(id_len == counter_len); 186 assert(counter_len == names_len); 187 188 TAILQ_INIT(counters); 189 190 for (size_t i = 0; i < id_len; i++) { 191 struct pfctl_status_counter *c; 192 193 c = malloc(sizeof(*c)); 194 195 c->id = ids[i]; 196 c->counter = counts[i]; 197 c->name = strdup(names[i]); 198 199 TAILQ_INSERT_TAIL(counters, c, entry); 200 } 201 } 202 203 struct pfctl_status * 204 pfctl_get_status(int dev) 205 { 206 struct pfctl_status *status; 207 nvlist_t *nvl; 208 size_t len; 209 const void *chksum; 210 211 status = calloc(1, sizeof(*status)); 212 if (status == NULL) 213 return (NULL); 214 215 nvl = nvlist_create(0); 216 217 if (pfctl_do_ioctl(dev, DIOCGETSTATUSNV, 4096, &nvl)) { 218 free(status); 219 return (NULL); 220 } 221 222 status->running = nvlist_get_bool(nvl, "running"); 223 status->since = nvlist_get_number(nvl, "since"); 224 status->debug = nvlist_get_number(nvl, "debug"); 225 status->hostid = ntohl(nvlist_get_number(nvl, "hostid")); 226 status->states = nvlist_get_number(nvl, "states"); 227 status->src_nodes = nvlist_get_number(nvl, "src_nodes"); 228 status->syncookies_active = nvlist_get_bool(nvl, "syncookies_active"); 229 status->reass = nvlist_get_number(nvl, "reass"); 230 231 strlcpy(status->ifname, nvlist_get_string(nvl, "ifname"), 232 IFNAMSIZ); 233 chksum = nvlist_get_binary(nvl, "chksum", &len); 234 assert(len == PF_MD5_DIGEST_LENGTH); 235 memcpy(status->pf_chksum, chksum, len); 236 237 _pfctl_get_status_counters(nvlist_get_nvlist(nvl, "counters"), 238 &status->counters); 239 _pfctl_get_status_counters(nvlist_get_nvlist(nvl, "lcounters"), 240 &status->lcounters); 241 _pfctl_get_status_counters(nvlist_get_nvlist(nvl, "fcounters"), 242 &status->fcounters); 243 _pfctl_get_status_counters(nvlist_get_nvlist(nvl, "scounters"), 244 &status->scounters); 245 246 pf_nvuint_64_array(nvl, "pcounters", 2 * 2 * 3, 247 (uint64_t *)status->pcounters, NULL); 248 pf_nvuint_64_array(nvl, "bcounters", 2 * 2, 249 (uint64_t *)status->bcounters, NULL); 250 251 nvlist_destroy(nvl); 252 253 return (status); 254 } 255 256 static uint64_t 257 _pfctl_status_counter(struct pfctl_status_counters *counters, uint64_t id) 258 { 259 struct pfctl_status_counter *c; 260 261 TAILQ_FOREACH(c, counters, entry) { 262 if (c->id == id) 263 return (c->counter); 264 } 265 266 return (0); 267 } 268 269 uint64_t 270 pfctl_status_counter(struct pfctl_status *status, int id) 271 { 272 return (_pfctl_status_counter(&status->counters, id)); 273 } 274 275 uint64_t 276 pfctl_status_lcounter(struct pfctl_status *status, int id) 277 { 278 return (_pfctl_status_counter(&status->lcounters, 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 nvlist_destroy(nvl); 768 769 return (0); 770 } 771 772 int 773 pfctl_get_eth_rules_info(int dev, struct pfctl_eth_rules_info *rules, 774 const char *path) 775 { 776 nvlist_t *nvl; 777 int ret; 778 779 bzero(rules, sizeof(*rules)); 780 781 nvl = nvlist_create(0); 782 nvlist_add_string(nvl, "anchor", path); 783 784 if ((ret = pfctl_do_ioctl(dev, DIOCGETETHRULES, 1024, &nvl)) != 0) 785 return (ret); 786 787 rules->nr = nvlist_get_number(nvl, "nr"); 788 rules->ticket = nvlist_get_number(nvl, "ticket"); 789 790 nvlist_destroy(nvl); 791 return (0); 792 } 793 794 int 795 pfctl_get_eth_rule(int dev, uint32_t nr, uint32_t ticket, 796 const char *path, struct pfctl_eth_rule *rule, bool clear, 797 char *anchor_call) 798 { 799 nvlist_t *nvl; 800 int ret; 801 802 nvl = nvlist_create(0); 803 804 nvlist_add_string(nvl, "anchor", path); 805 nvlist_add_number(nvl, "ticket", ticket); 806 nvlist_add_number(nvl, "nr", nr); 807 nvlist_add_bool(nvl, "clear", clear); 808 809 if ((ret = pfctl_do_ioctl(dev, DIOCGETETHRULE, 4096, &nvl)) != 0) 810 return (ret); 811 812 pfctl_nveth_rule_to_eth_rule(nvl, rule); 813 814 if (anchor_call) 815 strlcpy(anchor_call, nvlist_get_string(nvl, "anchor_call"), 816 MAXPATHLEN); 817 818 nvlist_destroy(nvl); 819 return (0); 820 } 821 822 int 823 pfctl_add_eth_rule(int dev, const struct pfctl_eth_rule *r, const char *anchor, 824 const char *anchor_call, uint32_t ticket) 825 { 826 struct pfioc_nv nv; 827 nvlist_t *nvl, *addr; 828 void *packed; 829 int error = 0; 830 size_t labelcount, size; 831 832 nvl = nvlist_create(0); 833 834 nvlist_add_number(nvl, "ticket", ticket); 835 nvlist_add_string(nvl, "anchor", anchor); 836 nvlist_add_string(nvl, "anchor_call", anchor_call); 837 838 nvlist_add_number(nvl, "nr", r->nr); 839 nvlist_add_bool(nvl, "quick", r->quick); 840 nvlist_add_string(nvl, "ifname", r->ifname); 841 nvlist_add_bool(nvl, "ifnot", r->ifnot); 842 nvlist_add_number(nvl, "direction", r->direction); 843 nvlist_add_number(nvl, "proto", r->proto); 844 nvlist_add_string(nvl, "match_tagname", r->match_tagname); 845 nvlist_add_bool(nvl, "match_tag_not", r->match_tag_not); 846 847 addr = pfctl_eth_addr_to_nveth_addr(&r->src); 848 if (addr == NULL) { 849 nvlist_destroy(nvl); 850 return (ENOMEM); 851 } 852 nvlist_add_nvlist(nvl, "src", addr); 853 nvlist_destroy(addr); 854 855 addr = pfctl_eth_addr_to_nveth_addr(&r->dst); 856 if (addr == NULL) { 857 nvlist_destroy(nvl); 858 return (ENOMEM); 859 } 860 nvlist_add_nvlist(nvl, "dst", addr); 861 nvlist_destroy(addr); 862 863 pfctl_nv_add_rule_addr(nvl, "ipsrc", &r->ipsrc); 864 pfctl_nv_add_rule_addr(nvl, "ipdst", &r->ipdst); 865 866 labelcount = 0; 867 while (labelcount < PF_RULE_MAX_LABEL_COUNT && 868 r->label[labelcount][0] != 0) { 869 nvlist_append_string_array(nvl, "labels", 870 r->label[labelcount]); 871 labelcount++; 872 } 873 nvlist_add_number(nvl, "ridentifier", r->ridentifier); 874 875 nvlist_add_string(nvl, "qname", r->qname); 876 nvlist_add_string(nvl, "tagname", r->tagname); 877 nvlist_add_number(nvl, "dnpipe", r->dnpipe); 878 nvlist_add_number(nvl, "dnflags", r->dnflags); 879 880 nvlist_add_string(nvl, "bridge_to", r->bridge_to); 881 882 nvlist_add_number(nvl, "action", r->action); 883 884 packed = nvlist_pack(nvl, &size); 885 if (packed == NULL) { 886 nvlist_destroy(nvl); 887 return (ENOMEM); 888 } 889 890 nv.len = size; 891 nv.size = size; 892 nv.data = packed; 893 894 if (ioctl(dev, DIOCADDETHRULE, &nv) != 0) 895 error = errno; 896 897 free(packed); 898 nvlist_destroy(nvl); 899 900 return (error); 901 } 902 903 int 904 pfctl_add_rule(int dev, const struct pfctl_rule *r, const char *anchor, 905 const char *anchor_call, uint32_t ticket, uint32_t pool_ticket) 906 { 907 struct pfioc_nv nv; 908 uint64_t timeouts[PFTM_MAX]; 909 uint64_t set_prio[2]; 910 nvlist_t *nvl, *nvlr; 911 size_t labelcount; 912 int ret; 913 914 nvl = nvlist_create(0); 915 nvlr = nvlist_create(0); 916 917 nvlist_add_number(nvl, "ticket", ticket); 918 nvlist_add_number(nvl, "pool_ticket", pool_ticket); 919 nvlist_add_string(nvl, "anchor", anchor); 920 nvlist_add_string(nvl, "anchor_call", anchor_call); 921 922 nvlist_add_number(nvlr, "nr", r->nr); 923 pfctl_nv_add_rule_addr(nvlr, "src", &r->src); 924 pfctl_nv_add_rule_addr(nvlr, "dst", &r->dst); 925 926 labelcount = 0; 927 while (r->label[labelcount][0] != 0 && 928 labelcount < PF_RULE_MAX_LABEL_COUNT) { 929 nvlist_append_string_array(nvlr, "labels", 930 r->label[labelcount]); 931 labelcount++; 932 } 933 nvlist_add_number(nvlr, "ridentifier", r->ridentifier); 934 935 nvlist_add_string(nvlr, "ifname", r->ifname); 936 nvlist_add_string(nvlr, "qname", r->qname); 937 nvlist_add_string(nvlr, "pqname", r->pqname); 938 nvlist_add_string(nvlr, "tagname", r->tagname); 939 nvlist_add_string(nvlr, "match_tagname", r->match_tagname); 940 nvlist_add_string(nvlr, "overload_tblname", r->overload_tblname); 941 942 pfctl_nv_add_pool(nvlr, "rpool", &r->rpool); 943 944 nvlist_add_number(nvlr, "os_fingerprint", r->os_fingerprint); 945 946 nvlist_add_number(nvlr, "rtableid", r->rtableid); 947 for (int i = 0; i < PFTM_MAX; i++) 948 timeouts[i] = r->timeout[i]; 949 nvlist_add_number_array(nvlr, "timeout", timeouts, PFTM_MAX); 950 nvlist_add_number(nvlr, "max_states", r->max_states); 951 nvlist_add_number(nvlr, "max_src_nodes", r->max_src_nodes); 952 nvlist_add_number(nvlr, "max_src_states", r->max_src_states); 953 nvlist_add_number(nvlr, "max_src_conn", r->max_src_conn); 954 nvlist_add_number(nvlr, "max_src_conn_rate.limit", 955 r->max_src_conn_rate.limit); 956 nvlist_add_number(nvlr, "max_src_conn_rate.seconds", 957 r->max_src_conn_rate.seconds); 958 nvlist_add_number(nvlr, "dnpipe", r->dnpipe); 959 nvlist_add_number(nvlr, "dnrpipe", r->dnrpipe); 960 nvlist_add_number(nvlr, "dnflags", r->free_flags); 961 nvlist_add_number(nvlr, "prob", r->prob); 962 nvlist_add_number(nvlr, "cuid", r->cuid); 963 nvlist_add_number(nvlr, "cpid", r->cpid); 964 965 nvlist_add_number(nvlr, "return_icmp", r->return_icmp); 966 nvlist_add_number(nvlr, "return_icmp6", r->return_icmp6); 967 968 nvlist_add_number(nvlr, "max_mss", r->max_mss); 969 nvlist_add_number(nvlr, "scrub_flags", r->scrub_flags); 970 971 pfctl_nv_add_uid(nvlr, "uid", &r->uid); 972 pfctl_nv_add_uid(nvlr, "gid", (const struct pf_rule_uid *)&r->gid); 973 974 nvlist_add_number(nvlr, "rule_flag", r->rule_flag); 975 nvlist_add_number(nvlr, "action", r->action); 976 nvlist_add_number(nvlr, "direction", r->direction); 977 nvlist_add_number(nvlr, "log", r->log); 978 nvlist_add_number(nvlr, "logif", r->logif); 979 nvlist_add_number(nvlr, "quick", r->quick); 980 nvlist_add_number(nvlr, "ifnot", r->ifnot); 981 nvlist_add_number(nvlr, "match_tag_not", r->match_tag_not); 982 nvlist_add_number(nvlr, "natpass", r->natpass); 983 984 nvlist_add_number(nvlr, "keep_state", r->keep_state); 985 nvlist_add_number(nvlr, "af", r->af); 986 nvlist_add_number(nvlr, "proto", r->proto); 987 nvlist_add_number(nvlr, "type", r->type); 988 nvlist_add_number(nvlr, "code", r->code); 989 nvlist_add_number(nvlr, "flags", r->flags); 990 nvlist_add_number(nvlr, "flagset", r->flagset); 991 nvlist_add_number(nvlr, "min_ttl", r->min_ttl); 992 nvlist_add_number(nvlr, "allow_opts", r->allow_opts); 993 nvlist_add_number(nvlr, "rt", r->rt); 994 nvlist_add_number(nvlr, "return_ttl", r->return_ttl); 995 nvlist_add_number(nvlr, "tos", r->tos); 996 nvlist_add_number(nvlr, "set_tos", r->set_tos); 997 nvlist_add_number(nvlr, "anchor_relative", r->anchor_relative); 998 nvlist_add_number(nvlr, "anchor_wildcard", r->anchor_wildcard); 999 1000 nvlist_add_number(nvlr, "flush", r->flush); 1001 1002 nvlist_add_number(nvlr, "prio", r->prio); 1003 set_prio[0] = r->set_prio[0]; 1004 set_prio[1] = r->set_prio[1]; 1005 nvlist_add_number_array(nvlr, "set_prio", set_prio, 2); 1006 1007 pfctl_nv_add_divert(nvlr, "divert", r); 1008 1009 nvlist_add_nvlist(nvl, "rule", nvlr); 1010 nvlist_destroy(nvlr); 1011 1012 /* Now do the call. */ 1013 nv.data = nvlist_pack(nvl, &nv.len); 1014 nv.size = nv.len; 1015 1016 ret = ioctl(dev, DIOCADDRULENV, &nv); 1017 if (ret == -1) 1018 ret = errno; 1019 1020 free(nv.data); 1021 nvlist_destroy(nvl); 1022 1023 return (ret); 1024 } 1025 1026 int 1027 pfctl_get_rules_info(int dev, struct pfctl_rules_info *rules, uint32_t ruleset, 1028 const char *path) 1029 { 1030 struct pfioc_rule pr; 1031 int ret; 1032 1033 bzero(&pr, sizeof(pr)); 1034 if (strlcpy(pr.anchor, path, sizeof(pr.anchor)) >= sizeof(pr.anchor)) 1035 return (E2BIG); 1036 1037 pr.rule.action = ruleset; 1038 ret = ioctl(dev, DIOCGETRULES, &pr); 1039 if (ret != 0) 1040 return (ret); 1041 1042 rules->nr = pr.nr; 1043 rules->ticket = pr.ticket; 1044 1045 return (0); 1046 } 1047 1048 int 1049 pfctl_get_rule(int dev, uint32_t nr, uint32_t ticket, const char *anchor, 1050 uint32_t ruleset, struct pfctl_rule *rule, char *anchor_call) 1051 { 1052 return (pfctl_get_clear_rule(dev, nr, ticket, anchor, ruleset, rule, 1053 anchor_call, false)); 1054 } 1055 1056 int pfctl_get_clear_rule(int dev, uint32_t nr, uint32_t ticket, 1057 const char *anchor, uint32_t ruleset, struct pfctl_rule *rule, 1058 char *anchor_call, bool clear) 1059 { 1060 nvlist_t *nvl; 1061 int ret; 1062 1063 nvl = nvlist_create(0); 1064 if (nvl == 0) 1065 return (ENOMEM); 1066 1067 nvlist_add_number(nvl, "nr", nr); 1068 nvlist_add_number(nvl, "ticket", ticket); 1069 nvlist_add_string(nvl, "anchor", anchor); 1070 nvlist_add_number(nvl, "ruleset", ruleset); 1071 1072 if (clear) 1073 nvlist_add_bool(nvl, "clear_counter", true); 1074 1075 if ((ret = pfctl_do_ioctl(dev, DIOCGETRULENV, 8192, &nvl)) != 0) 1076 return (ret); 1077 1078 pf_nvrule_to_rule(nvlist_get_nvlist(nvl, "rule"), rule); 1079 1080 if (anchor_call) 1081 strlcpy(anchor_call, nvlist_get_string(nvl, "anchor_call"), 1082 MAXPATHLEN); 1083 1084 nvlist_destroy(nvl); 1085 1086 return (0); 1087 } 1088 1089 int 1090 pfctl_set_keepcounters(int dev, bool keep) 1091 { 1092 struct pfioc_nv nv; 1093 nvlist_t *nvl; 1094 int ret; 1095 1096 nvl = nvlist_create(0); 1097 1098 nvlist_add_bool(nvl, "keep_counters", keep); 1099 1100 nv.data = nvlist_pack(nvl, &nv.len); 1101 nv.size = nv.len; 1102 1103 nvlist_destroy(nvl); 1104 1105 ret = ioctl(dev, DIOCKEEPCOUNTERS, &nv); 1106 1107 free(nv.data); 1108 return (ret); 1109 } 1110 1111 static void 1112 pfctl_nv_add_state_cmp(nvlist_t *nvl, const char *name, 1113 const struct pfctl_state_cmp *cmp) 1114 { 1115 nvlist_t *nv; 1116 1117 nv = nvlist_create(0); 1118 1119 nvlist_add_number(nv, "id", cmp->id); 1120 nvlist_add_number(nv, "creatorid", htonl(cmp->creatorid)); 1121 nvlist_add_number(nv, "direction", cmp->direction); 1122 1123 nvlist_add_nvlist(nvl, name, nv); 1124 nvlist_destroy(nv); 1125 } 1126 1127 static void 1128 pf_state_key_export_to_state_key(struct pfctl_state_key *ps, 1129 const struct pf_state_key_export *s) 1130 { 1131 bcopy(s->addr, ps->addr, sizeof(ps->addr[0]) * 2); 1132 ps->port[0] = s->port[0]; 1133 ps->port[1] = s->port[1]; 1134 } 1135 1136 static void 1137 pf_state_peer_export_to_state_peer(struct pfctl_state_peer *ps, 1138 const struct pf_state_peer_export *s) 1139 { 1140 /* Ignore scrub. */ 1141 ps->seqlo = s->seqlo; 1142 ps->seqhi = s->seqhi; 1143 ps->seqdiff = s->seqdiff; 1144 /* Ignore max_win & mss */ 1145 ps->state = s->state; 1146 ps->wscale = s->wscale; 1147 } 1148 1149 static void 1150 pf_state_export_to_state(struct pfctl_state *ps, const struct pf_state_export *s) 1151 { 1152 assert(s->version >= PF_STATE_VERSION); 1153 1154 ps->id = s->id; 1155 strlcpy(ps->ifname, s->ifname, sizeof(ps->ifname)); 1156 strlcpy(ps->orig_ifname, s->orig_ifname, sizeof(ps->orig_ifname)); 1157 strlcpy(ps->rt_ifname, s->rt_ifname, sizeof(ps->rt_ifname)); 1158 pf_state_key_export_to_state_key(&ps->key[0], &s->key[0]); 1159 pf_state_key_export_to_state_key(&ps->key[1], &s->key[1]); 1160 pf_state_peer_export_to_state_peer(&ps->src, &s->src); 1161 pf_state_peer_export_to_state_peer(&ps->dst, &s->dst); 1162 bcopy(&s->rt_addr, &ps->rt_addr, sizeof(ps->rt_addr)); 1163 ps->rule = ntohl(s->rule); 1164 ps->anchor = ntohl(s->anchor); 1165 ps->nat_rule = ntohl(s->nat_rule); 1166 ps->creation = ntohl(s->creation); 1167 ps->expire = ntohl(s->expire); 1168 ps->packets[0] = s->packets[0]; 1169 ps->packets[1] = s->packets[1]; 1170 ps->bytes[0] = s->bytes[0]; 1171 ps->bytes[1] = s->bytes[1]; 1172 ps->creatorid = ntohl(s->creatorid); 1173 ps->key[0].proto = s->proto; 1174 ps->key[1].proto = s->proto; 1175 ps->key[0].af = s->af; 1176 ps->key[1].af = s->af; 1177 ps->direction = s->direction; 1178 ps->state_flags = ntohs(s->state_flags); 1179 ps->sync_flags = ntohs(s->sync_flags); 1180 ps->qid = ntohs(s->qid); 1181 ps->pqid = ntohs(s->pqid); 1182 ps->dnpipe = ntohs(s->dnpipe); 1183 ps->dnrpipe = ntohs(s->dnrpipe); 1184 ps->rtableid = ntohl(s->rtableid); 1185 ps->min_ttl = s->min_ttl; 1186 ps->set_tos = s->set_tos; 1187 ps->max_mss = ntohs(s->max_mss); 1188 ps->rt = s->rt; 1189 ps->set_prio[0] = s->set_prio[0]; 1190 ps->set_prio[1] = s->set_prio[1]; 1191 } 1192 1193 int 1194 pfctl_get_states(int dev, struct pfctl_states *states) 1195 { 1196 struct pfioc_states_v2 ps; 1197 struct pf_state_export *p; 1198 char *inbuf = NULL, *newinbuf = NULL; 1199 unsigned int len = 0; 1200 int i, error; 1201 1202 bzero(&ps, sizeof(ps)); 1203 ps.ps_req_version = PF_STATE_VERSION; 1204 1205 bzero(states, sizeof(*states)); 1206 TAILQ_INIT(&states->states); 1207 1208 for (;;) { 1209 ps.ps_len = len; 1210 if (len) { 1211 newinbuf = realloc(inbuf, len); 1212 if (newinbuf == NULL) 1213 return (ENOMEM); 1214 ps.ps_buf = inbuf = newinbuf; 1215 } 1216 if ((error = ioctl(dev, DIOCGETSTATESV2, &ps)) < 0) { 1217 free(inbuf); 1218 return (error); 1219 } 1220 if (ps.ps_len + sizeof(struct pfioc_states_v2) < len) 1221 break; 1222 if (len == 0 && ps.ps_len == 0) 1223 goto out; 1224 if (len == 0 && ps.ps_len != 0) 1225 len = ps.ps_len; 1226 if (ps.ps_len == 0) 1227 goto out; /* no states */ 1228 len *= 2; 1229 } 1230 p = ps.ps_states; 1231 1232 for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) { 1233 struct pfctl_state *s = malloc(sizeof(*s)); 1234 if (s == NULL) { 1235 pfctl_free_states(states); 1236 error = ENOMEM; 1237 goto out; 1238 } 1239 1240 pf_state_export_to_state(s, p); 1241 TAILQ_INSERT_TAIL(&states->states, s, entry); 1242 } 1243 1244 out: 1245 free(inbuf); 1246 return (error); 1247 } 1248 1249 void 1250 pfctl_free_states(struct pfctl_states *states) 1251 { 1252 struct pfctl_state *s, *tmp; 1253 1254 TAILQ_FOREACH_SAFE(s, &states->states, entry, tmp) { 1255 free(s); 1256 } 1257 1258 bzero(states, sizeof(*states)); 1259 } 1260 1261 static int 1262 _pfctl_clear_states(int dev, const struct pfctl_kill *kill, 1263 unsigned int *killed, uint64_t ioctlval) 1264 { 1265 nvlist_t *nvl; 1266 int ret; 1267 1268 nvl = nvlist_create(0); 1269 1270 pfctl_nv_add_state_cmp(nvl, "cmp", &kill->cmp); 1271 nvlist_add_number(nvl, "af", kill->af); 1272 nvlist_add_number(nvl, "proto", kill->proto); 1273 pfctl_nv_add_rule_addr(nvl, "src", &kill->src); 1274 pfctl_nv_add_rule_addr(nvl, "dst", &kill->dst); 1275 pfctl_nv_add_rule_addr(nvl, "rt_addr", &kill->rt_addr); 1276 nvlist_add_string(nvl, "ifname", kill->ifname); 1277 nvlist_add_string(nvl, "label", kill->label); 1278 nvlist_add_bool(nvl, "kill_match", kill->kill_match); 1279 1280 if ((ret = pfctl_do_ioctl(dev, ioctlval, 1024, &nvl)) != 0) 1281 return (ret); 1282 1283 if (killed) 1284 *killed = nvlist_get_number(nvl, "killed"); 1285 1286 nvlist_destroy(nvl); 1287 1288 return (ret); 1289 } 1290 1291 int 1292 pfctl_clear_states(int dev, const struct pfctl_kill *kill, 1293 unsigned int *killed) 1294 { 1295 return (_pfctl_clear_states(dev, kill, killed, DIOCCLRSTATESNV)); 1296 } 1297 1298 int 1299 pfctl_kill_states(int dev, const struct pfctl_kill *kill, unsigned int *killed) 1300 { 1301 return (_pfctl_clear_states(dev, kill, killed, DIOCKILLSTATESNV)); 1302 } 1303 1304 int 1305 pfctl_clear_rules(int dev, const char *anchorname) 1306 { 1307 struct pfioc_trans trans; 1308 struct pfioc_trans_e transe[2]; 1309 int ret; 1310 1311 bzero(&trans, sizeof(trans)); 1312 bzero(&transe, sizeof(transe)); 1313 1314 transe[0].rs_num = PF_RULESET_SCRUB; 1315 if (strlcpy(transe[0].anchor, anchorname, sizeof(transe[0].anchor)) 1316 >= sizeof(transe[0].anchor)) 1317 return (E2BIG); 1318 1319 transe[1].rs_num = PF_RULESET_FILTER; 1320 if (strlcpy(transe[1].anchor, anchorname, sizeof(transe[1].anchor)) 1321 >= sizeof(transe[1].anchor)) 1322 return (E2BIG); 1323 1324 trans.size = 2; 1325 trans.esize = sizeof(transe[0]); 1326 trans.array = transe; 1327 1328 ret = ioctl(dev, DIOCXBEGIN, &trans); 1329 if (ret != 0) 1330 return (ret); 1331 return ioctl(dev, DIOCXCOMMIT, &trans); 1332 } 1333 1334 int 1335 pfctl_clear_nat(int dev, const char *anchorname) 1336 { 1337 struct pfioc_trans trans; 1338 struct pfioc_trans_e transe[3]; 1339 int ret; 1340 1341 bzero(&trans, sizeof(trans)); 1342 bzero(&transe, sizeof(transe)); 1343 1344 transe[0].rs_num = PF_RULESET_NAT; 1345 if (strlcpy(transe[0].anchor, anchorname, sizeof(transe[0].anchor)) 1346 >= sizeof(transe[0].anchor)) 1347 return (E2BIG); 1348 1349 transe[1].rs_num = PF_RULESET_BINAT; 1350 if (strlcpy(transe[1].anchor, anchorname, sizeof(transe[1].anchor)) 1351 >= sizeof(transe[0].anchor)) 1352 return (E2BIG); 1353 1354 transe[2].rs_num = PF_RULESET_RDR; 1355 if (strlcpy(transe[2].anchor, anchorname, sizeof(transe[2].anchor)) 1356 >= sizeof(transe[2].anchor)) 1357 return (E2BIG); 1358 1359 trans.size = 3; 1360 trans.esize = sizeof(transe[0]); 1361 trans.array = transe; 1362 1363 ret = ioctl(dev, DIOCXBEGIN, &trans); 1364 if (ret != 0) 1365 return (ret); 1366 return ioctl(dev, DIOCXCOMMIT, &trans); 1367 } 1368 int 1369 pfctl_clear_eth_rules(int dev, const char *anchorname) 1370 { 1371 struct pfioc_trans trans; 1372 struct pfioc_trans_e transe; 1373 int ret; 1374 1375 bzero(&trans, sizeof(trans)); 1376 bzero(&transe, sizeof(transe)); 1377 1378 transe.rs_num = PF_RULESET_ETH; 1379 if (strlcpy(transe.anchor, anchorname, sizeof(transe.anchor)) 1380 >= sizeof(transe.anchor)) 1381 return (E2BIG); 1382 1383 trans.size = 1; 1384 trans.esize = sizeof(transe); 1385 trans.array = &transe; 1386 1387 ret = ioctl(dev, DIOCXBEGIN, &trans); 1388 if (ret != 0) 1389 return (ret); 1390 return ioctl(dev, DIOCXCOMMIT, &trans); 1391 } 1392 1393 static int 1394 pfctl_get_limit(int dev, const int index, uint *limit) 1395 { 1396 struct pfioc_limit pl; 1397 1398 bzero(&pl, sizeof(pl)); 1399 pl.index = index; 1400 1401 if (ioctl(dev, DIOCGETLIMIT, &pl) == -1) 1402 return (errno); 1403 1404 *limit = pl.limit; 1405 1406 return (0); 1407 } 1408 1409 int 1410 pfctl_set_syncookies(int dev, const struct pfctl_syncookies *s) 1411 { 1412 struct pfioc_nv nv; 1413 nvlist_t *nvl; 1414 int ret; 1415 uint state_limit; 1416 uint64_t lim, hi, lo; 1417 1418 ret = pfctl_get_limit(dev, PF_LIMIT_STATES, &state_limit); 1419 if (ret != 0) 1420 return (ret); 1421 1422 lim = state_limit; 1423 hi = lim * s->highwater / 100; 1424 lo = lim * s->lowwater / 100; 1425 1426 if (lo == hi) 1427 hi++; 1428 1429 nvl = nvlist_create(0); 1430 1431 nvlist_add_bool(nvl, "enabled", s->mode != PFCTL_SYNCOOKIES_NEVER); 1432 nvlist_add_bool(nvl, "adaptive", s->mode == PFCTL_SYNCOOKIES_ADAPTIVE); 1433 nvlist_add_number(nvl, "highwater", hi); 1434 nvlist_add_number(nvl, "lowwater", lo); 1435 1436 nv.data = nvlist_pack(nvl, &nv.len); 1437 nv.size = nv.len; 1438 nvlist_destroy(nvl); 1439 nvl = NULL; 1440 1441 ret = ioctl(dev, DIOCSETSYNCOOKIES, &nv); 1442 1443 free(nv.data); 1444 return (ret); 1445 } 1446 1447 int 1448 pfctl_get_syncookies(int dev, struct pfctl_syncookies *s) 1449 { 1450 nvlist_t *nvl; 1451 int ret; 1452 uint state_limit; 1453 bool enabled, adaptive; 1454 1455 ret = pfctl_get_limit(dev, PF_LIMIT_STATES, &state_limit); 1456 if (ret != 0) 1457 return (ret); 1458 1459 bzero(s, sizeof(*s)); 1460 1461 nvl = nvlist_create(0); 1462 1463 if ((ret = pfctl_do_ioctl(dev, DIOCGETSYNCOOKIES, 256, &nvl)) != 0) 1464 return (errno); 1465 1466 enabled = nvlist_get_bool(nvl, "enabled"); 1467 adaptive = nvlist_get_bool(nvl, "adaptive"); 1468 1469 if (enabled) { 1470 if (adaptive) 1471 s->mode = PFCTL_SYNCOOKIES_ADAPTIVE; 1472 else 1473 s->mode = PFCTL_SYNCOOKIES_ALWAYS; 1474 } else { 1475 s->mode = PFCTL_SYNCOOKIES_NEVER; 1476 } 1477 1478 s->highwater = nvlist_get_number(nvl, "highwater") * 100 / state_limit; 1479 s->lowwater = nvlist_get_number(nvl, "lowwater") * 100 / state_limit; 1480 1481 nvlist_destroy(nvl); 1482 1483 return (0); 1484 } 1485 1486 int 1487 pfctl_table_add_addrs(int dev, struct pfr_table *tbl, struct pfr_addr 1488 *addr, int size, int *nadd, int flags) 1489 { 1490 struct pfioc_table io; 1491 1492 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 1493 return (EINVAL); 1494 } 1495 bzero(&io, sizeof io); 1496 io.pfrio_flags = flags; 1497 io.pfrio_table = *tbl; 1498 io.pfrio_buffer = addr; 1499 io.pfrio_esize = sizeof(*addr); 1500 io.pfrio_size = size; 1501 1502 if (ioctl(dev, DIOCRADDADDRS, &io)) 1503 return (errno); 1504 if (nadd != NULL) 1505 *nadd = io.pfrio_nadd; 1506 return (0); 1507 } 1508 1509 int 1510 pfctl_table_del_addrs(int dev, struct pfr_table *tbl, struct pfr_addr 1511 *addr, int size, int *ndel, int flags) 1512 { 1513 struct pfioc_table io; 1514 1515 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 1516 return (EINVAL); 1517 } 1518 bzero(&io, sizeof io); 1519 io.pfrio_flags = flags; 1520 io.pfrio_table = *tbl; 1521 io.pfrio_buffer = addr; 1522 io.pfrio_esize = sizeof(*addr); 1523 io.pfrio_size = size; 1524 1525 if (ioctl(dev, DIOCRDELADDRS, &io)) 1526 return (errno); 1527 if (ndel != NULL) 1528 *ndel = io.pfrio_ndel; 1529 return (0); 1530 } 1531 1532 int 1533 pfctl_table_set_addrs(int dev, struct pfr_table *tbl, struct pfr_addr 1534 *addr, int size, int *size2, int *nadd, int *ndel, int *nchange, int flags) 1535 { 1536 struct pfioc_table io; 1537 1538 if (tbl == NULL || size < 0 || (size && addr == NULL)) { 1539 return (EINVAL); 1540 } 1541 bzero(&io, sizeof io); 1542 io.pfrio_flags = flags; 1543 io.pfrio_table = *tbl; 1544 io.pfrio_buffer = addr; 1545 io.pfrio_esize = sizeof(*addr); 1546 io.pfrio_size = size; 1547 io.pfrio_size2 = (size2 != NULL) ? *size2 : 0; 1548 if (ioctl(dev, DIOCRSETADDRS, &io)) 1549 return (-1); 1550 if (nadd != NULL) 1551 *nadd = io.pfrio_nadd; 1552 if (ndel != NULL) 1553 *ndel = io.pfrio_ndel; 1554 if (nchange != NULL) 1555 *nchange = io.pfrio_nchange; 1556 if (size2 != NULL) 1557 *size2 = io.pfrio_size2; 1558 return (0); 1559 } 1560 1561 int pfctl_table_get_addrs(int dev, struct pfr_table *tbl, struct pfr_addr *addr, 1562 int *size, int flags) 1563 { 1564 struct pfioc_table io; 1565 1566 if (tbl == NULL || size == NULL || *size < 0 || 1567 (*size && addr == NULL)) { 1568 return (EINVAL); 1569 } 1570 bzero(&io, sizeof io); 1571 io.pfrio_flags = flags; 1572 io.pfrio_table = *tbl; 1573 io.pfrio_buffer = addr; 1574 io.pfrio_esize = sizeof(*addr); 1575 io.pfrio_size = *size; 1576 if (ioctl(dev, DIOCRGETADDRS, &io)) 1577 return (-1); 1578 *size = io.pfrio_size; 1579 return (0); 1580 } 1581