1 /*- 2 * Copyright (c) 2002-2009 Luigi Rizzo, Universita` di Pisa 3 * Copyright (c) 2014 Yandex LLC 4 * Copyright (c) 2014 Alexander V. Chernikov 5 * 6 * Supported by: Valeria Paoli 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 /* 34 * Control socket and rule management routines for ipfw. 35 * Control is currently implemented via IP_FW3 setsockopt() code. 36 */ 37 38 #include "opt_ipfw.h" 39 #include "opt_inet.h" 40 #ifndef INET 41 #error IPFIREWALL requires INET. 42 #endif /* INET */ 43 #include "opt_inet6.h" 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/malloc.h> 48 #include <sys/mbuf.h> /* struct m_tag used by nested headers */ 49 #include <sys/kernel.h> 50 #include <sys/lock.h> 51 #include <sys/priv.h> 52 #include <sys/proc.h> 53 #include <sys/rwlock.h> 54 #include <sys/rmlock.h> 55 #include <sys/socket.h> 56 #include <sys/socketvar.h> 57 #include <sys/sysctl.h> 58 #include <sys/syslog.h> 59 #include <sys/fnv_hash.h> 60 #include <net/if.h> 61 #include <net/route.h> 62 #include <net/vnet.h> 63 #include <vm/vm.h> 64 #include <vm/vm_extern.h> 65 66 #include <netinet/in.h> 67 #include <netinet/ip_var.h> /* hooks */ 68 #include <netinet/ip_fw.h> 69 70 #include <netpfil/ipfw/ip_fw_private.h> 71 #include <netpfil/ipfw/ip_fw_table.h> 72 73 #ifdef MAC 74 #include <security/mac/mac_framework.h> 75 #endif 76 77 static int ipfw_ctl(struct sockopt *sopt); 78 static int check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len, 79 struct rule_check_info *ci); 80 static int check_ipfw_rule1(struct ip_fw_rule *rule, int size, 81 struct rule_check_info *ci); 82 static int check_ipfw_rule0(struct ip_fw_rule0 *rule, int size, 83 struct rule_check_info *ci); 84 85 #define NAMEDOBJ_HASH_SIZE 32 86 87 struct namedobj_instance { 88 struct namedobjects_head *names; 89 struct namedobjects_head *values; 90 uint32_t nn_size; /* names hash size */ 91 uint32_t nv_size; /* number hash size */ 92 u_long *idx_mask; /* used items bitmask */ 93 uint32_t max_blocks; /* number of "long" blocks in bitmask */ 94 uint32_t count; /* number of items */ 95 uint16_t free_off[IPFW_MAX_SETS]; /* first possible free offset */ 96 objhash_hash_f *hash_f; 97 objhash_cmp_f *cmp_f; 98 }; 99 #define BLOCK_ITEMS (8 * sizeof(u_long)) /* Number of items for ffsl() */ 100 101 static uint32_t objhash_hash_name(struct namedobj_instance *ni, void *key, 102 uint32_t kopt); 103 static uint32_t objhash_hash_idx(struct namedobj_instance *ni, uint32_t val); 104 static int objhash_cmp_name(struct named_object *no, void *name, uint32_t set); 105 106 MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's"); 107 108 static int dump_config(struct ip_fw_chain *chain, ip_fw3_opheader *op3, 109 struct sockopt_data *sd); 110 static int add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, 111 struct sockopt_data *sd); 112 static int del_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, 113 struct sockopt_data *sd); 114 static int clear_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, 115 struct sockopt_data *sd); 116 static int move_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, 117 struct sockopt_data *sd); 118 static int manage_sets(struct ip_fw_chain *chain, ip_fw3_opheader *op3, 119 struct sockopt_data *sd); 120 static int dump_soptcodes(struct ip_fw_chain *chain, ip_fw3_opheader *op3, 121 struct sockopt_data *sd); 122 123 /* ctl3 handler data */ 124 struct mtx ctl3_lock; 125 #define CTL3_LOCK_INIT() mtx_init(&ctl3_lock, "ctl3_lock", NULL, MTX_DEF) 126 #define CTL3_LOCK_DESTROY() mtx_destroy(&ctl3_lock) 127 #define CTL3_LOCK() mtx_lock(&ctl3_lock) 128 #define CTL3_UNLOCK() mtx_unlock(&ctl3_lock) 129 130 static struct ipfw_sopt_handler *ctl3_handlers; 131 static size_t ctl3_hsize; 132 static uint64_t ctl3_refct, ctl3_gencnt; 133 #define CTL3_SMALLBUF 4096 /* small page-size write buffer */ 134 #define CTL3_LARGEBUF 16 * 1024 * 1024 /* handle large rulesets */ 135 136 static int ipfw_flush_sopt_data(struct sockopt_data *sd); 137 138 static struct ipfw_sopt_handler scodes[] = { 139 { IP_FW_XGET, 0, HDIR_GET, dump_config }, 140 { IP_FW_XADD, 0, HDIR_BOTH, add_rules }, 141 { IP_FW_XDEL, 0, HDIR_BOTH, del_rules }, 142 { IP_FW_XZERO, 0, HDIR_SET, clear_rules }, 143 { IP_FW_XRESETLOG, 0, HDIR_SET, clear_rules }, 144 { IP_FW_XMOVE, 0, HDIR_SET, move_rules }, 145 { IP_FW_SET_SWAP, 0, HDIR_SET, manage_sets }, 146 { IP_FW_SET_MOVE, 0, HDIR_SET, manage_sets }, 147 { IP_FW_SET_ENABLE, 0, HDIR_SET, manage_sets }, 148 { IP_FW_DUMP_SOPTCODES, 0, HDIR_GET, dump_soptcodes }, 149 }; 150 151 static int 152 set_legacy_obj_kidx(struct ip_fw_chain *ch, struct ip_fw_rule0 *rule); 153 struct opcode_obj_rewrite *ipfw_find_op_rw(uint16_t opcode); 154 static int mark_object_kidx(struct ip_fw_chain *ch, struct ip_fw *rule, 155 uint32_t *bmask); 156 static void unref_rule_objects(struct ip_fw_chain *chain, struct ip_fw *rule); 157 static int export_objhash_ntlv(struct namedobj_instance *ni, uint16_t kidx, 158 struct sockopt_data *sd); 159 160 /* 161 * Opcode object rewriter variables 162 */ 163 struct opcode_obj_rewrite *ctl3_rewriters; 164 static size_t ctl3_rsize; 165 166 /* 167 * static variables followed by global ones 168 */ 169 170 static VNET_DEFINE(uma_zone_t, ipfw_cntr_zone); 171 #define V_ipfw_cntr_zone VNET(ipfw_cntr_zone) 172 173 void 174 ipfw_init_counters() 175 { 176 177 V_ipfw_cntr_zone = uma_zcreate("IPFW counters", 178 IPFW_RULE_CNTR_SIZE, NULL, NULL, NULL, NULL, 179 UMA_ALIGN_PTR, UMA_ZONE_PCPU); 180 } 181 182 void 183 ipfw_destroy_counters() 184 { 185 186 uma_zdestroy(V_ipfw_cntr_zone); 187 } 188 189 struct ip_fw * 190 ipfw_alloc_rule(struct ip_fw_chain *chain, size_t rulesize) 191 { 192 struct ip_fw *rule; 193 194 rule = malloc(rulesize, M_IPFW, M_WAITOK | M_ZERO); 195 rule->cntr = uma_zalloc(V_ipfw_cntr_zone, M_WAITOK | M_ZERO); 196 197 return (rule); 198 } 199 200 static void 201 free_rule(struct ip_fw *rule) 202 { 203 204 uma_zfree(V_ipfw_cntr_zone, rule->cntr); 205 free(rule, M_IPFW); 206 } 207 208 209 /* 210 * Find the smallest rule >= key, id. 211 * We could use bsearch but it is so simple that we code it directly 212 */ 213 int 214 ipfw_find_rule(struct ip_fw_chain *chain, uint32_t key, uint32_t id) 215 { 216 int i, lo, hi; 217 struct ip_fw *r; 218 219 for (lo = 0, hi = chain->n_rules - 1; lo < hi;) { 220 i = (lo + hi) / 2; 221 r = chain->map[i]; 222 if (r->rulenum < key) 223 lo = i + 1; /* continue from the next one */ 224 else if (r->rulenum > key) 225 hi = i; /* this might be good */ 226 else if (r->id < id) 227 lo = i + 1; /* continue from the next one */ 228 else /* r->id >= id */ 229 hi = i; /* this might be good */ 230 }; 231 return hi; 232 } 233 234 /* 235 * Builds skipto cache on rule set @map. 236 */ 237 static void 238 update_skipto_cache(struct ip_fw_chain *chain, struct ip_fw **map) 239 { 240 int *smap, rulenum; 241 int i, mi; 242 243 IPFW_UH_WLOCK_ASSERT(chain); 244 245 mi = 0; 246 rulenum = map[mi]->rulenum; 247 smap = chain->idxmap_back; 248 249 if (smap == NULL) 250 return; 251 252 for (i = 0; i < 65536; i++) { 253 smap[i] = mi; 254 /* Use the same rule index until i < rulenum */ 255 if (i != rulenum || i == 65535) 256 continue; 257 /* Find next rule with num > i */ 258 rulenum = map[++mi]->rulenum; 259 while (rulenum == i) 260 rulenum = map[++mi]->rulenum; 261 } 262 } 263 264 /* 265 * Swaps prepared (backup) index with current one. 266 */ 267 static void 268 swap_skipto_cache(struct ip_fw_chain *chain) 269 { 270 int *map; 271 272 IPFW_UH_WLOCK_ASSERT(chain); 273 IPFW_WLOCK_ASSERT(chain); 274 275 map = chain->idxmap; 276 chain->idxmap = chain->idxmap_back; 277 chain->idxmap_back = map; 278 } 279 280 /* 281 * Allocate and initialize skipto cache. 282 */ 283 void 284 ipfw_init_skipto_cache(struct ip_fw_chain *chain) 285 { 286 int *idxmap, *idxmap_back; 287 288 idxmap = malloc(65536 * sizeof(uint32_t *), M_IPFW, 289 M_WAITOK | M_ZERO); 290 idxmap_back = malloc(65536 * sizeof(uint32_t *), M_IPFW, 291 M_WAITOK | M_ZERO); 292 293 /* 294 * Note we may be called at any time after initialization, 295 * for example, on first skipto rule, so we need to 296 * provide valid chain->idxmap on return 297 */ 298 299 IPFW_UH_WLOCK(chain); 300 if (chain->idxmap != NULL) { 301 IPFW_UH_WUNLOCK(chain); 302 free(idxmap, M_IPFW); 303 free(idxmap_back, M_IPFW); 304 return; 305 } 306 307 /* Set backup pointer first to permit building cache */ 308 chain->idxmap_back = idxmap_back; 309 update_skipto_cache(chain, chain->map); 310 IPFW_WLOCK(chain); 311 /* It is now safe to set chain->idxmap ptr */ 312 chain->idxmap = idxmap; 313 swap_skipto_cache(chain); 314 IPFW_WUNLOCK(chain); 315 IPFW_UH_WUNLOCK(chain); 316 } 317 318 /* 319 * Destroys skipto cache. 320 */ 321 void 322 ipfw_destroy_skipto_cache(struct ip_fw_chain *chain) 323 { 324 325 if (chain->idxmap != NULL) 326 free(chain->idxmap, M_IPFW); 327 if (chain->idxmap != NULL) 328 free(chain->idxmap_back, M_IPFW); 329 } 330 331 332 /* 333 * allocate a new map, returns the chain locked. extra is the number 334 * of entries to add or delete. 335 */ 336 static struct ip_fw ** 337 get_map(struct ip_fw_chain *chain, int extra, int locked) 338 { 339 340 for (;;) { 341 struct ip_fw **map; 342 int i, mflags; 343 344 mflags = M_ZERO | ((locked != 0) ? M_NOWAIT : M_WAITOK); 345 346 i = chain->n_rules + extra; 347 map = malloc(i * sizeof(struct ip_fw *), M_IPFW, mflags); 348 if (map == NULL) { 349 printf("%s: cannot allocate map\n", __FUNCTION__); 350 return NULL; 351 } 352 if (!locked) 353 IPFW_UH_WLOCK(chain); 354 if (i >= chain->n_rules + extra) /* good */ 355 return map; 356 /* otherwise we lost the race, free and retry */ 357 if (!locked) 358 IPFW_UH_WUNLOCK(chain); 359 free(map, M_IPFW); 360 } 361 } 362 363 /* 364 * swap the maps. It is supposed to be called with IPFW_UH_WLOCK 365 */ 366 static struct ip_fw ** 367 swap_map(struct ip_fw_chain *chain, struct ip_fw **new_map, int new_len) 368 { 369 struct ip_fw **old_map; 370 371 IPFW_WLOCK(chain); 372 chain->id++; 373 chain->n_rules = new_len; 374 old_map = chain->map; 375 chain->map = new_map; 376 swap_skipto_cache(chain); 377 IPFW_WUNLOCK(chain); 378 return old_map; 379 } 380 381 382 static void 383 export_cntr1_base(struct ip_fw *krule, struct ip_fw_bcounter *cntr) 384 { 385 386 cntr->size = sizeof(*cntr); 387 388 if (krule->cntr != NULL) { 389 cntr->pcnt = counter_u64_fetch(krule->cntr); 390 cntr->bcnt = counter_u64_fetch(krule->cntr + 1); 391 cntr->timestamp = krule->timestamp; 392 } 393 if (cntr->timestamp > 0) 394 cntr->timestamp += boottime.tv_sec; 395 } 396 397 static void 398 export_cntr0_base(struct ip_fw *krule, struct ip_fw_bcounter0 *cntr) 399 { 400 401 if (krule->cntr != NULL) { 402 cntr->pcnt = counter_u64_fetch(krule->cntr); 403 cntr->bcnt = counter_u64_fetch(krule->cntr + 1); 404 cntr->timestamp = krule->timestamp; 405 } 406 if (cntr->timestamp > 0) 407 cntr->timestamp += boottime.tv_sec; 408 } 409 410 /* 411 * Copies rule @urule from v1 userland format (current). 412 * to kernel @krule. 413 * Assume @krule is zeroed. 414 */ 415 static void 416 import_rule1(struct rule_check_info *ci) 417 { 418 struct ip_fw_rule *urule; 419 struct ip_fw *krule; 420 421 urule = (struct ip_fw_rule *)ci->urule; 422 krule = (struct ip_fw *)ci->krule; 423 424 /* copy header */ 425 krule->act_ofs = urule->act_ofs; 426 krule->cmd_len = urule->cmd_len; 427 krule->rulenum = urule->rulenum; 428 krule->set = urule->set; 429 krule->flags = urule->flags; 430 431 /* Save rulenum offset */ 432 ci->urule_numoff = offsetof(struct ip_fw_rule, rulenum); 433 434 /* Copy opcodes */ 435 memcpy(krule->cmd, urule->cmd, krule->cmd_len * sizeof(uint32_t)); 436 } 437 438 /* 439 * Export rule into v1 format (Current). 440 * Layout: 441 * [ ipfw_obj_tlv(IPFW_TLV_RULE_ENT) 442 * [ ip_fw_rule ] OR 443 * [ ip_fw_bcounter ip_fw_rule] (depends on rcntrs). 444 * ] 445 * Assume @data is zeroed. 446 */ 447 static void 448 export_rule1(struct ip_fw *krule, caddr_t data, int len, int rcntrs) 449 { 450 struct ip_fw_bcounter *cntr; 451 struct ip_fw_rule *urule; 452 ipfw_obj_tlv *tlv; 453 454 /* Fill in TLV header */ 455 tlv = (ipfw_obj_tlv *)data; 456 tlv->type = IPFW_TLV_RULE_ENT; 457 tlv->length = len; 458 459 if (rcntrs != 0) { 460 /* Copy counters */ 461 cntr = (struct ip_fw_bcounter *)(tlv + 1); 462 urule = (struct ip_fw_rule *)(cntr + 1); 463 export_cntr1_base(krule, cntr); 464 } else 465 urule = (struct ip_fw_rule *)(tlv + 1); 466 467 /* copy header */ 468 urule->act_ofs = krule->act_ofs; 469 urule->cmd_len = krule->cmd_len; 470 urule->rulenum = krule->rulenum; 471 urule->set = krule->set; 472 urule->flags = krule->flags; 473 urule->id = krule->id; 474 475 /* Copy opcodes */ 476 memcpy(urule->cmd, krule->cmd, krule->cmd_len * sizeof(uint32_t)); 477 } 478 479 480 /* 481 * Copies rule @urule from FreeBSD8 userland format (v0) 482 * to kernel @krule. 483 * Assume @krule is zeroed. 484 */ 485 static void 486 import_rule0(struct rule_check_info *ci) 487 { 488 struct ip_fw_rule0 *urule; 489 struct ip_fw *krule; 490 int cmdlen, l; 491 ipfw_insn *cmd; 492 ipfw_insn_limit *lcmd; 493 ipfw_insn_if *cmdif; 494 495 urule = (struct ip_fw_rule0 *)ci->urule; 496 krule = (struct ip_fw *)ci->krule; 497 498 /* copy header */ 499 krule->act_ofs = urule->act_ofs; 500 krule->cmd_len = urule->cmd_len; 501 krule->rulenum = urule->rulenum; 502 krule->set = urule->set; 503 if ((urule->_pad & 1) != 0) 504 krule->flags |= IPFW_RULE_NOOPT; 505 506 /* Save rulenum offset */ 507 ci->urule_numoff = offsetof(struct ip_fw_rule0, rulenum); 508 509 /* Copy opcodes */ 510 memcpy(krule->cmd, urule->cmd, krule->cmd_len * sizeof(uint32_t)); 511 512 /* 513 * Alter opcodes: 514 * 1) convert tablearg value from 65335 to 0 515 * 2) Add high bit to O_SETFIB/O_SETDSCP values (to make room for targ). 516 * 3) convert table number in iface opcodes to u16 517 */ 518 l = krule->cmd_len; 519 cmd = krule->cmd; 520 cmdlen = 0; 521 522 for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 523 cmdlen = F_LEN(cmd); 524 525 switch (cmd->opcode) { 526 /* Opcodes supporting tablearg */ 527 case O_TAG: 528 case O_TAGGED: 529 case O_PIPE: 530 case O_QUEUE: 531 case O_DIVERT: 532 case O_TEE: 533 case O_SKIPTO: 534 case O_CALLRETURN: 535 case O_NETGRAPH: 536 case O_NGTEE: 537 case O_NAT: 538 if (cmd->arg1 == 65535) 539 cmd->arg1 = IP_FW_TARG; 540 break; 541 case O_SETFIB: 542 case O_SETDSCP: 543 if (cmd->arg1 == 65535) 544 cmd->arg1 = IP_FW_TARG; 545 else 546 cmd->arg1 |= 0x8000; 547 break; 548 case O_LIMIT: 549 lcmd = (ipfw_insn_limit *)cmd; 550 if (lcmd->conn_limit == 65535) 551 lcmd->conn_limit = IP_FW_TARG; 552 break; 553 /* Interface tables */ 554 case O_XMIT: 555 case O_RECV: 556 case O_VIA: 557 /* Interface table, possibly */ 558 cmdif = (ipfw_insn_if *)cmd; 559 if (cmdif->name[0] != '\1') 560 break; 561 562 cmdif->p.kidx = (uint16_t)cmdif->p.glob; 563 break; 564 } 565 } 566 } 567 568 /* 569 * Copies rule @krule from kernel to FreeBSD8 userland format (v0) 570 */ 571 static void 572 export_rule0(struct ip_fw *krule, struct ip_fw_rule0 *urule, int len) 573 { 574 int cmdlen, l; 575 ipfw_insn *cmd; 576 ipfw_insn_limit *lcmd; 577 ipfw_insn_if *cmdif; 578 579 /* copy header */ 580 memset(urule, 0, len); 581 urule->act_ofs = krule->act_ofs; 582 urule->cmd_len = krule->cmd_len; 583 urule->rulenum = krule->rulenum; 584 urule->set = krule->set; 585 if ((krule->flags & IPFW_RULE_NOOPT) != 0) 586 urule->_pad |= 1; 587 588 /* Copy opcodes */ 589 memcpy(urule->cmd, krule->cmd, krule->cmd_len * sizeof(uint32_t)); 590 591 /* Export counters */ 592 export_cntr0_base(krule, (struct ip_fw_bcounter0 *)&urule->pcnt); 593 594 /* 595 * Alter opcodes: 596 * 1) convert tablearg value from 0 to 65335 597 * 2) Remove highest bit from O_SETFIB/O_SETDSCP values. 598 * 3) convert table number in iface opcodes to int 599 */ 600 l = urule->cmd_len; 601 cmd = urule->cmd; 602 cmdlen = 0; 603 604 for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 605 cmdlen = F_LEN(cmd); 606 607 switch (cmd->opcode) { 608 /* Opcodes supporting tablearg */ 609 case O_TAG: 610 case O_TAGGED: 611 case O_PIPE: 612 case O_QUEUE: 613 case O_DIVERT: 614 case O_TEE: 615 case O_SKIPTO: 616 case O_CALLRETURN: 617 case O_NETGRAPH: 618 case O_NGTEE: 619 case O_NAT: 620 if (cmd->arg1 == IP_FW_TARG) 621 cmd->arg1 = 65535; 622 break; 623 case O_SETFIB: 624 case O_SETDSCP: 625 if (cmd->arg1 == IP_FW_TARG) 626 cmd->arg1 = 65535; 627 else 628 cmd->arg1 &= ~0x8000; 629 break; 630 case O_LIMIT: 631 lcmd = (ipfw_insn_limit *)cmd; 632 if (lcmd->conn_limit == IP_FW_TARG) 633 lcmd->conn_limit = 65535; 634 break; 635 /* Interface tables */ 636 case O_XMIT: 637 case O_RECV: 638 case O_VIA: 639 /* Interface table, possibly */ 640 cmdif = (ipfw_insn_if *)cmd; 641 if (cmdif->name[0] != '\1') 642 break; 643 644 cmdif->p.glob = cmdif->p.kidx; 645 break; 646 } 647 } 648 } 649 650 /* 651 * Add new rule(s) to the list possibly creating rule number for each. 652 * Update the rule_number in the input struct so the caller knows it as well. 653 * Must be called without IPFW_UH held 654 */ 655 static int 656 commit_rules(struct ip_fw_chain *chain, struct rule_check_info *rci, int count) 657 { 658 int error, i, insert_before, tcount; 659 uint16_t rulenum, *pnum; 660 struct rule_check_info *ci; 661 struct ip_fw *krule; 662 struct ip_fw **map; /* the new array of pointers */ 663 664 /* Check if we need to do table/obj index remap */ 665 tcount = 0; 666 for (ci = rci, i = 0; i < count; ci++, i++) { 667 if (ci->object_opcodes == 0) 668 continue; 669 670 /* 671 * Rule has some object opcodes. 672 * We need to find (and create non-existing) 673 * kernel objects, and reference existing ones. 674 */ 675 error = ipfw_rewrite_rule_uidx(chain, ci); 676 if (error != 0) { 677 678 /* 679 * rewrite failed, state for current rule 680 * has been reverted. Check if we need to 681 * revert more. 682 */ 683 if (tcount > 0) { 684 685 /* 686 * We have some more table rules 687 * we need to rollback. 688 */ 689 690 IPFW_UH_WLOCK(chain); 691 while (ci != rci) { 692 ci--; 693 if (ci->object_opcodes == 0) 694 continue; 695 unref_rule_objects(chain,ci->krule); 696 697 } 698 IPFW_UH_WUNLOCK(chain); 699 700 } 701 702 return (error); 703 } 704 705 tcount++; 706 } 707 708 /* get_map returns with IPFW_UH_WLOCK if successful */ 709 map = get_map(chain, count, 0 /* not locked */); 710 if (map == NULL) { 711 if (tcount > 0) { 712 /* Unbind tables */ 713 IPFW_UH_WLOCK(chain); 714 for (ci = rci, i = 0; i < count; ci++, i++) { 715 if (ci->object_opcodes == 0) 716 continue; 717 718 unref_rule_objects(chain, ci->krule); 719 } 720 IPFW_UH_WUNLOCK(chain); 721 } 722 723 return (ENOSPC); 724 } 725 726 if (V_autoinc_step < 1) 727 V_autoinc_step = 1; 728 else if (V_autoinc_step > 1000) 729 V_autoinc_step = 1000; 730 731 /* FIXME: Handle count > 1 */ 732 ci = rci; 733 krule = ci->krule; 734 rulenum = krule->rulenum; 735 736 /* find the insertion point, we will insert before */ 737 insert_before = rulenum ? rulenum + 1 : IPFW_DEFAULT_RULE; 738 i = ipfw_find_rule(chain, insert_before, 0); 739 /* duplicate first part */ 740 if (i > 0) 741 bcopy(chain->map, map, i * sizeof(struct ip_fw *)); 742 map[i] = krule; 743 /* duplicate remaining part, we always have the default rule */ 744 bcopy(chain->map + i, map + i + 1, 745 sizeof(struct ip_fw *) *(chain->n_rules - i)); 746 if (rulenum == 0) { 747 /* Compute rule number and write it back */ 748 rulenum = i > 0 ? map[i-1]->rulenum : 0; 749 if (rulenum < IPFW_DEFAULT_RULE - V_autoinc_step) 750 rulenum += V_autoinc_step; 751 krule->rulenum = rulenum; 752 /* Save number to userland rule */ 753 pnum = (uint16_t *)((caddr_t)ci->urule + ci->urule_numoff); 754 *pnum = rulenum; 755 } 756 757 krule->id = chain->id + 1; 758 update_skipto_cache(chain, map); 759 map = swap_map(chain, map, chain->n_rules + 1); 760 chain->static_len += RULEUSIZE0(krule); 761 IPFW_UH_WUNLOCK(chain); 762 if (map) 763 free(map, M_IPFW); 764 return (0); 765 } 766 767 /* 768 * Adds @rule to the list of rules to reap 769 */ 770 void 771 ipfw_reap_add(struct ip_fw_chain *chain, struct ip_fw **head, 772 struct ip_fw *rule) 773 { 774 775 IPFW_UH_WLOCK_ASSERT(chain); 776 777 /* Unlink rule from everywhere */ 778 unref_rule_objects(chain, rule); 779 780 *((struct ip_fw **)rule) = *head; 781 *head = rule; 782 } 783 784 /* 785 * Reclaim storage associated with a list of rules. This is 786 * typically the list created using remove_rule. 787 * A NULL pointer on input is handled correctly. 788 */ 789 void 790 ipfw_reap_rules(struct ip_fw *head) 791 { 792 struct ip_fw *rule; 793 794 while ((rule = head) != NULL) { 795 head = *((struct ip_fw **)head); 796 free_rule(rule); 797 } 798 } 799 800 /* 801 * Rules to keep are 802 * (default || reserved || !match_set || !match_number) 803 * where 804 * default ::= (rule->rulenum == IPFW_DEFAULT_RULE) 805 * // the default rule is always protected 806 * 807 * reserved ::= (cmd == 0 && n == 0 && rule->set == RESVD_SET) 808 * // RESVD_SET is protected only if cmd == 0 and n == 0 ("ipfw flush") 809 * 810 * match_set ::= (cmd == 0 || rule->set == set) 811 * // set number is ignored for cmd == 0 812 * 813 * match_number ::= (cmd == 1 || n == 0 || n == rule->rulenum) 814 * // number is ignored for cmd == 1 or n == 0 815 * 816 */ 817 int 818 ipfw_match_range(struct ip_fw *rule, ipfw_range_tlv *rt) 819 { 820 821 /* Don't match default rule for modification queries */ 822 if (rule->rulenum == IPFW_DEFAULT_RULE && 823 (rt->flags & IPFW_RCFLAG_DEFAULT) == 0) 824 return (0); 825 826 /* Don't match rules in reserved set for flush requests */ 827 if ((rt->flags & IPFW_RCFLAG_ALL) != 0 && rule->set == RESVD_SET) 828 return (0); 829 830 /* If we're filtering by set, don't match other sets */ 831 if ((rt->flags & IPFW_RCFLAG_SET) != 0 && rule->set != rt->set) 832 return (0); 833 834 if ((rt->flags & IPFW_RCFLAG_RANGE) != 0 && 835 (rule->rulenum < rt->start_rule || rule->rulenum > rt->end_rule)) 836 return (0); 837 838 return (1); 839 } 840 841 /* 842 * Delete rules matching range @rt. 843 * Saves number of deleted rules in @ndel. 844 * 845 * Returns 0 on success. 846 */ 847 static int 848 delete_range(struct ip_fw_chain *chain, ipfw_range_tlv *rt, int *ndel) 849 { 850 struct ip_fw *reap, *rule, **map; 851 int end, start; 852 int i, n, ndyn, ofs; 853 854 reap = NULL; 855 IPFW_UH_WLOCK(chain); /* arbitrate writers */ 856 857 /* 858 * Stage 1: Determine range to inspect. 859 * Range is half-inclusive, e.g [start, end). 860 */ 861 start = 0; 862 end = chain->n_rules - 1; 863 864 if ((rt->flags & IPFW_RCFLAG_RANGE) != 0) { 865 start = ipfw_find_rule(chain, rt->start_rule, 0); 866 867 end = ipfw_find_rule(chain, rt->end_rule, 0); 868 if (rt->end_rule != IPFW_DEFAULT_RULE) 869 while (chain->map[end]->rulenum == rt->end_rule) 870 end++; 871 } 872 873 /* Allocate new map of the same size */ 874 map = get_map(chain, 0, 1 /* locked */); 875 if (map == NULL) { 876 IPFW_UH_WUNLOCK(chain); 877 return (ENOMEM); 878 } 879 880 n = 0; 881 ndyn = 0; 882 ofs = start; 883 /* 1. bcopy the initial part of the map */ 884 if (start > 0) 885 bcopy(chain->map, map, start * sizeof(struct ip_fw *)); 886 /* 2. copy active rules between start and end */ 887 for (i = start; i < end; i++) { 888 rule = chain->map[i]; 889 if (ipfw_match_range(rule, rt) == 0) { 890 map[ofs++] = rule; 891 continue; 892 } 893 894 n++; 895 if (ipfw_is_dyn_rule(rule) != 0) 896 ndyn++; 897 } 898 /* 3. copy the final part of the map */ 899 bcopy(chain->map + end, map + ofs, 900 (chain->n_rules - end) * sizeof(struct ip_fw *)); 901 /* 4. recalculate skipto cache */ 902 update_skipto_cache(chain, map); 903 /* 5. swap the maps (under UH_WLOCK + WHLOCK) */ 904 map = swap_map(chain, map, chain->n_rules - n); 905 /* 6. Remove all dynamic states originated by deleted rules */ 906 if (ndyn > 0) 907 ipfw_expire_dyn_rules(chain, rt); 908 /* 7. now remove the rules deleted from the old map */ 909 for (i = start; i < end; i++) { 910 rule = map[i]; 911 if (ipfw_match_range(rule, rt) == 0) 912 continue; 913 chain->static_len -= RULEUSIZE0(rule); 914 ipfw_reap_add(chain, &reap, rule); 915 } 916 IPFW_UH_WUNLOCK(chain); 917 918 ipfw_reap_rules(reap); 919 if (map != NULL) 920 free(map, M_IPFW); 921 *ndel = n; 922 return (0); 923 } 924 925 /* 926 * Changes set of given rule rannge @rt 927 * with each other. 928 * 929 * Returns 0 on success. 930 */ 931 static int 932 move_range(struct ip_fw_chain *chain, ipfw_range_tlv *rt) 933 { 934 struct ip_fw *rule; 935 int i; 936 937 IPFW_UH_WLOCK(chain); 938 939 /* 940 * Move rules with matching paramenerts to a new set. 941 * This one is much more complex. We have to ensure 942 * that all referenced tables (if any) are referenced 943 * by given rule subset only. Otherwise, we can't move 944 * them to new set and have to return error. 945 */ 946 if (V_fw_tables_sets != 0) { 947 if (ipfw_move_tables_sets(chain, rt, rt->new_set) != 0) { 948 IPFW_UH_WUNLOCK(chain); 949 return (EBUSY); 950 } 951 } 952 953 /* XXX: We have to do swap holding WLOCK */ 954 for (i = 0; i < chain->n_rules; i++) { 955 rule = chain->map[i]; 956 if (ipfw_match_range(rule, rt) == 0) 957 continue; 958 rule->set = rt->new_set; 959 } 960 961 IPFW_UH_WUNLOCK(chain); 962 963 return (0); 964 } 965 966 /* 967 * Clear counters for a specific rule. 968 * Normally run under IPFW_UH_RLOCK, but these are idempotent ops 969 * so we only care that rules do not disappear. 970 */ 971 static void 972 clear_counters(struct ip_fw *rule, int log_only) 973 { 974 ipfw_insn_log *l = (ipfw_insn_log *)ACTION_PTR(rule); 975 976 if (log_only == 0) 977 IPFW_ZERO_RULE_COUNTER(rule); 978 if (l->o.opcode == O_LOG) 979 l->log_left = l->max_log; 980 } 981 982 /* 983 * Flushes rules counters and/or log values on matching range. 984 * 985 * Returns number of items cleared. 986 */ 987 static int 988 clear_range(struct ip_fw_chain *chain, ipfw_range_tlv *rt, int log_only) 989 { 990 struct ip_fw *rule; 991 int num; 992 int i; 993 994 num = 0; 995 rt->flags |= IPFW_RCFLAG_DEFAULT; 996 997 IPFW_UH_WLOCK(chain); /* arbitrate writers */ 998 for (i = 0; i < chain->n_rules; i++) { 999 rule = chain->map[i]; 1000 if (ipfw_match_range(rule, rt) == 0) 1001 continue; 1002 clear_counters(rule, log_only); 1003 num++; 1004 } 1005 IPFW_UH_WUNLOCK(chain); 1006 1007 return (num); 1008 } 1009 1010 static int 1011 check_range_tlv(ipfw_range_tlv *rt) 1012 { 1013 1014 if (rt->head.length != sizeof(*rt)) 1015 return (1); 1016 if (rt->start_rule > rt->end_rule) 1017 return (1); 1018 if (rt->set >= IPFW_MAX_SETS || rt->new_set >= IPFW_MAX_SETS) 1019 return (1); 1020 1021 if ((rt->flags & IPFW_RCFLAG_USER) != rt->flags) 1022 return (1); 1023 1024 return (0); 1025 } 1026 1027 /* 1028 * Delete rules matching specified parameters 1029 * Data layout (v0)(current): 1030 * Request: [ ipfw_obj_header ipfw_range_tlv ] 1031 * Reply: [ ipfw_obj_header ipfw_range_tlv ] 1032 * 1033 * Saves number of deleted rules in ipfw_range_tlv->new_set. 1034 * 1035 * Returns 0 on success. 1036 */ 1037 static int 1038 del_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, 1039 struct sockopt_data *sd) 1040 { 1041 ipfw_range_header *rh; 1042 int error, ndel; 1043 1044 if (sd->valsize != sizeof(*rh)) 1045 return (EINVAL); 1046 1047 rh = (ipfw_range_header *)ipfw_get_sopt_space(sd, sd->valsize); 1048 1049 if (check_range_tlv(&rh->range) != 0) 1050 return (EINVAL); 1051 1052 ndel = 0; 1053 if ((error = delete_range(chain, &rh->range, &ndel)) != 0) 1054 return (error); 1055 1056 /* Save number of rules deleted */ 1057 rh->range.new_set = ndel; 1058 return (0); 1059 } 1060 1061 /* 1062 * Move rules/sets matching specified parameters 1063 * Data layout (v0)(current): 1064 * Request: [ ipfw_obj_header ipfw_range_tlv ] 1065 * 1066 * Returns 0 on success. 1067 */ 1068 static int 1069 move_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, 1070 struct sockopt_data *sd) 1071 { 1072 ipfw_range_header *rh; 1073 1074 if (sd->valsize != sizeof(*rh)) 1075 return (EINVAL); 1076 1077 rh = (ipfw_range_header *)ipfw_get_sopt_space(sd, sd->valsize); 1078 1079 if (check_range_tlv(&rh->range) != 0) 1080 return (EINVAL); 1081 1082 return (move_range(chain, &rh->range)); 1083 } 1084 1085 /* 1086 * Clear rule accounting data matching specified parameters 1087 * Data layout (v0)(current): 1088 * Request: [ ipfw_obj_header ipfw_range_tlv ] 1089 * Reply: [ ipfw_obj_header ipfw_range_tlv ] 1090 * 1091 * Saves number of cleared rules in ipfw_range_tlv->new_set. 1092 * 1093 * Returns 0 on success. 1094 */ 1095 static int 1096 clear_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, 1097 struct sockopt_data *sd) 1098 { 1099 ipfw_range_header *rh; 1100 int log_only, num; 1101 char *msg; 1102 1103 if (sd->valsize != sizeof(*rh)) 1104 return (EINVAL); 1105 1106 rh = (ipfw_range_header *)ipfw_get_sopt_space(sd, sd->valsize); 1107 1108 if (check_range_tlv(&rh->range) != 0) 1109 return (EINVAL); 1110 1111 log_only = (op3->opcode == IP_FW_XRESETLOG); 1112 1113 num = clear_range(chain, &rh->range, log_only); 1114 1115 if (rh->range.flags & IPFW_RCFLAG_ALL) 1116 msg = log_only ? "All logging counts reset" : 1117 "Accounting cleared"; 1118 else 1119 msg = log_only ? "logging count reset" : "cleared"; 1120 1121 if (V_fw_verbose) { 1122 int lev = LOG_SECURITY | LOG_NOTICE; 1123 log(lev, "ipfw: %s.\n", msg); 1124 } 1125 1126 /* Save number of rules cleared */ 1127 rh->range.new_set = num; 1128 return (0); 1129 } 1130 1131 static void 1132 enable_sets(struct ip_fw_chain *chain, ipfw_range_tlv *rt) 1133 { 1134 uint32_t v_set; 1135 1136 IPFW_UH_WLOCK_ASSERT(chain); 1137 1138 /* Change enabled/disabled sets mask */ 1139 v_set = (V_set_disable | rt->set) & ~rt->new_set; 1140 v_set &= ~(1 << RESVD_SET); /* set RESVD_SET always enabled */ 1141 IPFW_WLOCK(chain); 1142 V_set_disable = v_set; 1143 IPFW_WUNLOCK(chain); 1144 } 1145 1146 static void 1147 swap_sets(struct ip_fw_chain *chain, ipfw_range_tlv *rt, int mv) 1148 { 1149 struct ip_fw *rule; 1150 int i; 1151 1152 IPFW_UH_WLOCK_ASSERT(chain); 1153 1154 /* Swap or move two sets */ 1155 for (i = 0; i < chain->n_rules - 1; i++) { 1156 rule = chain->map[i]; 1157 if (rule->set == rt->set) 1158 rule->set = rt->new_set; 1159 else if (rule->set == rt->new_set && mv == 0) 1160 rule->set = rt->set; 1161 } 1162 if (V_fw_tables_sets != 0) 1163 ipfw_swap_tables_sets(chain, rt->set, rt->new_set, mv); 1164 } 1165 1166 /* 1167 * Swaps or moves set 1168 * Data layout (v0)(current): 1169 * Request: [ ipfw_obj_header ipfw_range_tlv ] 1170 * 1171 * Returns 0 on success. 1172 */ 1173 static int 1174 manage_sets(struct ip_fw_chain *chain, ip_fw3_opheader *op3, 1175 struct sockopt_data *sd) 1176 { 1177 ipfw_range_header *rh; 1178 1179 if (sd->valsize != sizeof(*rh)) 1180 return (EINVAL); 1181 1182 rh = (ipfw_range_header *)ipfw_get_sopt_space(sd, sd->valsize); 1183 1184 if (rh->range.head.length != sizeof(ipfw_range_tlv)) 1185 return (1); 1186 1187 IPFW_UH_WLOCK(chain); 1188 switch (op3->opcode) { 1189 case IP_FW_SET_SWAP: 1190 case IP_FW_SET_MOVE: 1191 swap_sets(chain, &rh->range, op3->opcode == IP_FW_SET_MOVE); 1192 break; 1193 case IP_FW_SET_ENABLE: 1194 enable_sets(chain, &rh->range); 1195 break; 1196 } 1197 IPFW_UH_WUNLOCK(chain); 1198 1199 return (0); 1200 } 1201 1202 /** 1203 * Remove all rules with given number, or do set manipulation. 1204 * Assumes chain != NULL && *chain != NULL. 1205 * 1206 * The argument is an uint32_t. The low 16 bit are the rule or set number; 1207 * the next 8 bits are the new set; the top 8 bits indicate the command: 1208 * 1209 * 0 delete rules numbered "rulenum" 1210 * 1 delete rules in set "rulenum" 1211 * 2 move rules "rulenum" to set "new_set" 1212 * 3 move rules from set "rulenum" to set "new_set" 1213 * 4 swap sets "rulenum" and "new_set" 1214 * 5 delete rules "rulenum" and set "new_set" 1215 */ 1216 static int 1217 del_entry(struct ip_fw_chain *chain, uint32_t arg) 1218 { 1219 uint32_t num; /* rule number or old_set */ 1220 uint8_t cmd, new_set; 1221 int do_del, ndel; 1222 int error = 0; 1223 ipfw_range_tlv rt; 1224 1225 num = arg & 0xffff; 1226 cmd = (arg >> 24) & 0xff; 1227 new_set = (arg >> 16) & 0xff; 1228 1229 if (cmd > 5 || new_set > RESVD_SET) 1230 return EINVAL; 1231 if (cmd == 0 || cmd == 2 || cmd == 5) { 1232 if (num >= IPFW_DEFAULT_RULE) 1233 return EINVAL; 1234 } else { 1235 if (num > RESVD_SET) /* old_set */ 1236 return EINVAL; 1237 } 1238 1239 /* Convert old requests into new representation */ 1240 memset(&rt, 0, sizeof(rt)); 1241 rt.start_rule = num; 1242 rt.end_rule = num; 1243 rt.set = num; 1244 rt.new_set = new_set; 1245 do_del = 0; 1246 1247 switch (cmd) { 1248 case 0: /* delete rules numbered "rulenum" */ 1249 if (num == 0) 1250 rt.flags |= IPFW_RCFLAG_ALL; 1251 else 1252 rt.flags |= IPFW_RCFLAG_RANGE; 1253 do_del = 1; 1254 break; 1255 case 1: /* delete rules in set "rulenum" */ 1256 rt.flags |= IPFW_RCFLAG_SET; 1257 do_del = 1; 1258 break; 1259 case 5: /* delete rules "rulenum" and set "new_set" */ 1260 rt.flags |= IPFW_RCFLAG_RANGE | IPFW_RCFLAG_SET; 1261 rt.set = new_set; 1262 rt.new_set = 0; 1263 do_del = 1; 1264 break; 1265 case 2: /* move rules "rulenum" to set "new_set" */ 1266 rt.flags |= IPFW_RCFLAG_RANGE; 1267 break; 1268 case 3: /* move rules from set "rulenum" to set "new_set" */ 1269 IPFW_UH_WLOCK(chain); 1270 swap_sets(chain, &rt, 1); 1271 IPFW_UH_WUNLOCK(chain); 1272 return (0); 1273 case 4: /* swap sets "rulenum" and "new_set" */ 1274 IPFW_UH_WLOCK(chain); 1275 swap_sets(chain, &rt, 0); 1276 IPFW_UH_WUNLOCK(chain); 1277 return (0); 1278 default: 1279 return (ENOTSUP); 1280 } 1281 1282 if (do_del != 0) { 1283 if ((error = delete_range(chain, &rt, &ndel)) != 0) 1284 return (error); 1285 1286 if (ndel == 0 && (cmd != 1 && num != 0)) 1287 return (EINVAL); 1288 1289 return (0); 1290 } 1291 1292 return (move_range(chain, &rt)); 1293 } 1294 1295 /** 1296 * Reset some or all counters on firewall rules. 1297 * The argument `arg' is an u_int32_t. The low 16 bit are the rule number, 1298 * the next 8 bits are the set number, the top 8 bits are the command: 1299 * 0 work with rules from all set's; 1300 * 1 work with rules only from specified set. 1301 * Specified rule number is zero if we want to clear all entries. 1302 * log_only is 1 if we only want to reset logs, zero otherwise. 1303 */ 1304 static int 1305 zero_entry(struct ip_fw_chain *chain, u_int32_t arg, int log_only) 1306 { 1307 struct ip_fw *rule; 1308 char *msg; 1309 int i; 1310 1311 uint16_t rulenum = arg & 0xffff; 1312 uint8_t set = (arg >> 16) & 0xff; 1313 uint8_t cmd = (arg >> 24) & 0xff; 1314 1315 if (cmd > 1) 1316 return (EINVAL); 1317 if (cmd == 1 && set > RESVD_SET) 1318 return (EINVAL); 1319 1320 IPFW_UH_RLOCK(chain); 1321 if (rulenum == 0) { 1322 V_norule_counter = 0; 1323 for (i = 0; i < chain->n_rules; i++) { 1324 rule = chain->map[i]; 1325 /* Skip rules not in our set. */ 1326 if (cmd == 1 && rule->set != set) 1327 continue; 1328 clear_counters(rule, log_only); 1329 } 1330 msg = log_only ? "All logging counts reset" : 1331 "Accounting cleared"; 1332 } else { 1333 int cleared = 0; 1334 for (i = 0; i < chain->n_rules; i++) { 1335 rule = chain->map[i]; 1336 if (rule->rulenum == rulenum) { 1337 if (cmd == 0 || rule->set == set) 1338 clear_counters(rule, log_only); 1339 cleared = 1; 1340 } 1341 if (rule->rulenum > rulenum) 1342 break; 1343 } 1344 if (!cleared) { /* we did not find any matching rules */ 1345 IPFW_UH_RUNLOCK(chain); 1346 return (EINVAL); 1347 } 1348 msg = log_only ? "logging count reset" : "cleared"; 1349 } 1350 IPFW_UH_RUNLOCK(chain); 1351 1352 if (V_fw_verbose) { 1353 int lev = LOG_SECURITY | LOG_NOTICE; 1354 1355 if (rulenum) 1356 log(lev, "ipfw: Entry %d %s.\n", rulenum, msg); 1357 else 1358 log(lev, "ipfw: %s.\n", msg); 1359 } 1360 return (0); 1361 } 1362 1363 1364 /* 1365 * Check rule head in FreeBSD11 format 1366 * 1367 */ 1368 static int 1369 check_ipfw_rule1(struct ip_fw_rule *rule, int size, 1370 struct rule_check_info *ci) 1371 { 1372 int l; 1373 1374 if (size < sizeof(*rule)) { 1375 printf("ipfw: rule too short\n"); 1376 return (EINVAL); 1377 } 1378 1379 /* Check for valid cmd_len */ 1380 l = roundup2(RULESIZE(rule), sizeof(uint64_t)); 1381 if (l != size) { 1382 printf("ipfw: size mismatch (have %d want %d)\n", size, l); 1383 return (EINVAL); 1384 } 1385 if (rule->act_ofs >= rule->cmd_len) { 1386 printf("ipfw: bogus action offset (%u > %u)\n", 1387 rule->act_ofs, rule->cmd_len - 1); 1388 return (EINVAL); 1389 } 1390 1391 if (rule->rulenum > IPFW_DEFAULT_RULE - 1) 1392 return (EINVAL); 1393 1394 return (check_ipfw_rule_body(rule->cmd, rule->cmd_len, ci)); 1395 } 1396 1397 /* 1398 * Check rule head in FreeBSD8 format 1399 * 1400 */ 1401 static int 1402 check_ipfw_rule0(struct ip_fw_rule0 *rule, int size, 1403 struct rule_check_info *ci) 1404 { 1405 int l; 1406 1407 if (size < sizeof(*rule)) { 1408 printf("ipfw: rule too short\n"); 1409 return (EINVAL); 1410 } 1411 1412 /* Check for valid cmd_len */ 1413 l = sizeof(*rule) + rule->cmd_len * 4 - 4; 1414 if (l != size) { 1415 printf("ipfw: size mismatch (have %d want %d)\n", size, l); 1416 return (EINVAL); 1417 } 1418 if (rule->act_ofs >= rule->cmd_len) { 1419 printf("ipfw: bogus action offset (%u > %u)\n", 1420 rule->act_ofs, rule->cmd_len - 1); 1421 return (EINVAL); 1422 } 1423 1424 if (rule->rulenum > IPFW_DEFAULT_RULE - 1) 1425 return (EINVAL); 1426 1427 return (check_ipfw_rule_body(rule->cmd, rule->cmd_len, ci)); 1428 } 1429 1430 static int 1431 check_ipfw_rule_body(ipfw_insn *cmd, int cmd_len, struct rule_check_info *ci) 1432 { 1433 int cmdlen, l; 1434 int have_action; 1435 1436 have_action = 0; 1437 1438 /* 1439 * Now go for the individual checks. Very simple ones, basically only 1440 * instruction sizes. 1441 */ 1442 for (l = cmd_len; l > 0 ; l -= cmdlen, cmd += cmdlen) { 1443 cmdlen = F_LEN(cmd); 1444 if (cmdlen > l) { 1445 printf("ipfw: opcode %d size truncated\n", 1446 cmd->opcode); 1447 return EINVAL; 1448 } 1449 switch (cmd->opcode) { 1450 case O_PROBE_STATE: 1451 case O_KEEP_STATE: 1452 case O_PROTO: 1453 case O_IP_SRC_ME: 1454 case O_IP_DST_ME: 1455 case O_LAYER2: 1456 case O_IN: 1457 case O_FRAG: 1458 case O_DIVERTED: 1459 case O_IPOPT: 1460 case O_IPTOS: 1461 case O_IPPRECEDENCE: 1462 case O_IPVER: 1463 case O_SOCKARG: 1464 case O_TCPFLAGS: 1465 case O_TCPOPTS: 1466 case O_ESTAB: 1467 case O_VERREVPATH: 1468 case O_VERSRCREACH: 1469 case O_ANTISPOOF: 1470 case O_IPSEC: 1471 #ifdef INET6 1472 case O_IP6_SRC_ME: 1473 case O_IP6_DST_ME: 1474 case O_EXT_HDR: 1475 case O_IP6: 1476 #endif 1477 case O_IP4: 1478 case O_TAG: 1479 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 1480 goto bad_size; 1481 break; 1482 1483 case O_FIB: 1484 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 1485 goto bad_size; 1486 if (cmd->arg1 >= rt_numfibs) { 1487 printf("ipfw: invalid fib number %d\n", 1488 cmd->arg1); 1489 return EINVAL; 1490 } 1491 break; 1492 1493 case O_SETFIB: 1494 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 1495 goto bad_size; 1496 if ((cmd->arg1 != IP_FW_TARG) && 1497 ((cmd->arg1 & 0x7FFFF) >= rt_numfibs)) { 1498 printf("ipfw: invalid fib number %d\n", 1499 cmd->arg1 & 0x7FFFF); 1500 return EINVAL; 1501 } 1502 goto check_action; 1503 1504 case O_UID: 1505 case O_GID: 1506 case O_JAIL: 1507 case O_IP_SRC: 1508 case O_IP_DST: 1509 case O_TCPSEQ: 1510 case O_TCPACK: 1511 case O_PROB: 1512 case O_ICMPTYPE: 1513 if (cmdlen != F_INSN_SIZE(ipfw_insn_u32)) 1514 goto bad_size; 1515 break; 1516 1517 case O_LIMIT: 1518 if (cmdlen != F_INSN_SIZE(ipfw_insn_limit)) 1519 goto bad_size; 1520 break; 1521 1522 case O_LOG: 1523 if (cmdlen != F_INSN_SIZE(ipfw_insn_log)) 1524 goto bad_size; 1525 1526 ((ipfw_insn_log *)cmd)->log_left = 1527 ((ipfw_insn_log *)cmd)->max_log; 1528 1529 break; 1530 1531 case O_IP_SRC_MASK: 1532 case O_IP_DST_MASK: 1533 /* only odd command lengths */ 1534 if ( !(cmdlen & 1) || cmdlen > 31) 1535 goto bad_size; 1536 break; 1537 1538 case O_IP_SRC_SET: 1539 case O_IP_DST_SET: 1540 if (cmd->arg1 == 0 || cmd->arg1 > 256) { 1541 printf("ipfw: invalid set size %d\n", 1542 cmd->arg1); 1543 return EINVAL; 1544 } 1545 if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1546 (cmd->arg1+31)/32 ) 1547 goto bad_size; 1548 break; 1549 1550 case O_IP_SRC_LOOKUP: 1551 case O_IP_DST_LOOKUP: 1552 if (cmd->arg1 >= V_fw_tables_max) { 1553 printf("ipfw: invalid table number %d\n", 1554 cmd->arg1); 1555 return (EINVAL); 1556 } 1557 if (cmdlen != F_INSN_SIZE(ipfw_insn) && 1558 cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1 && 1559 cmdlen != F_INSN_SIZE(ipfw_insn_u32)) 1560 goto bad_size; 1561 ci->object_opcodes++; 1562 break; 1563 case O_IP_FLOW_LOOKUP: 1564 if (cmd->arg1 >= V_fw_tables_max) { 1565 printf("ipfw: invalid table number %d\n", 1566 cmd->arg1); 1567 return (EINVAL); 1568 } 1569 if (cmdlen != F_INSN_SIZE(ipfw_insn) && 1570 cmdlen != F_INSN_SIZE(ipfw_insn_u32)) 1571 goto bad_size; 1572 ci->object_opcodes++; 1573 break; 1574 case O_MACADDR2: 1575 if (cmdlen != F_INSN_SIZE(ipfw_insn_mac)) 1576 goto bad_size; 1577 break; 1578 1579 case O_NOP: 1580 case O_IPID: 1581 case O_IPTTL: 1582 case O_IPLEN: 1583 case O_TCPDATALEN: 1584 case O_TCPWIN: 1585 case O_TAGGED: 1586 if (cmdlen < 1 || cmdlen > 31) 1587 goto bad_size; 1588 break; 1589 1590 case O_DSCP: 1591 if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1) 1592 goto bad_size; 1593 break; 1594 1595 case O_MAC_TYPE: 1596 case O_IP_SRCPORT: 1597 case O_IP_DSTPORT: /* XXX artificial limit, 30 port pairs */ 1598 if (cmdlen < 2 || cmdlen > 31) 1599 goto bad_size; 1600 break; 1601 1602 case O_RECV: 1603 case O_XMIT: 1604 case O_VIA: 1605 if (((ipfw_insn_if *)cmd)->name[0] == '\1') 1606 ci->object_opcodes++; 1607 if (cmdlen != F_INSN_SIZE(ipfw_insn_if)) 1608 goto bad_size; 1609 break; 1610 1611 case O_ALTQ: 1612 if (cmdlen != F_INSN_SIZE(ipfw_insn_altq)) 1613 goto bad_size; 1614 break; 1615 1616 case O_PIPE: 1617 case O_QUEUE: 1618 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 1619 goto bad_size; 1620 goto check_action; 1621 1622 case O_FORWARD_IP: 1623 if (cmdlen != F_INSN_SIZE(ipfw_insn_sa)) 1624 goto bad_size; 1625 goto check_action; 1626 #ifdef INET6 1627 case O_FORWARD_IP6: 1628 if (cmdlen != F_INSN_SIZE(ipfw_insn_sa6)) 1629 goto bad_size; 1630 goto check_action; 1631 #endif /* INET6 */ 1632 1633 case O_DIVERT: 1634 case O_TEE: 1635 if (ip_divert_ptr == NULL) 1636 return EINVAL; 1637 else 1638 goto check_size; 1639 case O_NETGRAPH: 1640 case O_NGTEE: 1641 if (ng_ipfw_input_p == NULL) 1642 return EINVAL; 1643 else 1644 goto check_size; 1645 case O_NAT: 1646 if (!IPFW_NAT_LOADED) 1647 return EINVAL; 1648 if (cmdlen != F_INSN_SIZE(ipfw_insn_nat)) 1649 goto bad_size; 1650 ci->object_opcodes++; 1651 goto check_action; 1652 case O_FORWARD_MAC: /* XXX not implemented yet */ 1653 case O_CHECK_STATE: 1654 case O_COUNT: 1655 case O_ACCEPT: 1656 case O_DENY: 1657 case O_REJECT: 1658 case O_SETDSCP: 1659 #ifdef INET6 1660 case O_UNREACH6: 1661 #endif 1662 case O_SKIPTO: 1663 case O_REASS: 1664 case O_CALLRETURN: 1665 check_size: 1666 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 1667 goto bad_size; 1668 check_action: 1669 if (have_action) { 1670 printf("ipfw: opcode %d, multiple actions" 1671 " not allowed\n", 1672 cmd->opcode); 1673 return (EINVAL); 1674 } 1675 have_action = 1; 1676 if (l != cmdlen) { 1677 printf("ipfw: opcode %d, action must be" 1678 " last opcode\n", 1679 cmd->opcode); 1680 return (EINVAL); 1681 } 1682 break; 1683 #ifdef INET6 1684 case O_IP6_SRC: 1685 case O_IP6_DST: 1686 if (cmdlen != F_INSN_SIZE(struct in6_addr) + 1687 F_INSN_SIZE(ipfw_insn)) 1688 goto bad_size; 1689 break; 1690 1691 case O_FLOW6ID: 1692 if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1693 ((ipfw_insn_u32 *)cmd)->o.arg1) 1694 goto bad_size; 1695 break; 1696 1697 case O_IP6_SRC_MASK: 1698 case O_IP6_DST_MASK: 1699 if ( !(cmdlen & 1) || cmdlen > 127) 1700 goto bad_size; 1701 break; 1702 case O_ICMP6TYPE: 1703 if( cmdlen != F_INSN_SIZE( ipfw_insn_icmp6 ) ) 1704 goto bad_size; 1705 break; 1706 #endif 1707 1708 default: 1709 switch (cmd->opcode) { 1710 #ifndef INET6 1711 case O_IP6_SRC_ME: 1712 case O_IP6_DST_ME: 1713 case O_EXT_HDR: 1714 case O_IP6: 1715 case O_UNREACH6: 1716 case O_IP6_SRC: 1717 case O_IP6_DST: 1718 case O_FLOW6ID: 1719 case O_IP6_SRC_MASK: 1720 case O_IP6_DST_MASK: 1721 case O_ICMP6TYPE: 1722 printf("ipfw: no IPv6 support in kernel\n"); 1723 return (EPROTONOSUPPORT); 1724 #endif 1725 default: 1726 printf("ipfw: opcode %d, unknown opcode\n", 1727 cmd->opcode); 1728 return (EINVAL); 1729 } 1730 } 1731 } 1732 if (have_action == 0) { 1733 printf("ipfw: missing action\n"); 1734 return (EINVAL); 1735 } 1736 return 0; 1737 1738 bad_size: 1739 printf("ipfw: opcode %d size %d wrong\n", 1740 cmd->opcode, cmdlen); 1741 return (EINVAL); 1742 } 1743 1744 1745 /* 1746 * Translation of requests for compatibility with FreeBSD 7.2/8. 1747 * a static variable tells us if we have an old client from userland, 1748 * and if necessary we translate requests and responses between the 1749 * two formats. 1750 */ 1751 static int is7 = 0; 1752 1753 struct ip_fw7 { 1754 struct ip_fw7 *next; /* linked list of rules */ 1755 struct ip_fw7 *next_rule; /* ptr to next [skipto] rule */ 1756 /* 'next_rule' is used to pass up 'set_disable' status */ 1757 1758 uint16_t act_ofs; /* offset of action in 32-bit units */ 1759 uint16_t cmd_len; /* # of 32-bit words in cmd */ 1760 uint16_t rulenum; /* rule number */ 1761 uint8_t set; /* rule set (0..31) */ 1762 // #define RESVD_SET 31 /* set for default and persistent rules */ 1763 uint8_t _pad; /* padding */ 1764 // uint32_t id; /* rule id, only in v.8 */ 1765 /* These fields are present in all rules. */ 1766 uint64_t pcnt; /* Packet counter */ 1767 uint64_t bcnt; /* Byte counter */ 1768 uint32_t timestamp; /* tv_sec of last match */ 1769 1770 ipfw_insn cmd[1]; /* storage for commands */ 1771 }; 1772 1773 static int convert_rule_to_7(struct ip_fw_rule0 *rule); 1774 static int convert_rule_to_8(struct ip_fw_rule0 *rule); 1775 1776 #ifndef RULESIZE7 1777 #define RULESIZE7(rule) (sizeof(struct ip_fw7) + \ 1778 ((struct ip_fw7 *)(rule))->cmd_len * 4 - 4) 1779 #endif 1780 1781 1782 /* 1783 * Copy the static and dynamic rules to the supplied buffer 1784 * and return the amount of space actually used. 1785 * Must be run under IPFW_UH_RLOCK 1786 */ 1787 static size_t 1788 ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space) 1789 { 1790 char *bp = buf; 1791 char *ep = bp + space; 1792 struct ip_fw *rule; 1793 struct ip_fw_rule0 *dst; 1794 int error, i, l, warnflag; 1795 time_t boot_seconds; 1796 1797 warnflag = 0; 1798 1799 boot_seconds = boottime.tv_sec; 1800 for (i = 0; i < chain->n_rules; i++) { 1801 rule = chain->map[i]; 1802 1803 if (is7) { 1804 /* Convert rule to FreeBSd 7.2 format */ 1805 l = RULESIZE7(rule); 1806 if (bp + l + sizeof(uint32_t) <= ep) { 1807 bcopy(rule, bp, l + sizeof(uint32_t)); 1808 error = set_legacy_obj_kidx(chain, 1809 (struct ip_fw_rule0 *)bp); 1810 if (error != 0) 1811 return (0); 1812 error = convert_rule_to_7((struct ip_fw_rule0 *) bp); 1813 if (error) 1814 return 0; /*XXX correct? */ 1815 /* 1816 * XXX HACK. Store the disable mask in the "next" 1817 * pointer in a wild attempt to keep the ABI the same. 1818 * Why do we do this on EVERY rule? 1819 */ 1820 bcopy(&V_set_disable, 1821 &(((struct ip_fw7 *)bp)->next_rule), 1822 sizeof(V_set_disable)); 1823 if (((struct ip_fw7 *)bp)->timestamp) 1824 ((struct ip_fw7 *)bp)->timestamp += boot_seconds; 1825 bp += l; 1826 } 1827 continue; /* go to next rule */ 1828 } 1829 1830 l = RULEUSIZE0(rule); 1831 if (bp + l > ep) { /* should not happen */ 1832 printf("overflow dumping static rules\n"); 1833 break; 1834 } 1835 dst = (struct ip_fw_rule0 *)bp; 1836 export_rule0(rule, dst, l); 1837 error = set_legacy_obj_kidx(chain, dst); 1838 1839 /* 1840 * XXX HACK. Store the disable mask in the "next" 1841 * pointer in a wild attempt to keep the ABI the same. 1842 * Why do we do this on EVERY rule? 1843 * 1844 * XXX: "ipfw set show" (ab)uses IP_FW_GET to read disabled mask 1845 * so we need to fail _after_ saving at least one mask. 1846 */ 1847 bcopy(&V_set_disable, &dst->next_rule, sizeof(V_set_disable)); 1848 if (dst->timestamp) 1849 dst->timestamp += boot_seconds; 1850 bp += l; 1851 1852 if (error != 0) { 1853 if (error == 2) { 1854 /* Non-fatal table rewrite error. */ 1855 warnflag = 1; 1856 continue; 1857 } 1858 printf("Stop on rule %d. Fail to convert table\n", 1859 rule->rulenum); 1860 break; 1861 } 1862 } 1863 if (warnflag != 0) 1864 printf("ipfw: process %s is using legacy interfaces," 1865 " consider rebuilding\n", ""); 1866 ipfw_get_dynamic(chain, &bp, ep); /* protected by the dynamic lock */ 1867 return (bp - (char *)buf); 1868 } 1869 1870 1871 struct dump_args { 1872 uint32_t b; /* start rule */ 1873 uint32_t e; /* end rule */ 1874 uint32_t rcount; /* number of rules */ 1875 uint32_t rsize; /* rules size */ 1876 uint32_t tcount; /* number of tables */ 1877 int rcounters; /* counters */ 1878 }; 1879 1880 /* 1881 * Export named object info in instance @ni, identified by @kidx 1882 * to ipfw_obj_ntlv. TLV is allocated from @sd space. 1883 * 1884 * Returns 0 on success. 1885 */ 1886 static int 1887 export_objhash_ntlv(struct namedobj_instance *ni, uint16_t kidx, 1888 struct sockopt_data *sd) 1889 { 1890 struct named_object *no; 1891 ipfw_obj_ntlv *ntlv; 1892 1893 no = ipfw_objhash_lookup_kidx(ni, kidx); 1894 KASSERT(no != NULL, ("invalid object kernel index passed")); 1895 1896 ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv)); 1897 if (ntlv == NULL) 1898 return (ENOMEM); 1899 1900 ntlv->head.type = no->etlv; 1901 ntlv->head.length = sizeof(*ntlv); 1902 ntlv->idx = no->kidx; 1903 strlcpy(ntlv->name, no->name, sizeof(ntlv->name)); 1904 1905 return (0); 1906 } 1907 1908 /* 1909 * Dumps static rules with table TLVs in buffer @sd. 1910 * 1911 * Returns 0 on success. 1912 */ 1913 static int 1914 dump_static_rules(struct ip_fw_chain *chain, struct dump_args *da, 1915 uint32_t *bmask, struct sockopt_data *sd) 1916 { 1917 int error; 1918 int i, l; 1919 uint32_t tcount; 1920 ipfw_obj_ctlv *ctlv; 1921 struct ip_fw *krule; 1922 struct namedobj_instance *ni; 1923 caddr_t dst; 1924 1925 /* Dump table names first (if any) */ 1926 if (da->tcount > 0) { 1927 /* Header first */ 1928 ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv)); 1929 if (ctlv == NULL) 1930 return (ENOMEM); 1931 ctlv->head.type = IPFW_TLV_TBLNAME_LIST; 1932 ctlv->head.length = da->tcount * sizeof(ipfw_obj_ntlv) + 1933 sizeof(*ctlv); 1934 ctlv->count = da->tcount; 1935 ctlv->objsize = sizeof(ipfw_obj_ntlv); 1936 } 1937 1938 i = 0; 1939 tcount = da->tcount; 1940 ni = ipfw_get_table_objhash(chain); 1941 while (tcount > 0) { 1942 if ((bmask[i / 32] & (1 << (i % 32))) == 0) { 1943 i++; 1944 continue; 1945 } 1946 1947 /* Jump to shared named object bitmask */ 1948 if (i >= IPFW_TABLES_MAX) { 1949 ni = CHAIN_TO_SRV(chain); 1950 i -= IPFW_TABLES_MAX; 1951 bmask += IPFW_TABLES_MAX / 32; 1952 } 1953 1954 if ((error = export_objhash_ntlv(ni, i, sd)) != 0) 1955 return (error); 1956 1957 i++; 1958 tcount--; 1959 } 1960 1961 /* Dump rules */ 1962 ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv)); 1963 if (ctlv == NULL) 1964 return (ENOMEM); 1965 ctlv->head.type = IPFW_TLV_RULE_LIST; 1966 ctlv->head.length = da->rsize + sizeof(*ctlv); 1967 ctlv->count = da->rcount; 1968 1969 for (i = da->b; i < da->e; i++) { 1970 krule = chain->map[i]; 1971 1972 l = RULEUSIZE1(krule) + sizeof(ipfw_obj_tlv); 1973 if (da->rcounters != 0) 1974 l += sizeof(struct ip_fw_bcounter); 1975 dst = (caddr_t)ipfw_get_sopt_space(sd, l); 1976 if (dst == NULL) 1977 return (ENOMEM); 1978 1979 export_rule1(krule, dst, l, da->rcounters); 1980 } 1981 1982 return (0); 1983 } 1984 1985 /* 1986 * Marks every object index used in @rule with bit in @bmask. 1987 * Used to generate bitmask of referenced tables/objects for given ruleset 1988 * or its part. 1989 * 1990 * Returns number of newly-referenced objects. 1991 */ 1992 static int 1993 mark_object_kidx(struct ip_fw_chain *ch, struct ip_fw *rule, 1994 uint32_t *bmask) 1995 { 1996 int cmdlen, l, count; 1997 ipfw_insn *cmd; 1998 uint16_t kidx; 1999 struct opcode_obj_rewrite *rw; 2000 int bidx; 2001 uint8_t subtype; 2002 2003 l = rule->cmd_len; 2004 cmd = rule->cmd; 2005 cmdlen = 0; 2006 count = 0; 2007 for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2008 cmdlen = F_LEN(cmd); 2009 2010 rw = ipfw_find_op_rw(cmd->opcode); 2011 if (rw == NULL) 2012 continue; 2013 2014 if (rw->classifier(cmd, &kidx, &subtype) != 0) 2015 continue; 2016 2017 bidx = kidx / 32; 2018 /* Maintain separate bitmasks for table and non-table objects */ 2019 if (rw->etlv != IPFW_TLV_TBL_NAME) 2020 bidx += IPFW_TABLES_MAX / 32; 2021 2022 if ((bmask[bidx] & (1 << (kidx % 32))) == 0) 2023 count++; 2024 2025 bmask[bidx] |= 1 << (kidx % 32); 2026 } 2027 2028 return (count); 2029 } 2030 2031 /* 2032 * Dumps requested objects data 2033 * Data layout (version 0)(current): 2034 * Request: [ ipfw_cfg_lheader ] + IPFW_CFG_GET_* flags 2035 * size = ipfw_cfg_lheader.size 2036 * Reply: [ ipfw_cfg_lheader 2037 * [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional) 2038 * [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) 2039 * ipfw_obj_tlv(IPFW_TLV_RULE_ENT) [ ip_fw_bcounter (optional) ip_fw_rule ] 2040 * ] (optional) 2041 * [ ipfw_obj_ctlv(IPFW_TLV_STATE_LIST) ipfw_obj_dyntlv x N ] (optional) 2042 * ] 2043 * * NOTE IPFW_TLV_STATE_LIST has the single valid field: objsize. 2044 * The rest (size, count) are set to zero and needs to be ignored. 2045 * 2046 * Returns 0 on success. 2047 */ 2048 static int 2049 dump_config(struct ip_fw_chain *chain, ip_fw3_opheader *op3, 2050 struct sockopt_data *sd) 2051 { 2052 ipfw_cfg_lheader *hdr; 2053 struct ip_fw *rule; 2054 size_t sz, rnum; 2055 uint32_t hdr_flags; 2056 int error, i; 2057 struct dump_args da; 2058 uint32_t *bmask; 2059 2060 hdr = (ipfw_cfg_lheader *)ipfw_get_sopt_header(sd, sizeof(*hdr)); 2061 if (hdr == NULL) 2062 return (EINVAL); 2063 2064 error = 0; 2065 bmask = NULL; 2066 /* Allocate needed state. Note we allocate 2xspace mask, for table&srv */ 2067 if (hdr->flags & IPFW_CFG_GET_STATIC) 2068 bmask = malloc(IPFW_TABLES_MAX / 4, M_TEMP, M_WAITOK | M_ZERO); 2069 2070 IPFW_UH_RLOCK(chain); 2071 2072 /* 2073 * STAGE 1: Determine size/count for objects in range. 2074 * Prepare used tables bitmask. 2075 */ 2076 sz = sizeof(ipfw_cfg_lheader); 2077 memset(&da, 0, sizeof(da)); 2078 2079 da.b = 0; 2080 da.e = chain->n_rules; 2081 2082 if (hdr->end_rule != 0) { 2083 /* Handle custom range */ 2084 if ((rnum = hdr->start_rule) > IPFW_DEFAULT_RULE) 2085 rnum = IPFW_DEFAULT_RULE; 2086 da.b = ipfw_find_rule(chain, rnum, 0); 2087 rnum = hdr->end_rule; 2088 rnum = (rnum < IPFW_DEFAULT_RULE) ? rnum+1 : IPFW_DEFAULT_RULE; 2089 da.e = ipfw_find_rule(chain, rnum, 0) + 1; 2090 } 2091 2092 if (hdr->flags & IPFW_CFG_GET_STATIC) { 2093 for (i = da.b; i < da.e; i++) { 2094 rule = chain->map[i]; 2095 da.rsize += RULEUSIZE1(rule) + sizeof(ipfw_obj_tlv); 2096 da.rcount++; 2097 /* Update bitmask of used objects for given range */ 2098 da.tcount += mark_object_kidx(chain, rule, bmask); 2099 } 2100 /* Add counters if requested */ 2101 if (hdr->flags & IPFW_CFG_GET_COUNTERS) { 2102 da.rsize += sizeof(struct ip_fw_bcounter) * da.rcount; 2103 da.rcounters = 1; 2104 } 2105 2106 if (da.tcount > 0) 2107 sz += da.tcount * sizeof(ipfw_obj_ntlv) + 2108 sizeof(ipfw_obj_ctlv); 2109 sz += da.rsize + sizeof(ipfw_obj_ctlv); 2110 } 2111 2112 if (hdr->flags & IPFW_CFG_GET_STATES) 2113 sz += ipfw_dyn_get_count() * sizeof(ipfw_obj_dyntlv) + 2114 sizeof(ipfw_obj_ctlv); 2115 2116 2117 /* 2118 * Fill header anyway. 2119 * Note we have to save header fields to stable storage 2120 * buffer inside @sd can be flushed after dumping rules 2121 */ 2122 hdr->size = sz; 2123 hdr->set_mask = ~V_set_disable; 2124 hdr_flags = hdr->flags; 2125 hdr = NULL; 2126 2127 if (sd->valsize < sz) { 2128 error = ENOMEM; 2129 goto cleanup; 2130 } 2131 2132 /* STAGE2: Store actual data */ 2133 if (hdr_flags & IPFW_CFG_GET_STATIC) { 2134 error = dump_static_rules(chain, &da, bmask, sd); 2135 if (error != 0) 2136 goto cleanup; 2137 } 2138 2139 if (hdr_flags & IPFW_CFG_GET_STATES) 2140 error = ipfw_dump_states(chain, sd); 2141 2142 cleanup: 2143 IPFW_UH_RUNLOCK(chain); 2144 2145 if (bmask != NULL) 2146 free(bmask, M_TEMP); 2147 2148 return (error); 2149 } 2150 2151 static int 2152 check_object_name(ipfw_obj_ntlv *ntlv) 2153 { 2154 int error; 2155 2156 switch (ntlv->head.type) { 2157 case IPFW_TLV_TBL_NAME: 2158 error = ipfw_check_table_name(ntlv->name); 2159 break; 2160 default: 2161 error = ENOTSUP; 2162 } 2163 2164 return (0); 2165 } 2166 2167 /* 2168 * Creates non-existent objects referenced by rule. 2169 * 2170 * Return 0 on success. 2171 */ 2172 int 2173 create_objects_compat(struct ip_fw_chain *ch, ipfw_insn *cmd, 2174 struct obj_idx *oib, struct obj_idx *pidx, struct tid_info *ti) 2175 { 2176 struct opcode_obj_rewrite *rw; 2177 struct obj_idx *p; 2178 uint16_t kidx; 2179 int error; 2180 2181 /* 2182 * Compatibility stuff: do actual creation for non-existing, 2183 * but referenced objects. 2184 */ 2185 for (p = oib; p < pidx; p++) { 2186 if (p->kidx != 0) 2187 continue; 2188 2189 ti->uidx = p->uidx; 2190 ti->type = p->type; 2191 ti->atype = 0; 2192 2193 rw = ipfw_find_op_rw((cmd + p->off)->opcode); 2194 KASSERT(rw != NULL, ("Unable to find handler for op %d", 2195 (cmd + p->off)->opcode)); 2196 2197 error = rw->create_object(ch, ti, &kidx); 2198 if (error == 0) { 2199 p->kidx = kidx; 2200 continue; 2201 } 2202 2203 /* 2204 * Error happened. We have to rollback everything. 2205 * Drop all already acquired references. 2206 */ 2207 IPFW_UH_WLOCK(ch); 2208 unref_oib_objects(ch, cmd, oib, pidx); 2209 IPFW_UH_WUNLOCK(ch); 2210 2211 return (error); 2212 } 2213 2214 return (0); 2215 } 2216 2217 /* 2218 * Compatibility function for old ipfw(8) binaries. 2219 * Rewrites table/nat kernel indices with userland ones. 2220 * Convert tables matching '/^\d+$/' to their atoi() value. 2221 * Use number 65535 for other tables. 2222 * 2223 * Returns 0 on success. 2224 */ 2225 static int 2226 set_legacy_obj_kidx(struct ip_fw_chain *ch, struct ip_fw_rule0 *rule) 2227 { 2228 int cmdlen, error, l; 2229 ipfw_insn *cmd; 2230 uint16_t kidx, uidx; 2231 struct named_object *no; 2232 struct opcode_obj_rewrite *rw; 2233 uint8_t subtype; 2234 char *end; 2235 long val; 2236 2237 error = 0; 2238 2239 l = rule->cmd_len; 2240 cmd = rule->cmd; 2241 cmdlen = 0; 2242 for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2243 cmdlen = F_LEN(cmd); 2244 2245 rw = ipfw_find_op_rw(cmd->opcode); 2246 if (rw == NULL) 2247 continue; 2248 2249 /* Check if is index in given opcode */ 2250 if (rw->classifier(cmd, &kidx, &subtype) != 0) 2251 continue; 2252 2253 /* Try to find referenced kernel object */ 2254 no = rw->find_bykidx(ch, kidx); 2255 if (no == NULL) 2256 continue; 2257 2258 val = strtol(no->name, &end, 10); 2259 if (*end == '\0' && val < 65535) { 2260 uidx = val; 2261 } else { 2262 2263 /* 2264 * We are called via legacy opcode. 2265 * Save error and show table as fake number 2266 * not to make ipfw(8) hang. 2267 */ 2268 uidx = 65535; 2269 error = 2; 2270 } 2271 2272 rw->update(cmd, uidx); 2273 } 2274 2275 return (error); 2276 } 2277 2278 2279 /* 2280 * Unreferences all already-referenced objects in given @cmd rule, 2281 * using information in @oib. 2282 * 2283 * Used to rollback partially converted rule on error. 2284 */ 2285 void 2286 unref_oib_objects(struct ip_fw_chain *ch, ipfw_insn *cmd, struct obj_idx *oib, 2287 struct obj_idx *end) 2288 { 2289 struct opcode_obj_rewrite *rw; 2290 struct named_object *no; 2291 struct obj_idx *p; 2292 2293 IPFW_UH_WLOCK_ASSERT(ch); 2294 2295 for (p = oib; p < end; p++) { 2296 if (p->kidx == 0) 2297 continue; 2298 2299 rw = ipfw_find_op_rw((cmd + p->off)->opcode); 2300 KASSERT(rw != NULL, ("Unable to find handler for op %d", 2301 (cmd + p->off)->opcode)); 2302 2303 /* Find & unref by existing idx */ 2304 no = rw->find_bykidx(ch, p->kidx); 2305 KASSERT(no != NULL, ("Ref'd object %d disappeared", p->kidx)); 2306 no->refcnt--; 2307 } 2308 } 2309 2310 /* 2311 * Remove references from every object used in @rule. 2312 * Used at rule removal code. 2313 */ 2314 static void 2315 unref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule) 2316 { 2317 int cmdlen, l; 2318 ipfw_insn *cmd; 2319 struct named_object *no; 2320 uint16_t kidx; 2321 struct opcode_obj_rewrite *rw; 2322 uint8_t subtype; 2323 2324 IPFW_UH_WLOCK_ASSERT(ch); 2325 2326 l = rule->cmd_len; 2327 cmd = rule->cmd; 2328 cmdlen = 0; 2329 for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2330 cmdlen = F_LEN(cmd); 2331 2332 rw = ipfw_find_op_rw(cmd->opcode); 2333 if (rw == NULL) 2334 continue; 2335 if (rw->classifier(cmd, &kidx, &subtype) != 0) 2336 continue; 2337 2338 no = rw->find_bykidx(ch, kidx); 2339 2340 KASSERT(no != NULL, ("table id %d not found", kidx)); 2341 KASSERT(no->subtype == subtype, 2342 ("wrong type %d (%d) for table id %d", 2343 no->subtype, subtype, kidx)); 2344 KASSERT(no->refcnt > 0, ("refcount for table %d is %d", 2345 kidx, no->refcnt)); 2346 2347 no->refcnt--; 2348 } 2349 } 2350 2351 2352 /* 2353 * Find and reference object (if any) stored in instruction @cmd. 2354 * 2355 * Saves object info in @pidx, sets 2356 * - @found to 1 if object was found and references 2357 * - @unresolved to 1 if object should exists but not found 2358 * 2359 * Returns non-zero value in case of error. 2360 */ 2361 int 2362 ref_opcode_object(struct ip_fw_chain *ch, ipfw_insn *cmd, struct tid_info *ti, 2363 struct obj_idx *pidx, int *found, int *unresolved) 2364 { 2365 struct named_object *no; 2366 struct opcode_obj_rewrite *rw; 2367 int error; 2368 2369 *found = 0; 2370 *unresolved = 0; 2371 2372 /* Check if this opcode is candidate for rewrite */ 2373 rw = ipfw_find_op_rw(cmd->opcode); 2374 if (rw == NULL) 2375 return (0); 2376 2377 /* Check if we need to rewrite this opcode */ 2378 if (rw->classifier(cmd, &ti->uidx, &ti->type) != 0) 2379 return (0); 2380 2381 /* Need to rewrite. Save necessary fields */ 2382 pidx->uidx = ti->uidx; 2383 pidx->type = ti->type; 2384 2385 /* Try to find referenced kernel object */ 2386 error = rw->find_byname(ch, ti, &no); 2387 if (error != 0) 2388 return (error); 2389 if (no == NULL) { 2390 *unresolved = 1; 2391 return (0); 2392 } 2393 2394 /* Found. bump refcount */ 2395 *found = 1; 2396 no->refcnt++; 2397 pidx->kidx = no->kidx; 2398 2399 return (0); 2400 } 2401 2402 /* 2403 * Adds one or more rules to ipfw @chain. 2404 * Data layout (version 0)(current): 2405 * Request: 2406 * [ 2407 * ip_fw3_opheader 2408 * [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional *1) 2409 * [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) ip_fw x N ] (*2) (*3) 2410 * ] 2411 * Reply: 2412 * [ 2413 * ip_fw3_opheader 2414 * [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional) 2415 * [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) ip_fw x N ] 2416 * ] 2417 * 2418 * Rules in reply are modified to store their actual ruleset number. 2419 * 2420 * (*1) TLVs inside IPFW_TLV_TBL_LIST needs to be sorted ascending 2421 * accoring to their idx field and there has to be no duplicates. 2422 * (*2) Numbered rules inside IPFW_TLV_RULE_LIST needs to be sorted ascending. 2423 * (*3) Each ip_fw structure needs to be aligned to u64 boundary. 2424 * 2425 * Returns 0 on success. 2426 */ 2427 static int 2428 add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, 2429 struct sockopt_data *sd) 2430 { 2431 ipfw_obj_ctlv *ctlv, *rtlv, *tstate; 2432 ipfw_obj_ntlv *ntlv; 2433 int clen, error, idx; 2434 uint32_t count, read; 2435 struct ip_fw_rule *r; 2436 struct rule_check_info rci, *ci, *cbuf; 2437 int i, rsize; 2438 2439 op3 = (ip_fw3_opheader *)ipfw_get_sopt_space(sd, sd->valsize); 2440 ctlv = (ipfw_obj_ctlv *)(op3 + 1); 2441 2442 read = sizeof(ip_fw3_opheader); 2443 rtlv = NULL; 2444 tstate = NULL; 2445 cbuf = NULL; 2446 memset(&rci, 0, sizeof(struct rule_check_info)); 2447 2448 if (read + sizeof(*ctlv) > sd->valsize) 2449 return (EINVAL); 2450 2451 if (ctlv->head.type == IPFW_TLV_TBLNAME_LIST) { 2452 clen = ctlv->head.length; 2453 /* Check size and alignment */ 2454 if (clen > sd->valsize || clen < sizeof(*ctlv)) 2455 return (EINVAL); 2456 if ((clen % sizeof(uint64_t)) != 0) 2457 return (EINVAL); 2458 2459 /* 2460 * Some table names or other named objects. 2461 * Check for validness. 2462 */ 2463 count = (ctlv->head.length - sizeof(*ctlv)) / sizeof(*ntlv); 2464 if (ctlv->count != count || ctlv->objsize != sizeof(*ntlv)) 2465 return (EINVAL); 2466 2467 /* 2468 * Check each TLV. 2469 * Ensure TLVs are sorted ascending and 2470 * there are no duplicates. 2471 */ 2472 idx = -1; 2473 ntlv = (ipfw_obj_ntlv *)(ctlv + 1); 2474 while (count > 0) { 2475 if (ntlv->head.length != sizeof(ipfw_obj_ntlv)) 2476 return (EINVAL); 2477 2478 error = check_object_name(ntlv); 2479 if (error != 0) 2480 return (error); 2481 2482 if (ntlv->idx <= idx) 2483 return (EINVAL); 2484 2485 idx = ntlv->idx; 2486 count--; 2487 ntlv++; 2488 } 2489 2490 tstate = ctlv; 2491 read += ctlv->head.length; 2492 ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length); 2493 } 2494 2495 if (read + sizeof(*ctlv) > sd->valsize) 2496 return (EINVAL); 2497 2498 if (ctlv->head.type == IPFW_TLV_RULE_LIST) { 2499 clen = ctlv->head.length; 2500 if (clen + read > sd->valsize || clen < sizeof(*ctlv)) 2501 return (EINVAL); 2502 if ((clen % sizeof(uint64_t)) != 0) 2503 return (EINVAL); 2504 2505 /* 2506 * TODO: Permit adding multiple rules at once 2507 */ 2508 if (ctlv->count != 1) 2509 return (ENOTSUP); 2510 2511 clen -= sizeof(*ctlv); 2512 2513 if (ctlv->count > clen / sizeof(struct ip_fw_rule)) 2514 return (EINVAL); 2515 2516 /* Allocate state for each rule or use stack */ 2517 if (ctlv->count == 1) { 2518 memset(&rci, 0, sizeof(struct rule_check_info)); 2519 cbuf = &rci; 2520 } else 2521 cbuf = malloc(ctlv->count * sizeof(*ci), M_TEMP, 2522 M_WAITOK | M_ZERO); 2523 ci = cbuf; 2524 2525 /* 2526 * Check each rule for validness. 2527 * Ensure numbered rules are sorted ascending 2528 * and properly aligned 2529 */ 2530 idx = 0; 2531 r = (struct ip_fw_rule *)(ctlv + 1); 2532 count = 0; 2533 error = 0; 2534 while (clen > 0) { 2535 rsize = roundup2(RULESIZE(r), sizeof(uint64_t)); 2536 if (rsize > clen || ctlv->count <= count) { 2537 error = EINVAL; 2538 break; 2539 } 2540 2541 ci->ctlv = tstate; 2542 error = check_ipfw_rule1(r, rsize, ci); 2543 if (error != 0) 2544 break; 2545 2546 /* Check sorting */ 2547 if (r->rulenum != 0 && r->rulenum < idx) { 2548 printf("rulenum %d idx %d\n", r->rulenum, idx); 2549 error = EINVAL; 2550 break; 2551 } 2552 idx = r->rulenum; 2553 2554 ci->urule = (caddr_t)r; 2555 2556 rsize = roundup2(rsize, sizeof(uint64_t)); 2557 clen -= rsize; 2558 r = (struct ip_fw_rule *)((caddr_t)r + rsize); 2559 count++; 2560 ci++; 2561 } 2562 2563 if (ctlv->count != count || error != 0) { 2564 if (cbuf != &rci) 2565 free(cbuf, M_TEMP); 2566 return (EINVAL); 2567 } 2568 2569 rtlv = ctlv; 2570 read += ctlv->head.length; 2571 ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length); 2572 } 2573 2574 if (read != sd->valsize || rtlv == NULL || rtlv->count == 0) { 2575 if (cbuf != NULL && cbuf != &rci) 2576 free(cbuf, M_TEMP); 2577 return (EINVAL); 2578 } 2579 2580 /* 2581 * Passed rules seems to be valid. 2582 * Allocate storage and try to add them to chain. 2583 */ 2584 for (i = 0, ci = cbuf; i < rtlv->count; i++, ci++) { 2585 clen = RULEKSIZE1((struct ip_fw_rule *)ci->urule); 2586 ci->krule = ipfw_alloc_rule(chain, clen); 2587 import_rule1(ci); 2588 } 2589 2590 if ((error = commit_rules(chain, cbuf, rtlv->count)) != 0) { 2591 /* Free allocate krules */ 2592 for (i = 0, ci = cbuf; i < rtlv->count; i++, ci++) 2593 free(ci->krule, M_IPFW); 2594 } 2595 2596 if (cbuf != NULL && cbuf != &rci) 2597 free(cbuf, M_TEMP); 2598 2599 return (error); 2600 } 2601 2602 /* 2603 * Lists all sopts currently registered. 2604 * Data layout (v0)(current): 2605 * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size 2606 * Reply: [ ipfw_obj_lheader ipfw_sopt_info x N ] 2607 * 2608 * Returns 0 on success 2609 */ 2610 static int 2611 dump_soptcodes(struct ip_fw_chain *chain, ip_fw3_opheader *op3, 2612 struct sockopt_data *sd) 2613 { 2614 struct _ipfw_obj_lheader *olh; 2615 ipfw_sopt_info *i; 2616 struct ipfw_sopt_handler *sh; 2617 uint32_t count, n, size; 2618 2619 olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh)); 2620 if (olh == NULL) 2621 return (EINVAL); 2622 if (sd->valsize < olh->size) 2623 return (EINVAL); 2624 2625 CTL3_LOCK(); 2626 count = ctl3_hsize; 2627 size = count * sizeof(ipfw_sopt_info) + sizeof(ipfw_obj_lheader); 2628 2629 /* Fill in header regadless of buffer size */ 2630 olh->count = count; 2631 olh->objsize = sizeof(ipfw_sopt_info); 2632 2633 if (size > olh->size) { 2634 olh->size = size; 2635 CTL3_UNLOCK(); 2636 return (ENOMEM); 2637 } 2638 olh->size = size; 2639 2640 for (n = 1; n <= count; n++) { 2641 i = (ipfw_sopt_info *)ipfw_get_sopt_space(sd, sizeof(*i)); 2642 KASSERT(i != 0, ("previously checked buffer is not enough")); 2643 sh = &ctl3_handlers[n]; 2644 i->opcode = sh->opcode; 2645 i->version = sh->version; 2646 i->refcnt = sh->refcnt; 2647 } 2648 CTL3_UNLOCK(); 2649 2650 return (0); 2651 } 2652 2653 /* 2654 * Compares two opcodes. 2655 * Used both in qsort() and bsearch(). 2656 * 2657 * Returns 0 if match is found. 2658 */ 2659 static int 2660 compare_opcodes(const void *_a, const void *_b) 2661 { 2662 const struct opcode_obj_rewrite *a, *b; 2663 2664 a = (const struct opcode_obj_rewrite *)_a; 2665 b = (const struct opcode_obj_rewrite *)_b; 2666 2667 if (a->opcode < b->opcode) 2668 return (-1); 2669 else if (a->opcode > b->opcode) 2670 return (1); 2671 2672 return (0); 2673 } 2674 2675 /* 2676 * Finds opcode object rewriter based on @code. 2677 * 2678 * Returns pointer to handler or NULL. 2679 */ 2680 struct opcode_obj_rewrite * 2681 ipfw_find_op_rw(uint16_t opcode) 2682 { 2683 struct opcode_obj_rewrite *rw, h; 2684 2685 memset(&h, 0, sizeof(h)); 2686 h.opcode = opcode; 2687 2688 rw = (struct opcode_obj_rewrite *)bsearch(&h, ctl3_rewriters, 2689 ctl3_rsize, sizeof(h), compare_opcodes); 2690 2691 return (rw); 2692 } 2693 2694 int 2695 classify_opcode_kidx(ipfw_insn *cmd, uint16_t *puidx) 2696 { 2697 struct opcode_obj_rewrite *rw; 2698 uint8_t subtype; 2699 2700 rw = ipfw_find_op_rw(cmd->opcode); 2701 if (rw == NULL) 2702 return (1); 2703 2704 return (rw->classifier(cmd, puidx, &subtype)); 2705 } 2706 2707 void 2708 update_opcode_kidx(ipfw_insn *cmd, uint16_t idx) 2709 { 2710 struct opcode_obj_rewrite *rw; 2711 2712 rw = ipfw_find_op_rw(cmd->opcode); 2713 KASSERT(rw != NULL, ("No handler to update opcode %d", cmd->opcode)); 2714 rw->update(cmd, idx); 2715 } 2716 2717 void 2718 ipfw_init_obj_rewriter() 2719 { 2720 2721 ctl3_rewriters = NULL; 2722 ctl3_rsize = 0; 2723 } 2724 2725 void 2726 ipfw_destroy_obj_rewriter() 2727 { 2728 2729 if (ctl3_rewriters != NULL) 2730 free(ctl3_rewriters, M_IPFW); 2731 ctl3_rewriters = NULL; 2732 ctl3_rsize = 0; 2733 } 2734 2735 /* 2736 * Adds one or more opcode object rewrite handlers to the global array. 2737 * Function may sleep. 2738 */ 2739 void 2740 ipfw_add_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count) 2741 { 2742 size_t sz; 2743 struct opcode_obj_rewrite *tmp; 2744 2745 CTL3_LOCK(); 2746 2747 for (;;) { 2748 sz = ctl3_rsize + count; 2749 CTL3_UNLOCK(); 2750 tmp = malloc(sizeof(*rw) * sz, M_IPFW, M_WAITOK | M_ZERO); 2751 CTL3_LOCK(); 2752 if (ctl3_rsize + count <= sz) 2753 break; 2754 2755 /* Retry */ 2756 free(tmp, M_IPFW); 2757 } 2758 2759 /* Merge old & new arrays */ 2760 sz = ctl3_rsize + count; 2761 memcpy(tmp, ctl3_rewriters, ctl3_rsize * sizeof(*rw)); 2762 memcpy(&tmp[ctl3_rsize], rw, count * sizeof(*rw)); 2763 qsort(tmp, sz, sizeof(*rw), compare_opcodes); 2764 /* Switch new and free old */ 2765 if (ctl3_rewriters != NULL) 2766 free(ctl3_rewriters, M_IPFW); 2767 ctl3_rewriters = tmp; 2768 ctl3_rsize = sz; 2769 2770 CTL3_UNLOCK(); 2771 } 2772 2773 /* 2774 * Removes one or more object rewrite handlers from the global array. 2775 */ 2776 int 2777 ipfw_del_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count) 2778 { 2779 size_t sz; 2780 struct opcode_obj_rewrite *tmp, *h; 2781 int i; 2782 2783 CTL3_LOCK(); 2784 2785 for (i = 0; i < count; i++) { 2786 tmp = &rw[i]; 2787 h = ipfw_find_op_rw(tmp->opcode); 2788 if (h == NULL) 2789 continue; 2790 2791 sz = (ctl3_rewriters + ctl3_rsize - (h + 1)) * sizeof(*h); 2792 memmove(h, h + 1, sz); 2793 ctl3_rsize--; 2794 } 2795 2796 if (ctl3_rsize == 0) { 2797 if (ctl3_rewriters != NULL) 2798 free(ctl3_rewriters, M_IPFW); 2799 ctl3_rewriters = NULL; 2800 } 2801 2802 CTL3_UNLOCK(); 2803 2804 return (0); 2805 } 2806 2807 /* 2808 * Compares two sopt handlers (code, version and handler ptr). 2809 * Used both as qsort() and bsearch(). 2810 * Does not compare handler for latter case. 2811 * 2812 * Returns 0 if match is found. 2813 */ 2814 static int 2815 compare_sh(const void *_a, const void *_b) 2816 { 2817 const struct ipfw_sopt_handler *a, *b; 2818 2819 a = (const struct ipfw_sopt_handler *)_a; 2820 b = (const struct ipfw_sopt_handler *)_b; 2821 2822 if (a->opcode < b->opcode) 2823 return (-1); 2824 else if (a->opcode > b->opcode) 2825 return (1); 2826 2827 if (a->version < b->version) 2828 return (-1); 2829 else if (a->version > b->version) 2830 return (1); 2831 2832 /* bsearch helper */ 2833 if (a->handler == NULL) 2834 return (0); 2835 2836 if ((uintptr_t)a->handler < (uintptr_t)b->handler) 2837 return (-1); 2838 else if ((uintptr_t)b->handler > (uintptr_t)b->handler) 2839 return (1); 2840 2841 return (0); 2842 } 2843 2844 /* 2845 * Finds sopt handler based on @code and @version. 2846 * 2847 * Returns pointer to handler or NULL. 2848 */ 2849 static struct ipfw_sopt_handler * 2850 find_sh(uint16_t code, uint8_t version, void *handler) 2851 { 2852 struct ipfw_sopt_handler *sh, h; 2853 2854 memset(&h, 0, sizeof(h)); 2855 h.opcode = code; 2856 h.version = version; 2857 h.handler = handler; 2858 2859 sh = (struct ipfw_sopt_handler *)bsearch(&h, ctl3_handlers, 2860 ctl3_hsize, sizeof(h), compare_sh); 2861 2862 return (sh); 2863 } 2864 2865 static int 2866 find_ref_sh(uint16_t opcode, uint8_t version, struct ipfw_sopt_handler *psh) 2867 { 2868 struct ipfw_sopt_handler *sh; 2869 2870 CTL3_LOCK(); 2871 if ((sh = find_sh(opcode, version, NULL)) == NULL) { 2872 CTL3_UNLOCK(); 2873 printf("ipfw: ipfw_ctl3 invalid option %d""v""%d\n", 2874 opcode, version); 2875 return (EINVAL); 2876 } 2877 sh->refcnt++; 2878 ctl3_refct++; 2879 /* Copy handler data to requested buffer */ 2880 *psh = *sh; 2881 CTL3_UNLOCK(); 2882 2883 return (0); 2884 } 2885 2886 static void 2887 find_unref_sh(struct ipfw_sopt_handler *psh) 2888 { 2889 struct ipfw_sopt_handler *sh; 2890 2891 CTL3_LOCK(); 2892 sh = find_sh(psh->opcode, psh->version, NULL); 2893 KASSERT(sh != NULL, ("ctl3 handler disappeared")); 2894 sh->refcnt--; 2895 ctl3_refct--; 2896 CTL3_UNLOCK(); 2897 } 2898 2899 void 2900 ipfw_init_sopt_handler() 2901 { 2902 2903 CTL3_LOCK_INIT(); 2904 IPFW_ADD_SOPT_HANDLER(1, scodes); 2905 } 2906 2907 void 2908 ipfw_destroy_sopt_handler() 2909 { 2910 2911 IPFW_DEL_SOPT_HANDLER(1, scodes); 2912 CTL3_LOCK_DESTROY(); 2913 } 2914 2915 /* 2916 * Adds one or more sockopt handlers to the global array. 2917 * Function may sleep. 2918 */ 2919 void 2920 ipfw_add_sopt_handler(struct ipfw_sopt_handler *sh, size_t count) 2921 { 2922 size_t sz; 2923 struct ipfw_sopt_handler *tmp; 2924 2925 CTL3_LOCK(); 2926 2927 for (;;) { 2928 sz = ctl3_hsize + count; 2929 CTL3_UNLOCK(); 2930 tmp = malloc(sizeof(*sh) * sz, M_IPFW, M_WAITOK | M_ZERO); 2931 CTL3_LOCK(); 2932 if (ctl3_hsize + count <= sz) 2933 break; 2934 2935 /* Retry */ 2936 free(tmp, M_IPFW); 2937 } 2938 2939 /* Merge old & new arrays */ 2940 sz = ctl3_hsize + count; 2941 memcpy(tmp, ctl3_handlers, ctl3_hsize * sizeof(*sh)); 2942 memcpy(&tmp[ctl3_hsize], sh, count * sizeof(*sh)); 2943 qsort(tmp, sz, sizeof(*sh), compare_sh); 2944 /* Switch new and free old */ 2945 if (ctl3_handlers != NULL) 2946 free(ctl3_handlers, M_IPFW); 2947 ctl3_handlers = tmp; 2948 ctl3_hsize = sz; 2949 ctl3_gencnt++; 2950 2951 CTL3_UNLOCK(); 2952 } 2953 2954 /* 2955 * Removes one or more sockopt handlers from the global array. 2956 */ 2957 int 2958 ipfw_del_sopt_handler(struct ipfw_sopt_handler *sh, size_t count) 2959 { 2960 size_t sz; 2961 struct ipfw_sopt_handler *tmp, *h; 2962 int i; 2963 2964 CTL3_LOCK(); 2965 2966 for (i = 0; i < count; i++) { 2967 tmp = &sh[i]; 2968 h = find_sh(tmp->opcode, tmp->version, tmp->handler); 2969 if (h == NULL) 2970 continue; 2971 2972 sz = (ctl3_handlers + ctl3_hsize - (h + 1)) * sizeof(*h); 2973 memmove(h, h + 1, sz); 2974 ctl3_hsize--; 2975 } 2976 2977 if (ctl3_hsize == 0) { 2978 if (ctl3_handlers != NULL) 2979 free(ctl3_handlers, M_IPFW); 2980 ctl3_handlers = NULL; 2981 } 2982 2983 ctl3_gencnt++; 2984 2985 CTL3_UNLOCK(); 2986 2987 return (0); 2988 } 2989 2990 /* 2991 * Writes data accumulated in @sd to sockopt buffer. 2992 * Zeroes internal @sd buffer. 2993 */ 2994 static int 2995 ipfw_flush_sopt_data(struct sockopt_data *sd) 2996 { 2997 struct sockopt *sopt; 2998 int error; 2999 size_t sz; 3000 3001 sz = sd->koff; 3002 if (sz == 0) 3003 return (0); 3004 3005 sopt = sd->sopt; 3006 3007 if (sopt->sopt_dir == SOPT_GET) { 3008 error = copyout(sd->kbuf, sopt->sopt_val, sz); 3009 if (error != 0) 3010 return (error); 3011 } 3012 3013 memset(sd->kbuf, 0, sd->ksize); 3014 sd->ktotal += sz; 3015 sd->koff = 0; 3016 if (sd->ktotal + sd->ksize < sd->valsize) 3017 sd->kavail = sd->ksize; 3018 else 3019 sd->kavail = sd->valsize - sd->ktotal; 3020 3021 /* Update sopt buffer data */ 3022 sopt->sopt_valsize = sd->ktotal; 3023 sopt->sopt_val = sd->sopt_val + sd->ktotal; 3024 3025 return (0); 3026 } 3027 3028 /* 3029 * Ensures that @sd buffer has contigious @neeeded number of 3030 * bytes. 3031 * 3032 * Returns pointer to requested space or NULL. 3033 */ 3034 caddr_t 3035 ipfw_get_sopt_space(struct sockopt_data *sd, size_t needed) 3036 { 3037 int error; 3038 caddr_t addr; 3039 3040 if (sd->kavail < needed) { 3041 /* 3042 * Flush data and try another time. 3043 */ 3044 error = ipfw_flush_sopt_data(sd); 3045 3046 if (sd->kavail < needed || error != 0) 3047 return (NULL); 3048 } 3049 3050 addr = sd->kbuf + sd->koff; 3051 sd->koff += needed; 3052 sd->kavail -= needed; 3053 return (addr); 3054 } 3055 3056 /* 3057 * Requests @needed contigious bytes from @sd buffer. 3058 * Function is used to notify subsystem that we are 3059 * interesed in first @needed bytes (request header) 3060 * and the rest buffer can be safely zeroed. 3061 * 3062 * Returns pointer to requested space or NULL. 3063 */ 3064 caddr_t 3065 ipfw_get_sopt_header(struct sockopt_data *sd, size_t needed) 3066 { 3067 caddr_t addr; 3068 3069 if ((addr = ipfw_get_sopt_space(sd, needed)) == NULL) 3070 return (NULL); 3071 3072 if (sd->kavail > 0) 3073 memset(sd->kbuf + sd->koff, 0, sd->kavail); 3074 3075 return (addr); 3076 } 3077 3078 /* 3079 * New sockopt handler. 3080 */ 3081 int 3082 ipfw_ctl3(struct sockopt *sopt) 3083 { 3084 int error, locked; 3085 size_t size, valsize; 3086 struct ip_fw_chain *chain; 3087 char xbuf[256]; 3088 struct sockopt_data sdata; 3089 struct ipfw_sopt_handler h; 3090 ip_fw3_opheader *op3 = NULL; 3091 3092 error = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW); 3093 if (error != 0) 3094 return (error); 3095 3096 if (sopt->sopt_name != IP_FW3) 3097 return (ipfw_ctl(sopt)); 3098 3099 chain = &V_layer3_chain; 3100 error = 0; 3101 3102 /* Save original valsize before it is altered via sooptcopyin() */ 3103 valsize = sopt->sopt_valsize; 3104 memset(&sdata, 0, sizeof(sdata)); 3105 /* Read op3 header first to determine actual operation */ 3106 op3 = (ip_fw3_opheader *)xbuf; 3107 error = sooptcopyin(sopt, op3, sizeof(*op3), sizeof(*op3)); 3108 if (error != 0) 3109 return (error); 3110 sopt->sopt_valsize = valsize; 3111 3112 /* 3113 * Find and reference command. 3114 */ 3115 error = find_ref_sh(op3->opcode, op3->version, &h); 3116 if (error != 0) 3117 return (error); 3118 3119 /* 3120 * Disallow modifications in really-really secure mode, but still allow 3121 * the logging counters to be reset. 3122 */ 3123 if ((h.dir & HDIR_SET) != 0 && h.opcode != IP_FW_XRESETLOG) { 3124 error = securelevel_ge(sopt->sopt_td->td_ucred, 3); 3125 if (error != 0) { 3126 find_unref_sh(&h); 3127 return (error); 3128 } 3129 } 3130 3131 /* 3132 * Fill in sockopt_data structure that may be useful for 3133 * IP_FW3 get requests. 3134 */ 3135 locked = 0; 3136 if (valsize <= sizeof(xbuf)) { 3137 /* use on-stack buffer */ 3138 sdata.kbuf = xbuf; 3139 sdata.ksize = sizeof(xbuf); 3140 sdata.kavail = valsize; 3141 } else { 3142 3143 /* 3144 * Determine opcode type/buffer size: 3145 * allocate sliding-window buf for data export or 3146 * contigious buffer for special ops. 3147 */ 3148 if ((h.dir & HDIR_SET) != 0) { 3149 /* Set request. Allocate contigous buffer. */ 3150 if (valsize > CTL3_LARGEBUF) { 3151 find_unref_sh(&h); 3152 return (EFBIG); 3153 } 3154 3155 size = valsize; 3156 } else { 3157 /* Get request. Allocate sliding window buffer */ 3158 size = (valsize<CTL3_SMALLBUF) ? valsize:CTL3_SMALLBUF; 3159 3160 if (size < valsize) { 3161 /* We have to wire user buffer */ 3162 error = vslock(sopt->sopt_val, valsize); 3163 if (error != 0) 3164 return (error); 3165 locked = 1; 3166 } 3167 } 3168 3169 sdata.kbuf = malloc(size, M_TEMP, M_WAITOK | M_ZERO); 3170 sdata.ksize = size; 3171 sdata.kavail = size; 3172 } 3173 3174 sdata.sopt = sopt; 3175 sdata.sopt_val = sopt->sopt_val; 3176 sdata.valsize = valsize; 3177 3178 /* 3179 * Copy either all request (if valsize < bsize_max) 3180 * or first bsize_max bytes to guarantee most consumers 3181 * that all necessary data has been copied). 3182 * Anyway, copy not less than sizeof(ip_fw3_opheader). 3183 */ 3184 if ((error = sooptcopyin(sopt, sdata.kbuf, sdata.ksize, 3185 sizeof(ip_fw3_opheader))) != 0) 3186 return (error); 3187 op3 = (ip_fw3_opheader *)sdata.kbuf; 3188 3189 /* Finally, run handler */ 3190 error = h.handler(chain, op3, &sdata); 3191 find_unref_sh(&h); 3192 3193 /* Flush state and free buffers */ 3194 if (error == 0) 3195 error = ipfw_flush_sopt_data(&sdata); 3196 else 3197 ipfw_flush_sopt_data(&sdata); 3198 3199 if (locked != 0) 3200 vsunlock(sdata.sopt_val, valsize); 3201 3202 /* Restore original pointer and set number of bytes written */ 3203 sopt->sopt_val = sdata.sopt_val; 3204 sopt->sopt_valsize = sdata.ktotal; 3205 if (sdata.kbuf != xbuf) 3206 free(sdata.kbuf, M_TEMP); 3207 3208 return (error); 3209 } 3210 3211 /** 3212 * {set|get}sockopt parser. 3213 */ 3214 int 3215 ipfw_ctl(struct sockopt *sopt) 3216 { 3217 #define RULE_MAXSIZE (512*sizeof(u_int32_t)) 3218 int error; 3219 size_t size, valsize; 3220 struct ip_fw *buf; 3221 struct ip_fw_rule0 *rule; 3222 struct ip_fw_chain *chain; 3223 u_int32_t rulenum[2]; 3224 uint32_t opt; 3225 struct rule_check_info ci; 3226 IPFW_RLOCK_TRACKER; 3227 3228 chain = &V_layer3_chain; 3229 error = 0; 3230 3231 /* Save original valsize before it is altered via sooptcopyin() */ 3232 valsize = sopt->sopt_valsize; 3233 opt = sopt->sopt_name; 3234 3235 /* 3236 * Disallow modifications in really-really secure mode, but still allow 3237 * the logging counters to be reset. 3238 */ 3239 if (opt == IP_FW_ADD || 3240 (sopt->sopt_dir == SOPT_SET && opt != IP_FW_RESETLOG)) { 3241 error = securelevel_ge(sopt->sopt_td->td_ucred, 3); 3242 if (error != 0) 3243 return (error); 3244 } 3245 3246 switch (opt) { 3247 case IP_FW_GET: 3248 /* 3249 * pass up a copy of the current rules. Static rules 3250 * come first (the last of which has number IPFW_DEFAULT_RULE), 3251 * followed by a possibly empty list of dynamic rule. 3252 * The last dynamic rule has NULL in the "next" field. 3253 * 3254 * Note that the calculated size is used to bound the 3255 * amount of data returned to the user. The rule set may 3256 * change between calculating the size and returning the 3257 * data in which case we'll just return what fits. 3258 */ 3259 for (;;) { 3260 int len = 0, want; 3261 3262 size = chain->static_len; 3263 size += ipfw_dyn_len(); 3264 if (size >= sopt->sopt_valsize) 3265 break; 3266 buf = malloc(size, M_TEMP, M_WAITOK | M_ZERO); 3267 IPFW_UH_RLOCK(chain); 3268 /* check again how much space we need */ 3269 want = chain->static_len + ipfw_dyn_len(); 3270 if (size >= want) 3271 len = ipfw_getrules(chain, buf, size); 3272 IPFW_UH_RUNLOCK(chain); 3273 if (size >= want) 3274 error = sooptcopyout(sopt, buf, len); 3275 free(buf, M_TEMP); 3276 if (size >= want) 3277 break; 3278 } 3279 break; 3280 3281 case IP_FW_FLUSH: 3282 /* locking is done within del_entry() */ 3283 error = del_entry(chain, 0); /* special case, rule=0, cmd=0 means all */ 3284 break; 3285 3286 case IP_FW_ADD: 3287 rule = malloc(RULE_MAXSIZE, M_TEMP, M_WAITOK); 3288 error = sooptcopyin(sopt, rule, RULE_MAXSIZE, 3289 sizeof(struct ip_fw7) ); 3290 3291 memset(&ci, 0, sizeof(struct rule_check_info)); 3292 3293 /* 3294 * If the size of commands equals RULESIZE7 then we assume 3295 * a FreeBSD7.2 binary is talking to us (set is7=1). 3296 * is7 is persistent so the next 'ipfw list' command 3297 * will use this format. 3298 * NOTE: If wrong version is guessed (this can happen if 3299 * the first ipfw command is 'ipfw [pipe] list') 3300 * the ipfw binary may crash or loop infinitly... 3301 */ 3302 size = sopt->sopt_valsize; 3303 if (size == RULESIZE7(rule)) { 3304 is7 = 1; 3305 error = convert_rule_to_8(rule); 3306 if (error) { 3307 free(rule, M_TEMP); 3308 return error; 3309 } 3310 size = RULESIZE(rule); 3311 } else 3312 is7 = 0; 3313 if (error == 0) 3314 error = check_ipfw_rule0(rule, size, &ci); 3315 if (error == 0) { 3316 /* locking is done within add_rule() */ 3317 struct ip_fw *krule; 3318 krule = ipfw_alloc_rule(chain, RULEKSIZE0(rule)); 3319 ci.urule = (caddr_t)rule; 3320 ci.krule = krule; 3321 import_rule0(&ci); 3322 error = commit_rules(chain, &ci, 1); 3323 if (!error && sopt->sopt_dir == SOPT_GET) { 3324 if (is7) { 3325 error = convert_rule_to_7(rule); 3326 size = RULESIZE7(rule); 3327 if (error) { 3328 free(rule, M_TEMP); 3329 return error; 3330 } 3331 } 3332 error = sooptcopyout(sopt, rule, size); 3333 } 3334 } 3335 free(rule, M_TEMP); 3336 break; 3337 3338 case IP_FW_DEL: 3339 /* 3340 * IP_FW_DEL is used for deleting single rules or sets, 3341 * and (ab)used to atomically manipulate sets. Argument size 3342 * is used to distinguish between the two: 3343 * sizeof(u_int32_t) 3344 * delete single rule or set of rules, 3345 * or reassign rules (or sets) to a different set. 3346 * 2*sizeof(u_int32_t) 3347 * atomic disable/enable sets. 3348 * first u_int32_t contains sets to be disabled, 3349 * second u_int32_t contains sets to be enabled. 3350 */ 3351 error = sooptcopyin(sopt, rulenum, 3352 2*sizeof(u_int32_t), sizeof(u_int32_t)); 3353 if (error) 3354 break; 3355 size = sopt->sopt_valsize; 3356 if (size == sizeof(u_int32_t) && rulenum[0] != 0) { 3357 /* delete or reassign, locking done in del_entry() */ 3358 error = del_entry(chain, rulenum[0]); 3359 } else if (size == 2*sizeof(u_int32_t)) { /* set enable/disable */ 3360 IPFW_UH_WLOCK(chain); 3361 V_set_disable = 3362 (V_set_disable | rulenum[0]) & ~rulenum[1] & 3363 ~(1<<RESVD_SET); /* set RESVD_SET always enabled */ 3364 IPFW_UH_WUNLOCK(chain); 3365 } else 3366 error = EINVAL; 3367 break; 3368 3369 case IP_FW_ZERO: 3370 case IP_FW_RESETLOG: /* argument is an u_int_32, the rule number */ 3371 rulenum[0] = 0; 3372 if (sopt->sopt_val != 0) { 3373 error = sooptcopyin(sopt, rulenum, 3374 sizeof(u_int32_t), sizeof(u_int32_t)); 3375 if (error) 3376 break; 3377 } 3378 error = zero_entry(chain, rulenum[0], 3379 sopt->sopt_name == IP_FW_RESETLOG); 3380 break; 3381 3382 /*--- TABLE opcodes ---*/ 3383 case IP_FW_TABLE_ADD: 3384 case IP_FW_TABLE_DEL: 3385 { 3386 ipfw_table_entry ent; 3387 struct tentry_info tei; 3388 struct tid_info ti; 3389 struct table_value v; 3390 3391 error = sooptcopyin(sopt, &ent, 3392 sizeof(ent), sizeof(ent)); 3393 if (error) 3394 break; 3395 3396 memset(&tei, 0, sizeof(tei)); 3397 tei.paddr = &ent.addr; 3398 tei.subtype = AF_INET; 3399 tei.masklen = ent.masklen; 3400 ipfw_import_table_value_legacy(ent.value, &v); 3401 tei.pvalue = &v; 3402 memset(&ti, 0, sizeof(ti)); 3403 ti.uidx = ent.tbl; 3404 ti.type = IPFW_TABLE_CIDR; 3405 3406 error = (opt == IP_FW_TABLE_ADD) ? 3407 add_table_entry(chain, &ti, &tei, 0, 1) : 3408 del_table_entry(chain, &ti, &tei, 0, 1); 3409 } 3410 break; 3411 3412 3413 case IP_FW_TABLE_FLUSH: 3414 { 3415 u_int16_t tbl; 3416 struct tid_info ti; 3417 3418 error = sooptcopyin(sopt, &tbl, 3419 sizeof(tbl), sizeof(tbl)); 3420 if (error) 3421 break; 3422 memset(&ti, 0, sizeof(ti)); 3423 ti.uidx = tbl; 3424 error = flush_table(chain, &ti); 3425 } 3426 break; 3427 3428 case IP_FW_TABLE_GETSIZE: 3429 { 3430 u_int32_t tbl, cnt; 3431 struct tid_info ti; 3432 3433 if ((error = sooptcopyin(sopt, &tbl, sizeof(tbl), 3434 sizeof(tbl)))) 3435 break; 3436 memset(&ti, 0, sizeof(ti)); 3437 ti.uidx = tbl; 3438 IPFW_RLOCK(chain); 3439 error = ipfw_count_table(chain, &ti, &cnt); 3440 IPFW_RUNLOCK(chain); 3441 if (error) 3442 break; 3443 error = sooptcopyout(sopt, &cnt, sizeof(cnt)); 3444 } 3445 break; 3446 3447 case IP_FW_TABLE_LIST: 3448 { 3449 ipfw_table *tbl; 3450 struct tid_info ti; 3451 3452 if (sopt->sopt_valsize < sizeof(*tbl)) { 3453 error = EINVAL; 3454 break; 3455 } 3456 size = sopt->sopt_valsize; 3457 tbl = malloc(size, M_TEMP, M_WAITOK); 3458 error = sooptcopyin(sopt, tbl, size, sizeof(*tbl)); 3459 if (error) { 3460 free(tbl, M_TEMP); 3461 break; 3462 } 3463 tbl->size = (size - sizeof(*tbl)) / 3464 sizeof(ipfw_table_entry); 3465 memset(&ti, 0, sizeof(ti)); 3466 ti.uidx = tbl->tbl; 3467 IPFW_RLOCK(chain); 3468 error = ipfw_dump_table_legacy(chain, &ti, tbl); 3469 IPFW_RUNLOCK(chain); 3470 if (error) { 3471 free(tbl, M_TEMP); 3472 break; 3473 } 3474 error = sooptcopyout(sopt, tbl, size); 3475 free(tbl, M_TEMP); 3476 } 3477 break; 3478 3479 /*--- NAT operations are protected by the IPFW_LOCK ---*/ 3480 case IP_FW_NAT_CFG: 3481 if (IPFW_NAT_LOADED) 3482 error = ipfw_nat_cfg_ptr(sopt); 3483 else { 3484 printf("IP_FW_NAT_CFG: %s\n", 3485 "ipfw_nat not present, please load it"); 3486 error = EINVAL; 3487 } 3488 break; 3489 3490 case IP_FW_NAT_DEL: 3491 if (IPFW_NAT_LOADED) 3492 error = ipfw_nat_del_ptr(sopt); 3493 else { 3494 printf("IP_FW_NAT_DEL: %s\n", 3495 "ipfw_nat not present, please load it"); 3496 error = EINVAL; 3497 } 3498 break; 3499 3500 case IP_FW_NAT_GET_CONFIG: 3501 if (IPFW_NAT_LOADED) 3502 error = ipfw_nat_get_cfg_ptr(sopt); 3503 else { 3504 printf("IP_FW_NAT_GET_CFG: %s\n", 3505 "ipfw_nat not present, please load it"); 3506 error = EINVAL; 3507 } 3508 break; 3509 3510 case IP_FW_NAT_GET_LOG: 3511 if (IPFW_NAT_LOADED) 3512 error = ipfw_nat_get_log_ptr(sopt); 3513 else { 3514 printf("IP_FW_NAT_GET_LOG: %s\n", 3515 "ipfw_nat not present, please load it"); 3516 error = EINVAL; 3517 } 3518 break; 3519 3520 default: 3521 printf("ipfw: ipfw_ctl invalid option %d\n", sopt->sopt_name); 3522 error = EINVAL; 3523 } 3524 3525 return (error); 3526 #undef RULE_MAXSIZE 3527 } 3528 #define RULE_MAXSIZE (256*sizeof(u_int32_t)) 3529 3530 /* Functions to convert rules 7.2 <==> 8.0 */ 3531 static int 3532 convert_rule_to_7(struct ip_fw_rule0 *rule) 3533 { 3534 /* Used to modify original rule */ 3535 struct ip_fw7 *rule7 = (struct ip_fw7 *)rule; 3536 /* copy of original rule, version 8 */ 3537 struct ip_fw_rule0 *tmp; 3538 3539 /* Used to copy commands */ 3540 ipfw_insn *ccmd, *dst; 3541 int ll = 0, ccmdlen = 0; 3542 3543 tmp = malloc(RULE_MAXSIZE, M_TEMP, M_NOWAIT | M_ZERO); 3544 if (tmp == NULL) { 3545 return 1; //XXX error 3546 } 3547 bcopy(rule, tmp, RULE_MAXSIZE); 3548 3549 /* Copy fields */ 3550 //rule7->_pad = tmp->_pad; 3551 rule7->set = tmp->set; 3552 rule7->rulenum = tmp->rulenum; 3553 rule7->cmd_len = tmp->cmd_len; 3554 rule7->act_ofs = tmp->act_ofs; 3555 rule7->next_rule = (struct ip_fw7 *)tmp->next_rule; 3556 rule7->cmd_len = tmp->cmd_len; 3557 rule7->pcnt = tmp->pcnt; 3558 rule7->bcnt = tmp->bcnt; 3559 rule7->timestamp = tmp->timestamp; 3560 3561 /* Copy commands */ 3562 for (ll = tmp->cmd_len, ccmd = tmp->cmd, dst = rule7->cmd ; 3563 ll > 0 ; ll -= ccmdlen, ccmd += ccmdlen, dst += ccmdlen) { 3564 ccmdlen = F_LEN(ccmd); 3565 3566 bcopy(ccmd, dst, F_LEN(ccmd)*sizeof(uint32_t)); 3567 3568 if (dst->opcode > O_NAT) 3569 /* O_REASS doesn't exists in 7.2 version, so 3570 * decrement opcode if it is after O_REASS 3571 */ 3572 dst->opcode--; 3573 3574 if (ccmdlen > ll) { 3575 printf("ipfw: opcode %d size truncated\n", 3576 ccmd->opcode); 3577 return EINVAL; 3578 } 3579 } 3580 free(tmp, M_TEMP); 3581 3582 return 0; 3583 } 3584 3585 static int 3586 convert_rule_to_8(struct ip_fw_rule0 *rule) 3587 { 3588 /* Used to modify original rule */ 3589 struct ip_fw7 *rule7 = (struct ip_fw7 *) rule; 3590 3591 /* Used to copy commands */ 3592 ipfw_insn *ccmd, *dst; 3593 int ll = 0, ccmdlen = 0; 3594 3595 /* Copy of original rule */ 3596 struct ip_fw7 *tmp = malloc(RULE_MAXSIZE, M_TEMP, M_NOWAIT | M_ZERO); 3597 if (tmp == NULL) { 3598 return 1; //XXX error 3599 } 3600 3601 bcopy(rule7, tmp, RULE_MAXSIZE); 3602 3603 for (ll = tmp->cmd_len, ccmd = tmp->cmd, dst = rule->cmd ; 3604 ll > 0 ; ll -= ccmdlen, ccmd += ccmdlen, dst += ccmdlen) { 3605 ccmdlen = F_LEN(ccmd); 3606 3607 bcopy(ccmd, dst, F_LEN(ccmd)*sizeof(uint32_t)); 3608 3609 if (dst->opcode > O_NAT) 3610 /* O_REASS doesn't exists in 7.2 version, so 3611 * increment opcode if it is after O_REASS 3612 */ 3613 dst->opcode++; 3614 3615 if (ccmdlen > ll) { 3616 printf("ipfw: opcode %d size truncated\n", 3617 ccmd->opcode); 3618 return EINVAL; 3619 } 3620 } 3621 3622 rule->_pad = tmp->_pad; 3623 rule->set = tmp->set; 3624 rule->rulenum = tmp->rulenum; 3625 rule->cmd_len = tmp->cmd_len; 3626 rule->act_ofs = tmp->act_ofs; 3627 rule->next_rule = (struct ip_fw *)tmp->next_rule; 3628 rule->cmd_len = tmp->cmd_len; 3629 rule->id = 0; /* XXX see if is ok = 0 */ 3630 rule->pcnt = tmp->pcnt; 3631 rule->bcnt = tmp->bcnt; 3632 rule->timestamp = tmp->timestamp; 3633 3634 free (tmp, M_TEMP); 3635 return 0; 3636 } 3637 3638 /* 3639 * Named object api 3640 * 3641 */ 3642 3643 void 3644 ipfw_init_srv(struct ip_fw_chain *ch) 3645 { 3646 3647 ch->srvmap = ipfw_objhash_create(IPFW_OBJECTS_DEFAULT); 3648 ch->srvstate = malloc(sizeof(void *) * IPFW_OBJECTS_DEFAULT, 3649 M_IPFW, M_WAITOK | M_ZERO); 3650 } 3651 3652 void 3653 ipfw_destroy_srv(struct ip_fw_chain *ch) 3654 { 3655 3656 free(ch->srvstate, M_IPFW); 3657 ipfw_objhash_destroy(ch->srvmap); 3658 } 3659 3660 /* 3661 * Allocate new bitmask which can be used to enlarge/shrink 3662 * named instance index. 3663 */ 3664 void 3665 ipfw_objhash_bitmap_alloc(uint32_t items, void **idx, int *pblocks) 3666 { 3667 size_t size; 3668 int max_blocks; 3669 u_long *idx_mask; 3670 3671 KASSERT((items % BLOCK_ITEMS) == 0, 3672 ("bitmask size needs to power of 2 and greater or equal to %zu", 3673 BLOCK_ITEMS)); 3674 3675 max_blocks = items / BLOCK_ITEMS; 3676 size = items / 8; 3677 idx_mask = malloc(size * IPFW_MAX_SETS, M_IPFW, M_WAITOK); 3678 /* Mark all as free */ 3679 memset(idx_mask, 0xFF, size * IPFW_MAX_SETS); 3680 *idx_mask &= ~(u_long)1; /* Skip index 0 */ 3681 3682 *idx = idx_mask; 3683 *pblocks = max_blocks; 3684 } 3685 3686 /* 3687 * Copy current bitmask index to new one. 3688 */ 3689 void 3690 ipfw_objhash_bitmap_merge(struct namedobj_instance *ni, void **idx, int *blocks) 3691 { 3692 int old_blocks, new_blocks; 3693 u_long *old_idx, *new_idx; 3694 int i; 3695 3696 old_idx = ni->idx_mask; 3697 old_blocks = ni->max_blocks; 3698 new_idx = *idx; 3699 new_blocks = *blocks; 3700 3701 for (i = 0; i < IPFW_MAX_SETS; i++) { 3702 memcpy(&new_idx[new_blocks * i], &old_idx[old_blocks * i], 3703 old_blocks * sizeof(u_long)); 3704 } 3705 } 3706 3707 /* 3708 * Swaps current @ni index with new one. 3709 */ 3710 void 3711 ipfw_objhash_bitmap_swap(struct namedobj_instance *ni, void **idx, int *blocks) 3712 { 3713 int old_blocks; 3714 u_long *old_idx; 3715 3716 old_idx = ni->idx_mask; 3717 old_blocks = ni->max_blocks; 3718 3719 ni->idx_mask = *idx; 3720 ni->max_blocks = *blocks; 3721 3722 /* Save old values */ 3723 *idx = old_idx; 3724 *blocks = old_blocks; 3725 } 3726 3727 void 3728 ipfw_objhash_bitmap_free(void *idx, int blocks) 3729 { 3730 3731 free(idx, M_IPFW); 3732 } 3733 3734 /* 3735 * Creates named hash instance. 3736 * Must be called without holding any locks. 3737 * Return pointer to new instance. 3738 */ 3739 struct namedobj_instance * 3740 ipfw_objhash_create(uint32_t items) 3741 { 3742 struct namedobj_instance *ni; 3743 int i; 3744 size_t size; 3745 3746 size = sizeof(struct namedobj_instance) + 3747 sizeof(struct namedobjects_head) * NAMEDOBJ_HASH_SIZE + 3748 sizeof(struct namedobjects_head) * NAMEDOBJ_HASH_SIZE; 3749 3750 ni = malloc(size, M_IPFW, M_WAITOK | M_ZERO); 3751 ni->nn_size = NAMEDOBJ_HASH_SIZE; 3752 ni->nv_size = NAMEDOBJ_HASH_SIZE; 3753 3754 ni->names = (struct namedobjects_head *)(ni +1); 3755 ni->values = &ni->names[ni->nn_size]; 3756 3757 for (i = 0; i < ni->nn_size; i++) 3758 TAILQ_INIT(&ni->names[i]); 3759 3760 for (i = 0; i < ni->nv_size; i++) 3761 TAILQ_INIT(&ni->values[i]); 3762 3763 /* Set default hashing/comparison functions */ 3764 ni->hash_f = objhash_hash_name; 3765 ni->cmp_f = objhash_cmp_name; 3766 3767 /* Allocate bitmask separately due to possible resize */ 3768 ipfw_objhash_bitmap_alloc(items, (void*)&ni->idx_mask, &ni->max_blocks); 3769 3770 return (ni); 3771 } 3772 3773 void 3774 ipfw_objhash_destroy(struct namedobj_instance *ni) 3775 { 3776 3777 free(ni->idx_mask, M_IPFW); 3778 free(ni, M_IPFW); 3779 } 3780 3781 void 3782 ipfw_objhash_set_funcs(struct namedobj_instance *ni, objhash_hash_f *hash_f, 3783 objhash_cmp_f *cmp_f) 3784 { 3785 3786 ni->hash_f = hash_f; 3787 ni->cmp_f = cmp_f; 3788 } 3789 3790 static uint32_t 3791 objhash_hash_name(struct namedobj_instance *ni, void *name, uint32_t set) 3792 { 3793 3794 return (fnv_32_str((char *)name, FNV1_32_INIT)); 3795 } 3796 3797 static int 3798 objhash_cmp_name(struct named_object *no, void *name, uint32_t set) 3799 { 3800 3801 if ((strcmp(no->name, (char *)name) == 0) && (no->set == set)) 3802 return (0); 3803 3804 return (1); 3805 } 3806 3807 static uint32_t 3808 objhash_hash_idx(struct namedobj_instance *ni, uint32_t val) 3809 { 3810 uint32_t v; 3811 3812 v = val % (ni->nv_size - 1); 3813 3814 return (v); 3815 } 3816 3817 struct named_object * 3818 ipfw_objhash_lookup_name(struct namedobj_instance *ni, uint32_t set, char *name) 3819 { 3820 struct named_object *no; 3821 uint32_t hash; 3822 3823 hash = ni->hash_f(ni, name, set) % ni->nn_size; 3824 3825 TAILQ_FOREACH(no, &ni->names[hash], nn_next) { 3826 if (ni->cmp_f(no, name, set) == 0) 3827 return (no); 3828 } 3829 3830 return (NULL); 3831 } 3832 3833 /* 3834 * Find named object by name, considering also its TLV type. 3835 */ 3836 struct named_object * 3837 ipfw_objhash_lookup_name_type(struct namedobj_instance *ni, uint32_t set, 3838 uint32_t type, char *name) 3839 { 3840 struct named_object *no; 3841 uint32_t hash; 3842 3843 hash = ni->hash_f(ni, name, set) % ni->nn_size; 3844 3845 TAILQ_FOREACH(no, &ni->names[hash], nn_next) { 3846 if (ni->cmp_f(no, name, set) == 0 && no->etlv == type) 3847 return (no); 3848 } 3849 3850 return (NULL); 3851 } 3852 3853 struct named_object * 3854 ipfw_objhash_lookup_kidx(struct namedobj_instance *ni, uint16_t kidx) 3855 { 3856 struct named_object *no; 3857 uint32_t hash; 3858 3859 hash = objhash_hash_idx(ni, kidx); 3860 3861 TAILQ_FOREACH(no, &ni->values[hash], nv_next) { 3862 if (no->kidx == kidx) 3863 return (no); 3864 } 3865 3866 return (NULL); 3867 } 3868 3869 int 3870 ipfw_objhash_same_name(struct namedobj_instance *ni, struct named_object *a, 3871 struct named_object *b) 3872 { 3873 3874 if ((strcmp(a->name, b->name) == 0) && a->set == b->set) 3875 return (1); 3876 3877 return (0); 3878 } 3879 3880 void 3881 ipfw_objhash_add(struct namedobj_instance *ni, struct named_object *no) 3882 { 3883 uint32_t hash; 3884 3885 hash = ni->hash_f(ni, no->name, no->set) % ni->nn_size; 3886 TAILQ_INSERT_HEAD(&ni->names[hash], no, nn_next); 3887 3888 hash = objhash_hash_idx(ni, no->kidx); 3889 TAILQ_INSERT_HEAD(&ni->values[hash], no, nv_next); 3890 3891 ni->count++; 3892 } 3893 3894 void 3895 ipfw_objhash_del(struct namedobj_instance *ni, struct named_object *no) 3896 { 3897 uint32_t hash; 3898 3899 hash = ni->hash_f(ni, no->name, no->set) % ni->nn_size; 3900 TAILQ_REMOVE(&ni->names[hash], no, nn_next); 3901 3902 hash = objhash_hash_idx(ni, no->kidx); 3903 TAILQ_REMOVE(&ni->values[hash], no, nv_next); 3904 3905 ni->count--; 3906 } 3907 3908 uint32_t 3909 ipfw_objhash_count(struct namedobj_instance *ni) 3910 { 3911 3912 return (ni->count); 3913 } 3914 3915 /* 3916 * Runs @func for each found named object. 3917 * It is safe to delete objects from callback 3918 */ 3919 void 3920 ipfw_objhash_foreach(struct namedobj_instance *ni, objhash_cb_t *f, void *arg) 3921 { 3922 struct named_object *no, *no_tmp; 3923 int i; 3924 3925 for (i = 0; i < ni->nn_size; i++) { 3926 TAILQ_FOREACH_SAFE(no, &ni->names[i], nn_next, no_tmp) 3927 f(ni, no, arg); 3928 } 3929 } 3930 3931 /* 3932 * Removes index from given set. 3933 * Returns 0 on success. 3934 */ 3935 int 3936 ipfw_objhash_free_idx(struct namedobj_instance *ni, uint16_t idx) 3937 { 3938 u_long *mask; 3939 int i, v; 3940 3941 i = idx / BLOCK_ITEMS; 3942 v = idx % BLOCK_ITEMS; 3943 3944 if (i >= ni->max_blocks) 3945 return (1); 3946 3947 mask = &ni->idx_mask[i]; 3948 3949 if ((*mask & ((u_long)1 << v)) != 0) 3950 return (1); 3951 3952 /* Mark as free */ 3953 *mask |= (u_long)1 << v; 3954 3955 /* Update free offset */ 3956 if (ni->free_off[0] > i) 3957 ni->free_off[0] = i; 3958 3959 return (0); 3960 } 3961 3962 /* 3963 * Allocate new index in given instance and stores in in @pidx. 3964 * Returns 0 on success. 3965 */ 3966 int 3967 ipfw_objhash_alloc_idx(void *n, uint16_t *pidx) 3968 { 3969 struct namedobj_instance *ni; 3970 u_long *mask; 3971 int i, off, v; 3972 3973 ni = (struct namedobj_instance *)n; 3974 3975 off = ni->free_off[0]; 3976 mask = &ni->idx_mask[off]; 3977 3978 for (i = off; i < ni->max_blocks; i++, mask++) { 3979 if ((v = ffsl(*mask)) == 0) 3980 continue; 3981 3982 /* Mark as busy */ 3983 *mask &= ~ ((u_long)1 << (v - 1)); 3984 3985 ni->free_off[0] = i; 3986 3987 v = BLOCK_ITEMS * i + v - 1; 3988 3989 *pidx = v; 3990 return (0); 3991 } 3992 3993 return (1); 3994 } 3995 3996 /* end of file */ 3997