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