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