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