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