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 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 1683 goto bad_size; 1684 ci->object_opcodes++; 1685 break; 1686 case O_PROTO: 1687 case O_IP_SRC_ME: 1688 case O_IP_DST_ME: 1689 case O_LAYER2: 1690 case O_IN: 1691 case O_FRAG: 1692 case O_DIVERTED: 1693 case O_IPOPT: 1694 case O_IPTOS: 1695 case O_IPPRECEDENCE: 1696 case O_IPVER: 1697 case O_SOCKARG: 1698 case O_TCPFLAGS: 1699 case O_TCPOPTS: 1700 case O_ESTAB: 1701 case O_VERREVPATH: 1702 case O_VERSRCREACH: 1703 case O_ANTISPOOF: 1704 case O_IPSEC: 1705 #ifdef INET6 1706 case O_IP6_SRC_ME: 1707 case O_IP6_DST_ME: 1708 case O_EXT_HDR: 1709 case O_IP6: 1710 #endif 1711 case O_IP4: 1712 case O_TAG: 1713 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 1714 goto bad_size; 1715 break; 1716 1717 case O_EXTERNAL_ACTION: 1718 if (cmd->arg1 == 0 || 1719 cmdlen != F_INSN_SIZE(ipfw_insn)) { 1720 printf("ipfw: invalid external " 1721 "action opcode\n"); 1722 return (EINVAL); 1723 } 1724 ci->object_opcodes++; 1725 /* Do we have O_EXTERNAL_INSTANCE opcode? */ 1726 if (l != cmdlen) { 1727 l -= cmdlen; 1728 cmd += cmdlen; 1729 cmdlen = F_LEN(cmd); 1730 if (cmd->opcode != O_EXTERNAL_INSTANCE) { 1731 printf("ipfw: invalid opcode " 1732 "next to external action %u\n", 1733 cmd->opcode); 1734 return (EINVAL); 1735 } 1736 if (cmd->arg1 == 0 || 1737 cmdlen != F_INSN_SIZE(ipfw_insn)) { 1738 printf("ipfw: invalid external " 1739 "action instance opcode\n"); 1740 return (EINVAL); 1741 } 1742 ci->object_opcodes++; 1743 } 1744 goto check_action; 1745 1746 case O_FIB: 1747 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 1748 goto bad_size; 1749 if (cmd->arg1 >= rt_numfibs) { 1750 printf("ipfw: invalid fib number %d\n", 1751 cmd->arg1); 1752 return EINVAL; 1753 } 1754 break; 1755 1756 case O_SETFIB: 1757 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 1758 goto bad_size; 1759 if ((cmd->arg1 != IP_FW_TARG) && 1760 ((cmd->arg1 & 0x7FFF) >= rt_numfibs)) { 1761 printf("ipfw: invalid fib number %d\n", 1762 cmd->arg1 & 0x7FFF); 1763 return EINVAL; 1764 } 1765 goto check_action; 1766 1767 case O_UID: 1768 case O_GID: 1769 case O_JAIL: 1770 case O_IP_SRC: 1771 case O_IP_DST: 1772 case O_TCPSEQ: 1773 case O_TCPACK: 1774 case O_PROB: 1775 case O_ICMPTYPE: 1776 if (cmdlen != F_INSN_SIZE(ipfw_insn_u32)) 1777 goto bad_size; 1778 break; 1779 1780 case O_LIMIT: 1781 if (cmdlen != F_INSN_SIZE(ipfw_insn_limit)) 1782 goto bad_size; 1783 ci->object_opcodes++; 1784 break; 1785 1786 case O_LOG: 1787 if (cmdlen != F_INSN_SIZE(ipfw_insn_log)) 1788 goto bad_size; 1789 1790 ((ipfw_insn_log *)cmd)->log_left = 1791 ((ipfw_insn_log *)cmd)->max_log; 1792 1793 break; 1794 1795 case O_IP_SRC_MASK: 1796 case O_IP_DST_MASK: 1797 /* only odd command lengths */ 1798 if ((cmdlen & 1) == 0) 1799 goto bad_size; 1800 break; 1801 1802 case O_IP_SRC_SET: 1803 case O_IP_DST_SET: 1804 if (cmd->arg1 == 0 || cmd->arg1 > 256) { 1805 printf("ipfw: invalid set size %d\n", 1806 cmd->arg1); 1807 return EINVAL; 1808 } 1809 if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1810 (cmd->arg1+31)/32 ) 1811 goto bad_size; 1812 break; 1813 1814 case O_IP_SRC_LOOKUP: 1815 case O_IP_DST_LOOKUP: 1816 if (cmd->arg1 >= V_fw_tables_max) { 1817 printf("ipfw: invalid table number %d\n", 1818 cmd->arg1); 1819 return (EINVAL); 1820 } 1821 if (cmdlen != F_INSN_SIZE(ipfw_insn) && 1822 cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1 && 1823 cmdlen != F_INSN_SIZE(ipfw_insn_u32)) 1824 goto bad_size; 1825 ci->object_opcodes++; 1826 break; 1827 case O_IP_FLOW_LOOKUP: 1828 if (cmd->arg1 >= V_fw_tables_max) { 1829 printf("ipfw: invalid table number %d\n", 1830 cmd->arg1); 1831 return (EINVAL); 1832 } 1833 if (cmdlen != F_INSN_SIZE(ipfw_insn) && 1834 cmdlen != F_INSN_SIZE(ipfw_insn_u32)) 1835 goto bad_size; 1836 ci->object_opcodes++; 1837 break; 1838 case O_MACADDR2: 1839 if (cmdlen != F_INSN_SIZE(ipfw_insn_mac)) 1840 goto bad_size; 1841 break; 1842 1843 case O_NOP: 1844 case O_IPID: 1845 case O_IPTTL: 1846 case O_IPLEN: 1847 case O_TCPDATALEN: 1848 case O_TCPWIN: 1849 case O_TAGGED: 1850 if (cmdlen < 1 || cmdlen > 31) 1851 goto bad_size; 1852 break; 1853 1854 case O_DSCP: 1855 if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1) 1856 goto bad_size; 1857 break; 1858 1859 case O_MAC_TYPE: 1860 case O_IP_SRCPORT: 1861 case O_IP_DSTPORT: /* XXX artificial limit, 30 port pairs */ 1862 if (cmdlen < 2 || cmdlen > 31) 1863 goto bad_size; 1864 break; 1865 1866 case O_RECV: 1867 case O_XMIT: 1868 case O_VIA: 1869 if (cmdlen != F_INSN_SIZE(ipfw_insn_if)) 1870 goto bad_size; 1871 ci->object_opcodes++; 1872 break; 1873 1874 case O_ALTQ: 1875 if (cmdlen != F_INSN_SIZE(ipfw_insn_altq)) 1876 goto bad_size; 1877 break; 1878 1879 case O_PIPE: 1880 case O_QUEUE: 1881 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 1882 goto bad_size; 1883 goto check_action; 1884 1885 case O_FORWARD_IP: 1886 if (cmdlen != F_INSN_SIZE(ipfw_insn_sa)) 1887 goto bad_size; 1888 goto check_action; 1889 #ifdef INET6 1890 case O_FORWARD_IP6: 1891 if (cmdlen != F_INSN_SIZE(ipfw_insn_sa6)) 1892 goto bad_size; 1893 goto check_action; 1894 #endif /* INET6 */ 1895 1896 case O_DIVERT: 1897 case O_TEE: 1898 if (ip_divert_ptr == NULL) 1899 return EINVAL; 1900 else 1901 goto check_size; 1902 case O_NETGRAPH: 1903 case O_NGTEE: 1904 if (ng_ipfw_input_p == NULL) 1905 return EINVAL; 1906 else 1907 goto check_size; 1908 case O_NAT: 1909 if (!IPFW_NAT_LOADED) 1910 return EINVAL; 1911 if (cmdlen != F_INSN_SIZE(ipfw_insn_nat)) 1912 goto bad_size; 1913 goto check_action; 1914 case O_CHECK_STATE: 1915 ci->object_opcodes++; 1916 /* FALLTHROUGH */ 1917 case O_FORWARD_MAC: /* XXX not implemented yet */ 1918 case O_COUNT: 1919 case O_ACCEPT: 1920 case O_DENY: 1921 case O_REJECT: 1922 case O_SETDSCP: 1923 #ifdef INET6 1924 case O_UNREACH6: 1925 #endif 1926 case O_SKIPTO: 1927 case O_REASS: 1928 case O_CALLRETURN: 1929 check_size: 1930 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 1931 goto bad_size; 1932 check_action: 1933 if (have_action) { 1934 printf("ipfw: opcode %d, multiple actions" 1935 " not allowed\n", 1936 cmd->opcode); 1937 return (EINVAL); 1938 } 1939 have_action = 1; 1940 if (l != cmdlen) { 1941 printf("ipfw: opcode %d, action must be" 1942 " last opcode\n", 1943 cmd->opcode); 1944 return (EINVAL); 1945 } 1946 break; 1947 #ifdef INET6 1948 case O_IP6_SRC: 1949 case O_IP6_DST: 1950 if (cmdlen != F_INSN_SIZE(struct in6_addr) + 1951 F_INSN_SIZE(ipfw_insn)) 1952 goto bad_size; 1953 break; 1954 1955 case O_FLOW6ID: 1956 if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1957 ((ipfw_insn_u32 *)cmd)->o.arg1) 1958 goto bad_size; 1959 break; 1960 1961 case O_IP6_SRC_MASK: 1962 case O_IP6_DST_MASK: 1963 if ( !(cmdlen & 1) || cmdlen > 127) 1964 goto bad_size; 1965 break; 1966 case O_ICMP6TYPE: 1967 if( cmdlen != F_INSN_SIZE( ipfw_insn_icmp6 ) ) 1968 goto bad_size; 1969 break; 1970 #endif 1971 1972 default: 1973 switch (cmd->opcode) { 1974 #ifndef INET6 1975 case O_IP6_SRC_ME: 1976 case O_IP6_DST_ME: 1977 case O_EXT_HDR: 1978 case O_IP6: 1979 case O_UNREACH6: 1980 case O_IP6_SRC: 1981 case O_IP6_DST: 1982 case O_FLOW6ID: 1983 case O_IP6_SRC_MASK: 1984 case O_IP6_DST_MASK: 1985 case O_ICMP6TYPE: 1986 printf("ipfw: no IPv6 support in kernel\n"); 1987 return (EPROTONOSUPPORT); 1988 #endif 1989 default: 1990 printf("ipfw: opcode %d, unknown opcode\n", 1991 cmd->opcode); 1992 return (EINVAL); 1993 } 1994 } 1995 } 1996 if (have_action == 0) { 1997 printf("ipfw: missing action\n"); 1998 return (EINVAL); 1999 } 2000 return 0; 2001 2002 bad_size: 2003 printf("ipfw: opcode %d size %d wrong\n", 2004 cmd->opcode, cmdlen); 2005 return (EINVAL); 2006 } 2007 2008 2009 /* 2010 * Translation of requests for compatibility with FreeBSD 7.2/8. 2011 * a static variable tells us if we have an old client from userland, 2012 * and if necessary we translate requests and responses between the 2013 * two formats. 2014 */ 2015 static int is7 = 0; 2016 2017 struct ip_fw7 { 2018 struct ip_fw7 *next; /* linked list of rules */ 2019 struct ip_fw7 *next_rule; /* ptr to next [skipto] rule */ 2020 /* 'next_rule' is used to pass up 'set_disable' status */ 2021 2022 uint16_t act_ofs; /* offset of action in 32-bit units */ 2023 uint16_t cmd_len; /* # of 32-bit words in cmd */ 2024 uint16_t rulenum; /* rule number */ 2025 uint8_t set; /* rule set (0..31) */ 2026 // #define RESVD_SET 31 /* set for default and persistent rules */ 2027 uint8_t _pad; /* padding */ 2028 // uint32_t id; /* rule id, only in v.8 */ 2029 /* These fields are present in all rules. */ 2030 uint64_t pcnt; /* Packet counter */ 2031 uint64_t bcnt; /* Byte counter */ 2032 uint32_t timestamp; /* tv_sec of last match */ 2033 2034 ipfw_insn cmd[1]; /* storage for commands */ 2035 }; 2036 2037 static int convert_rule_to_7(struct ip_fw_rule0 *rule); 2038 static int convert_rule_to_8(struct ip_fw_rule0 *rule); 2039 2040 #ifndef RULESIZE7 2041 #define RULESIZE7(rule) (sizeof(struct ip_fw7) + \ 2042 ((struct ip_fw7 *)(rule))->cmd_len * 4 - 4) 2043 #endif 2044 2045 2046 /* 2047 * Copy the static and dynamic rules to the supplied buffer 2048 * and return the amount of space actually used. 2049 * Must be run under IPFW_UH_RLOCK 2050 */ 2051 static size_t 2052 ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space) 2053 { 2054 char *bp = buf; 2055 char *ep = bp + space; 2056 struct ip_fw *rule; 2057 struct ip_fw_rule0 *dst; 2058 int error, i, l, warnflag; 2059 time_t boot_seconds; 2060 2061 warnflag = 0; 2062 2063 boot_seconds = boottime.tv_sec; 2064 for (i = 0; i < chain->n_rules; i++) { 2065 rule = chain->map[i]; 2066 2067 if (is7) { 2068 /* Convert rule to FreeBSd 7.2 format */ 2069 l = RULESIZE7(rule); 2070 if (bp + l + sizeof(uint32_t) <= ep) { 2071 bcopy(rule, bp, l + sizeof(uint32_t)); 2072 error = set_legacy_obj_kidx(chain, 2073 (struct ip_fw_rule0 *)bp); 2074 if (error != 0) 2075 return (0); 2076 error = convert_rule_to_7((struct ip_fw_rule0 *) bp); 2077 if (error) 2078 return 0; /*XXX correct? */ 2079 /* 2080 * XXX HACK. Store the disable mask in the "next" 2081 * pointer in a wild attempt to keep the ABI the same. 2082 * Why do we do this on EVERY rule? 2083 */ 2084 bcopy(&V_set_disable, 2085 &(((struct ip_fw7 *)bp)->next_rule), 2086 sizeof(V_set_disable)); 2087 if (((struct ip_fw7 *)bp)->timestamp) 2088 ((struct ip_fw7 *)bp)->timestamp += boot_seconds; 2089 bp += l; 2090 } 2091 continue; /* go to next rule */ 2092 } 2093 2094 l = RULEUSIZE0(rule); 2095 if (bp + l > ep) { /* should not happen */ 2096 printf("overflow dumping static rules\n"); 2097 break; 2098 } 2099 dst = (struct ip_fw_rule0 *)bp; 2100 export_rule0(rule, dst, l); 2101 error = set_legacy_obj_kidx(chain, dst); 2102 2103 /* 2104 * XXX HACK. Store the disable mask in the "next" 2105 * pointer in a wild attempt to keep the ABI the same. 2106 * Why do we do this on EVERY rule? 2107 * 2108 * XXX: "ipfw set show" (ab)uses IP_FW_GET to read disabled mask 2109 * so we need to fail _after_ saving at least one mask. 2110 */ 2111 bcopy(&V_set_disable, &dst->next_rule, sizeof(V_set_disable)); 2112 if (dst->timestamp) 2113 dst->timestamp += boot_seconds; 2114 bp += l; 2115 2116 if (error != 0) { 2117 if (error == 2) { 2118 /* Non-fatal table rewrite error. */ 2119 warnflag = 1; 2120 continue; 2121 } 2122 printf("Stop on rule %d. Fail to convert table\n", 2123 rule->rulenum); 2124 break; 2125 } 2126 } 2127 if (warnflag != 0) 2128 printf("ipfw: process %s is using legacy interfaces," 2129 " consider rebuilding\n", ""); 2130 ipfw_get_dynamic(chain, &bp, ep); /* protected by the dynamic lock */ 2131 return (bp - (char *)buf); 2132 } 2133 2134 2135 struct dump_args { 2136 uint32_t b; /* start rule */ 2137 uint32_t e; /* end rule */ 2138 uint32_t rcount; /* number of rules */ 2139 uint32_t rsize; /* rules size */ 2140 uint32_t tcount; /* number of tables */ 2141 int rcounters; /* counters */ 2142 }; 2143 2144 void 2145 ipfw_export_obj_ntlv(struct named_object *no, ipfw_obj_ntlv *ntlv) 2146 { 2147 2148 ntlv->head.type = no->etlv; 2149 ntlv->head.length = sizeof(*ntlv); 2150 ntlv->idx = no->kidx; 2151 strlcpy(ntlv->name, no->name, sizeof(ntlv->name)); 2152 } 2153 2154 /* 2155 * Export named object info in instance @ni, identified by @kidx 2156 * to ipfw_obj_ntlv. TLV is allocated from @sd space. 2157 * 2158 * Returns 0 on success. 2159 */ 2160 static int 2161 export_objhash_ntlv(struct namedobj_instance *ni, uint16_t kidx, 2162 struct sockopt_data *sd) 2163 { 2164 struct named_object *no; 2165 ipfw_obj_ntlv *ntlv; 2166 2167 no = ipfw_objhash_lookup_kidx(ni, kidx); 2168 KASSERT(no != NULL, ("invalid object kernel index passed")); 2169 2170 ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv)); 2171 if (ntlv == NULL) 2172 return (ENOMEM); 2173 2174 ipfw_export_obj_ntlv(no, ntlv); 2175 return (0); 2176 } 2177 2178 /* 2179 * Dumps static rules with table TLVs in buffer @sd. 2180 * 2181 * Returns 0 on success. 2182 */ 2183 static int 2184 dump_static_rules(struct ip_fw_chain *chain, struct dump_args *da, 2185 uint32_t *bmask, struct sockopt_data *sd) 2186 { 2187 int error; 2188 int i, l; 2189 uint32_t tcount; 2190 ipfw_obj_ctlv *ctlv; 2191 struct ip_fw *krule; 2192 struct namedobj_instance *ni; 2193 caddr_t dst; 2194 2195 /* Dump table names first (if any) */ 2196 if (da->tcount > 0) { 2197 /* Header first */ 2198 ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv)); 2199 if (ctlv == NULL) 2200 return (ENOMEM); 2201 ctlv->head.type = IPFW_TLV_TBLNAME_LIST; 2202 ctlv->head.length = da->tcount * sizeof(ipfw_obj_ntlv) + 2203 sizeof(*ctlv); 2204 ctlv->count = da->tcount; 2205 ctlv->objsize = sizeof(ipfw_obj_ntlv); 2206 } 2207 2208 i = 0; 2209 tcount = da->tcount; 2210 ni = ipfw_get_table_objhash(chain); 2211 while (tcount > 0) { 2212 if ((bmask[i / 32] & (1 << (i % 32))) == 0) { 2213 i++; 2214 continue; 2215 } 2216 2217 /* Jump to shared named object bitmask */ 2218 if (i >= IPFW_TABLES_MAX) { 2219 ni = CHAIN_TO_SRV(chain); 2220 i -= IPFW_TABLES_MAX; 2221 bmask += IPFW_TABLES_MAX / 32; 2222 } 2223 2224 if ((error = export_objhash_ntlv(ni, i, sd)) != 0) 2225 return (error); 2226 2227 i++; 2228 tcount--; 2229 } 2230 2231 /* Dump rules */ 2232 ctlv = (ipfw_obj_ctlv *)ipfw_get_sopt_space(sd, sizeof(*ctlv)); 2233 if (ctlv == NULL) 2234 return (ENOMEM); 2235 ctlv->head.type = IPFW_TLV_RULE_LIST; 2236 ctlv->head.length = da->rsize + sizeof(*ctlv); 2237 ctlv->count = da->rcount; 2238 2239 for (i = da->b; i < da->e; i++) { 2240 krule = chain->map[i]; 2241 2242 l = RULEUSIZE1(krule) + sizeof(ipfw_obj_tlv); 2243 if (da->rcounters != 0) 2244 l += sizeof(struct ip_fw_bcounter); 2245 dst = (caddr_t)ipfw_get_sopt_space(sd, l); 2246 if (dst == NULL) 2247 return (ENOMEM); 2248 2249 export_rule1(krule, dst, l, da->rcounters); 2250 } 2251 2252 return (0); 2253 } 2254 2255 /* 2256 * Marks every object index used in @rule with bit in @bmask. 2257 * Used to generate bitmask of referenced tables/objects for given ruleset 2258 * or its part. 2259 * 2260 * Returns number of newly-referenced objects. 2261 */ 2262 static int 2263 mark_object_kidx(struct ip_fw_chain *ch, struct ip_fw *rule, 2264 uint32_t *bmask) 2265 { 2266 struct opcode_obj_rewrite *rw; 2267 ipfw_insn *cmd; 2268 int bidx, cmdlen, l, count; 2269 uint16_t kidx; 2270 uint8_t subtype; 2271 2272 l = rule->cmd_len; 2273 cmd = rule->cmd; 2274 cmdlen = 0; 2275 count = 0; 2276 for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2277 cmdlen = F_LEN(cmd); 2278 2279 rw = find_op_rw(cmd, &kidx, &subtype); 2280 if (rw == NULL) 2281 continue; 2282 2283 bidx = kidx / 32; 2284 /* 2285 * Maintain separate bitmasks for table and 2286 * non-table objects. 2287 */ 2288 if (rw->etlv != IPFW_TLV_TBL_NAME) 2289 bidx += IPFW_TABLES_MAX / 32; 2290 2291 if ((bmask[bidx] & (1 << (kidx % 32))) == 0) 2292 count++; 2293 2294 bmask[bidx] |= 1 << (kidx % 32); 2295 } 2296 2297 return (count); 2298 } 2299 2300 /* 2301 * Dumps requested objects data 2302 * Data layout (version 0)(current): 2303 * Request: [ ipfw_cfg_lheader ] + IPFW_CFG_GET_* flags 2304 * size = ipfw_cfg_lheader.size 2305 * Reply: [ ipfw_cfg_lheader 2306 * [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional) 2307 * [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) 2308 * ipfw_obj_tlv(IPFW_TLV_RULE_ENT) [ ip_fw_bcounter (optional) ip_fw_rule ] 2309 * ] (optional) 2310 * [ ipfw_obj_ctlv(IPFW_TLV_STATE_LIST) ipfw_obj_dyntlv x N ] (optional) 2311 * ] 2312 * * NOTE IPFW_TLV_STATE_LIST has the single valid field: objsize. 2313 * The rest (size, count) are set to zero and needs to be ignored. 2314 * 2315 * Returns 0 on success. 2316 */ 2317 static int 2318 dump_config(struct ip_fw_chain *chain, ip_fw3_opheader *op3, 2319 struct sockopt_data *sd) 2320 { 2321 ipfw_cfg_lheader *hdr; 2322 struct ip_fw *rule; 2323 size_t sz, rnum; 2324 uint32_t hdr_flags; 2325 int error, i; 2326 struct dump_args da; 2327 uint32_t *bmask; 2328 2329 hdr = (ipfw_cfg_lheader *)ipfw_get_sopt_header(sd, sizeof(*hdr)); 2330 if (hdr == NULL) 2331 return (EINVAL); 2332 2333 error = 0; 2334 bmask = NULL; 2335 /* Allocate needed state. Note we allocate 2xspace mask, for table&srv */ 2336 if (hdr->flags & IPFW_CFG_GET_STATIC) 2337 bmask = malloc(IPFW_TABLES_MAX / 4, M_TEMP, M_WAITOK | M_ZERO); 2338 2339 IPFW_UH_RLOCK(chain); 2340 2341 /* 2342 * STAGE 1: Determine size/count for objects in range. 2343 * Prepare used tables bitmask. 2344 */ 2345 sz = sizeof(ipfw_cfg_lheader); 2346 memset(&da, 0, sizeof(da)); 2347 2348 da.b = 0; 2349 da.e = chain->n_rules; 2350 2351 if (hdr->end_rule != 0) { 2352 /* Handle custom range */ 2353 if ((rnum = hdr->start_rule) > IPFW_DEFAULT_RULE) 2354 rnum = IPFW_DEFAULT_RULE; 2355 da.b = ipfw_find_rule(chain, rnum, 0); 2356 rnum = hdr->end_rule; 2357 rnum = (rnum < IPFW_DEFAULT_RULE) ? rnum+1 : IPFW_DEFAULT_RULE; 2358 da.e = ipfw_find_rule(chain, rnum, 0) + 1; 2359 } 2360 2361 if (hdr->flags & IPFW_CFG_GET_STATIC) { 2362 for (i = da.b; i < da.e; i++) { 2363 rule = chain->map[i]; 2364 da.rsize += RULEUSIZE1(rule) + sizeof(ipfw_obj_tlv); 2365 da.rcount++; 2366 /* Update bitmask of used objects for given range */ 2367 da.tcount += mark_object_kidx(chain, rule, bmask); 2368 } 2369 /* Add counters if requested */ 2370 if (hdr->flags & IPFW_CFG_GET_COUNTERS) { 2371 da.rsize += sizeof(struct ip_fw_bcounter) * da.rcount; 2372 da.rcounters = 1; 2373 } 2374 2375 if (da.tcount > 0) 2376 sz += da.tcount * sizeof(ipfw_obj_ntlv) + 2377 sizeof(ipfw_obj_ctlv); 2378 sz += da.rsize + sizeof(ipfw_obj_ctlv); 2379 } 2380 2381 if (hdr->flags & IPFW_CFG_GET_STATES) 2382 sz += ipfw_dyn_get_count() * sizeof(ipfw_obj_dyntlv) + 2383 sizeof(ipfw_obj_ctlv); 2384 2385 2386 /* 2387 * Fill header anyway. 2388 * Note we have to save header fields to stable storage 2389 * buffer inside @sd can be flushed after dumping rules 2390 */ 2391 hdr->size = sz; 2392 hdr->set_mask = ~V_set_disable; 2393 hdr_flags = hdr->flags; 2394 hdr = NULL; 2395 2396 if (sd->valsize < sz) { 2397 error = ENOMEM; 2398 goto cleanup; 2399 } 2400 2401 /* STAGE2: Store actual data */ 2402 if (hdr_flags & IPFW_CFG_GET_STATIC) { 2403 error = dump_static_rules(chain, &da, bmask, sd); 2404 if (error != 0) 2405 goto cleanup; 2406 } 2407 2408 if (hdr_flags & IPFW_CFG_GET_STATES) 2409 error = ipfw_dump_states(chain, sd); 2410 2411 cleanup: 2412 IPFW_UH_RUNLOCK(chain); 2413 2414 if (bmask != NULL) 2415 free(bmask, M_TEMP); 2416 2417 return (error); 2418 } 2419 2420 int 2421 ipfw_check_object_name_generic(const char *name) 2422 { 2423 int nsize; 2424 2425 nsize = sizeof(((ipfw_obj_ntlv *)0)->name); 2426 if (strnlen(name, nsize) == nsize) 2427 return (EINVAL); 2428 if (name[0] == '\0') 2429 return (EINVAL); 2430 return (0); 2431 } 2432 2433 /* 2434 * Creates non-existent objects referenced by rule. 2435 * 2436 * Return 0 on success. 2437 */ 2438 int 2439 create_objects_compat(struct ip_fw_chain *ch, ipfw_insn *cmd, 2440 struct obj_idx *oib, struct obj_idx *pidx, struct tid_info *ti) 2441 { 2442 struct opcode_obj_rewrite *rw; 2443 struct obj_idx *p; 2444 uint16_t kidx; 2445 int error; 2446 2447 /* 2448 * Compatibility stuff: do actual creation for non-existing, 2449 * but referenced objects. 2450 */ 2451 for (p = oib; p < pidx; p++) { 2452 if (p->kidx != 0) 2453 continue; 2454 2455 ti->uidx = p->uidx; 2456 ti->type = p->type; 2457 ti->atype = 0; 2458 2459 rw = find_op_rw(cmd + p->off, NULL, NULL); 2460 KASSERT(rw != NULL, ("Unable to find handler for op %d", 2461 (cmd + p->off)->opcode)); 2462 2463 if (rw->create_object == NULL) 2464 error = EOPNOTSUPP; 2465 else 2466 error = rw->create_object(ch, ti, &kidx); 2467 if (error == 0) { 2468 p->kidx = kidx; 2469 continue; 2470 } 2471 2472 /* 2473 * Error happened. We have to rollback everything. 2474 * Drop all already acquired references. 2475 */ 2476 IPFW_UH_WLOCK(ch); 2477 unref_oib_objects(ch, cmd, oib, pidx); 2478 IPFW_UH_WUNLOCK(ch); 2479 2480 return (error); 2481 } 2482 2483 return (0); 2484 } 2485 2486 /* 2487 * Compatibility function for old ipfw(8) binaries. 2488 * Rewrites table/nat kernel indices with userland ones. 2489 * Convert tables matching '/^\d+$/' to their atoi() value. 2490 * Use number 65535 for other tables. 2491 * 2492 * Returns 0 on success. 2493 */ 2494 static int 2495 set_legacy_obj_kidx(struct ip_fw_chain *ch, struct ip_fw_rule0 *rule) 2496 { 2497 struct opcode_obj_rewrite *rw; 2498 struct named_object *no; 2499 ipfw_insn *cmd; 2500 char *end; 2501 long val; 2502 int cmdlen, error, l; 2503 uint16_t kidx, uidx; 2504 uint8_t subtype; 2505 2506 error = 0; 2507 2508 l = rule->cmd_len; 2509 cmd = rule->cmd; 2510 cmdlen = 0; 2511 for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2512 cmdlen = F_LEN(cmd); 2513 2514 /* Check if is index in given opcode */ 2515 rw = find_op_rw(cmd, &kidx, &subtype); 2516 if (rw == NULL) 2517 continue; 2518 2519 /* Try to find referenced kernel object */ 2520 no = rw->find_bykidx(ch, kidx); 2521 if (no == NULL) 2522 continue; 2523 2524 val = strtol(no->name, &end, 10); 2525 if (*end == '\0' && val < 65535) { 2526 uidx = val; 2527 } else { 2528 2529 /* 2530 * We are called via legacy opcode. 2531 * Save error and show table as fake number 2532 * not to make ipfw(8) hang. 2533 */ 2534 uidx = 65535; 2535 error = 2; 2536 } 2537 2538 rw->update(cmd, uidx); 2539 } 2540 2541 return (error); 2542 } 2543 2544 2545 /* 2546 * Unreferences all already-referenced objects in given @cmd rule, 2547 * using information in @oib. 2548 * 2549 * Used to rollback partially converted rule on error. 2550 */ 2551 static void 2552 unref_oib_objects(struct ip_fw_chain *ch, ipfw_insn *cmd, struct obj_idx *oib, 2553 struct obj_idx *end) 2554 { 2555 struct opcode_obj_rewrite *rw; 2556 struct named_object *no; 2557 struct obj_idx *p; 2558 2559 IPFW_UH_WLOCK_ASSERT(ch); 2560 2561 for (p = oib; p < end; p++) { 2562 if (p->kidx == 0) 2563 continue; 2564 2565 rw = find_op_rw(cmd + p->off, NULL, NULL); 2566 KASSERT(rw != NULL, ("Unable to find handler for op %d", 2567 (cmd + p->off)->opcode)); 2568 2569 /* Find & unref by existing idx */ 2570 no = rw->find_bykidx(ch, p->kidx); 2571 KASSERT(no != NULL, ("Ref'd object %d disappeared", p->kidx)); 2572 no->refcnt--; 2573 } 2574 } 2575 2576 /* 2577 * Remove references from every object used in @rule. 2578 * Used at rule removal code. 2579 */ 2580 static void 2581 unref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule) 2582 { 2583 struct opcode_obj_rewrite *rw; 2584 struct named_object *no; 2585 ipfw_insn *cmd; 2586 int cmdlen, l; 2587 uint16_t kidx; 2588 uint8_t subtype; 2589 2590 IPFW_UH_WLOCK_ASSERT(ch); 2591 2592 l = rule->cmd_len; 2593 cmd = rule->cmd; 2594 cmdlen = 0; 2595 for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2596 cmdlen = F_LEN(cmd); 2597 2598 rw = find_op_rw(cmd, &kidx, &subtype); 2599 if (rw == NULL) 2600 continue; 2601 no = rw->find_bykidx(ch, kidx); 2602 2603 KASSERT(no != NULL, ("table id %d not found", kidx)); 2604 KASSERT(no->subtype == subtype, 2605 ("wrong type %d (%d) for table id %d", 2606 no->subtype, subtype, kidx)); 2607 KASSERT(no->refcnt > 0, ("refcount for table %d is %d", 2608 kidx, no->refcnt)); 2609 2610 if (no->refcnt == 1 && rw->destroy_object != NULL) 2611 rw->destroy_object(ch, no); 2612 else 2613 no->refcnt--; 2614 } 2615 } 2616 2617 2618 /* 2619 * Find and reference object (if any) stored in instruction @cmd. 2620 * 2621 * Saves object info in @pidx, sets 2622 * - @unresolved to 1 if object should exists but not found 2623 * 2624 * Returns non-zero value in case of error. 2625 */ 2626 static int 2627 ref_opcode_object(struct ip_fw_chain *ch, ipfw_insn *cmd, struct tid_info *ti, 2628 struct obj_idx *pidx, int *unresolved) 2629 { 2630 struct named_object *no; 2631 struct opcode_obj_rewrite *rw; 2632 int error; 2633 2634 /* Check if this opcode is candidate for rewrite */ 2635 rw = find_op_rw(cmd, &ti->uidx, &ti->type); 2636 if (rw == NULL) 2637 return (0); 2638 2639 /* Need to rewrite. Save necessary fields */ 2640 pidx->uidx = ti->uidx; 2641 pidx->type = ti->type; 2642 2643 /* Try to find referenced kernel object */ 2644 error = rw->find_byname(ch, ti, &no); 2645 if (error != 0) 2646 return (error); 2647 if (no == NULL) { 2648 /* 2649 * Report about unresolved object for automaic 2650 * creation. 2651 */ 2652 *unresolved = 1; 2653 return (0); 2654 } 2655 2656 /* Found. Bump refcount and update kidx. */ 2657 no->refcnt++; 2658 rw->update(cmd, no->kidx); 2659 return (0); 2660 } 2661 2662 /* 2663 * Finds and bumps refcount for objects referenced by given @rule. 2664 * Auto-creates non-existing tables. 2665 * Fills in @oib array with userland/kernel indexes. 2666 * 2667 * Returns 0 on success. 2668 */ 2669 static int 2670 ref_rule_objects(struct ip_fw_chain *ch, struct ip_fw *rule, 2671 struct rule_check_info *ci, struct obj_idx *oib, struct tid_info *ti) 2672 { 2673 struct obj_idx *pidx; 2674 ipfw_insn *cmd; 2675 int cmdlen, error, l, unresolved; 2676 2677 pidx = oib; 2678 l = rule->cmd_len; 2679 cmd = rule->cmd; 2680 cmdlen = 0; 2681 error = 0; 2682 2683 IPFW_UH_WLOCK(ch); 2684 2685 /* Increase refcount on each existing referenced table. */ 2686 for ( ; l > 0 ; l -= cmdlen, cmd += cmdlen) { 2687 cmdlen = F_LEN(cmd); 2688 unresolved = 0; 2689 2690 error = ref_opcode_object(ch, cmd, ti, pidx, &unresolved); 2691 if (error != 0) 2692 break; 2693 /* 2694 * Compatibility stuff for old clients: 2695 * prepare to automaitcally create non-existing objects. 2696 */ 2697 if (unresolved != 0) { 2698 pidx->off = rule->cmd_len - l; 2699 pidx++; 2700 } 2701 } 2702 2703 if (error != 0) { 2704 /* Unref everything we have already done */ 2705 unref_oib_objects(ch, rule->cmd, oib, pidx); 2706 IPFW_UH_WUNLOCK(ch); 2707 return (error); 2708 } 2709 IPFW_UH_WUNLOCK(ch); 2710 2711 /* Perform auto-creation for non-existing objects */ 2712 if (pidx != oib) 2713 error = create_objects_compat(ch, rule->cmd, oib, pidx, ti); 2714 2715 /* Calculate real number of dynamic objects */ 2716 ci->object_opcodes = (uint16_t)(pidx - oib); 2717 2718 return (error); 2719 } 2720 2721 /* 2722 * Checks is opcode is referencing table of appropriate type. 2723 * Adds reference count for found table if true. 2724 * Rewrites user-supplied opcode values with kernel ones. 2725 * 2726 * Returns 0 on success and appropriate error code otherwise. 2727 */ 2728 static int 2729 rewrite_rule_uidx(struct ip_fw_chain *chain, struct rule_check_info *ci) 2730 { 2731 int error; 2732 ipfw_insn *cmd; 2733 uint8_t type; 2734 struct obj_idx *p, *pidx_first, *pidx_last; 2735 struct tid_info ti; 2736 2737 /* 2738 * Prepare an array for storing opcode indices. 2739 * Use stack allocation by default. 2740 */ 2741 if (ci->object_opcodes <= (sizeof(ci->obuf)/sizeof(ci->obuf[0]))) { 2742 /* Stack */ 2743 pidx_first = ci->obuf; 2744 } else 2745 pidx_first = malloc( 2746 ci->object_opcodes * sizeof(struct obj_idx), 2747 M_IPFW, M_WAITOK | M_ZERO); 2748 2749 error = 0; 2750 type = 0; 2751 memset(&ti, 0, sizeof(ti)); 2752 2753 /* Use set rule is assigned to. */ 2754 ti.set = ci->krule->set; 2755 if (ci->ctlv != NULL) { 2756 ti.tlvs = (void *)(ci->ctlv + 1); 2757 ti.tlen = ci->ctlv->head.length - sizeof(ipfw_obj_ctlv); 2758 } 2759 2760 /* Reference all used tables and other objects */ 2761 error = ref_rule_objects(chain, ci->krule, ci, pidx_first, &ti); 2762 if (error != 0) 2763 goto free; 2764 /* 2765 * Note that ref_rule_objects() might have updated ci->object_opcodes 2766 * to reflect actual number of object opcodes. 2767 */ 2768 2769 /* Perform rewrite of remaining opcodes */ 2770 p = pidx_first; 2771 pidx_last = pidx_first + ci->object_opcodes; 2772 for (p = pidx_first; p < pidx_last; p++) { 2773 cmd = ci->krule->cmd + p->off; 2774 update_opcode_kidx(cmd, p->kidx); 2775 } 2776 2777 free: 2778 if (pidx_first != ci->obuf) 2779 free(pidx_first, M_IPFW); 2780 2781 return (error); 2782 } 2783 2784 /* 2785 * Adds one or more rules to ipfw @chain. 2786 * Data layout (version 0)(current): 2787 * Request: 2788 * [ 2789 * ip_fw3_opheader 2790 * [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional *1) 2791 * [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) ip_fw x N ] (*2) (*3) 2792 * ] 2793 * Reply: 2794 * [ 2795 * ip_fw3_opheader 2796 * [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional) 2797 * [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) ip_fw x N ] 2798 * ] 2799 * 2800 * Rules in reply are modified to store their actual ruleset number. 2801 * 2802 * (*1) TLVs inside IPFW_TLV_TBL_LIST needs to be sorted ascending 2803 * according to their idx field and there has to be no duplicates. 2804 * (*2) Numbered rules inside IPFW_TLV_RULE_LIST needs to be sorted ascending. 2805 * (*3) Each ip_fw structure needs to be aligned to u64 boundary. 2806 * 2807 * Returns 0 on success. 2808 */ 2809 static int 2810 add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, 2811 struct sockopt_data *sd) 2812 { 2813 ipfw_obj_ctlv *ctlv, *rtlv, *tstate; 2814 ipfw_obj_ntlv *ntlv; 2815 int clen, error, idx; 2816 uint32_t count, read; 2817 struct ip_fw_rule *r; 2818 struct rule_check_info rci, *ci, *cbuf; 2819 int i, rsize; 2820 2821 op3 = (ip_fw3_opheader *)ipfw_get_sopt_space(sd, sd->valsize); 2822 ctlv = (ipfw_obj_ctlv *)(op3 + 1); 2823 2824 read = sizeof(ip_fw3_opheader); 2825 rtlv = NULL; 2826 tstate = NULL; 2827 cbuf = NULL; 2828 memset(&rci, 0, sizeof(struct rule_check_info)); 2829 2830 if (read + sizeof(*ctlv) > sd->valsize) 2831 return (EINVAL); 2832 2833 if (ctlv->head.type == IPFW_TLV_TBLNAME_LIST) { 2834 clen = ctlv->head.length; 2835 /* Check size and alignment */ 2836 if (clen > sd->valsize || clen < sizeof(*ctlv)) 2837 return (EINVAL); 2838 if ((clen % sizeof(uint64_t)) != 0) 2839 return (EINVAL); 2840 2841 /* 2842 * Some table names or other named objects. 2843 * Check for validness. 2844 */ 2845 count = (ctlv->head.length - sizeof(*ctlv)) / sizeof(*ntlv); 2846 if (ctlv->count != count || ctlv->objsize != sizeof(*ntlv)) 2847 return (EINVAL); 2848 2849 /* 2850 * Check each TLV. 2851 * Ensure TLVs are sorted ascending and 2852 * there are no duplicates. 2853 */ 2854 idx = -1; 2855 ntlv = (ipfw_obj_ntlv *)(ctlv + 1); 2856 while (count > 0) { 2857 if (ntlv->head.length != sizeof(ipfw_obj_ntlv)) 2858 return (EINVAL); 2859 2860 error = ipfw_check_object_name_generic(ntlv->name); 2861 if (error != 0) 2862 return (error); 2863 2864 if (ntlv->idx <= idx) 2865 return (EINVAL); 2866 2867 idx = ntlv->idx; 2868 count--; 2869 ntlv++; 2870 } 2871 2872 tstate = ctlv; 2873 read += ctlv->head.length; 2874 ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length); 2875 } 2876 2877 if (read + sizeof(*ctlv) > sd->valsize) 2878 return (EINVAL); 2879 2880 if (ctlv->head.type == IPFW_TLV_RULE_LIST) { 2881 clen = ctlv->head.length; 2882 if (clen + read > sd->valsize || clen < sizeof(*ctlv)) 2883 return (EINVAL); 2884 if ((clen % sizeof(uint64_t)) != 0) 2885 return (EINVAL); 2886 2887 /* 2888 * TODO: Permit adding multiple rules at once 2889 */ 2890 if (ctlv->count != 1) 2891 return (ENOTSUP); 2892 2893 clen -= sizeof(*ctlv); 2894 2895 if (ctlv->count > clen / sizeof(struct ip_fw_rule)) 2896 return (EINVAL); 2897 2898 /* Allocate state for each rule or use stack */ 2899 if (ctlv->count == 1) { 2900 memset(&rci, 0, sizeof(struct rule_check_info)); 2901 cbuf = &rci; 2902 } else 2903 cbuf = malloc(ctlv->count * sizeof(*ci), M_TEMP, 2904 M_WAITOK | M_ZERO); 2905 ci = cbuf; 2906 2907 /* 2908 * Check each rule for validness. 2909 * Ensure numbered rules are sorted ascending 2910 * and properly aligned 2911 */ 2912 idx = 0; 2913 r = (struct ip_fw_rule *)(ctlv + 1); 2914 count = 0; 2915 error = 0; 2916 while (clen > 0) { 2917 rsize = roundup2(RULESIZE(r), sizeof(uint64_t)); 2918 if (rsize > clen || ctlv->count <= count) { 2919 error = EINVAL; 2920 break; 2921 } 2922 2923 ci->ctlv = tstate; 2924 error = check_ipfw_rule1(r, rsize, ci); 2925 if (error != 0) 2926 break; 2927 2928 /* Check sorting */ 2929 if (r->rulenum != 0 && r->rulenum < idx) { 2930 printf("rulenum %d idx %d\n", r->rulenum, idx); 2931 error = EINVAL; 2932 break; 2933 } 2934 idx = r->rulenum; 2935 2936 ci->urule = (caddr_t)r; 2937 2938 rsize = roundup2(rsize, sizeof(uint64_t)); 2939 clen -= rsize; 2940 r = (struct ip_fw_rule *)((caddr_t)r + rsize); 2941 count++; 2942 ci++; 2943 } 2944 2945 if (ctlv->count != count || error != 0) { 2946 if (cbuf != &rci) 2947 free(cbuf, M_TEMP); 2948 return (EINVAL); 2949 } 2950 2951 rtlv = ctlv; 2952 read += ctlv->head.length; 2953 ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length); 2954 } 2955 2956 if (read != sd->valsize || rtlv == NULL || rtlv->count == 0) { 2957 if (cbuf != NULL && cbuf != &rci) 2958 free(cbuf, M_TEMP); 2959 return (EINVAL); 2960 } 2961 2962 /* 2963 * Passed rules seems to be valid. 2964 * Allocate storage and try to add them to chain. 2965 */ 2966 for (i = 0, ci = cbuf; i < rtlv->count; i++, ci++) { 2967 clen = RULEKSIZE1((struct ip_fw_rule *)ci->urule); 2968 ci->krule = ipfw_alloc_rule(chain, clen); 2969 import_rule1(ci); 2970 } 2971 2972 if ((error = commit_rules(chain, cbuf, rtlv->count)) != 0) { 2973 /* Free allocate krules */ 2974 for (i = 0, ci = cbuf; i < rtlv->count; i++, ci++) 2975 free_rule(ci->krule); 2976 } 2977 2978 if (cbuf != NULL && cbuf != &rci) 2979 free(cbuf, M_TEMP); 2980 2981 return (error); 2982 } 2983 2984 /* 2985 * Lists all sopts currently registered. 2986 * Data layout (v0)(current): 2987 * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size 2988 * Reply: [ ipfw_obj_lheader ipfw_sopt_info x N ] 2989 * 2990 * Returns 0 on success 2991 */ 2992 static int 2993 dump_soptcodes(struct ip_fw_chain *chain, ip_fw3_opheader *op3, 2994 struct sockopt_data *sd) 2995 { 2996 struct _ipfw_obj_lheader *olh; 2997 ipfw_sopt_info *i; 2998 struct ipfw_sopt_handler *sh; 2999 uint32_t count, n, size; 3000 3001 olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh)); 3002 if (olh == NULL) 3003 return (EINVAL); 3004 if (sd->valsize < olh->size) 3005 return (EINVAL); 3006 3007 CTL3_LOCK(); 3008 count = ctl3_hsize; 3009 size = count * sizeof(ipfw_sopt_info) + sizeof(ipfw_obj_lheader); 3010 3011 /* Fill in header regadless of buffer size */ 3012 olh->count = count; 3013 olh->objsize = sizeof(ipfw_sopt_info); 3014 3015 if (size > olh->size) { 3016 olh->size = size; 3017 CTL3_UNLOCK(); 3018 return (ENOMEM); 3019 } 3020 olh->size = size; 3021 3022 for (n = 1; n <= count; n++) { 3023 i = (ipfw_sopt_info *)ipfw_get_sopt_space(sd, sizeof(*i)); 3024 KASSERT(i != NULL, ("previously checked buffer is not enough")); 3025 sh = &ctl3_handlers[n]; 3026 i->opcode = sh->opcode; 3027 i->version = sh->version; 3028 i->refcnt = sh->refcnt; 3029 } 3030 CTL3_UNLOCK(); 3031 3032 return (0); 3033 } 3034 3035 /* 3036 * Compares two opcodes. 3037 * Used both in qsort() and bsearch(). 3038 * 3039 * Returns 0 if match is found. 3040 */ 3041 static int 3042 compare_opcodes(const void *_a, const void *_b) 3043 { 3044 const struct opcode_obj_rewrite *a, *b; 3045 3046 a = (const struct opcode_obj_rewrite *)_a; 3047 b = (const struct opcode_obj_rewrite *)_b; 3048 3049 if (a->opcode < b->opcode) 3050 return (-1); 3051 else if (a->opcode > b->opcode) 3052 return (1); 3053 3054 return (0); 3055 } 3056 3057 /* 3058 * XXX: Rewrite bsearch() 3059 */ 3060 static int 3061 find_op_rw_range(uint16_t op, struct opcode_obj_rewrite **plo, 3062 struct opcode_obj_rewrite **phi) 3063 { 3064 struct opcode_obj_rewrite *ctl3_max, *lo, *hi, h, *rw; 3065 3066 memset(&h, 0, sizeof(h)); 3067 h.opcode = op; 3068 3069 rw = (struct opcode_obj_rewrite *)bsearch(&h, ctl3_rewriters, 3070 ctl3_rsize, sizeof(h), compare_opcodes); 3071 if (rw == NULL) 3072 return (1); 3073 3074 /* Find the first element matching the same opcode */ 3075 lo = rw; 3076 for ( ; lo > ctl3_rewriters && (lo - 1)->opcode == op; lo--) 3077 ; 3078 3079 /* Find the last element matching the same opcode */ 3080 hi = rw; 3081 ctl3_max = ctl3_rewriters + ctl3_rsize; 3082 for ( ; (hi + 1) < ctl3_max && (hi + 1)->opcode == op; hi++) 3083 ; 3084 3085 *plo = lo; 3086 *phi = hi; 3087 3088 return (0); 3089 } 3090 3091 /* 3092 * Finds opcode object rewriter based on @code. 3093 * 3094 * Returns pointer to handler or NULL. 3095 */ 3096 static struct opcode_obj_rewrite * 3097 find_op_rw(ipfw_insn *cmd, uint16_t *puidx, uint8_t *ptype) 3098 { 3099 struct opcode_obj_rewrite *rw, *lo, *hi; 3100 uint16_t uidx; 3101 uint8_t subtype; 3102 3103 if (find_op_rw_range(cmd->opcode, &lo, &hi) != 0) 3104 return (NULL); 3105 3106 for (rw = lo; rw <= hi; rw++) { 3107 if (rw->classifier(cmd, &uidx, &subtype) == 0) { 3108 if (puidx != NULL) 3109 *puidx = uidx; 3110 if (ptype != NULL) 3111 *ptype = subtype; 3112 return (rw); 3113 } 3114 } 3115 3116 return (NULL); 3117 } 3118 int 3119 classify_opcode_kidx(ipfw_insn *cmd, uint16_t *puidx) 3120 { 3121 3122 if (find_op_rw(cmd, puidx, NULL) == 0) 3123 return (1); 3124 return (0); 3125 } 3126 3127 void 3128 update_opcode_kidx(ipfw_insn *cmd, uint16_t idx) 3129 { 3130 struct opcode_obj_rewrite *rw; 3131 3132 rw = find_op_rw(cmd, NULL, NULL); 3133 KASSERT(rw != NULL, ("No handler to update opcode %d", cmd->opcode)); 3134 rw->update(cmd, idx); 3135 } 3136 3137 void 3138 ipfw_init_obj_rewriter() 3139 { 3140 3141 ctl3_rewriters = NULL; 3142 ctl3_rsize = 0; 3143 } 3144 3145 void 3146 ipfw_destroy_obj_rewriter() 3147 { 3148 3149 if (ctl3_rewriters != NULL) 3150 free(ctl3_rewriters, M_IPFW); 3151 ctl3_rewriters = NULL; 3152 ctl3_rsize = 0; 3153 } 3154 3155 /* 3156 * Adds one or more opcode object rewrite handlers to the global array. 3157 * Function may sleep. 3158 */ 3159 void 3160 ipfw_add_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count) 3161 { 3162 size_t sz; 3163 struct opcode_obj_rewrite *tmp; 3164 3165 CTL3_LOCK(); 3166 3167 for (;;) { 3168 sz = ctl3_rsize + count; 3169 CTL3_UNLOCK(); 3170 tmp = malloc(sizeof(*rw) * sz, M_IPFW, M_WAITOK | M_ZERO); 3171 CTL3_LOCK(); 3172 if (ctl3_rsize + count <= sz) 3173 break; 3174 3175 /* Retry */ 3176 free(tmp, M_IPFW); 3177 } 3178 3179 /* Merge old & new arrays */ 3180 sz = ctl3_rsize + count; 3181 memcpy(tmp, ctl3_rewriters, ctl3_rsize * sizeof(*rw)); 3182 memcpy(&tmp[ctl3_rsize], rw, count * sizeof(*rw)); 3183 qsort(tmp, sz, sizeof(*rw), compare_opcodes); 3184 /* Switch new and free old */ 3185 if (ctl3_rewriters != NULL) 3186 free(ctl3_rewriters, M_IPFW); 3187 ctl3_rewriters = tmp; 3188 ctl3_rsize = sz; 3189 3190 CTL3_UNLOCK(); 3191 } 3192 3193 /* 3194 * Removes one or more object rewrite handlers from the global array. 3195 */ 3196 int 3197 ipfw_del_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count) 3198 { 3199 size_t sz; 3200 struct opcode_obj_rewrite *ctl3_max, *ktmp, *lo, *hi; 3201 int i; 3202 3203 CTL3_LOCK(); 3204 3205 for (i = 0; i < count; i++) { 3206 if (find_op_rw_range(rw[i].opcode, &lo, &hi) != 0) 3207 continue; 3208 3209 for (ktmp = lo; ktmp <= hi; ktmp++) { 3210 if (ktmp->classifier != rw[i].classifier) 3211 continue; 3212 3213 ctl3_max = ctl3_rewriters + ctl3_rsize; 3214 sz = (ctl3_max - (ktmp + 1)) * sizeof(*ktmp); 3215 memmove(ktmp, ktmp + 1, sz); 3216 ctl3_rsize--; 3217 break; 3218 } 3219 3220 } 3221 3222 if (ctl3_rsize == 0) { 3223 if (ctl3_rewriters != NULL) 3224 free(ctl3_rewriters, M_IPFW); 3225 ctl3_rewriters = NULL; 3226 } 3227 3228 CTL3_UNLOCK(); 3229 3230 return (0); 3231 } 3232 3233 static int 3234 export_objhash_ntlv_internal(struct namedobj_instance *ni, 3235 struct named_object *no, void *arg) 3236 { 3237 struct sockopt_data *sd; 3238 ipfw_obj_ntlv *ntlv; 3239 3240 sd = (struct sockopt_data *)arg; 3241 ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv)); 3242 if (ntlv == NULL) 3243 return (ENOMEM); 3244 ipfw_export_obj_ntlv(no, ntlv); 3245 return (0); 3246 } 3247 3248 /* 3249 * Lists all service objects. 3250 * Data layout (v0)(current): 3251 * Request: [ ipfw_obj_lheader ] size = ipfw_obj_lheader.size 3252 * Reply: [ ipfw_obj_lheader [ ipfw_obj_ntlv x N ] (optional) ] 3253 * Returns 0 on success 3254 */ 3255 static int 3256 dump_srvobjects(struct ip_fw_chain *chain, ip_fw3_opheader *op3, 3257 struct sockopt_data *sd) 3258 { 3259 ipfw_obj_lheader *hdr; 3260 int count; 3261 3262 hdr = (ipfw_obj_lheader *)ipfw_get_sopt_header(sd, sizeof(*hdr)); 3263 if (hdr == NULL) 3264 return (EINVAL); 3265 3266 IPFW_UH_RLOCK(chain); 3267 count = ipfw_objhash_count(CHAIN_TO_SRV(chain)); 3268 hdr->size = sizeof(ipfw_obj_lheader) + count * sizeof(ipfw_obj_ntlv); 3269 if (sd->valsize < hdr->size) { 3270 IPFW_UH_RUNLOCK(chain); 3271 return (ENOMEM); 3272 } 3273 hdr->count = count; 3274 hdr->objsize = sizeof(ipfw_obj_ntlv); 3275 if (count > 0) 3276 ipfw_objhash_foreach(CHAIN_TO_SRV(chain), 3277 export_objhash_ntlv_internal, sd); 3278 IPFW_UH_RUNLOCK(chain); 3279 return (0); 3280 } 3281 3282 /* 3283 * Compares two sopt handlers (code, version and handler ptr). 3284 * Used both as qsort() and bsearch(). 3285 * Does not compare handler for latter case. 3286 * 3287 * Returns 0 if match is found. 3288 */ 3289 static int 3290 compare_sh(const void *_a, const void *_b) 3291 { 3292 const struct ipfw_sopt_handler *a, *b; 3293 3294 a = (const struct ipfw_sopt_handler *)_a; 3295 b = (const struct ipfw_sopt_handler *)_b; 3296 3297 if (a->opcode < b->opcode) 3298 return (-1); 3299 else if (a->opcode > b->opcode) 3300 return (1); 3301 3302 if (a->version < b->version) 3303 return (-1); 3304 else if (a->version > b->version) 3305 return (1); 3306 3307 /* bsearch helper */ 3308 if (a->handler == NULL) 3309 return (0); 3310 3311 if ((uintptr_t)a->handler < (uintptr_t)b->handler) 3312 return (-1); 3313 else if ((uintptr_t)a->handler > (uintptr_t)b->handler) 3314 return (1); 3315 3316 return (0); 3317 } 3318 3319 /* 3320 * Finds sopt handler based on @code and @version. 3321 * 3322 * Returns pointer to handler or NULL. 3323 */ 3324 static struct ipfw_sopt_handler * 3325 find_sh(uint16_t code, uint8_t version, sopt_handler_f *handler) 3326 { 3327 struct ipfw_sopt_handler *sh, h; 3328 3329 memset(&h, 0, sizeof(h)); 3330 h.opcode = code; 3331 h.version = version; 3332 h.handler = handler; 3333 3334 sh = (struct ipfw_sopt_handler *)bsearch(&h, ctl3_handlers, 3335 ctl3_hsize, sizeof(h), compare_sh); 3336 3337 return (sh); 3338 } 3339 3340 static int 3341 find_ref_sh(uint16_t opcode, uint8_t version, struct ipfw_sopt_handler *psh) 3342 { 3343 struct ipfw_sopt_handler *sh; 3344 3345 CTL3_LOCK(); 3346 if ((sh = find_sh(opcode, version, NULL)) == NULL) { 3347 CTL3_UNLOCK(); 3348 printf("ipfw: ipfw_ctl3 invalid option %d""v""%d\n", 3349 opcode, version); 3350 return (EINVAL); 3351 } 3352 sh->refcnt++; 3353 ctl3_refct++; 3354 /* Copy handler data to requested buffer */ 3355 *psh = *sh; 3356 CTL3_UNLOCK(); 3357 3358 return (0); 3359 } 3360 3361 static void 3362 find_unref_sh(struct ipfw_sopt_handler *psh) 3363 { 3364 struct ipfw_sopt_handler *sh; 3365 3366 CTL3_LOCK(); 3367 sh = find_sh(psh->opcode, psh->version, NULL); 3368 KASSERT(sh != NULL, ("ctl3 handler disappeared")); 3369 sh->refcnt--; 3370 ctl3_refct--; 3371 CTL3_UNLOCK(); 3372 } 3373 3374 void 3375 ipfw_init_sopt_handler() 3376 { 3377 3378 CTL3_LOCK_INIT(); 3379 IPFW_ADD_SOPT_HANDLER(1, scodes); 3380 } 3381 3382 void 3383 ipfw_destroy_sopt_handler() 3384 { 3385 3386 IPFW_DEL_SOPT_HANDLER(1, scodes); 3387 CTL3_LOCK_DESTROY(); 3388 } 3389 3390 /* 3391 * Adds one or more sockopt handlers to the global array. 3392 * Function may sleep. 3393 */ 3394 void 3395 ipfw_add_sopt_handler(struct ipfw_sopt_handler *sh, size_t count) 3396 { 3397 size_t sz; 3398 struct ipfw_sopt_handler *tmp; 3399 3400 CTL3_LOCK(); 3401 3402 for (;;) { 3403 sz = ctl3_hsize + count; 3404 CTL3_UNLOCK(); 3405 tmp = malloc(sizeof(*sh) * sz, M_IPFW, M_WAITOK | M_ZERO); 3406 CTL3_LOCK(); 3407 if (ctl3_hsize + count <= sz) 3408 break; 3409 3410 /* Retry */ 3411 free(tmp, M_IPFW); 3412 } 3413 3414 /* Merge old & new arrays */ 3415 sz = ctl3_hsize + count; 3416 memcpy(tmp, ctl3_handlers, ctl3_hsize * sizeof(*sh)); 3417 memcpy(&tmp[ctl3_hsize], sh, count * sizeof(*sh)); 3418 qsort(tmp, sz, sizeof(*sh), compare_sh); 3419 /* Switch new and free old */ 3420 if (ctl3_handlers != NULL) 3421 free(ctl3_handlers, M_IPFW); 3422 ctl3_handlers = tmp; 3423 ctl3_hsize = sz; 3424 ctl3_gencnt++; 3425 3426 CTL3_UNLOCK(); 3427 } 3428 3429 /* 3430 * Removes one or more sockopt handlers from the global array. 3431 */ 3432 int 3433 ipfw_del_sopt_handler(struct ipfw_sopt_handler *sh, size_t count) 3434 { 3435 size_t sz; 3436 struct ipfw_sopt_handler *tmp, *h; 3437 int i; 3438 3439 CTL3_LOCK(); 3440 3441 for (i = 0; i < count; i++) { 3442 tmp = &sh[i]; 3443 h = find_sh(tmp->opcode, tmp->version, tmp->handler); 3444 if (h == NULL) 3445 continue; 3446 3447 sz = (ctl3_handlers + ctl3_hsize - (h + 1)) * sizeof(*h); 3448 memmove(h, h + 1, sz); 3449 ctl3_hsize--; 3450 } 3451 3452 if (ctl3_hsize == 0) { 3453 if (ctl3_handlers != NULL) 3454 free(ctl3_handlers, M_IPFW); 3455 ctl3_handlers = NULL; 3456 } 3457 3458 ctl3_gencnt++; 3459 3460 CTL3_UNLOCK(); 3461 3462 return (0); 3463 } 3464 3465 /* 3466 * Writes data accumulated in @sd to sockopt buffer. 3467 * Zeroes internal @sd buffer. 3468 */ 3469 static int 3470 ipfw_flush_sopt_data(struct sockopt_data *sd) 3471 { 3472 struct sockopt *sopt; 3473 int error; 3474 size_t sz; 3475 3476 sz = sd->koff; 3477 if (sz == 0) 3478 return (0); 3479 3480 sopt = sd->sopt; 3481 3482 if (sopt->sopt_dir == SOPT_GET) { 3483 error = copyout(sd->kbuf, sopt->sopt_val, sz); 3484 if (error != 0) 3485 return (error); 3486 } 3487 3488 memset(sd->kbuf, 0, sd->ksize); 3489 sd->ktotal += sz; 3490 sd->koff = 0; 3491 if (sd->ktotal + sd->ksize < sd->valsize) 3492 sd->kavail = sd->ksize; 3493 else 3494 sd->kavail = sd->valsize - sd->ktotal; 3495 3496 /* Update sopt buffer data */ 3497 sopt->sopt_valsize = sd->ktotal; 3498 sopt->sopt_val = sd->sopt_val + sd->ktotal; 3499 3500 return (0); 3501 } 3502 3503 /* 3504 * Ensures that @sd buffer has contiguous @neeeded number of 3505 * bytes. 3506 * 3507 * Returns pointer to requested space or NULL. 3508 */ 3509 caddr_t 3510 ipfw_get_sopt_space(struct sockopt_data *sd, size_t needed) 3511 { 3512 int error; 3513 caddr_t addr; 3514 3515 if (sd->kavail < needed) { 3516 /* 3517 * Flush data and try another time. 3518 */ 3519 error = ipfw_flush_sopt_data(sd); 3520 3521 if (sd->kavail < needed || error != 0) 3522 return (NULL); 3523 } 3524 3525 addr = sd->kbuf + sd->koff; 3526 sd->koff += needed; 3527 sd->kavail -= needed; 3528 return (addr); 3529 } 3530 3531 /* 3532 * Requests @needed contiguous bytes from @sd buffer. 3533 * Function is used to notify subsystem that we are 3534 * interesed in first @needed bytes (request header) 3535 * and the rest buffer can be safely zeroed. 3536 * 3537 * Returns pointer to requested space or NULL. 3538 */ 3539 caddr_t 3540 ipfw_get_sopt_header(struct sockopt_data *sd, size_t needed) 3541 { 3542 caddr_t addr; 3543 3544 if ((addr = ipfw_get_sopt_space(sd, needed)) == NULL) 3545 return (NULL); 3546 3547 if (sd->kavail > 0) 3548 memset(sd->kbuf + sd->koff, 0, sd->kavail); 3549 3550 return (addr); 3551 } 3552 3553 /* 3554 * New sockopt handler. 3555 */ 3556 int 3557 ipfw_ctl3(struct sockopt *sopt) 3558 { 3559 int error, locked; 3560 size_t size, valsize; 3561 struct ip_fw_chain *chain; 3562 char xbuf[256]; 3563 struct sockopt_data sdata; 3564 struct ipfw_sopt_handler h; 3565 ip_fw3_opheader *op3 = NULL; 3566 3567 error = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW); 3568 if (error != 0) 3569 return (error); 3570 3571 if (sopt->sopt_name != IP_FW3) 3572 return (ipfw_ctl(sopt)); 3573 3574 chain = &V_layer3_chain; 3575 error = 0; 3576 3577 /* Save original valsize before it is altered via sooptcopyin() */ 3578 valsize = sopt->sopt_valsize; 3579 memset(&sdata, 0, sizeof(sdata)); 3580 /* Read op3 header first to determine actual operation */ 3581 op3 = (ip_fw3_opheader *)xbuf; 3582 error = sooptcopyin(sopt, op3, sizeof(*op3), sizeof(*op3)); 3583 if (error != 0) 3584 return (error); 3585 sopt->sopt_valsize = valsize; 3586 3587 /* 3588 * Find and reference command. 3589 */ 3590 error = find_ref_sh(op3->opcode, op3->version, &h); 3591 if (error != 0) 3592 return (error); 3593 3594 /* 3595 * Disallow modifications in really-really secure mode, but still allow 3596 * the logging counters to be reset. 3597 */ 3598 if ((h.dir & HDIR_SET) != 0 && h.opcode != IP_FW_XRESETLOG) { 3599 error = securelevel_ge(sopt->sopt_td->td_ucred, 3); 3600 if (error != 0) { 3601 find_unref_sh(&h); 3602 return (error); 3603 } 3604 } 3605 3606 /* 3607 * Fill in sockopt_data structure that may be useful for 3608 * IP_FW3 get requests. 3609 */ 3610 locked = 0; 3611 if (valsize <= sizeof(xbuf)) { 3612 /* use on-stack buffer */ 3613 sdata.kbuf = xbuf; 3614 sdata.ksize = sizeof(xbuf); 3615 sdata.kavail = valsize; 3616 } else { 3617 3618 /* 3619 * Determine opcode type/buffer size: 3620 * allocate sliding-window buf for data export or 3621 * contiguous buffer for special ops. 3622 */ 3623 if ((h.dir & HDIR_SET) != 0) { 3624 /* Set request. Allocate contigous buffer. */ 3625 if (valsize > CTL3_LARGEBUF) { 3626 find_unref_sh(&h); 3627 return (EFBIG); 3628 } 3629 3630 size = valsize; 3631 } else { 3632 /* Get request. Allocate sliding window buffer */ 3633 size = (valsize<CTL3_SMALLBUF) ? valsize:CTL3_SMALLBUF; 3634 3635 if (size < valsize) { 3636 /* We have to wire user buffer */ 3637 error = vslock(sopt->sopt_val, valsize); 3638 if (error != 0) 3639 return (error); 3640 locked = 1; 3641 } 3642 } 3643 3644 sdata.kbuf = malloc(size, M_TEMP, M_WAITOK | M_ZERO); 3645 sdata.ksize = size; 3646 sdata.kavail = size; 3647 } 3648 3649 sdata.sopt = sopt; 3650 sdata.sopt_val = sopt->sopt_val; 3651 sdata.valsize = valsize; 3652 3653 /* 3654 * Copy either all request (if valsize < bsize_max) 3655 * or first bsize_max bytes to guarantee most consumers 3656 * that all necessary data has been copied). 3657 * Anyway, copy not less than sizeof(ip_fw3_opheader). 3658 */ 3659 if ((error = sooptcopyin(sopt, sdata.kbuf, sdata.ksize, 3660 sizeof(ip_fw3_opheader))) != 0) 3661 return (error); 3662 op3 = (ip_fw3_opheader *)sdata.kbuf; 3663 3664 /* Finally, run handler */ 3665 error = h.handler(chain, op3, &sdata); 3666 find_unref_sh(&h); 3667 3668 /* Flush state and free buffers */ 3669 if (error == 0) 3670 error = ipfw_flush_sopt_data(&sdata); 3671 else 3672 ipfw_flush_sopt_data(&sdata); 3673 3674 if (locked != 0) 3675 vsunlock(sdata.sopt_val, valsize); 3676 3677 /* Restore original pointer and set number of bytes written */ 3678 sopt->sopt_val = sdata.sopt_val; 3679 sopt->sopt_valsize = sdata.ktotal; 3680 if (sdata.kbuf != xbuf) 3681 free(sdata.kbuf, M_TEMP); 3682 3683 return (error); 3684 } 3685 3686 /** 3687 * {set|get}sockopt parser. 3688 */ 3689 int 3690 ipfw_ctl(struct sockopt *sopt) 3691 { 3692 #define RULE_MAXSIZE (512*sizeof(u_int32_t)) 3693 int error; 3694 size_t size, valsize; 3695 struct ip_fw *buf; 3696 struct ip_fw_rule0 *rule; 3697 struct ip_fw_chain *chain; 3698 u_int32_t rulenum[2]; 3699 uint32_t opt; 3700 struct rule_check_info ci; 3701 IPFW_RLOCK_TRACKER; 3702 3703 chain = &V_layer3_chain; 3704 error = 0; 3705 3706 /* Save original valsize before it is altered via sooptcopyin() */ 3707 valsize = sopt->sopt_valsize; 3708 opt = sopt->sopt_name; 3709 3710 /* 3711 * Disallow modifications in really-really secure mode, but still allow 3712 * the logging counters to be reset. 3713 */ 3714 if (opt == IP_FW_ADD || 3715 (sopt->sopt_dir == SOPT_SET && opt != IP_FW_RESETLOG)) { 3716 error = securelevel_ge(sopt->sopt_td->td_ucred, 3); 3717 if (error != 0) 3718 return (error); 3719 } 3720 3721 switch (opt) { 3722 case IP_FW_GET: 3723 /* 3724 * pass up a copy of the current rules. Static rules 3725 * come first (the last of which has number IPFW_DEFAULT_RULE), 3726 * followed by a possibly empty list of dynamic rule. 3727 * The last dynamic rule has NULL in the "next" field. 3728 * 3729 * Note that the calculated size is used to bound the 3730 * amount of data returned to the user. The rule set may 3731 * change between calculating the size and returning the 3732 * data in which case we'll just return what fits. 3733 */ 3734 for (;;) { 3735 int len = 0, want; 3736 3737 size = chain->static_len; 3738 size += ipfw_dyn_len(); 3739 if (size >= sopt->sopt_valsize) 3740 break; 3741 buf = malloc(size, M_TEMP, M_WAITOK | M_ZERO); 3742 IPFW_UH_RLOCK(chain); 3743 /* check again how much space we need */ 3744 want = chain->static_len + ipfw_dyn_len(); 3745 if (size >= want) 3746 len = ipfw_getrules(chain, buf, size); 3747 IPFW_UH_RUNLOCK(chain); 3748 if (size >= want) 3749 error = sooptcopyout(sopt, buf, len); 3750 free(buf, M_TEMP); 3751 if (size >= want) 3752 break; 3753 } 3754 break; 3755 3756 case IP_FW_FLUSH: 3757 /* locking is done within del_entry() */ 3758 error = del_entry(chain, 0); /* special case, rule=0, cmd=0 means all */ 3759 break; 3760 3761 case IP_FW_ADD: 3762 rule = malloc(RULE_MAXSIZE, M_TEMP, M_WAITOK); 3763 error = sooptcopyin(sopt, rule, RULE_MAXSIZE, 3764 sizeof(struct ip_fw7) ); 3765 3766 memset(&ci, 0, sizeof(struct rule_check_info)); 3767 3768 /* 3769 * If the size of commands equals RULESIZE7 then we assume 3770 * a FreeBSD7.2 binary is talking to us (set is7=1). 3771 * is7 is persistent so the next 'ipfw list' command 3772 * will use this format. 3773 * NOTE: If wrong version is guessed (this can happen if 3774 * the first ipfw command is 'ipfw [pipe] list') 3775 * the ipfw binary may crash or loop infinitly... 3776 */ 3777 size = sopt->sopt_valsize; 3778 if (size == RULESIZE7(rule)) { 3779 is7 = 1; 3780 error = convert_rule_to_8(rule); 3781 if (error) { 3782 free(rule, M_TEMP); 3783 return error; 3784 } 3785 size = RULESIZE(rule); 3786 } else 3787 is7 = 0; 3788 if (error == 0) 3789 error = check_ipfw_rule0(rule, size, &ci); 3790 if (error == 0) { 3791 /* locking is done within add_rule() */ 3792 struct ip_fw *krule; 3793 krule = ipfw_alloc_rule(chain, RULEKSIZE0(rule)); 3794 ci.urule = (caddr_t)rule; 3795 ci.krule = krule; 3796 import_rule0(&ci); 3797 error = commit_rules(chain, &ci, 1); 3798 if (error != 0) 3799 free_rule(ci.krule); 3800 else if (sopt->sopt_dir == SOPT_GET) { 3801 if (is7) { 3802 error = convert_rule_to_7(rule); 3803 size = RULESIZE7(rule); 3804 if (error) { 3805 free(rule, M_TEMP); 3806 return error; 3807 } 3808 } 3809 error = sooptcopyout(sopt, rule, size); 3810 } 3811 } 3812 free(rule, M_TEMP); 3813 break; 3814 3815 case IP_FW_DEL: 3816 /* 3817 * IP_FW_DEL is used for deleting single rules or sets, 3818 * and (ab)used to atomically manipulate sets. Argument size 3819 * is used to distinguish between the two: 3820 * sizeof(u_int32_t) 3821 * delete single rule or set of rules, 3822 * or reassign rules (or sets) to a different set. 3823 * 2*sizeof(u_int32_t) 3824 * atomic disable/enable sets. 3825 * first u_int32_t contains sets to be disabled, 3826 * second u_int32_t contains sets to be enabled. 3827 */ 3828 error = sooptcopyin(sopt, rulenum, 3829 2*sizeof(u_int32_t), sizeof(u_int32_t)); 3830 if (error) 3831 break; 3832 size = sopt->sopt_valsize; 3833 if (size == sizeof(u_int32_t) && rulenum[0] != 0) { 3834 /* delete or reassign, locking done in del_entry() */ 3835 error = del_entry(chain, rulenum[0]); 3836 } else if (size == 2*sizeof(u_int32_t)) { /* set enable/disable */ 3837 IPFW_UH_WLOCK(chain); 3838 V_set_disable = 3839 (V_set_disable | rulenum[0]) & ~rulenum[1] & 3840 ~(1<<RESVD_SET); /* set RESVD_SET always enabled */ 3841 IPFW_UH_WUNLOCK(chain); 3842 } else 3843 error = EINVAL; 3844 break; 3845 3846 case IP_FW_ZERO: 3847 case IP_FW_RESETLOG: /* argument is an u_int_32, the rule number */ 3848 rulenum[0] = 0; 3849 if (sopt->sopt_val != 0) { 3850 error = sooptcopyin(sopt, rulenum, 3851 sizeof(u_int32_t), sizeof(u_int32_t)); 3852 if (error) 3853 break; 3854 } 3855 error = zero_entry(chain, rulenum[0], 3856 sopt->sopt_name == IP_FW_RESETLOG); 3857 break; 3858 3859 /*--- TABLE opcodes ---*/ 3860 case IP_FW_TABLE_ADD: 3861 case IP_FW_TABLE_DEL: 3862 { 3863 ipfw_table_entry ent; 3864 struct tentry_info tei; 3865 struct tid_info ti; 3866 struct table_value v; 3867 3868 error = sooptcopyin(sopt, &ent, 3869 sizeof(ent), sizeof(ent)); 3870 if (error) 3871 break; 3872 3873 memset(&tei, 0, sizeof(tei)); 3874 tei.paddr = &ent.addr; 3875 tei.subtype = AF_INET; 3876 tei.masklen = ent.masklen; 3877 ipfw_import_table_value_legacy(ent.value, &v); 3878 tei.pvalue = &v; 3879 memset(&ti, 0, sizeof(ti)); 3880 ti.uidx = ent.tbl; 3881 ti.type = IPFW_TABLE_CIDR; 3882 3883 error = (opt == IP_FW_TABLE_ADD) ? 3884 add_table_entry(chain, &ti, &tei, 0, 1) : 3885 del_table_entry(chain, &ti, &tei, 0, 1); 3886 } 3887 break; 3888 3889 3890 case IP_FW_TABLE_FLUSH: 3891 { 3892 u_int16_t tbl; 3893 struct tid_info ti; 3894 3895 error = sooptcopyin(sopt, &tbl, 3896 sizeof(tbl), sizeof(tbl)); 3897 if (error) 3898 break; 3899 memset(&ti, 0, sizeof(ti)); 3900 ti.uidx = tbl; 3901 error = flush_table(chain, &ti); 3902 } 3903 break; 3904 3905 case IP_FW_TABLE_GETSIZE: 3906 { 3907 u_int32_t tbl, cnt; 3908 struct tid_info ti; 3909 3910 if ((error = sooptcopyin(sopt, &tbl, sizeof(tbl), 3911 sizeof(tbl)))) 3912 break; 3913 memset(&ti, 0, sizeof(ti)); 3914 ti.uidx = tbl; 3915 IPFW_RLOCK(chain); 3916 error = ipfw_count_table(chain, &ti, &cnt); 3917 IPFW_RUNLOCK(chain); 3918 if (error) 3919 break; 3920 error = sooptcopyout(sopt, &cnt, sizeof(cnt)); 3921 } 3922 break; 3923 3924 case IP_FW_TABLE_LIST: 3925 { 3926 ipfw_table *tbl; 3927 struct tid_info ti; 3928 3929 if (sopt->sopt_valsize < sizeof(*tbl)) { 3930 error = EINVAL; 3931 break; 3932 } 3933 size = sopt->sopt_valsize; 3934 tbl = malloc(size, M_TEMP, M_WAITOK); 3935 error = sooptcopyin(sopt, tbl, size, sizeof(*tbl)); 3936 if (error) { 3937 free(tbl, M_TEMP); 3938 break; 3939 } 3940 tbl->size = (size - sizeof(*tbl)) / 3941 sizeof(ipfw_table_entry); 3942 memset(&ti, 0, sizeof(ti)); 3943 ti.uidx = tbl->tbl; 3944 IPFW_RLOCK(chain); 3945 error = ipfw_dump_table_legacy(chain, &ti, tbl); 3946 IPFW_RUNLOCK(chain); 3947 if (error) { 3948 free(tbl, M_TEMP); 3949 break; 3950 } 3951 error = sooptcopyout(sopt, tbl, size); 3952 free(tbl, M_TEMP); 3953 } 3954 break; 3955 3956 /*--- NAT operations are protected by the IPFW_LOCK ---*/ 3957 case IP_FW_NAT_CFG: 3958 if (IPFW_NAT_LOADED) 3959 error = ipfw_nat_cfg_ptr(sopt); 3960 else { 3961 printf("IP_FW_NAT_CFG: %s\n", 3962 "ipfw_nat not present, please load it"); 3963 error = EINVAL; 3964 } 3965 break; 3966 3967 case IP_FW_NAT_DEL: 3968 if (IPFW_NAT_LOADED) 3969 error = ipfw_nat_del_ptr(sopt); 3970 else { 3971 printf("IP_FW_NAT_DEL: %s\n", 3972 "ipfw_nat not present, please load it"); 3973 error = EINVAL; 3974 } 3975 break; 3976 3977 case IP_FW_NAT_GET_CONFIG: 3978 if (IPFW_NAT_LOADED) 3979 error = ipfw_nat_get_cfg_ptr(sopt); 3980 else { 3981 printf("IP_FW_NAT_GET_CFG: %s\n", 3982 "ipfw_nat not present, please load it"); 3983 error = EINVAL; 3984 } 3985 break; 3986 3987 case IP_FW_NAT_GET_LOG: 3988 if (IPFW_NAT_LOADED) 3989 error = ipfw_nat_get_log_ptr(sopt); 3990 else { 3991 printf("IP_FW_NAT_GET_LOG: %s\n", 3992 "ipfw_nat not present, please load it"); 3993 error = EINVAL; 3994 } 3995 break; 3996 3997 default: 3998 printf("ipfw: ipfw_ctl invalid option %d\n", sopt->sopt_name); 3999 error = EINVAL; 4000 } 4001 4002 return (error); 4003 #undef RULE_MAXSIZE 4004 } 4005 #define RULE_MAXSIZE (256*sizeof(u_int32_t)) 4006 4007 /* Functions to convert rules 7.2 <==> 8.0 */ 4008 static int 4009 convert_rule_to_7(struct ip_fw_rule0 *rule) 4010 { 4011 /* Used to modify original rule */ 4012 struct ip_fw7 *rule7 = (struct ip_fw7 *)rule; 4013 /* copy of original rule, version 8 */ 4014 struct ip_fw_rule0 *tmp; 4015 4016 /* Used to copy commands */ 4017 ipfw_insn *ccmd, *dst; 4018 int ll = 0, ccmdlen = 0; 4019 4020 tmp = malloc(RULE_MAXSIZE, M_TEMP, M_NOWAIT | M_ZERO); 4021 if (tmp == NULL) { 4022 return 1; //XXX error 4023 } 4024 bcopy(rule, tmp, RULE_MAXSIZE); 4025 4026 /* Copy fields */ 4027 //rule7->_pad = tmp->_pad; 4028 rule7->set = tmp->set; 4029 rule7->rulenum = tmp->rulenum; 4030 rule7->cmd_len = tmp->cmd_len; 4031 rule7->act_ofs = tmp->act_ofs; 4032 rule7->next_rule = (struct ip_fw7 *)tmp->next_rule; 4033 rule7->cmd_len = tmp->cmd_len; 4034 rule7->pcnt = tmp->pcnt; 4035 rule7->bcnt = tmp->bcnt; 4036 rule7->timestamp = tmp->timestamp; 4037 4038 /* Copy commands */ 4039 for (ll = tmp->cmd_len, ccmd = tmp->cmd, dst = rule7->cmd ; 4040 ll > 0 ; ll -= ccmdlen, ccmd += ccmdlen, dst += ccmdlen) { 4041 ccmdlen = F_LEN(ccmd); 4042 4043 bcopy(ccmd, dst, F_LEN(ccmd)*sizeof(uint32_t)); 4044 4045 if (dst->opcode > O_NAT) 4046 /* O_REASS doesn't exists in 7.2 version, so 4047 * decrement opcode if it is after O_REASS 4048 */ 4049 dst->opcode--; 4050 4051 if (ccmdlen > ll) { 4052 printf("ipfw: opcode %d size truncated\n", 4053 ccmd->opcode); 4054 return EINVAL; 4055 } 4056 } 4057 free(tmp, M_TEMP); 4058 4059 return 0; 4060 } 4061 4062 static int 4063 convert_rule_to_8(struct ip_fw_rule0 *rule) 4064 { 4065 /* Used to modify original rule */ 4066 struct ip_fw7 *rule7 = (struct ip_fw7 *) rule; 4067 4068 /* Used to copy commands */ 4069 ipfw_insn *ccmd, *dst; 4070 int ll = 0, ccmdlen = 0; 4071 4072 /* Copy of original rule */ 4073 struct ip_fw7 *tmp = malloc(RULE_MAXSIZE, M_TEMP, M_NOWAIT | M_ZERO); 4074 if (tmp == NULL) { 4075 return 1; //XXX error 4076 } 4077 4078 bcopy(rule7, tmp, RULE_MAXSIZE); 4079 4080 for (ll = tmp->cmd_len, ccmd = tmp->cmd, dst = rule->cmd ; 4081 ll > 0 ; ll -= ccmdlen, ccmd += ccmdlen, dst += ccmdlen) { 4082 ccmdlen = F_LEN(ccmd); 4083 4084 bcopy(ccmd, dst, F_LEN(ccmd)*sizeof(uint32_t)); 4085 4086 if (dst->opcode > O_NAT) 4087 /* O_REASS doesn't exists in 7.2 version, so 4088 * increment opcode if it is after O_REASS 4089 */ 4090 dst->opcode++; 4091 4092 if (ccmdlen > ll) { 4093 printf("ipfw: opcode %d size truncated\n", 4094 ccmd->opcode); 4095 return EINVAL; 4096 } 4097 } 4098 4099 rule->_pad = tmp->_pad; 4100 rule->set = tmp->set; 4101 rule->rulenum = tmp->rulenum; 4102 rule->cmd_len = tmp->cmd_len; 4103 rule->act_ofs = tmp->act_ofs; 4104 rule->next_rule = (struct ip_fw *)tmp->next_rule; 4105 rule->cmd_len = tmp->cmd_len; 4106 rule->id = 0; /* XXX see if is ok = 0 */ 4107 rule->pcnt = tmp->pcnt; 4108 rule->bcnt = tmp->bcnt; 4109 rule->timestamp = tmp->timestamp; 4110 4111 free (tmp, M_TEMP); 4112 return 0; 4113 } 4114 4115 /* 4116 * Named object api 4117 * 4118 */ 4119 4120 void 4121 ipfw_init_srv(struct ip_fw_chain *ch) 4122 { 4123 4124 ch->srvmap = ipfw_objhash_create(IPFW_OBJECTS_DEFAULT); 4125 ch->srvstate = malloc(sizeof(void *) * IPFW_OBJECTS_DEFAULT, 4126 M_IPFW, M_WAITOK | M_ZERO); 4127 } 4128 4129 void 4130 ipfw_destroy_srv(struct ip_fw_chain *ch) 4131 { 4132 4133 free(ch->srvstate, M_IPFW); 4134 ipfw_objhash_destroy(ch->srvmap); 4135 } 4136 4137 /* 4138 * Allocate new bitmask which can be used to enlarge/shrink 4139 * named instance index. 4140 */ 4141 void 4142 ipfw_objhash_bitmap_alloc(uint32_t items, void **idx, int *pblocks) 4143 { 4144 size_t size; 4145 int max_blocks; 4146 u_long *idx_mask; 4147 4148 KASSERT((items % BLOCK_ITEMS) == 0, 4149 ("bitmask size needs to power of 2 and greater or equal to %zu", 4150 BLOCK_ITEMS)); 4151 4152 max_blocks = items / BLOCK_ITEMS; 4153 size = items / 8; 4154 idx_mask = malloc(size * IPFW_MAX_SETS, M_IPFW, M_WAITOK); 4155 /* Mark all as free */ 4156 memset(idx_mask, 0xFF, size * IPFW_MAX_SETS); 4157 *idx_mask &= ~(u_long)1; /* Skip index 0 */ 4158 4159 *idx = idx_mask; 4160 *pblocks = max_blocks; 4161 } 4162 4163 /* 4164 * Copy current bitmask index to new one. 4165 */ 4166 void 4167 ipfw_objhash_bitmap_merge(struct namedobj_instance *ni, void **idx, int *blocks) 4168 { 4169 int old_blocks, new_blocks; 4170 u_long *old_idx, *new_idx; 4171 int i; 4172 4173 old_idx = ni->idx_mask; 4174 old_blocks = ni->max_blocks; 4175 new_idx = *idx; 4176 new_blocks = *blocks; 4177 4178 for (i = 0; i < IPFW_MAX_SETS; i++) { 4179 memcpy(&new_idx[new_blocks * i], &old_idx[old_blocks * i], 4180 old_blocks * sizeof(u_long)); 4181 } 4182 } 4183 4184 /* 4185 * Swaps current @ni index with new one. 4186 */ 4187 void 4188 ipfw_objhash_bitmap_swap(struct namedobj_instance *ni, void **idx, int *blocks) 4189 { 4190 int old_blocks; 4191 u_long *old_idx; 4192 4193 old_idx = ni->idx_mask; 4194 old_blocks = ni->max_blocks; 4195 4196 ni->idx_mask = *idx; 4197 ni->max_blocks = *blocks; 4198 4199 /* Save old values */ 4200 *idx = old_idx; 4201 *blocks = old_blocks; 4202 } 4203 4204 void 4205 ipfw_objhash_bitmap_free(void *idx, int blocks) 4206 { 4207 4208 free(idx, M_IPFW); 4209 } 4210 4211 /* 4212 * Creates named hash instance. 4213 * Must be called without holding any locks. 4214 * Return pointer to new instance. 4215 */ 4216 struct namedobj_instance * 4217 ipfw_objhash_create(uint32_t items) 4218 { 4219 struct namedobj_instance *ni; 4220 int i; 4221 size_t size; 4222 4223 size = sizeof(struct namedobj_instance) + 4224 sizeof(struct namedobjects_head) * NAMEDOBJ_HASH_SIZE + 4225 sizeof(struct namedobjects_head) * NAMEDOBJ_HASH_SIZE; 4226 4227 ni = malloc(size, M_IPFW, M_WAITOK | M_ZERO); 4228 ni->nn_size = NAMEDOBJ_HASH_SIZE; 4229 ni->nv_size = NAMEDOBJ_HASH_SIZE; 4230 4231 ni->names = (struct namedobjects_head *)(ni +1); 4232 ni->values = &ni->names[ni->nn_size]; 4233 4234 for (i = 0; i < ni->nn_size; i++) 4235 TAILQ_INIT(&ni->names[i]); 4236 4237 for (i = 0; i < ni->nv_size; i++) 4238 TAILQ_INIT(&ni->values[i]); 4239 4240 /* Set default hashing/comparison functions */ 4241 ni->hash_f = objhash_hash_name; 4242 ni->cmp_f = objhash_cmp_name; 4243 4244 /* Allocate bitmask separately due to possible resize */ 4245 ipfw_objhash_bitmap_alloc(items, (void*)&ni->idx_mask, &ni->max_blocks); 4246 4247 return (ni); 4248 } 4249 4250 void 4251 ipfw_objhash_destroy(struct namedobj_instance *ni) 4252 { 4253 4254 free(ni->idx_mask, M_IPFW); 4255 free(ni, M_IPFW); 4256 } 4257 4258 void 4259 ipfw_objhash_set_funcs(struct namedobj_instance *ni, objhash_hash_f *hash_f, 4260 objhash_cmp_f *cmp_f) 4261 { 4262 4263 ni->hash_f = hash_f; 4264 ni->cmp_f = cmp_f; 4265 } 4266 4267 static uint32_t 4268 objhash_hash_name(struct namedobj_instance *ni, const void *name, uint32_t set) 4269 { 4270 4271 return (fnv_32_str((const char *)name, FNV1_32_INIT)); 4272 } 4273 4274 static int 4275 objhash_cmp_name(struct named_object *no, const void *name, uint32_t set) 4276 { 4277 4278 if ((strcmp(no->name, (const char *)name) == 0) && (no->set == set)) 4279 return (0); 4280 4281 return (1); 4282 } 4283 4284 static uint32_t 4285 objhash_hash_idx(struct namedobj_instance *ni, uint32_t val) 4286 { 4287 uint32_t v; 4288 4289 v = val % (ni->nv_size - 1); 4290 4291 return (v); 4292 } 4293 4294 struct named_object * 4295 ipfw_objhash_lookup_name(struct namedobj_instance *ni, uint32_t set, char *name) 4296 { 4297 struct named_object *no; 4298 uint32_t hash; 4299 4300 hash = ni->hash_f(ni, name, set) % ni->nn_size; 4301 4302 TAILQ_FOREACH(no, &ni->names[hash], nn_next) { 4303 if (ni->cmp_f(no, name, set) == 0) 4304 return (no); 4305 } 4306 4307 return (NULL); 4308 } 4309 4310 /* 4311 * Find named object by @uid. 4312 * Check @tlvs for valid data inside. 4313 * 4314 * Returns pointer to found TLV or NULL. 4315 */ 4316 ipfw_obj_ntlv * 4317 ipfw_find_name_tlv_type(void *tlvs, int len, uint16_t uidx, uint32_t etlv) 4318 { 4319 ipfw_obj_ntlv *ntlv; 4320 uintptr_t pa, pe; 4321 int l; 4322 4323 pa = (uintptr_t)tlvs; 4324 pe = pa + len; 4325 l = 0; 4326 for (; pa < pe; pa += l) { 4327 ntlv = (ipfw_obj_ntlv *)pa; 4328 l = ntlv->head.length; 4329 4330 if (l != sizeof(*ntlv)) 4331 return (NULL); 4332 4333 if (ntlv->idx != uidx) 4334 continue; 4335 /* 4336 * When userland has specified zero TLV type, do 4337 * not compare it with eltv. In some cases userland 4338 * doesn't know what type should it have. Use only 4339 * uidx and name for search named_object. 4340 */ 4341 if (ntlv->head.type != 0 && 4342 ntlv->head.type != (uint16_t)etlv) 4343 continue; 4344 4345 if (ipfw_check_object_name_generic(ntlv->name) != 0) 4346 return (NULL); 4347 4348 return (ntlv); 4349 } 4350 4351 return (NULL); 4352 } 4353 4354 /* 4355 * Finds object config based on either legacy index 4356 * or name in ntlv. 4357 * Note @ti structure contains unchecked data from userland. 4358 * 4359 * Returns 0 in success and fills in @pno with found config 4360 */ 4361 int 4362 ipfw_objhash_find_type(struct namedobj_instance *ni, struct tid_info *ti, 4363 uint32_t etlv, struct named_object **pno) 4364 { 4365 char *name; 4366 ipfw_obj_ntlv *ntlv; 4367 uint32_t set; 4368 4369 if (ti->tlvs == NULL) 4370 return (EINVAL); 4371 4372 ntlv = ipfw_find_name_tlv_type(ti->tlvs, ti->tlen, ti->uidx, etlv); 4373 if (ntlv == NULL) 4374 return (EINVAL); 4375 name = ntlv->name; 4376 4377 /* 4378 * Use set provided by @ti instead of @ntlv one. 4379 * This is needed due to different sets behavior 4380 * controlled by V_fw_tables_sets. 4381 */ 4382 set = ti->set; 4383 *pno = ipfw_objhash_lookup_name(ni, set, name); 4384 if (*pno == NULL) 4385 return (ESRCH); 4386 return (0); 4387 } 4388 4389 /* 4390 * Find named object by name, considering also its TLV type. 4391 */ 4392 struct named_object * 4393 ipfw_objhash_lookup_name_type(struct namedobj_instance *ni, uint32_t set, 4394 uint32_t type, const char *name) 4395 { 4396 struct named_object *no; 4397 uint32_t hash; 4398 4399 hash = ni->hash_f(ni, name, set) % ni->nn_size; 4400 4401 TAILQ_FOREACH(no, &ni->names[hash], nn_next) { 4402 if (ni->cmp_f(no, name, set) == 0 && 4403 no->etlv == (uint16_t)type) 4404 return (no); 4405 } 4406 4407 return (NULL); 4408 } 4409 4410 struct named_object * 4411 ipfw_objhash_lookup_kidx(struct namedobj_instance *ni, uint16_t kidx) 4412 { 4413 struct named_object *no; 4414 uint32_t hash; 4415 4416 hash = objhash_hash_idx(ni, kidx); 4417 4418 TAILQ_FOREACH(no, &ni->values[hash], nv_next) { 4419 if (no->kidx == kidx) 4420 return (no); 4421 } 4422 4423 return (NULL); 4424 } 4425 4426 int 4427 ipfw_objhash_same_name(struct namedobj_instance *ni, struct named_object *a, 4428 struct named_object *b) 4429 { 4430 4431 if ((strcmp(a->name, b->name) == 0) && a->set == b->set) 4432 return (1); 4433 4434 return (0); 4435 } 4436 4437 void 4438 ipfw_objhash_add(struct namedobj_instance *ni, struct named_object *no) 4439 { 4440 uint32_t hash; 4441 4442 hash = ni->hash_f(ni, no->name, no->set) % ni->nn_size; 4443 TAILQ_INSERT_HEAD(&ni->names[hash], no, nn_next); 4444 4445 hash = objhash_hash_idx(ni, no->kidx); 4446 TAILQ_INSERT_HEAD(&ni->values[hash], no, nv_next); 4447 4448 ni->count++; 4449 } 4450 4451 void 4452 ipfw_objhash_del(struct namedobj_instance *ni, struct named_object *no) 4453 { 4454 uint32_t hash; 4455 4456 hash = ni->hash_f(ni, no->name, no->set) % ni->nn_size; 4457 TAILQ_REMOVE(&ni->names[hash], no, nn_next); 4458 4459 hash = objhash_hash_idx(ni, no->kidx); 4460 TAILQ_REMOVE(&ni->values[hash], no, nv_next); 4461 4462 ni->count--; 4463 } 4464 4465 uint32_t 4466 ipfw_objhash_count(struct namedobj_instance *ni) 4467 { 4468 4469 return (ni->count); 4470 } 4471 4472 uint32_t 4473 ipfw_objhash_count_type(struct namedobj_instance *ni, uint16_t type) 4474 { 4475 struct named_object *no; 4476 uint32_t count; 4477 int i; 4478 4479 count = 0; 4480 for (i = 0; i < ni->nn_size; i++) { 4481 TAILQ_FOREACH(no, &ni->names[i], nn_next) { 4482 if (no->etlv == type) 4483 count++; 4484 } 4485 } 4486 return (count); 4487 } 4488 4489 /* 4490 * Runs @func for each found named object. 4491 * It is safe to delete objects from callback 4492 */ 4493 int 4494 ipfw_objhash_foreach(struct namedobj_instance *ni, objhash_cb_t *f, void *arg) 4495 { 4496 struct named_object *no, *no_tmp; 4497 int i, ret; 4498 4499 for (i = 0; i < ni->nn_size; i++) { 4500 TAILQ_FOREACH_SAFE(no, &ni->names[i], nn_next, no_tmp) { 4501 ret = f(ni, no, arg); 4502 if (ret != 0) 4503 return (ret); 4504 } 4505 } 4506 return (0); 4507 } 4508 4509 /* 4510 * Runs @f for each found named object with type @type. 4511 * It is safe to delete objects from callback 4512 */ 4513 int 4514 ipfw_objhash_foreach_type(struct namedobj_instance *ni, objhash_cb_t *f, 4515 void *arg, uint16_t type) 4516 { 4517 struct named_object *no, *no_tmp; 4518 int i, ret; 4519 4520 for (i = 0; i < ni->nn_size; i++) { 4521 TAILQ_FOREACH_SAFE(no, &ni->names[i], nn_next, no_tmp) { 4522 if (no->etlv != type) 4523 continue; 4524 ret = f(ni, no, arg); 4525 if (ret != 0) 4526 return (ret); 4527 } 4528 } 4529 return (0); 4530 } 4531 4532 /* 4533 * Removes index from given set. 4534 * Returns 0 on success. 4535 */ 4536 int 4537 ipfw_objhash_free_idx(struct namedobj_instance *ni, uint16_t idx) 4538 { 4539 u_long *mask; 4540 int i, v; 4541 4542 i = idx / BLOCK_ITEMS; 4543 v = idx % BLOCK_ITEMS; 4544 4545 if (i >= ni->max_blocks) 4546 return (1); 4547 4548 mask = &ni->idx_mask[i]; 4549 4550 if ((*mask & ((u_long)1 << v)) != 0) 4551 return (1); 4552 4553 /* Mark as free */ 4554 *mask |= (u_long)1 << v; 4555 4556 /* Update free offset */ 4557 if (ni->free_off[0] > i) 4558 ni->free_off[0] = i; 4559 4560 return (0); 4561 } 4562 4563 /* 4564 * Allocate new index in given instance and stores in in @pidx. 4565 * Returns 0 on success. 4566 */ 4567 int 4568 ipfw_objhash_alloc_idx(void *n, uint16_t *pidx) 4569 { 4570 struct namedobj_instance *ni; 4571 u_long *mask; 4572 int i, off, v; 4573 4574 ni = (struct namedobj_instance *)n; 4575 4576 off = ni->free_off[0]; 4577 mask = &ni->idx_mask[off]; 4578 4579 for (i = off; i < ni->max_blocks; i++, mask++) { 4580 if ((v = ffsl(*mask)) == 0) 4581 continue; 4582 4583 /* Mark as busy */ 4584 *mask &= ~ ((u_long)1 << (v - 1)); 4585 4586 ni->free_off[0] = i; 4587 4588 v = BLOCK_ITEMS * i + v - 1; 4589 4590 *pidx = v; 4591 return (0); 4592 } 4593 4594 return (1); 4595 } 4596 4597 /* end of file */ 4598