1/* $NetBSD: npf.c,v 1.7.2.9 2013/02/11 21:49:48 riz Exp $ */ 2 3/*- 4 * Copyright (c) 2010-2013 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This material is based upon work partially supported by The 8 * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN 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__KERNEL_RCSID(0, "$NetBSD: npf.c,v 1.7.2.9 2013/02/11 21:49:48 riz Exp $"); 34 35#include <sys/types.h> 36#include <netinet/in_systm.h> 37#include <netinet/in.h> 38#include <net/if.h> 39#include <prop/proplib.h> 40 41#include <stdlib.h> 42#include <string.h> 43#include <assert.h> 44#include <errno.h> 45#include <err.h> 46 47#define _NPF_PRIVATE 48#include "npf.h" 49 50struct nl_config { 51 /* Rules, translations, tables, procedures. */ 52 prop_dictionary_t ncf_dict; 53 prop_array_t ncf_rules_list; 54 prop_array_t ncf_rproc_list; 55 prop_array_t ncf_table_list; 56 prop_array_t ncf_nat_list; 57 /* Debug information. */ 58 prop_dictionary_t ncf_debug; 59 /* Error report. */ 60 prop_dictionary_t ncf_err; 61 /* Custom file to externalise property-list. */ 62 const char * ncf_plist; 63 bool ncf_flush; 64}; 65 66struct nl_rule { 67 prop_dictionary_t nrl_dict; 68}; 69 70struct nl_rproc { 71 prop_dictionary_t nrp_dict; 72}; 73 74struct nl_table { 75 prop_dictionary_t ntl_dict; 76}; 77 78struct nl_ext { 79 const char * nxt_name; 80 prop_dictionary_t nxt_dict; 81}; 82 83static prop_array_t _npf_ruleset_transform(prop_array_t); 84 85/* 86 * CONFIGURATION INTERFACE. 87 */ 88 89nl_config_t * 90npf_config_create(void) 91{ 92 nl_config_t *ncf; 93 94 ncf = calloc(1, sizeof(*ncf)); 95 if (ncf == NULL) { 96 return NULL; 97 } 98 ncf->ncf_rules_list = prop_array_create(); 99 ncf->ncf_rproc_list = prop_array_create(); 100 ncf->ncf_table_list = prop_array_create(); 101 ncf->ncf_nat_list = prop_array_create(); 102 103 ncf->ncf_plist = NULL; 104 ncf->ncf_flush = false; 105 106 return ncf; 107} 108 109int 110npf_config_submit(nl_config_t *ncf, int fd) 111{ 112 const char *plist = ncf->ncf_plist; 113 prop_dictionary_t npf_dict; 114 prop_array_t rlset; 115 int error = 0; 116 117 npf_dict = prop_dictionary_create(); 118 if (npf_dict == NULL) { 119 return ENOMEM; 120 } 121 prop_dictionary_set_uint32(npf_dict, "version", NPF_VERSION); 122 123 rlset = _npf_ruleset_transform(ncf->ncf_rules_list); 124 if (rlset == NULL) { 125 prop_object_release(npf_dict); 126 return ENOMEM; 127 } 128 prop_dictionary_set(npf_dict, "rules", rlset); 129 prop_object_release(rlset); 130 131 prop_dictionary_set(npf_dict, "rprocs", ncf->ncf_rproc_list); 132 prop_dictionary_set(npf_dict, "tables", ncf->ncf_table_list); 133 prop_dictionary_set(npf_dict, "translation", ncf->ncf_nat_list); 134 prop_dictionary_set_bool(npf_dict, "flush", ncf->ncf_flush); 135 if (ncf->ncf_debug) { 136 prop_dictionary_set(npf_dict, "debug", ncf->ncf_debug); 137 } 138 139 if (plist) { 140 if (!prop_dictionary_externalize_to_file(npf_dict, plist)) { 141 error = errno; 142 } 143 prop_object_release(npf_dict); 144 return error; 145 } 146 147 error = prop_dictionary_sendrecv_ioctl(npf_dict, fd, 148 IOC_NPF_RELOAD, &ncf->ncf_err); 149 if (error) { 150 prop_object_release(npf_dict); 151 assert(ncf->ncf_err == NULL); 152 return error; 153 } 154 155 prop_dictionary_get_int32(ncf->ncf_err, "errno", &error); 156 prop_object_release(npf_dict); 157 return error; 158} 159 160nl_config_t * 161npf_config_retrieve(int fd, bool *active, bool *loaded) 162{ 163 prop_dictionary_t npf_dict; 164 nl_config_t *ncf; 165 int error; 166 167 error = prop_dictionary_recv_ioctl(fd, IOC_NPF_GETCONF, &npf_dict); 168 if (error) { 169 return NULL; 170 } 171 ncf = calloc(1, sizeof(*ncf)); 172 if (ncf == NULL) { 173 prop_object_release(npf_dict); 174 return NULL; 175 } 176 ncf->ncf_dict = npf_dict; 177 ncf->ncf_rules_list = prop_dictionary_get(npf_dict, "rules"); 178 ncf->ncf_rproc_list = prop_dictionary_get(npf_dict, "rprocs"); 179 ncf->ncf_table_list = prop_dictionary_get(npf_dict, "tables"); 180 ncf->ncf_nat_list = prop_dictionary_get(npf_dict, "translation"); 181 182 prop_dictionary_get_bool(npf_dict, "active", active); 183 *loaded = (ncf->ncf_rules_list != NULL); 184 return ncf; 185} 186 187int 188npf_config_flush(int fd) 189{ 190 nl_config_t *ncf; 191 int error; 192 193 ncf = npf_config_create(); 194 if (ncf == NULL) { 195 return ENOMEM; 196 } 197 ncf->ncf_flush = true; 198 error = npf_config_submit(ncf, fd); 199 npf_config_destroy(ncf); 200 return error; 201} 202 203void 204_npf_config_error(nl_config_t *ncf, nl_error_t *ne) 205{ 206 memset(ne, 0, sizeof(*ne)); 207 prop_dictionary_get_int32(ncf->ncf_err, "id", &ne->ne_id); 208 prop_dictionary_get_cstring(ncf->ncf_err, 209 "source-file", &ne->ne_source_file); 210 prop_dictionary_get_uint32(ncf->ncf_err, 211 "source-line", &ne->ne_source_line); 212 prop_dictionary_get_int32(ncf->ncf_err, 213 "code-error", &ne->ne_ncode_error); 214 prop_dictionary_get_int32(ncf->ncf_err, 215 "code-errat", &ne->ne_ncode_errat); 216} 217 218void 219npf_config_destroy(nl_config_t *ncf) 220{ 221 222 if (!ncf->ncf_dict) { 223 prop_object_release(ncf->ncf_rules_list); 224 prop_object_release(ncf->ncf_rproc_list); 225 prop_object_release(ncf->ncf_table_list); 226 prop_object_release(ncf->ncf_nat_list); 227 } 228 if (ncf->ncf_err) { 229 prop_object_release(ncf->ncf_err); 230 } 231 if (ncf->ncf_debug) { 232 prop_object_release(ncf->ncf_debug); 233 } 234 free(ncf); 235} 236 237void 238_npf_config_setsubmit(nl_config_t *ncf, const char *plist_file) 239{ 240 241 ncf->ncf_plist = plist_file; 242} 243 244static bool 245_npf_prop_array_lookup(prop_array_t array, const char *key, const char *name) 246{ 247 prop_dictionary_t dict; 248 prop_object_iterator_t it; 249 250 it = prop_array_iterator(array); 251 while ((dict = prop_object_iterator_next(it)) != NULL) { 252 const char *lname; 253 prop_dictionary_get_cstring_nocopy(dict, key, &lname); 254 if (strcmp(name, lname) == 0) 255 break; 256 } 257 prop_object_iterator_release(it); 258 return dict ? true : false; 259} 260 261/* 262 * DYNAMIC RULESET INTERFACE. 263 */ 264 265int 266npf_ruleset_add(int fd, const char *rname, nl_rule_t *rl, uint64_t *id) 267{ 268 prop_dictionary_t rldict = rl->nrl_dict; 269 prop_dictionary_t ret; 270 int error; 271 272 prop_dictionary_set_cstring(rldict, "ruleset-name", rname); 273 prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_ADD); 274 error = prop_dictionary_sendrecv_ioctl(rldict, fd, IOC_NPF_RULE, &ret); 275 if (!error) { 276 prop_dictionary_get_uint64(ret, "id", id); 277 } 278 return error; 279} 280 281int 282npf_ruleset_remove(int fd, const char *rname, uint64_t id) 283{ 284 prop_dictionary_t rldict; 285 286 rldict = prop_dictionary_create(); 287 if (rldict == NULL) { 288 return ENOMEM; 289 } 290 prop_dictionary_set_cstring(rldict, "ruleset-name", rname); 291 prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_REMOVE); 292 prop_dictionary_set_uint64(rldict, "id", id); 293 return prop_dictionary_send_ioctl(rldict, fd, IOC_NPF_RULE); 294} 295 296int 297npf_ruleset_remkey(int fd, const char *rname, const void *key, size_t len) 298{ 299 prop_dictionary_t rldict; 300 prop_data_t keyobj; 301 302 rldict = prop_dictionary_create(); 303 if (rldict == NULL) { 304 return ENOMEM; 305 } 306 prop_dictionary_set_cstring(rldict, "ruleset-name", rname); 307 prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_REMKEY); 308 309 keyobj = prop_data_create_data(key, len); 310 if (keyobj == NULL) { 311 prop_object_release(rldict); 312 return ENOMEM; 313 } 314 prop_dictionary_set(rldict, "key", keyobj); 315 prop_object_release(keyobj); 316 317 return prop_dictionary_send_ioctl(rldict, fd, IOC_NPF_RULE); 318} 319 320int 321npf_ruleset_flush(int fd, const char *rname) 322{ 323 prop_dictionary_t rldict; 324 325 rldict = prop_dictionary_create(); 326 if (rldict == NULL) { 327 return ENOMEM; 328 } 329 prop_dictionary_set_cstring(rldict, "ruleset-name", rname); 330 prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_FLUSH); 331 return prop_dictionary_send_ioctl(rldict, fd, IOC_NPF_RULE); 332} 333 334/* 335 * _npf_ruleset_transform: transform the ruleset representing nested 336 * rules with lists into an array. 337 */ 338 339static void 340_npf_ruleset_transform1(prop_array_t rlset, prop_array_t rules) 341{ 342 prop_object_iterator_t it; 343 prop_dictionary_t rldict; 344 prop_array_t subrlset; 345 346 it = prop_array_iterator(rules); 347 while ((rldict = prop_object_iterator_next(it)) != NULL) { 348 unsigned idx; 349 350 /* Add rules to the array (reference is retained). */ 351 prop_array_add(rlset, rldict); 352 353 subrlset = prop_dictionary_get(rldict, "subrules"); 354 if (subrlset) { 355 /* Process subrules recursively. */ 356 _npf_ruleset_transform1(rlset, subrlset); 357 /* Add the skip-to position. */ 358 idx = prop_array_count(rlset); 359 prop_dictionary_set_uint32(rldict, "skip-to", idx); 360 prop_dictionary_remove(rldict, "subrules"); 361 } 362 } 363 prop_object_iterator_release(it); 364} 365 366static prop_array_t 367_npf_ruleset_transform(prop_array_t rlset) 368{ 369 prop_array_t nrlset; 370 371 nrlset = prop_array_create(); 372 _npf_ruleset_transform1(nrlset, rlset); 373 return nrlset; 374} 375 376/* 377 * NPF EXTENSION INTERFACE. 378 */ 379 380nl_ext_t * 381npf_ext_construct(const char *name) 382{ 383 nl_ext_t *ext; 384 385 ext = malloc(sizeof(*ext)); 386 if (ext == NULL) { 387 return NULL; 388 } 389 ext->nxt_name = strdup(name); 390 if (ext->nxt_name == NULL) { 391 free(ext); 392 return NULL; 393 } 394 ext->nxt_dict = prop_dictionary_create(); 395 396 return ext; 397} 398 399void 400npf_ext_param_u32(nl_ext_t *ext, const char *key, uint32_t val) 401{ 402 prop_dictionary_t extdict = ext->nxt_dict; 403 prop_dictionary_set_uint32(extdict, key, val); 404} 405 406void 407npf_ext_param_bool(nl_ext_t *ext, const char *key, bool val) 408{ 409 prop_dictionary_t extdict = ext->nxt_dict; 410 prop_dictionary_set_bool(extdict, key, val); 411} 412 413/* 414 * RULE INTERFACE. 415 */ 416 417nl_rule_t * 418npf_rule_create(const char *name, uint32_t attr, u_int if_idx) 419{ 420 prop_dictionary_t rldict; 421 nl_rule_t *rl; 422 423 rl = malloc(sizeof(*rl)); 424 if (rl == NULL) { 425 return NULL; 426 } 427 rldict = prop_dictionary_create(); 428 if (rldict == NULL) { 429 free(rl); 430 return NULL; 431 } 432 if (name) { 433 prop_dictionary_set_cstring(rldict, "name", name); 434 } 435 prop_dictionary_set_uint32(rldict, "attributes", attr); 436 437 if (if_idx) { 438 prop_dictionary_set_uint32(rldict, "interface", if_idx); 439 } 440 rl->nrl_dict = rldict; 441 return rl; 442} 443 444int 445npf_rule_setcode(nl_rule_t *rl, int type, const void *code, size_t len) 446{ 447 prop_dictionary_t rldict = rl->nrl_dict; 448 prop_data_t cdata; 449 450 switch (type) { 451 case NPF_CODE_NC: 452 case NPF_CODE_BPF: 453 break; 454 default: 455 return ENOTSUP; 456 } 457 prop_dictionary_set_uint32(rldict, "code-type", type); 458 if ((cdata = prop_data_create_data(code, len)) == NULL) { 459 return ENOMEM; 460 } 461 prop_dictionary_set(rldict, "code", cdata); 462 prop_object_release(cdata); 463 return 0; 464} 465 466int 467npf_rule_setkey(nl_rule_t *rl, const void *key, size_t len) 468{ 469 prop_dictionary_t rldict = rl->nrl_dict; 470 prop_data_t kdata; 471 472 if ((kdata = prop_data_create_data(key, len)) == NULL) { 473 return ENOMEM; 474 } 475 prop_dictionary_set(rldict, "key", kdata); 476 prop_object_release(kdata); 477 return 0; 478} 479 480int 481npf_rule_setprio(nl_rule_t *rl, pri_t pri) 482{ 483 prop_dictionary_t rldict = rl->nrl_dict; 484 485 prop_dictionary_set_int32(rldict, "priority", pri); 486 return 0; 487} 488 489int 490npf_rule_setproc(nl_rule_t *rl, const char *name) 491{ 492 prop_dictionary_t rldict = rl->nrl_dict; 493 494 prop_dictionary_set_cstring(rldict, "rproc", name); 495 return 0; 496} 497 498void * 499npf_rule_export(nl_rule_t *rl, size_t *length) 500{ 501 prop_dictionary_t rldict = rl->nrl_dict; 502 void *xml; 503 504 if ((xml = prop_dictionary_externalize(rldict)) == NULL) { 505 return NULL; 506 } 507 *length = strlen(xml); 508 return xml; 509} 510 511bool 512npf_rule_exists_p(nl_config_t *ncf, const char *name) 513{ 514 return _npf_prop_array_lookup(ncf->ncf_rules_list, "name", name); 515} 516 517int 518npf_rule_insert(nl_config_t *ncf, nl_rule_t *parent, nl_rule_t *rl) 519{ 520 prop_dictionary_t rldict = rl->nrl_dict; 521 prop_array_t rlset; 522 523 if (parent) { 524 prop_dictionary_t pdict = parent->nrl_dict; 525 rlset = prop_dictionary_get(pdict, "subrules"); 526 if (rlset == NULL) { 527 rlset = prop_array_create(); 528 prop_dictionary_set(pdict, "subrules", rlset); 529 prop_object_release(rlset); 530 } 531 } else { 532 rlset = ncf->ncf_rules_list; 533 } 534 prop_array_add(rlset, rldict); 535 return 0; 536} 537 538static int 539_npf_rule_foreach1(prop_array_t rules, nl_rule_callback_t func) 540{ 541 prop_dictionary_t rldict; 542 prop_object_iterator_t it; 543 unsigned reduce[16], n; 544 unsigned nlevel; 545 546 if (!rules || prop_object_type(rules) != PROP_TYPE_ARRAY) { 547 return ENOENT; 548 } 549 it = prop_array_iterator(rules); 550 if (it == NULL) { 551 return ENOMEM; 552 } 553 554 nlevel = 0; 555 reduce[nlevel] = 0; 556 n = 0; 557 558 while ((rldict = prop_object_iterator_next(it)) != NULL) { 559 nl_rule_t nrl = { .nrl_dict = rldict }; 560 uint32_t skipto = 0; 561 562 prop_dictionary_get_uint32(rldict, "skip-to", &skipto); 563 (*func)(&nrl, nlevel); 564 if (skipto) { 565 nlevel++; 566 reduce[nlevel] = skipto; 567 } 568 if (reduce[nlevel] == ++n) { 569 assert(nlevel > 0); 570 nlevel--; 571 } 572 } 573 prop_object_iterator_release(it); 574 return 0; 575} 576 577int 578_npf_rule_foreach(nl_config_t *ncf, nl_rule_callback_t func) 579{ 580 return _npf_rule_foreach1(ncf->ncf_rules_list, func); 581} 582 583int 584_npf_ruleset_list(int fd, const char *rname, nl_config_t *ncf) 585{ 586 prop_dictionary_t rldict, ret; 587 int error; 588 589 rldict = prop_dictionary_create(); 590 if (rldict == NULL) { 591 return ENOMEM; 592 } 593 prop_dictionary_set_cstring(rldict, "ruleset-name", rname); 594 prop_dictionary_set_uint32(rldict, "command", NPF_CMD_RULE_LIST); 595 error = prop_dictionary_sendrecv_ioctl(rldict, fd, IOC_NPF_RULE, &ret); 596 if (!error) { 597 prop_array_t rules; 598 599 rules = prop_dictionary_get(ret, "rules"); 600 if (rules == NULL) { 601 return EINVAL; 602 } 603 prop_object_release(ncf->ncf_rules_list); 604 ncf->ncf_rules_list = rules; 605 } 606 return error; 607} 608 609pri_t 610_npf_rule_getinfo(nl_rule_t *nrl, const char **rname, uint32_t *attr, 611 u_int *if_idx) 612{ 613 prop_dictionary_t rldict = nrl->nrl_dict; 614 pri_t prio; 615 616 prop_dictionary_get_cstring_nocopy(rldict, "name", rname); 617 prop_dictionary_get_uint32(rldict, "attributes", attr); 618 prop_dictionary_get_int32(rldict, "priority", &prio); 619 prop_dictionary_get_uint32(rldict, "interface", if_idx); 620 return prio; 621} 622 623const void * 624_npf_rule_ncode(nl_rule_t *nrl, size_t *size) 625{ 626 prop_dictionary_t rldict = nrl->nrl_dict; 627 prop_object_t obj = prop_dictionary_get(rldict, "code"); 628 *size = prop_data_size(obj); 629 return prop_data_data_nocopy(obj); 630} 631 632const char * 633_npf_rule_rproc(nl_rule_t *nrl) 634{ 635 prop_dictionary_t rldict = nrl->nrl_dict; 636 const char *rpname = NULL; 637 638 prop_dictionary_get_cstring_nocopy(rldict, "rproc", &rpname); 639 return rpname; 640} 641 642void 643npf_rule_destroy(nl_rule_t *rl) 644{ 645 646 prop_object_release(rl->nrl_dict); 647 free(rl); 648} 649 650/* 651 * RULE PROCEDURE INTERFACE. 652 */ 653 654nl_rproc_t * 655npf_rproc_create(const char *name) 656{ 657 prop_dictionary_t rpdict; 658 prop_array_t extcalls; 659 nl_rproc_t *nrp; 660 661 nrp = malloc(sizeof(nl_rproc_t)); 662 if (nrp == NULL) { 663 return NULL; 664 } 665 rpdict = prop_dictionary_create(); 666 if (rpdict == NULL) { 667 free(nrp); 668 return NULL; 669 } 670 prop_dictionary_set_cstring(rpdict, "name", name); 671 672 extcalls = prop_array_create(); 673 if (extcalls == NULL) { 674 prop_object_release(rpdict); 675 free(nrp); 676 return NULL; 677 } 678 prop_dictionary_set(rpdict, "extcalls", extcalls); 679 prop_object_release(extcalls); 680 681 nrp->nrp_dict = rpdict; 682 return nrp; 683} 684 685int 686npf_rproc_extcall(nl_rproc_t *rp, nl_ext_t *ext) 687{ 688 prop_dictionary_t rpdict = rp->nrp_dict; 689 prop_dictionary_t extdict = ext->nxt_dict; 690 prop_array_t extcalls; 691 692 extcalls = prop_dictionary_get(rpdict, "extcalls"); 693 if (_npf_prop_array_lookup(extcalls, "name", ext->nxt_name)) { 694 return EEXIST; 695 } 696 prop_dictionary_set_cstring(extdict, "name", ext->nxt_name); 697 prop_array_add(extcalls, extdict); 698 return 0; 699} 700 701bool 702npf_rproc_exists_p(nl_config_t *ncf, const char *name) 703{ 704 705 return _npf_prop_array_lookup(ncf->ncf_rproc_list, "name", name); 706} 707 708int 709npf_rproc_insert(nl_config_t *ncf, nl_rproc_t *rp) 710{ 711 prop_dictionary_t rpdict = rp->nrp_dict; 712 const char *name; 713 714 if (!prop_dictionary_get_cstring_nocopy(rpdict, "name", &name)) { 715 return EINVAL; 716 } 717 if (npf_rproc_exists_p(ncf, name)) { 718 return EEXIST; 719 } 720 prop_array_add(ncf->ncf_rproc_list, rpdict); 721 return 0; 722} 723 724/* 725 * TRANSLATION INTERFACE. 726 */ 727 728nl_nat_t * 729npf_nat_create(int type, u_int flags, u_int if_idx, 730 npf_addr_t *addr, int af, in_port_t port) 731{ 732 nl_rule_t *rl; 733 prop_dictionary_t rldict; 734 prop_data_t addrdat; 735 uint32_t attr; 736 size_t sz; 737 738 if (af == AF_INET) { 739 sz = sizeof(struct in_addr); 740 } else if (af == AF_INET6) { 741 sz = sizeof(struct in6_addr); 742 } else { 743 return NULL; 744 } 745 746 attr = NPF_RULE_PASS | NPF_RULE_FINAL | 747 (type == NPF_NATOUT ? NPF_RULE_OUT : NPF_RULE_IN); 748 749 /* Create a rule for NAT policy. Next, will add translation data. */ 750 rl = npf_rule_create(NULL, attr, if_idx); 751 if (rl == NULL) { 752 return NULL; 753 } 754 rldict = rl->nrl_dict; 755 756 /* Translation type and flags. */ 757 prop_dictionary_set_int32(rldict, "type", type); 758 prop_dictionary_set_uint32(rldict, "flags", flags); 759 760 /* Translation IP. */ 761 addrdat = prop_data_create_data(addr, sz); 762 if (addrdat == NULL) { 763 npf_rule_destroy(rl); 764 return NULL; 765 } 766 prop_dictionary_set(rldict, "translation-ip", addrdat); 767 prop_object_release(addrdat); 768 769 /* Translation port (for redirect case). */ 770 prop_dictionary_set_uint16(rldict, "translation-port", port); 771 772 return (nl_nat_t *)rl; 773} 774 775int 776npf_nat_insert(nl_config_t *ncf, nl_nat_t *nt, pri_t pri) 777{ 778 prop_dictionary_t rldict = nt->nrl_dict; 779 780 prop_dictionary_set_int32(rldict, "priority", NPF_PRI_LAST); 781 prop_array_add(ncf->ncf_nat_list, rldict); 782 return 0; 783} 784 785int 786_npf_nat_foreach(nl_config_t *ncf, nl_rule_callback_t func) 787{ 788 return _npf_rule_foreach1(ncf->ncf_nat_list, func); 789} 790 791void 792_npf_nat_getinfo(nl_nat_t *nt, int *type, u_int *flags, npf_addr_t *addr, 793 size_t *alen, in_port_t *port) 794{ 795 prop_dictionary_t rldict = nt->nrl_dict; 796 797 prop_dictionary_get_int32(rldict, "type", type); 798 prop_dictionary_get_uint32(rldict, "flags", flags); 799 800 prop_object_t obj = prop_dictionary_get(rldict, "translation-ip"); 801 *alen = prop_data_size(obj); 802 memcpy(addr, prop_data_data_nocopy(obj), *alen); 803 804 prop_dictionary_get_uint16(rldict, "translation-port", port); 805} 806 807/* 808 * TABLE INTERFACE. 809 */ 810 811nl_table_t * 812npf_table_create(u_int id, int type) 813{ 814 prop_dictionary_t tldict; 815 prop_array_t tblents; 816 nl_table_t *tl; 817 818 tl = malloc(sizeof(*tl)); 819 if (tl == NULL) { 820 return NULL; 821 } 822 tldict = prop_dictionary_create(); 823 if (tldict == NULL) { 824 free(tl); 825 return NULL; 826 } 827 prop_dictionary_set_uint32(tldict, "id", id); 828 prop_dictionary_set_int32(tldict, "type", type); 829 830 tblents = prop_array_create(); 831 if (tblents == NULL) { 832 prop_object_release(tldict); 833 free(tl); 834 return NULL; 835 } 836 prop_dictionary_set(tldict, "entries", tblents); 837 prop_object_release(tblents); 838 839 tl->ntl_dict = tldict; 840 return tl; 841} 842 843int 844npf_table_add_entry(nl_table_t *tl, int af, const npf_addr_t *addr, 845 const npf_netmask_t mask) 846{ 847 prop_dictionary_t tldict = tl->ntl_dict, entdict; 848 prop_array_t tblents; 849 prop_data_t addrdata; 850 unsigned alen; 851 852 /* Create the table entry. */ 853 entdict = prop_dictionary_create(); 854 if (entdict == NULL) { 855 return ENOMEM; 856 } 857 858 switch (af) { 859 case AF_INET: 860 alen = sizeof(struct in_addr); 861 break; 862 case AF_INET6: 863 alen = sizeof(struct in6_addr); 864 break; 865 default: 866 return EINVAL; 867 } 868 869 addrdata = prop_data_create_data(addr, alen); 870 prop_dictionary_set(entdict, "addr", addrdata); 871 prop_dictionary_set_uint8(entdict, "mask", mask); 872 prop_object_release(addrdata); 873 874 tblents = prop_dictionary_get(tldict, "entries"); 875 prop_array_add(tblents, entdict); 876 prop_object_release(entdict); 877 return 0; 878} 879 880bool 881npf_table_exists_p(nl_config_t *ncf, u_int tid) 882{ 883 prop_dictionary_t tldict; 884 prop_object_iterator_t it; 885 886 it = prop_array_iterator(ncf->ncf_table_list); 887 while ((tldict = prop_object_iterator_next(it)) != NULL) { 888 u_int i; 889 if (prop_dictionary_get_uint32(tldict, "id", &i) && tid == i) 890 break; 891 } 892 prop_object_iterator_release(it); 893 return tldict ? true : false; 894} 895 896int 897npf_table_insert(nl_config_t *ncf, nl_table_t *tl) 898{ 899 prop_dictionary_t tldict = tl->ntl_dict; 900 u_int tid; 901 902 if (!prop_dictionary_get_uint32(tldict, "id", &tid)) { 903 return EINVAL; 904 } 905 if (npf_table_exists_p(ncf, tid)) { 906 return EEXIST; 907 } 908 prop_array_add(ncf->ncf_table_list, tldict); 909 return 0; 910} 911 912void 913npf_table_destroy(nl_table_t *tl) 914{ 915 916 prop_object_release(tl->ntl_dict); 917 free(tl); 918} 919 920void 921_npf_table_foreach(nl_config_t *ncf, nl_table_callback_t func) 922{ 923 prop_dictionary_t tldict; 924 prop_object_iterator_t it; 925 926 it = prop_array_iterator(ncf->ncf_table_list); 927 while ((tldict = prop_object_iterator_next(it)) != NULL) { 928 u_int id; 929 int type; 930 931 prop_dictionary_get_uint32(tldict, "id", &id); 932 prop_dictionary_get_int32(tldict, "type", &type); 933 (*func)(id, type); 934 } 935 prop_object_iterator_release(it); 936} 937 938/* 939 * MISC. 940 */ 941 942int 943npf_sessions_recv(int fd, const char *fpath) 944{ 945 prop_dictionary_t sdict; 946 int error; 947 948 error = prop_dictionary_recv_ioctl(fd, IOC_NPF_SESSIONS_SAVE, &sdict); 949 if (error) { 950 return error; 951 } 952 if (!prop_dictionary_externalize_to_file(sdict, fpath)) { 953 error = errno; 954 } 955 prop_object_release(sdict); 956 return error; 957} 958 959int 960npf_sessions_send(int fd, const char *fpath) 961{ 962 prop_dictionary_t sdict; 963 int error; 964 965 if (fpath) { 966 sdict = prop_dictionary_internalize_from_file(fpath); 967 if (sdict == NULL) { 968 return errno; 969 } 970 } else { 971 /* Empty: will flush the sessions. */ 972 prop_array_t selist = prop_array_create(); 973 sdict = prop_dictionary_create(); 974 prop_dictionary_set(sdict, "session-list", selist); 975 prop_object_release(selist); 976 } 977 error = prop_dictionary_send_ioctl(sdict, fd, IOC_NPF_SESSIONS_LOAD); 978 prop_object_release(sdict); 979 return error; 980} 981 982static prop_dictionary_t 983_npf_debug_initonce(nl_config_t *ncf) 984{ 985 if (!ncf->ncf_debug) { 986 prop_array_t iflist = prop_array_create(); 987 ncf->ncf_debug = prop_dictionary_create(); 988 prop_dictionary_set(ncf->ncf_debug, "interfaces", iflist); 989 prop_object_release(iflist); 990 } 991 return ncf->ncf_debug; 992} 993 994void 995_npf_debug_addif(nl_config_t *ncf, struct ifaddrs *ifa, u_int if_idx) 996{ 997 prop_dictionary_t ifdict, dbg = _npf_debug_initonce(ncf); 998 prop_array_t iflist = prop_dictionary_get(dbg, "interfaces"); 999 1000 if (_npf_prop_array_lookup(iflist, "name", ifa->ifa_name)) { 1001 return; 1002 } 1003 1004 ifdict = prop_dictionary_create(); 1005 prop_dictionary_set_cstring(ifdict, "name", ifa->ifa_name); 1006 prop_dictionary_set_uint32(ifdict, "flags", ifa->ifa_flags); 1007 if (!if_idx) { 1008 if_idx = if_nametoindex(ifa->ifa_name); 1009 } 1010 prop_dictionary_set_uint32(ifdict, "idx", if_idx); 1011 1012 const struct sockaddr *sa = ifa->ifa_addr; 1013 npf_addr_t addr; 1014 size_t alen = 0; 1015 1016 switch (sa ? sa->sa_family : -1) { 1017 case AF_INET: { 1018 const struct sockaddr_in *sin = (const void *)sa; 1019 alen = sizeof(sin->sin_addr); 1020 memcpy(&addr, &sin->sin_addr, alen); 1021 break; 1022 } 1023 case AF_INET6: { 1024 const struct sockaddr_in6 *sin6 = (const void *)sa; 1025 alen = sizeof(sin6->sin6_addr); 1026 memcpy(&addr, &sin6->sin6_addr, alen); 1027 break; 1028 } 1029 default: 1030 break; 1031 } 1032 1033 if (alen) { 1034 prop_data_t addrdata = prop_data_create_data(&addr, alen); 1035 prop_dictionary_set(ifdict, "addr", addrdata); 1036 prop_object_release(addrdata); 1037 } 1038 prop_array_add(iflist, ifdict); 1039 prop_object_release(ifdict); 1040} 1041