1 /* $NetBSD: npf_ctl.c,v 1.33 2014/02/06 02:51:28 rmind Exp $ */ 2 3 /*- 4 * Copyright (c) 2009-2014 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 /* 33 * NPF device control. 34 * 35 * Implementation of (re)loading, construction of tables and rules. 36 * NPF proplib(9) dictionary consumer. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: npf_ctl.c,v 1.33 2014/02/06 02:51:28 rmind Exp $"); 41 42 #include <sys/param.h> 43 #include <sys/conf.h> 44 #include <sys/kmem.h> 45 #include <net/bpf.h> 46 47 #include <prop/proplib.h> 48 49 #include "npf_impl.h" 50 51 #if defined(DEBUG) || defined(DIAGNOSTIC) 52 #define NPF_ERR_DEBUG(e) \ 53 prop_dictionary_set_cstring_nocopy((e), "source-file", __FILE__); \ 54 prop_dictionary_set_uint32((e), "source-line", __LINE__); 55 #else 56 #define NPF_ERR_DEBUG(e) 57 #endif 58 59 /* 60 * npfctl_switch: enable or disable packet inspection. 61 */ 62 int 63 npfctl_switch(void *data) 64 { 65 const bool onoff = *(int *)data ? true : false; 66 int error; 67 68 if (onoff) { 69 /* Enable: add pfil hooks. */ 70 error = npf_pfil_register(false); 71 } else { 72 /* Disable: remove pfil hooks. */ 73 npf_pfil_unregister(false); 74 error = 0; 75 } 76 return error; 77 } 78 79 static int __noinline 80 npf_mk_table_entries(npf_table_t *t, prop_array_t entries) 81 { 82 prop_object_iterator_t eit; 83 prop_dictionary_t ent; 84 int error = 0; 85 86 /* Fill all the entries. */ 87 eit = prop_array_iterator(entries); 88 while ((ent = prop_object_iterator_next(eit)) != NULL) { 89 const npf_addr_t *addr; 90 npf_netmask_t mask; 91 int alen; 92 93 /* Get address and mask. Add a table entry. */ 94 prop_object_t obj = prop_dictionary_get(ent, "addr"); 95 addr = (const npf_addr_t *)prop_data_data_nocopy(obj); 96 prop_dictionary_get_uint8(ent, "mask", &mask); 97 alen = prop_data_size(obj); 98 99 error = npf_table_insert(t, alen, addr, mask); 100 if (error) 101 break; 102 } 103 prop_object_iterator_release(eit); 104 return error; 105 } 106 107 static int __noinline 108 npf_mk_tables(npf_tableset_t *tblset, prop_array_t tables, 109 prop_dictionary_t errdict) 110 { 111 prop_object_iterator_t it; 112 prop_dictionary_t tbldict; 113 int error = 0; 114 115 /* Tables - array. */ 116 if (prop_object_type(tables) != PROP_TYPE_ARRAY) { 117 NPF_ERR_DEBUG(errdict); 118 return EINVAL; 119 } 120 121 it = prop_array_iterator(tables); 122 while ((tbldict = prop_object_iterator_next(it)) != NULL) { 123 const char *name; 124 npf_table_t *t; 125 u_int tid; 126 int type; 127 128 /* Table - dictionary. */ 129 if (prop_object_type(tbldict) != PROP_TYPE_DICTIONARY) { 130 NPF_ERR_DEBUG(errdict); 131 error = EINVAL; 132 break; 133 } 134 135 /* Table name, ID and type. Validate them. */ 136 if (!prop_dictionary_get_cstring_nocopy(tbldict, "name", &name)) { 137 NPF_ERR_DEBUG(errdict); 138 error = EINVAL; 139 break; 140 } 141 prop_dictionary_get_uint32(tbldict, "id", &tid); 142 prop_dictionary_get_int32(tbldict, "type", &type); 143 error = npf_table_check(tblset, name, tid, type); 144 if (error) { 145 NPF_ERR_DEBUG(errdict); 146 break; 147 } 148 149 /* Get the entries or binary data. */ 150 prop_array_t entries = prop_dictionary_get(tbldict, "entries"); 151 if (prop_object_type(entries) != PROP_TYPE_ARRAY) { 152 NPF_ERR_DEBUG(errdict); 153 error = EINVAL; 154 break; 155 } 156 prop_object_t obj = prop_dictionary_get(tbldict, "data"); 157 void *blob = prop_data_data(obj); 158 size_t size = prop_data_size(obj); 159 160 if (type == NPF_TABLE_CDB && (blob == NULL || size == 0)) { 161 NPF_ERR_DEBUG(errdict); 162 error = EINVAL; 163 break; 164 } 165 166 /* Create and insert the table. */ 167 t = npf_table_create(name, tid, type, blob, size); 168 if (t == NULL) { 169 NPF_ERR_DEBUG(errdict); 170 error = ENOMEM; 171 break; 172 } 173 error = npf_tableset_insert(tblset, t); 174 KASSERT(error == 0); 175 176 if ((error = npf_mk_table_entries(t, entries)) != 0) { 177 NPF_ERR_DEBUG(errdict); 178 break; 179 } 180 } 181 prop_object_iterator_release(it); 182 /* 183 * Note: in a case of error, caller will free the tableset. 184 */ 185 return error; 186 } 187 188 static npf_rproc_t * 189 npf_mk_singlerproc(prop_dictionary_t rpdict) 190 { 191 prop_object_iterator_t it; 192 prop_dictionary_t extdict; 193 prop_array_t extlist; 194 npf_rproc_t *rp; 195 196 extlist = prop_dictionary_get(rpdict, "extcalls"); 197 if (prop_object_type(extlist) != PROP_TYPE_ARRAY) { 198 return NULL; 199 } 200 201 rp = npf_rproc_create(rpdict); 202 if (rp == NULL) { 203 return NULL; 204 } 205 206 it = prop_array_iterator(extlist); 207 while ((extdict = prop_object_iterator_next(it)) != NULL) { 208 const char *name; 209 210 if (!prop_dictionary_get_cstring_nocopy(extdict, 211 "name", &name) || npf_ext_construct(name, rp, extdict)) { 212 npf_rproc_release(rp); 213 rp = NULL; 214 break; 215 } 216 } 217 prop_object_iterator_release(it); 218 return rp; 219 } 220 221 static int __noinline 222 npf_mk_rprocs(npf_rprocset_t *rpset, prop_array_t rprocs, 223 prop_dictionary_t errdict) 224 { 225 prop_object_iterator_t it; 226 prop_dictionary_t rpdict; 227 int error = 0; 228 229 it = prop_array_iterator(rprocs); 230 while ((rpdict = prop_object_iterator_next(it)) != NULL) { 231 npf_rproc_t *rp; 232 233 if ((rp = npf_mk_singlerproc(rpdict)) == NULL) { 234 NPF_ERR_DEBUG(errdict); 235 error = EINVAL; 236 break; 237 } 238 npf_rprocset_insert(rpset, rp); 239 } 240 prop_object_iterator_release(it); 241 return error; 242 } 243 244 static npf_alg_t * 245 npf_mk_singlealg(prop_dictionary_t aldict) 246 { 247 const char *name; 248 249 if (!prop_dictionary_get_cstring_nocopy(aldict, "name", &name)) 250 return NULL; 251 return npf_alg_construct(name); 252 } 253 254 static int __noinline 255 npf_mk_algs(prop_array_t alglist, prop_dictionary_t errdict) 256 { 257 prop_object_iterator_t it; 258 prop_dictionary_t nadict; 259 int error = 0; 260 261 it = prop_array_iterator(alglist); 262 while ((nadict = prop_object_iterator_next(it)) != NULL) { 263 if (npf_mk_singlealg(nadict) == NULL) { 264 NPF_ERR_DEBUG(errdict); 265 error = EINVAL; 266 break; 267 } 268 } 269 prop_object_iterator_release(it); 270 return error; 271 } 272 273 static int __noinline 274 npf_mk_code(prop_object_t obj, int type, void **code, size_t *csize, 275 prop_dictionary_t errdict) 276 { 277 const void *cptr; 278 size_t clen; 279 void *bc; 280 281 if (type != NPF_CODE_BPF) { 282 return ENOTSUP; 283 } 284 cptr = prop_data_data_nocopy(obj); 285 if (cptr == NULL || (clen = prop_data_size(obj)) == 0) { 286 NPF_ERR_DEBUG(errdict); 287 return EINVAL; 288 } 289 if (!npf_bpf_validate(cptr, clen)) { 290 NPF_ERR_DEBUG(errdict); 291 return EINVAL; 292 } 293 bc = kmem_alloc(clen, KM_SLEEP); 294 memcpy(bc, cptr, clen); 295 296 *code = bc; 297 *csize = clen; 298 return 0; 299 } 300 301 static int __noinline 302 npf_mk_singlerule(prop_dictionary_t rldict, npf_rprocset_t *rpset, 303 npf_rule_t **rlret, prop_dictionary_t errdict) 304 { 305 npf_rule_t *rl; 306 const char *rname; 307 prop_object_t obj; 308 int p, error = 0; 309 310 /* Rule - dictionary. */ 311 if (prop_object_type(rldict) != PROP_TYPE_DICTIONARY) { 312 NPF_ERR_DEBUG(errdict); 313 return EINVAL; 314 } 315 if ((rl = npf_rule_alloc(rldict)) == NULL) { 316 NPF_ERR_DEBUG(errdict); 317 return EINVAL; 318 } 319 320 /* Assign rule procedure, if any. */ 321 if (prop_dictionary_get_cstring_nocopy(rldict, "rproc", &rname)) { 322 npf_rproc_t *rp; 323 324 if (rpset == NULL) { 325 error = EINVAL; 326 goto err; 327 } 328 if ((rp = npf_rprocset_lookup(rpset, rname)) == NULL) { 329 NPF_ERR_DEBUG(errdict); 330 error = EINVAL; 331 goto err; 332 } 333 npf_rule_setrproc(rl, rp); 334 } 335 336 /* Filter code (binary data). */ 337 if ((obj = prop_dictionary_get(rldict, "code")) != NULL) { 338 int type; 339 size_t len; 340 void *code; 341 342 prop_dictionary_get_int32(rldict, "code-type", &type); 343 error = npf_mk_code(obj, type, &code, &len, errdict); 344 if (error) { 345 goto err; 346 } 347 npf_rule_setcode(rl, type, code, len); 348 } 349 350 *rlret = rl; 351 return 0; 352 err: 353 npf_rule_free(rl); 354 prop_dictionary_get_int32(rldict, "priority", &p); /* XXX */ 355 prop_dictionary_set_int32(errdict, "id", p); 356 return error; 357 } 358 359 static int __noinline 360 npf_mk_rules(npf_ruleset_t *rlset, prop_array_t rules, npf_rprocset_t *rpset, 361 prop_dictionary_t errdict) 362 { 363 prop_object_iterator_t it; 364 prop_dictionary_t rldict; 365 int error; 366 367 if (prop_object_type(rules) != PROP_TYPE_ARRAY) { 368 NPF_ERR_DEBUG(errdict); 369 return EINVAL; 370 } 371 372 error = 0; 373 it = prop_array_iterator(rules); 374 while ((rldict = prop_object_iterator_next(it)) != NULL) { 375 npf_rule_t *rl = NULL; 376 377 /* Generate a single rule. */ 378 error = npf_mk_singlerule(rldict, rpset, &rl, errdict); 379 if (error) { 380 break; 381 } 382 npf_ruleset_insert(rlset, rl); 383 } 384 prop_object_iterator_release(it); 385 /* 386 * Note: in a case of error, caller will free the ruleset. 387 */ 388 return error; 389 } 390 391 static int __noinline 392 npf_mk_natlist(npf_ruleset_t *nset, prop_array_t natlist, 393 prop_dictionary_t errdict) 394 { 395 prop_object_iterator_t it; 396 prop_dictionary_t natdict; 397 int error; 398 399 /* NAT policies - array. */ 400 if (prop_object_type(natlist) != PROP_TYPE_ARRAY) { 401 NPF_ERR_DEBUG(errdict); 402 return EINVAL; 403 } 404 405 error = 0; 406 it = prop_array_iterator(natlist); 407 while ((natdict = prop_object_iterator_next(it)) != NULL) { 408 npf_rule_t *rl = NULL; 409 npf_natpolicy_t *np; 410 411 /* NAT policy - dictionary. */ 412 if (prop_object_type(natdict) != PROP_TYPE_DICTIONARY) { 413 NPF_ERR_DEBUG(errdict); 414 error = EINVAL; 415 break; 416 } 417 418 /* 419 * NAT policies are standard rules, plus additional 420 * information for translation. Make a rule. 421 */ 422 error = npf_mk_singlerule(natdict, NULL, &rl, errdict); 423 if (error) { 424 break; 425 } 426 npf_ruleset_insert(nset, rl); 427 428 /* If rule is named, it is a group with NAT policies. */ 429 if (prop_dictionary_get(natdict, "name") && 430 prop_dictionary_get(natdict, "subrules")) { 431 continue; 432 } 433 434 /* Allocate a new NAT policy and assign to the rule. */ 435 np = npf_nat_newpolicy(natdict, nset); 436 if (np == NULL) { 437 NPF_ERR_DEBUG(errdict); 438 error = ENOMEM; 439 break; 440 } 441 npf_rule_setnat(rl, np); 442 } 443 prop_object_iterator_release(it); 444 /* 445 * Note: in a case of error, caller will free entire NAT ruleset 446 * with assigned NAT policies. 447 */ 448 return error; 449 } 450 451 /* 452 * npfctl_reload: store passed data i.e. update settings, create passed 453 * tables, rules and atomically activate all them. 454 */ 455 int 456 npfctl_reload(u_long cmd, void *data) 457 { 458 struct plistref *pref = data; 459 prop_dictionary_t npf_dict, errdict; 460 prop_array_t alglist, natlist, tables, rprocs, rules; 461 npf_tableset_t *tblset = NULL; 462 npf_rprocset_t *rpset = NULL; 463 npf_ruleset_t *rlset = NULL; 464 npf_ruleset_t *nset = NULL; 465 uint32_t ver = 0; 466 size_t nitems; 467 bool flush; 468 int error; 469 470 /* Retrieve the dictionary. */ 471 #ifndef _NPF_TESTING 472 error = prop_dictionary_copyin_ioctl(pref, cmd, &npf_dict); 473 if (error) 474 return error; 475 #else 476 npf_dict = (prop_dictionary_t)pref; 477 #endif 478 479 /* Dictionary for error reporting and version check. */ 480 errdict = prop_dictionary_create(); 481 prop_dictionary_get_uint32(npf_dict, "version", &ver); 482 if (ver != NPF_VERSION) { 483 error = EPROGMISMATCH; 484 goto fail; 485 } 486 487 /* ALGs. */ 488 alglist = prop_dictionary_get(npf_dict, "algs"); 489 error = npf_mk_algs(alglist, errdict); 490 if (error) { 491 goto fail; 492 } 493 494 /* NAT policies. */ 495 natlist = prop_dictionary_get(npf_dict, "translation"); 496 if ((nitems = prop_array_count(natlist)) > NPF_MAX_RULES) { 497 goto fail; 498 } 499 500 nset = npf_ruleset_create(nitems); 501 error = npf_mk_natlist(nset, natlist, errdict); 502 if (error) { 503 goto fail; 504 } 505 506 /* Tables. */ 507 tables = prop_dictionary_get(npf_dict, "tables"); 508 if ((nitems = prop_array_count(tables)) > NPF_MAX_TABLES) { 509 goto fail; 510 } 511 tblset = npf_tableset_create(nitems); 512 error = npf_mk_tables(tblset, tables, errdict); 513 if (error) { 514 goto fail; 515 } 516 517 /* Rule procedures. */ 518 rprocs = prop_dictionary_get(npf_dict, "rprocs"); 519 if ((nitems = prop_array_count(rprocs)) > NPF_MAX_RPROCS) { 520 goto fail; 521 } 522 rpset = npf_rprocset_create(); 523 error = npf_mk_rprocs(rpset, rprocs, errdict); 524 if (error) { 525 goto fail; 526 } 527 528 /* Rules. */ 529 rules = prop_dictionary_get(npf_dict, "rules"); 530 if ((nitems = prop_array_count(rules)) > NPF_MAX_RULES) { 531 goto fail; 532 } 533 534 rlset = npf_ruleset_create(nitems); 535 error = npf_mk_rules(rlset, rules, rpset, errdict); 536 if (error) { 537 goto fail; 538 } 539 540 flush = false; 541 prop_dictionary_get_bool(npf_dict, "flush", &flush); 542 543 /* 544 * Finally - perform the reload. 545 */ 546 npf_config_reload(npf_dict, rlset, tblset, nset, rpset, flush); 547 548 /* Turn on/off session tracking accordingly. */ 549 npf_session_tracking(!flush); 550 551 /* Done. Since data is consumed now, we shall not destroy it. */ 552 tblset = NULL; 553 rpset = NULL; 554 rlset = NULL; 555 nset = NULL; 556 fail: 557 /* 558 * Note: destroy rulesets first, to drop references to the tableset. 559 */ 560 KASSERT(error == 0 || (nset || rpset || rlset || tblset)); 561 if (nset) { 562 npf_ruleset_destroy(nset); 563 } 564 if (rlset) { 565 npf_ruleset_destroy(rlset); 566 } 567 if (rpset) { 568 npf_rprocset_destroy(rpset); 569 } 570 if (tblset) { 571 npf_tableset_destroy(tblset); 572 } 573 if (error) { 574 prop_object_release(npf_dict); 575 } 576 577 /* Error report. */ 578 #ifndef _NPF_TESTING 579 prop_dictionary_set_int32(errdict, "errno", error); 580 prop_dictionary_copyout_ioctl(pref, cmd, errdict); 581 prop_object_release(errdict); 582 error = 0; 583 #endif 584 return error; 585 } 586 587 /* 588 * npfctl_rule: add or remove dynamic rules in the specified ruleset. 589 */ 590 int 591 npfctl_rule(u_long cmd, void *data) 592 { 593 struct plistref *pref = data; 594 prop_dictionary_t npf_rule, retdict = NULL; 595 npf_ruleset_t *rlset; 596 npf_rule_t *rl = NULL; 597 const char *ruleset_name; 598 uint32_t rcmd = 0; 599 int error; 600 601 error = prop_dictionary_copyin_ioctl(pref, cmd, &npf_rule); 602 if (error) { 603 return error; 604 } 605 prop_dictionary_get_uint32(npf_rule, "command", &rcmd); 606 if (!prop_dictionary_get_cstring_nocopy(npf_rule, 607 "ruleset-name", &ruleset_name)) { 608 error = EINVAL; 609 goto out; 610 } 611 612 if (rcmd == NPF_CMD_RULE_ADD) { 613 retdict = prop_dictionary_create(); 614 if (npf_mk_singlerule(npf_rule, NULL, &rl, retdict) != 0) { 615 error = EINVAL; 616 goto out; 617 } 618 } 619 620 npf_config_enter(); 621 rlset = npf_config_ruleset(); 622 623 switch (rcmd) { 624 case NPF_CMD_RULE_ADD: { 625 if ((error = npf_ruleset_add(rlset, ruleset_name, rl)) == 0) { 626 /* Success. */ 627 uint64_t id = npf_rule_getid(rl); 628 prop_dictionary_set_uint64(retdict, "id", id); 629 rl = NULL; 630 } 631 break; 632 } 633 case NPF_CMD_RULE_REMOVE: { 634 uint64_t id; 635 636 if (!prop_dictionary_get_uint64(npf_rule, "id", &id)) { 637 error = EINVAL; 638 break; 639 } 640 error = npf_ruleset_remove(rlset, ruleset_name, id); 641 break; 642 } 643 case NPF_CMD_RULE_REMKEY: { 644 prop_object_t obj = prop_dictionary_get(npf_rule, "key"); 645 const void *key = prop_data_data_nocopy(obj); 646 size_t len = prop_data_size(obj); 647 648 if (len == 0 || len > NPF_RULE_MAXKEYLEN) { 649 error = EINVAL; 650 break; 651 } 652 error = npf_ruleset_remkey(rlset, ruleset_name, key, len); 653 break; 654 } 655 case NPF_CMD_RULE_LIST: { 656 retdict = npf_ruleset_list(rlset, ruleset_name); 657 break; 658 } 659 case NPF_CMD_RULE_FLUSH: { 660 error = npf_ruleset_flush(rlset, ruleset_name); 661 break; 662 } 663 default: 664 error = EINVAL; 665 break; 666 } 667 668 /* Destroy any removed rules. */ 669 if (!error && rcmd != NPF_CMD_RULE_ADD && rcmd != NPF_CMD_RULE_LIST) { 670 npf_config_sync(); 671 npf_ruleset_gc(rlset); 672 } 673 npf_config_exit(); 674 675 if (rl) { 676 npf_rule_free(rl); 677 } 678 out: 679 if (retdict) { 680 prop_object_release(npf_rule); 681 prop_dictionary_copyout_ioctl(pref, cmd, retdict); 682 prop_object_release(retdict); 683 } 684 return error; 685 } 686 687 /* 688 * npfctl_getconf: return the config dictionary as it was submitted. 689 * Additionally, indicate whether the ruleset is currently active. 690 */ 691 int 692 npfctl_getconf(u_long cmd, void *data) 693 { 694 struct plistref *pref = data; 695 prop_dictionary_t npf_dict; 696 int error; 697 698 npf_config_enter(); 699 npf_dict = npf_config_dict(); 700 prop_dictionary_set_bool(npf_dict, "active", npf_pfil_registered_p()); 701 error = prop_dictionary_copyout_ioctl(pref, cmd, npf_dict); 702 npf_config_exit(); 703 704 return error; 705 } 706 707 /* 708 * npfctl_sessions_save: construct a list of sessions and export for saving. 709 */ 710 int 711 npfctl_sessions_save(u_long cmd, void *data) 712 { 713 struct plistref *pref = data; 714 prop_dictionary_t sesdict; 715 prop_array_t selist, nplist; 716 int error; 717 718 /* Create a dictionary and two lists. */ 719 sesdict = prop_dictionary_create(); 720 selist = prop_array_create(); 721 nplist = prop_array_create(); 722 723 /* Save the sessions. */ 724 error = npf_session_save(selist, nplist); 725 if (error) { 726 goto fail; 727 } 728 729 /* Set the session list, NAT policy list and export the dictionary. */ 730 prop_dictionary_set(sesdict, "session-list", selist); 731 prop_dictionary_set(sesdict, "nat-policy-list", nplist); 732 error = prop_dictionary_copyout_ioctl(pref, cmd, sesdict); 733 fail: 734 prop_object_release(sesdict); 735 return error; 736 } 737 738 /* 739 * npfctl_sessions_load: import a list of sessions, reconstruct them and load. 740 */ 741 int 742 npfctl_sessions_load(u_long cmd, void *data) 743 { 744 const struct plistref *pref = data; 745 npf_sehash_t *sehasht = NULL; 746 prop_dictionary_t sesdict, sedict; 747 prop_object_iterator_t it; 748 prop_array_t selist; 749 int error; 750 751 /* Retrieve the dictionary containing session and NAT policy lists. */ 752 error = prop_dictionary_copyin_ioctl(pref, cmd, &sesdict); 753 if (error) 754 return error; 755 756 /* 757 * Note: session objects contain the references to the NAT policy 758 * entries. Therefore, no need to directly access it. 759 */ 760 selist = prop_dictionary_get(sesdict, "session-list"); 761 if (prop_object_type(selist) != PROP_TYPE_ARRAY) { 762 prop_object_release(selist); 763 return EINVAL; 764 } 765 766 /* Create a session hash table. */ 767 sehasht = sess_htable_create(); 768 769 /* 770 * Iterate through and construct each session. Note: acquire the 771 * config lock as we access NAT policies during the restore. 772 */ 773 error = 0; 774 it = prop_array_iterator(selist); 775 776 npf_config_enter(); 777 while ((sedict = prop_object_iterator_next(it)) != NULL) { 778 /* Session - dictionary. */ 779 if (prop_object_type(sedict) != PROP_TYPE_DICTIONARY) { 780 error = EINVAL; 781 break; 782 } 783 /* Construct and insert real session structure. */ 784 error = npf_session_restore(sehasht, sedict); 785 if (error) { 786 break; 787 } 788 } 789 npf_config_exit(); 790 791 prop_object_iterator_release(it); 792 prop_object_release(selist); 793 794 if (!error) { 795 /* Finally, load the new table. */ 796 npf_session_load(sehasht); 797 } else { 798 /* Destroy session table. */ 799 sess_htable_destroy(sehasht); 800 } 801 return error; 802 } 803 804 /* 805 * npfctl_table: add, remove or query entries in the specified table. 806 * 807 * For maximum performance, interface is avoiding proplib(3)'s overhead. 808 */ 809 int 810 npfctl_table(void *data) 811 { 812 const npf_ioctl_table_t *nct = data; 813 char tname[NPF_TABLE_MAXNAMELEN]; 814 npf_tableset_t *ts; 815 npf_table_t *t; 816 int s, error; 817 818 error = copyinstr(nct->nct_name, tname, sizeof(tname), NULL); 819 if (error) { 820 return error; 821 } 822 823 s = npf_config_read_enter(); /* XXX */ 824 ts = npf_config_tableset(); 825 if ((t = npf_tableset_getbyname(ts, tname)) == NULL) { 826 npf_config_read_exit(s); 827 return EINVAL; 828 } 829 830 switch (nct->nct_cmd) { 831 case NPF_CMD_TABLE_LOOKUP: 832 error = npf_table_lookup(t, nct->nct_data.ent.alen, 833 &nct->nct_data.ent.addr); 834 break; 835 case NPF_CMD_TABLE_ADD: 836 error = npf_table_insert(t, nct->nct_data.ent.alen, 837 &nct->nct_data.ent.addr, nct->nct_data.ent.mask); 838 break; 839 case NPF_CMD_TABLE_REMOVE: 840 error = npf_table_remove(t, nct->nct_data.ent.alen, 841 &nct->nct_data.ent.addr, nct->nct_data.ent.mask); 842 break; 843 case NPF_CMD_TABLE_LIST: 844 error = npf_table_list(t, nct->nct_data.buf.buf, 845 nct->nct_data.buf.len); 846 break; 847 case NPF_CMD_TABLE_FLUSH: 848 error = npf_table_flush(t); 849 break; 850 default: 851 error = EINVAL; 852 break; 853 } 854 npf_config_read_exit(s); 855 856 return error; 857 } 858