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