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