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