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