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 if (no->refcnt == 1 && rw->destroy_object != NULL) 2352 rw->destroy_object(ch, no); 2353 else 2354 no->refcnt--; 2355 } 2356 } 2357 2358 2359 /* 2360 * Find and reference object (if any) stored in instruction @cmd. 2361 * 2362 * Saves object info in @pidx, sets 2363 * - @found to 1 if object was found and references 2364 * - @unresolved to 1 if object should exists but not found 2365 * 2366 * Returns non-zero value in case of error. 2367 */ 2368 int 2369 ref_opcode_object(struct ip_fw_chain *ch, ipfw_insn *cmd, struct tid_info *ti, 2370 struct obj_idx *pidx, int *found, int *unresolved) 2371 { 2372 struct named_object *no; 2373 struct opcode_obj_rewrite *rw; 2374 int error; 2375 2376 *found = 0; 2377 *unresolved = 0; 2378 2379 /* Check if this opcode is candidate for rewrite */ 2380 rw = ipfw_find_op_rw(cmd->opcode); 2381 if (rw == NULL) 2382 return (0); 2383 2384 /* Check if we need to rewrite this opcode */ 2385 if (rw->classifier(cmd, &ti->uidx, &ti->type) != 0) 2386 return (0); 2387 2388 /* Need to rewrite. Save necessary fields */ 2389 pidx->uidx = ti->uidx; 2390 pidx->type = ti->type; 2391 2392 /* Try to find referenced kernel object */ 2393 error = rw->find_byname(ch, ti, &no); 2394 if (error != 0) 2395 return (error); 2396 if (no == NULL) { 2397 *unresolved = 1; 2398 return (0); 2399 } 2400 2401 /* Found. bump refcount */ 2402 *found = 1; 2403 no->refcnt++; 2404 pidx->kidx = no->kidx; 2405 2406 return (0); 2407 } 2408 2409 /* 2410 * Adds one or more rules to ipfw @chain. 2411 * Data layout (version 0)(current): 2412 * Request: 2413 * [ 2414 * ip_fw3_opheader 2415 * [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional *1) 2416 * [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) ip_fw x N ] (*2) (*3) 2417 * ] 2418 * Reply: 2419 * [ 2420 * ip_fw3_opheader 2421 * [ ipfw_obj_ctlv(IPFW_TLV_TBL_LIST) ipfw_obj_ntlv x N ] (optional) 2422 * [ ipfw_obj_ctlv(IPFW_TLV_RULE_LIST) ip_fw x N ] 2423 * ] 2424 * 2425 * Rules in reply are modified to store their actual ruleset number. 2426 * 2427 * (*1) TLVs inside IPFW_TLV_TBL_LIST needs to be sorted ascending 2428 * accoring to their idx field and there has to be no duplicates. 2429 * (*2) Numbered rules inside IPFW_TLV_RULE_LIST needs to be sorted ascending. 2430 * (*3) Each ip_fw structure needs to be aligned to u64 boundary. 2431 * 2432 * Returns 0 on success. 2433 */ 2434 static int 2435 add_rules(struct ip_fw_chain *chain, ip_fw3_opheader *op3, 2436 struct sockopt_data *sd) 2437 { 2438 ipfw_obj_ctlv *ctlv, *rtlv, *tstate; 2439 ipfw_obj_ntlv *ntlv; 2440 int clen, error, idx; 2441 uint32_t count, read; 2442 struct ip_fw_rule *r; 2443 struct rule_check_info rci, *ci, *cbuf; 2444 int i, rsize; 2445 2446 op3 = (ip_fw3_opheader *)ipfw_get_sopt_space(sd, sd->valsize); 2447 ctlv = (ipfw_obj_ctlv *)(op3 + 1); 2448 2449 read = sizeof(ip_fw3_opheader); 2450 rtlv = NULL; 2451 tstate = NULL; 2452 cbuf = NULL; 2453 memset(&rci, 0, sizeof(struct rule_check_info)); 2454 2455 if (read + sizeof(*ctlv) > sd->valsize) 2456 return (EINVAL); 2457 2458 if (ctlv->head.type == IPFW_TLV_TBLNAME_LIST) { 2459 clen = ctlv->head.length; 2460 /* Check size and alignment */ 2461 if (clen > sd->valsize || clen < sizeof(*ctlv)) 2462 return (EINVAL); 2463 if ((clen % sizeof(uint64_t)) != 0) 2464 return (EINVAL); 2465 2466 /* 2467 * Some table names or other named objects. 2468 * Check for validness. 2469 */ 2470 count = (ctlv->head.length - sizeof(*ctlv)) / sizeof(*ntlv); 2471 if (ctlv->count != count || ctlv->objsize != sizeof(*ntlv)) 2472 return (EINVAL); 2473 2474 /* 2475 * Check each TLV. 2476 * Ensure TLVs are sorted ascending and 2477 * there are no duplicates. 2478 */ 2479 idx = -1; 2480 ntlv = (ipfw_obj_ntlv *)(ctlv + 1); 2481 while (count > 0) { 2482 if (ntlv->head.length != sizeof(ipfw_obj_ntlv)) 2483 return (EINVAL); 2484 2485 error = ipfw_check_object_name_generic(ntlv->name); 2486 if (error != 0) 2487 return (error); 2488 2489 if (ntlv->idx <= idx) 2490 return (EINVAL); 2491 2492 idx = ntlv->idx; 2493 count--; 2494 ntlv++; 2495 } 2496 2497 tstate = ctlv; 2498 read += ctlv->head.length; 2499 ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length); 2500 } 2501 2502 if (read + sizeof(*ctlv) > sd->valsize) 2503 return (EINVAL); 2504 2505 if (ctlv->head.type == IPFW_TLV_RULE_LIST) { 2506 clen = ctlv->head.length; 2507 if (clen + read > sd->valsize || clen < sizeof(*ctlv)) 2508 return (EINVAL); 2509 if ((clen % sizeof(uint64_t)) != 0) 2510 return (EINVAL); 2511 2512 /* 2513 * TODO: Permit adding multiple rules at once 2514 */ 2515 if (ctlv->count != 1) 2516 return (ENOTSUP); 2517 2518 clen -= sizeof(*ctlv); 2519 2520 if (ctlv->count > clen / sizeof(struct ip_fw_rule)) 2521 return (EINVAL); 2522 2523 /* Allocate state for each rule or use stack */ 2524 if (ctlv->count == 1) { 2525 memset(&rci, 0, sizeof(struct rule_check_info)); 2526 cbuf = &rci; 2527 } else 2528 cbuf = malloc(ctlv->count * sizeof(*ci), M_TEMP, 2529 M_WAITOK | M_ZERO); 2530 ci = cbuf; 2531 2532 /* 2533 * Check each rule for validness. 2534 * Ensure numbered rules are sorted ascending 2535 * and properly aligned 2536 */ 2537 idx = 0; 2538 r = (struct ip_fw_rule *)(ctlv + 1); 2539 count = 0; 2540 error = 0; 2541 while (clen > 0) { 2542 rsize = roundup2(RULESIZE(r), sizeof(uint64_t)); 2543 if (rsize > clen || ctlv->count <= count) { 2544 error = EINVAL; 2545 break; 2546 } 2547 2548 ci->ctlv = tstate; 2549 error = check_ipfw_rule1(r, rsize, ci); 2550 if (error != 0) 2551 break; 2552 2553 /* Check sorting */ 2554 if (r->rulenum != 0 && r->rulenum < idx) { 2555 printf("rulenum %d idx %d\n", r->rulenum, idx); 2556 error = EINVAL; 2557 break; 2558 } 2559 idx = r->rulenum; 2560 2561 ci->urule = (caddr_t)r; 2562 2563 rsize = roundup2(rsize, sizeof(uint64_t)); 2564 clen -= rsize; 2565 r = (struct ip_fw_rule *)((caddr_t)r + rsize); 2566 count++; 2567 ci++; 2568 } 2569 2570 if (ctlv->count != count || error != 0) { 2571 if (cbuf != &rci) 2572 free(cbuf, M_TEMP); 2573 return (EINVAL); 2574 } 2575 2576 rtlv = ctlv; 2577 read += ctlv->head.length; 2578 ctlv = (ipfw_obj_ctlv *)((caddr_t)ctlv + ctlv->head.length); 2579 } 2580 2581 if (read != sd->valsize || rtlv == NULL || rtlv->count == 0) { 2582 if (cbuf != NULL && cbuf != &rci) 2583 free(cbuf, M_TEMP); 2584 return (EINVAL); 2585 } 2586 2587 /* 2588 * Passed rules seems to be valid. 2589 * Allocate storage and try to add them to chain. 2590 */ 2591 for (i = 0, ci = cbuf; i < rtlv->count; i++, ci++) { 2592 clen = RULEKSIZE1((struct ip_fw_rule *)ci->urule); 2593 ci->krule = ipfw_alloc_rule(chain, clen); 2594 import_rule1(ci); 2595 } 2596 2597 if ((error = commit_rules(chain, cbuf, rtlv->count)) != 0) { 2598 /* Free allocate krules */ 2599 for (i = 0, ci = cbuf; i < rtlv->count; i++, ci++) 2600 free(ci->krule, M_IPFW); 2601 } 2602 2603 if (cbuf != NULL && cbuf != &rci) 2604 free(cbuf, M_TEMP); 2605 2606 return (error); 2607 } 2608 2609 /* 2610 * Lists all sopts currently registered. 2611 * Data layout (v0)(current): 2612 * Request: [ ipfw_obj_lheader ], size = ipfw_obj_lheader.size 2613 * Reply: [ ipfw_obj_lheader ipfw_sopt_info x N ] 2614 * 2615 * Returns 0 on success 2616 */ 2617 static int 2618 dump_soptcodes(struct ip_fw_chain *chain, ip_fw3_opheader *op3, 2619 struct sockopt_data *sd) 2620 { 2621 struct _ipfw_obj_lheader *olh; 2622 ipfw_sopt_info *i; 2623 struct ipfw_sopt_handler *sh; 2624 uint32_t count, n, size; 2625 2626 olh = (struct _ipfw_obj_lheader *)ipfw_get_sopt_header(sd,sizeof(*olh)); 2627 if (olh == NULL) 2628 return (EINVAL); 2629 if (sd->valsize < olh->size) 2630 return (EINVAL); 2631 2632 CTL3_LOCK(); 2633 count = ctl3_hsize; 2634 size = count * sizeof(ipfw_sopt_info) + sizeof(ipfw_obj_lheader); 2635 2636 /* Fill in header regadless of buffer size */ 2637 olh->count = count; 2638 olh->objsize = sizeof(ipfw_sopt_info); 2639 2640 if (size > olh->size) { 2641 olh->size = size; 2642 CTL3_UNLOCK(); 2643 return (ENOMEM); 2644 } 2645 olh->size = size; 2646 2647 for (n = 1; n <= count; n++) { 2648 i = (ipfw_sopt_info *)ipfw_get_sopt_space(sd, sizeof(*i)); 2649 KASSERT(i != 0, ("previously checked buffer is not enough")); 2650 sh = &ctl3_handlers[n]; 2651 i->opcode = sh->opcode; 2652 i->version = sh->version; 2653 i->refcnt = sh->refcnt; 2654 } 2655 CTL3_UNLOCK(); 2656 2657 return (0); 2658 } 2659 2660 /* 2661 * Compares two opcodes. 2662 * Used both in qsort() and bsearch(). 2663 * 2664 * Returns 0 if match is found. 2665 */ 2666 static int 2667 compare_opcodes(const void *_a, const void *_b) 2668 { 2669 const struct opcode_obj_rewrite *a, *b; 2670 2671 a = (const struct opcode_obj_rewrite *)_a; 2672 b = (const struct opcode_obj_rewrite *)_b; 2673 2674 if (a->opcode < b->opcode) 2675 return (-1); 2676 else if (a->opcode > b->opcode) 2677 return (1); 2678 2679 return (0); 2680 } 2681 2682 /* 2683 * Finds opcode object rewriter based on @code. 2684 * 2685 * Returns pointer to handler or NULL. 2686 */ 2687 struct opcode_obj_rewrite * 2688 ipfw_find_op_rw(uint16_t opcode) 2689 { 2690 struct opcode_obj_rewrite *rw, h; 2691 2692 memset(&h, 0, sizeof(h)); 2693 h.opcode = opcode; 2694 2695 rw = (struct opcode_obj_rewrite *)bsearch(&h, ctl3_rewriters, 2696 ctl3_rsize, sizeof(h), compare_opcodes); 2697 2698 return (rw); 2699 } 2700 2701 int 2702 classify_opcode_kidx(ipfw_insn *cmd, uint16_t *puidx) 2703 { 2704 struct opcode_obj_rewrite *rw; 2705 uint8_t subtype; 2706 2707 rw = ipfw_find_op_rw(cmd->opcode); 2708 if (rw == NULL) 2709 return (1); 2710 2711 return (rw->classifier(cmd, puidx, &subtype)); 2712 } 2713 2714 void 2715 update_opcode_kidx(ipfw_insn *cmd, uint16_t idx) 2716 { 2717 struct opcode_obj_rewrite *rw; 2718 2719 rw = ipfw_find_op_rw(cmd->opcode); 2720 KASSERT(rw != NULL, ("No handler to update opcode %d", cmd->opcode)); 2721 rw->update(cmd, idx); 2722 } 2723 2724 void 2725 ipfw_init_obj_rewriter() 2726 { 2727 2728 ctl3_rewriters = NULL; 2729 ctl3_rsize = 0; 2730 } 2731 2732 void 2733 ipfw_destroy_obj_rewriter() 2734 { 2735 2736 if (ctl3_rewriters != NULL) 2737 free(ctl3_rewriters, M_IPFW); 2738 ctl3_rewriters = NULL; 2739 ctl3_rsize = 0; 2740 } 2741 2742 /* 2743 * Adds one or more opcode object rewrite handlers to the global array. 2744 * Function may sleep. 2745 */ 2746 void 2747 ipfw_add_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count) 2748 { 2749 size_t sz; 2750 struct opcode_obj_rewrite *tmp; 2751 2752 CTL3_LOCK(); 2753 2754 for (;;) { 2755 sz = ctl3_rsize + count; 2756 CTL3_UNLOCK(); 2757 tmp = malloc(sizeof(*rw) * sz, M_IPFW, M_WAITOK | M_ZERO); 2758 CTL3_LOCK(); 2759 if (ctl3_rsize + count <= sz) 2760 break; 2761 2762 /* Retry */ 2763 free(tmp, M_IPFW); 2764 } 2765 2766 /* Merge old & new arrays */ 2767 sz = ctl3_rsize + count; 2768 memcpy(tmp, ctl3_rewriters, ctl3_rsize * sizeof(*rw)); 2769 memcpy(&tmp[ctl3_rsize], rw, count * sizeof(*rw)); 2770 qsort(tmp, sz, sizeof(*rw), compare_opcodes); 2771 /* Switch new and free old */ 2772 if (ctl3_rewriters != NULL) 2773 free(ctl3_rewriters, M_IPFW); 2774 ctl3_rewriters = tmp; 2775 ctl3_rsize = sz; 2776 2777 CTL3_UNLOCK(); 2778 } 2779 2780 /* 2781 * Removes one or more object rewrite handlers from the global array. 2782 */ 2783 int 2784 ipfw_del_obj_rewriter(struct opcode_obj_rewrite *rw, size_t count) 2785 { 2786 size_t sz; 2787 struct opcode_obj_rewrite *tmp, *h; 2788 int i; 2789 2790 CTL3_LOCK(); 2791 2792 for (i = 0; i < count; i++) { 2793 tmp = &rw[i]; 2794 h = ipfw_find_op_rw(tmp->opcode); 2795 if (h == NULL) 2796 continue; 2797 2798 sz = (ctl3_rewriters + ctl3_rsize - (h + 1)) * sizeof(*h); 2799 memmove(h, h + 1, sz); 2800 ctl3_rsize--; 2801 } 2802 2803 if (ctl3_rsize == 0) { 2804 if (ctl3_rewriters != NULL) 2805 free(ctl3_rewriters, M_IPFW); 2806 ctl3_rewriters = NULL; 2807 } 2808 2809 CTL3_UNLOCK(); 2810 2811 return (0); 2812 } 2813 2814 static void 2815 export_objhash_ntlv_internal(struct namedobj_instance *ni, 2816 struct named_object *no, void *arg) 2817 { 2818 struct sockopt_data *sd; 2819 ipfw_obj_ntlv *ntlv; 2820 2821 sd = (struct sockopt_data *)arg; 2822 ntlv = (ipfw_obj_ntlv *)ipfw_get_sopt_space(sd, sizeof(*ntlv)); 2823 if (ntlv == NULL) 2824 return; 2825 ipfw_export_obj_ntlv(no, ntlv); 2826 } 2827 2828 /* 2829 * Lists all service objects. 2830 * Data layout (v0)(current): 2831 * Request: [ ipfw_obj_lheader ] size = ipfw_cfg_lheader.size 2832 * Reply: [ ipfw_obj_lheader [ ipfw_obj_ntlv x N ] (optional) ] 2833 * Returns 0 on success 2834 */ 2835 static int 2836 dump_srvobjects(struct ip_fw_chain *chain, ip_fw3_opheader *op3, 2837 struct sockopt_data *sd) 2838 { 2839 ipfw_obj_lheader *hdr; 2840 int count; 2841 2842 hdr = (ipfw_obj_lheader *)ipfw_get_sopt_header(sd, sizeof(*hdr)); 2843 if (hdr == NULL) 2844 return (EINVAL); 2845 2846 IPFW_UH_RLOCK(chain); 2847 count = ipfw_objhash_count(CHAIN_TO_SRV(chain)); 2848 hdr->size = sizeof(ipfw_obj_lheader) + count * sizeof(ipfw_obj_ntlv); 2849 if (sd->valsize < hdr->size) { 2850 IPFW_UH_RUNLOCK(chain); 2851 return (ENOMEM); 2852 } 2853 hdr->count = count; 2854 hdr->objsize = sizeof(ipfw_obj_ntlv); 2855 if (count > 0) 2856 ipfw_objhash_foreach(CHAIN_TO_SRV(chain), 2857 export_objhash_ntlv_internal, sd); 2858 IPFW_UH_RUNLOCK(chain); 2859 return (0); 2860 } 2861 2862 /* 2863 * Compares two sopt handlers (code, version and handler ptr). 2864 * Used both as qsort() and bsearch(). 2865 * Does not compare handler for latter case. 2866 * 2867 * Returns 0 if match is found. 2868 */ 2869 static int 2870 compare_sh(const void *_a, const void *_b) 2871 { 2872 const struct ipfw_sopt_handler *a, *b; 2873 2874 a = (const struct ipfw_sopt_handler *)_a; 2875 b = (const struct ipfw_sopt_handler *)_b; 2876 2877 if (a->opcode < b->opcode) 2878 return (-1); 2879 else if (a->opcode > b->opcode) 2880 return (1); 2881 2882 if (a->version < b->version) 2883 return (-1); 2884 else if (a->version > b->version) 2885 return (1); 2886 2887 /* bsearch helper */ 2888 if (a->handler == NULL) 2889 return (0); 2890 2891 if ((uintptr_t)a->handler < (uintptr_t)b->handler) 2892 return (-1); 2893 else if ((uintptr_t)a->handler > (uintptr_t)b->handler) 2894 return (1); 2895 2896 return (0); 2897 } 2898 2899 /* 2900 * Finds sopt handler based on @code and @version. 2901 * 2902 * Returns pointer to handler or NULL. 2903 */ 2904 static struct ipfw_sopt_handler * 2905 find_sh(uint16_t code, uint8_t version, sopt_handler_f *handler) 2906 { 2907 struct ipfw_sopt_handler *sh, h; 2908 2909 memset(&h, 0, sizeof(h)); 2910 h.opcode = code; 2911 h.version = version; 2912 h.handler = handler; 2913 2914 sh = (struct ipfw_sopt_handler *)bsearch(&h, ctl3_handlers, 2915 ctl3_hsize, sizeof(h), compare_sh); 2916 2917 return (sh); 2918 } 2919 2920 static int 2921 find_ref_sh(uint16_t opcode, uint8_t version, struct ipfw_sopt_handler *psh) 2922 { 2923 struct ipfw_sopt_handler *sh; 2924 2925 CTL3_LOCK(); 2926 if ((sh = find_sh(opcode, version, NULL)) == NULL) { 2927 CTL3_UNLOCK(); 2928 printf("ipfw: ipfw_ctl3 invalid option %d""v""%d\n", 2929 opcode, version); 2930 return (EINVAL); 2931 } 2932 sh->refcnt++; 2933 ctl3_refct++; 2934 /* Copy handler data to requested buffer */ 2935 *psh = *sh; 2936 CTL3_UNLOCK(); 2937 2938 return (0); 2939 } 2940 2941 static void 2942 find_unref_sh(struct ipfw_sopt_handler *psh) 2943 { 2944 struct ipfw_sopt_handler *sh; 2945 2946 CTL3_LOCK(); 2947 sh = find_sh(psh->opcode, psh->version, NULL); 2948 KASSERT(sh != NULL, ("ctl3 handler disappeared")); 2949 sh->refcnt--; 2950 ctl3_refct--; 2951 CTL3_UNLOCK(); 2952 } 2953 2954 void 2955 ipfw_init_sopt_handler() 2956 { 2957 2958 CTL3_LOCK_INIT(); 2959 IPFW_ADD_SOPT_HANDLER(1, scodes); 2960 } 2961 2962 void 2963 ipfw_destroy_sopt_handler() 2964 { 2965 2966 IPFW_DEL_SOPT_HANDLER(1, scodes); 2967 CTL3_LOCK_DESTROY(); 2968 } 2969 2970 /* 2971 * Adds one or more sockopt handlers to the global array. 2972 * Function may sleep. 2973 */ 2974 void 2975 ipfw_add_sopt_handler(struct ipfw_sopt_handler *sh, size_t count) 2976 { 2977 size_t sz; 2978 struct ipfw_sopt_handler *tmp; 2979 2980 CTL3_LOCK(); 2981 2982 for (;;) { 2983 sz = ctl3_hsize + count; 2984 CTL3_UNLOCK(); 2985 tmp = malloc(sizeof(*sh) * sz, M_IPFW, M_WAITOK | M_ZERO); 2986 CTL3_LOCK(); 2987 if (ctl3_hsize + count <= sz) 2988 break; 2989 2990 /* Retry */ 2991 free(tmp, M_IPFW); 2992 } 2993 2994 /* Merge old & new arrays */ 2995 sz = ctl3_hsize + count; 2996 memcpy(tmp, ctl3_handlers, ctl3_hsize * sizeof(*sh)); 2997 memcpy(&tmp[ctl3_hsize], sh, count * sizeof(*sh)); 2998 qsort(tmp, sz, sizeof(*sh), compare_sh); 2999 /* Switch new and free old */ 3000 if (ctl3_handlers != NULL) 3001 free(ctl3_handlers, M_IPFW); 3002 ctl3_handlers = tmp; 3003 ctl3_hsize = sz; 3004 ctl3_gencnt++; 3005 3006 CTL3_UNLOCK(); 3007 } 3008 3009 /* 3010 * Removes one or more sockopt handlers from the global array. 3011 */ 3012 int 3013 ipfw_del_sopt_handler(struct ipfw_sopt_handler *sh, size_t count) 3014 { 3015 size_t sz; 3016 struct ipfw_sopt_handler *tmp, *h; 3017 int i; 3018 3019 CTL3_LOCK(); 3020 3021 for (i = 0; i < count; i++) { 3022 tmp = &sh[i]; 3023 h = find_sh(tmp->opcode, tmp->version, tmp->handler); 3024 if (h == NULL) 3025 continue; 3026 3027 sz = (ctl3_handlers + ctl3_hsize - (h + 1)) * sizeof(*h); 3028 memmove(h, h + 1, sz); 3029 ctl3_hsize--; 3030 } 3031 3032 if (ctl3_hsize == 0) { 3033 if (ctl3_handlers != NULL) 3034 free(ctl3_handlers, M_IPFW); 3035 ctl3_handlers = NULL; 3036 } 3037 3038 ctl3_gencnt++; 3039 3040 CTL3_UNLOCK(); 3041 3042 return (0); 3043 } 3044 3045 /* 3046 * Writes data accumulated in @sd to sockopt buffer. 3047 * Zeroes internal @sd buffer. 3048 */ 3049 static int 3050 ipfw_flush_sopt_data(struct sockopt_data *sd) 3051 { 3052 struct sockopt *sopt; 3053 int error; 3054 size_t sz; 3055 3056 sz = sd->koff; 3057 if (sz == 0) 3058 return (0); 3059 3060 sopt = sd->sopt; 3061 3062 if (sopt->sopt_dir == SOPT_GET) { 3063 error = copyout(sd->kbuf, sopt->sopt_val, sz); 3064 if (error != 0) 3065 return (error); 3066 } 3067 3068 memset(sd->kbuf, 0, sd->ksize); 3069 sd->ktotal += sz; 3070 sd->koff = 0; 3071 if (sd->ktotal + sd->ksize < sd->valsize) 3072 sd->kavail = sd->ksize; 3073 else 3074 sd->kavail = sd->valsize - sd->ktotal; 3075 3076 /* Update sopt buffer data */ 3077 sopt->sopt_valsize = sd->ktotal; 3078 sopt->sopt_val = sd->sopt_val + sd->ktotal; 3079 3080 return (0); 3081 } 3082 3083 /* 3084 * Ensures that @sd buffer has contigious @neeeded number of 3085 * bytes. 3086 * 3087 * Returns pointer to requested space or NULL. 3088 */ 3089 caddr_t 3090 ipfw_get_sopt_space(struct sockopt_data *sd, size_t needed) 3091 { 3092 int error; 3093 caddr_t addr; 3094 3095 if (sd->kavail < needed) { 3096 /* 3097 * Flush data and try another time. 3098 */ 3099 error = ipfw_flush_sopt_data(sd); 3100 3101 if (sd->kavail < needed || error != 0) 3102 return (NULL); 3103 } 3104 3105 addr = sd->kbuf + sd->koff; 3106 sd->koff += needed; 3107 sd->kavail -= needed; 3108 return (addr); 3109 } 3110 3111 /* 3112 * Requests @needed contigious bytes from @sd buffer. 3113 * Function is used to notify subsystem that we are 3114 * interesed in first @needed bytes (request header) 3115 * and the rest buffer can be safely zeroed. 3116 * 3117 * Returns pointer to requested space or NULL. 3118 */ 3119 caddr_t 3120 ipfw_get_sopt_header(struct sockopt_data *sd, size_t needed) 3121 { 3122 caddr_t addr; 3123 3124 if ((addr = ipfw_get_sopt_space(sd, needed)) == NULL) 3125 return (NULL); 3126 3127 if (sd->kavail > 0) 3128 memset(sd->kbuf + sd->koff, 0, sd->kavail); 3129 3130 return (addr); 3131 } 3132 3133 /* 3134 * New sockopt handler. 3135 */ 3136 int 3137 ipfw_ctl3(struct sockopt *sopt) 3138 { 3139 int error, locked; 3140 size_t size, valsize; 3141 struct ip_fw_chain *chain; 3142 char xbuf[256]; 3143 struct sockopt_data sdata; 3144 struct ipfw_sopt_handler h; 3145 ip_fw3_opheader *op3 = NULL; 3146 3147 error = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW); 3148 if (error != 0) 3149 return (error); 3150 3151 if (sopt->sopt_name != IP_FW3) 3152 return (ipfw_ctl(sopt)); 3153 3154 chain = &V_layer3_chain; 3155 error = 0; 3156 3157 /* Save original valsize before it is altered via sooptcopyin() */ 3158 valsize = sopt->sopt_valsize; 3159 memset(&sdata, 0, sizeof(sdata)); 3160 /* Read op3 header first to determine actual operation */ 3161 op3 = (ip_fw3_opheader *)xbuf; 3162 error = sooptcopyin(sopt, op3, sizeof(*op3), sizeof(*op3)); 3163 if (error != 0) 3164 return (error); 3165 sopt->sopt_valsize = valsize; 3166 3167 /* 3168 * Find and reference command. 3169 */ 3170 error = find_ref_sh(op3->opcode, op3->version, &h); 3171 if (error != 0) 3172 return (error); 3173 3174 /* 3175 * Disallow modifications in really-really secure mode, but still allow 3176 * the logging counters to be reset. 3177 */ 3178 if ((h.dir & HDIR_SET) != 0 && h.opcode != IP_FW_XRESETLOG) { 3179 error = securelevel_ge(sopt->sopt_td->td_ucred, 3); 3180 if (error != 0) { 3181 find_unref_sh(&h); 3182 return (error); 3183 } 3184 } 3185 3186 /* 3187 * Fill in sockopt_data structure that may be useful for 3188 * IP_FW3 get requests. 3189 */ 3190 locked = 0; 3191 if (valsize <= sizeof(xbuf)) { 3192 /* use on-stack buffer */ 3193 sdata.kbuf = xbuf; 3194 sdata.ksize = sizeof(xbuf); 3195 sdata.kavail = valsize; 3196 } else { 3197 3198 /* 3199 * Determine opcode type/buffer size: 3200 * allocate sliding-window buf for data export or 3201 * contigious buffer for special ops. 3202 */ 3203 if ((h.dir & HDIR_SET) != 0) { 3204 /* Set request. Allocate contigous buffer. */ 3205 if (valsize > CTL3_LARGEBUF) { 3206 find_unref_sh(&h); 3207 return (EFBIG); 3208 } 3209 3210 size = valsize; 3211 } else { 3212 /* Get request. Allocate sliding window buffer */ 3213 size = (valsize<CTL3_SMALLBUF) ? valsize:CTL3_SMALLBUF; 3214 3215 if (size < valsize) { 3216 /* We have to wire user buffer */ 3217 error = vslock(sopt->sopt_val, valsize); 3218 if (error != 0) 3219 return (error); 3220 locked = 1; 3221 } 3222 } 3223 3224 sdata.kbuf = malloc(size, M_TEMP, M_WAITOK | M_ZERO); 3225 sdata.ksize = size; 3226 sdata.kavail = size; 3227 } 3228 3229 sdata.sopt = sopt; 3230 sdata.sopt_val = sopt->sopt_val; 3231 sdata.valsize = valsize; 3232 3233 /* 3234 * Copy either all request (if valsize < bsize_max) 3235 * or first bsize_max bytes to guarantee most consumers 3236 * that all necessary data has been copied). 3237 * Anyway, copy not less than sizeof(ip_fw3_opheader). 3238 */ 3239 if ((error = sooptcopyin(sopt, sdata.kbuf, sdata.ksize, 3240 sizeof(ip_fw3_opheader))) != 0) 3241 return (error); 3242 op3 = (ip_fw3_opheader *)sdata.kbuf; 3243 3244 /* Finally, run handler */ 3245 error = h.handler(chain, op3, &sdata); 3246 find_unref_sh(&h); 3247 3248 /* Flush state and free buffers */ 3249 if (error == 0) 3250 error = ipfw_flush_sopt_data(&sdata); 3251 else 3252 ipfw_flush_sopt_data(&sdata); 3253 3254 if (locked != 0) 3255 vsunlock(sdata.sopt_val, valsize); 3256 3257 /* Restore original pointer and set number of bytes written */ 3258 sopt->sopt_val = sdata.sopt_val; 3259 sopt->sopt_valsize = sdata.ktotal; 3260 if (sdata.kbuf != xbuf) 3261 free(sdata.kbuf, M_TEMP); 3262 3263 return (error); 3264 } 3265 3266 /** 3267 * {set|get}sockopt parser. 3268 */ 3269 int 3270 ipfw_ctl(struct sockopt *sopt) 3271 { 3272 #define RULE_MAXSIZE (512*sizeof(u_int32_t)) 3273 int error; 3274 size_t size, valsize; 3275 struct ip_fw *buf; 3276 struct ip_fw_rule0 *rule; 3277 struct ip_fw_chain *chain; 3278 u_int32_t rulenum[2]; 3279 uint32_t opt; 3280 struct rule_check_info ci; 3281 IPFW_RLOCK_TRACKER; 3282 3283 chain = &V_layer3_chain; 3284 error = 0; 3285 3286 /* Save original valsize before it is altered via sooptcopyin() */ 3287 valsize = sopt->sopt_valsize; 3288 opt = sopt->sopt_name; 3289 3290 /* 3291 * Disallow modifications in really-really secure mode, but still allow 3292 * the logging counters to be reset. 3293 */ 3294 if (opt == IP_FW_ADD || 3295 (sopt->sopt_dir == SOPT_SET && opt != IP_FW_RESETLOG)) { 3296 error = securelevel_ge(sopt->sopt_td->td_ucred, 3); 3297 if (error != 0) 3298 return (error); 3299 } 3300 3301 switch (opt) { 3302 case IP_FW_GET: 3303 /* 3304 * pass up a copy of the current rules. Static rules 3305 * come first (the last of which has number IPFW_DEFAULT_RULE), 3306 * followed by a possibly empty list of dynamic rule. 3307 * The last dynamic rule has NULL in the "next" field. 3308 * 3309 * Note that the calculated size is used to bound the 3310 * amount of data returned to the user. The rule set may 3311 * change between calculating the size and returning the 3312 * data in which case we'll just return what fits. 3313 */ 3314 for (;;) { 3315 int len = 0, want; 3316 3317 size = chain->static_len; 3318 size += ipfw_dyn_len(); 3319 if (size >= sopt->sopt_valsize) 3320 break; 3321 buf = malloc(size, M_TEMP, M_WAITOK | M_ZERO); 3322 IPFW_UH_RLOCK(chain); 3323 /* check again how much space we need */ 3324 want = chain->static_len + ipfw_dyn_len(); 3325 if (size >= want) 3326 len = ipfw_getrules(chain, buf, size); 3327 IPFW_UH_RUNLOCK(chain); 3328 if (size >= want) 3329 error = sooptcopyout(sopt, buf, len); 3330 free(buf, M_TEMP); 3331 if (size >= want) 3332 break; 3333 } 3334 break; 3335 3336 case IP_FW_FLUSH: 3337 /* locking is done within del_entry() */ 3338 error = del_entry(chain, 0); /* special case, rule=0, cmd=0 means all */ 3339 break; 3340 3341 case IP_FW_ADD: 3342 rule = malloc(RULE_MAXSIZE, M_TEMP, M_WAITOK); 3343 error = sooptcopyin(sopt, rule, RULE_MAXSIZE, 3344 sizeof(struct ip_fw7) ); 3345 3346 memset(&ci, 0, sizeof(struct rule_check_info)); 3347 3348 /* 3349 * If the size of commands equals RULESIZE7 then we assume 3350 * a FreeBSD7.2 binary is talking to us (set is7=1). 3351 * is7 is persistent so the next 'ipfw list' command 3352 * will use this format. 3353 * NOTE: If wrong version is guessed (this can happen if 3354 * the first ipfw command is 'ipfw [pipe] list') 3355 * the ipfw binary may crash or loop infinitly... 3356 */ 3357 size = sopt->sopt_valsize; 3358 if (size == RULESIZE7(rule)) { 3359 is7 = 1; 3360 error = convert_rule_to_8(rule); 3361 if (error) { 3362 free(rule, M_TEMP); 3363 return error; 3364 } 3365 size = RULESIZE(rule); 3366 } else 3367 is7 = 0; 3368 if (error == 0) 3369 error = check_ipfw_rule0(rule, size, &ci); 3370 if (error == 0) { 3371 /* locking is done within add_rule() */ 3372 struct ip_fw *krule; 3373 krule = ipfw_alloc_rule(chain, RULEKSIZE0(rule)); 3374 ci.urule = (caddr_t)rule; 3375 ci.krule = krule; 3376 import_rule0(&ci); 3377 error = commit_rules(chain, &ci, 1); 3378 if (!error && sopt->sopt_dir == SOPT_GET) { 3379 if (is7) { 3380 error = convert_rule_to_7(rule); 3381 size = RULESIZE7(rule); 3382 if (error) { 3383 free(rule, M_TEMP); 3384 return error; 3385 } 3386 } 3387 error = sooptcopyout(sopt, rule, size); 3388 } 3389 } 3390 free(rule, M_TEMP); 3391 break; 3392 3393 case IP_FW_DEL: 3394 /* 3395 * IP_FW_DEL is used for deleting single rules or sets, 3396 * and (ab)used to atomically manipulate sets. Argument size 3397 * is used to distinguish between the two: 3398 * sizeof(u_int32_t) 3399 * delete single rule or set of rules, 3400 * or reassign rules (or sets) to a different set. 3401 * 2*sizeof(u_int32_t) 3402 * atomic disable/enable sets. 3403 * first u_int32_t contains sets to be disabled, 3404 * second u_int32_t contains sets to be enabled. 3405 */ 3406 error = sooptcopyin(sopt, rulenum, 3407 2*sizeof(u_int32_t), sizeof(u_int32_t)); 3408 if (error) 3409 break; 3410 size = sopt->sopt_valsize; 3411 if (size == sizeof(u_int32_t) && rulenum[0] != 0) { 3412 /* delete or reassign, locking done in del_entry() */ 3413 error = del_entry(chain, rulenum[0]); 3414 } else if (size == 2*sizeof(u_int32_t)) { /* set enable/disable */ 3415 IPFW_UH_WLOCK(chain); 3416 V_set_disable = 3417 (V_set_disable | rulenum[0]) & ~rulenum[1] & 3418 ~(1<<RESVD_SET); /* set RESVD_SET always enabled */ 3419 IPFW_UH_WUNLOCK(chain); 3420 } else 3421 error = EINVAL; 3422 break; 3423 3424 case IP_FW_ZERO: 3425 case IP_FW_RESETLOG: /* argument is an u_int_32, the rule number */ 3426 rulenum[0] = 0; 3427 if (sopt->sopt_val != 0) { 3428 error = sooptcopyin(sopt, rulenum, 3429 sizeof(u_int32_t), sizeof(u_int32_t)); 3430 if (error) 3431 break; 3432 } 3433 error = zero_entry(chain, rulenum[0], 3434 sopt->sopt_name == IP_FW_RESETLOG); 3435 break; 3436 3437 /*--- TABLE opcodes ---*/ 3438 case IP_FW_TABLE_ADD: 3439 case IP_FW_TABLE_DEL: 3440 { 3441 ipfw_table_entry ent; 3442 struct tentry_info tei; 3443 struct tid_info ti; 3444 struct table_value v; 3445 3446 error = sooptcopyin(sopt, &ent, 3447 sizeof(ent), sizeof(ent)); 3448 if (error) 3449 break; 3450 3451 memset(&tei, 0, sizeof(tei)); 3452 tei.paddr = &ent.addr; 3453 tei.subtype = AF_INET; 3454 tei.masklen = ent.masklen; 3455 ipfw_import_table_value_legacy(ent.value, &v); 3456 tei.pvalue = &v; 3457 memset(&ti, 0, sizeof(ti)); 3458 ti.uidx = ent.tbl; 3459 ti.type = IPFW_TABLE_CIDR; 3460 3461 error = (opt == IP_FW_TABLE_ADD) ? 3462 add_table_entry(chain, &ti, &tei, 0, 1) : 3463 del_table_entry(chain, &ti, &tei, 0, 1); 3464 } 3465 break; 3466 3467 3468 case IP_FW_TABLE_FLUSH: 3469 { 3470 u_int16_t tbl; 3471 struct tid_info ti; 3472 3473 error = sooptcopyin(sopt, &tbl, 3474 sizeof(tbl), sizeof(tbl)); 3475 if (error) 3476 break; 3477 memset(&ti, 0, sizeof(ti)); 3478 ti.uidx = tbl; 3479 error = flush_table(chain, &ti); 3480 } 3481 break; 3482 3483 case IP_FW_TABLE_GETSIZE: 3484 { 3485 u_int32_t tbl, cnt; 3486 struct tid_info ti; 3487 3488 if ((error = sooptcopyin(sopt, &tbl, sizeof(tbl), 3489 sizeof(tbl)))) 3490 break; 3491 memset(&ti, 0, sizeof(ti)); 3492 ti.uidx = tbl; 3493 IPFW_RLOCK(chain); 3494 error = ipfw_count_table(chain, &ti, &cnt); 3495 IPFW_RUNLOCK(chain); 3496 if (error) 3497 break; 3498 error = sooptcopyout(sopt, &cnt, sizeof(cnt)); 3499 } 3500 break; 3501 3502 case IP_FW_TABLE_LIST: 3503 { 3504 ipfw_table *tbl; 3505 struct tid_info ti; 3506 3507 if (sopt->sopt_valsize < sizeof(*tbl)) { 3508 error = EINVAL; 3509 break; 3510 } 3511 size = sopt->sopt_valsize; 3512 tbl = malloc(size, M_TEMP, M_WAITOK); 3513 error = sooptcopyin(sopt, tbl, size, sizeof(*tbl)); 3514 if (error) { 3515 free(tbl, M_TEMP); 3516 break; 3517 } 3518 tbl->size = (size - sizeof(*tbl)) / 3519 sizeof(ipfw_table_entry); 3520 memset(&ti, 0, sizeof(ti)); 3521 ti.uidx = tbl->tbl; 3522 IPFW_RLOCK(chain); 3523 error = ipfw_dump_table_legacy(chain, &ti, tbl); 3524 IPFW_RUNLOCK(chain); 3525 if (error) { 3526 free(tbl, M_TEMP); 3527 break; 3528 } 3529 error = sooptcopyout(sopt, tbl, size); 3530 free(tbl, M_TEMP); 3531 } 3532 break; 3533 3534 /*--- NAT operations are protected by the IPFW_LOCK ---*/ 3535 case IP_FW_NAT_CFG: 3536 if (IPFW_NAT_LOADED) 3537 error = ipfw_nat_cfg_ptr(sopt); 3538 else { 3539 printf("IP_FW_NAT_CFG: %s\n", 3540 "ipfw_nat not present, please load it"); 3541 error = EINVAL; 3542 } 3543 break; 3544 3545 case IP_FW_NAT_DEL: 3546 if (IPFW_NAT_LOADED) 3547 error = ipfw_nat_del_ptr(sopt); 3548 else { 3549 printf("IP_FW_NAT_DEL: %s\n", 3550 "ipfw_nat not present, please load it"); 3551 error = EINVAL; 3552 } 3553 break; 3554 3555 case IP_FW_NAT_GET_CONFIG: 3556 if (IPFW_NAT_LOADED) 3557 error = ipfw_nat_get_cfg_ptr(sopt); 3558 else { 3559 printf("IP_FW_NAT_GET_CFG: %s\n", 3560 "ipfw_nat not present, please load it"); 3561 error = EINVAL; 3562 } 3563 break; 3564 3565 case IP_FW_NAT_GET_LOG: 3566 if (IPFW_NAT_LOADED) 3567 error = ipfw_nat_get_log_ptr(sopt); 3568 else { 3569 printf("IP_FW_NAT_GET_LOG: %s\n", 3570 "ipfw_nat not present, please load it"); 3571 error = EINVAL; 3572 } 3573 break; 3574 3575 default: 3576 printf("ipfw: ipfw_ctl invalid option %d\n", sopt->sopt_name); 3577 error = EINVAL; 3578 } 3579 3580 return (error); 3581 #undef RULE_MAXSIZE 3582 } 3583 #define RULE_MAXSIZE (256*sizeof(u_int32_t)) 3584 3585 /* Functions to convert rules 7.2 <==> 8.0 */ 3586 static int 3587 convert_rule_to_7(struct ip_fw_rule0 *rule) 3588 { 3589 /* Used to modify original rule */ 3590 struct ip_fw7 *rule7 = (struct ip_fw7 *)rule; 3591 /* copy of original rule, version 8 */ 3592 struct ip_fw_rule0 *tmp; 3593 3594 /* Used to copy commands */ 3595 ipfw_insn *ccmd, *dst; 3596 int ll = 0, ccmdlen = 0; 3597 3598 tmp = malloc(RULE_MAXSIZE, M_TEMP, M_NOWAIT | M_ZERO); 3599 if (tmp == NULL) { 3600 return 1; //XXX error 3601 } 3602 bcopy(rule, tmp, RULE_MAXSIZE); 3603 3604 /* Copy fields */ 3605 //rule7->_pad = tmp->_pad; 3606 rule7->set = tmp->set; 3607 rule7->rulenum = tmp->rulenum; 3608 rule7->cmd_len = tmp->cmd_len; 3609 rule7->act_ofs = tmp->act_ofs; 3610 rule7->next_rule = (struct ip_fw7 *)tmp->next_rule; 3611 rule7->cmd_len = tmp->cmd_len; 3612 rule7->pcnt = tmp->pcnt; 3613 rule7->bcnt = tmp->bcnt; 3614 rule7->timestamp = tmp->timestamp; 3615 3616 /* Copy commands */ 3617 for (ll = tmp->cmd_len, ccmd = tmp->cmd, dst = rule7->cmd ; 3618 ll > 0 ; ll -= ccmdlen, ccmd += ccmdlen, dst += ccmdlen) { 3619 ccmdlen = F_LEN(ccmd); 3620 3621 bcopy(ccmd, dst, F_LEN(ccmd)*sizeof(uint32_t)); 3622 3623 if (dst->opcode > O_NAT) 3624 /* O_REASS doesn't exists in 7.2 version, so 3625 * decrement opcode if it is after O_REASS 3626 */ 3627 dst->opcode--; 3628 3629 if (ccmdlen > ll) { 3630 printf("ipfw: opcode %d size truncated\n", 3631 ccmd->opcode); 3632 return EINVAL; 3633 } 3634 } 3635 free(tmp, M_TEMP); 3636 3637 return 0; 3638 } 3639 3640 static int 3641 convert_rule_to_8(struct ip_fw_rule0 *rule) 3642 { 3643 /* Used to modify original rule */ 3644 struct ip_fw7 *rule7 = (struct ip_fw7 *) rule; 3645 3646 /* Used to copy commands */ 3647 ipfw_insn *ccmd, *dst; 3648 int ll = 0, ccmdlen = 0; 3649 3650 /* Copy of original rule */ 3651 struct ip_fw7 *tmp = malloc(RULE_MAXSIZE, M_TEMP, M_NOWAIT | M_ZERO); 3652 if (tmp == NULL) { 3653 return 1; //XXX error 3654 } 3655 3656 bcopy(rule7, tmp, RULE_MAXSIZE); 3657 3658 for (ll = tmp->cmd_len, ccmd = tmp->cmd, dst = rule->cmd ; 3659 ll > 0 ; ll -= ccmdlen, ccmd += ccmdlen, dst += ccmdlen) { 3660 ccmdlen = F_LEN(ccmd); 3661 3662 bcopy(ccmd, dst, F_LEN(ccmd)*sizeof(uint32_t)); 3663 3664 if (dst->opcode > O_NAT) 3665 /* O_REASS doesn't exists in 7.2 version, so 3666 * increment opcode if it is after O_REASS 3667 */ 3668 dst->opcode++; 3669 3670 if (ccmdlen > ll) { 3671 printf("ipfw: opcode %d size truncated\n", 3672 ccmd->opcode); 3673 return EINVAL; 3674 } 3675 } 3676 3677 rule->_pad = tmp->_pad; 3678 rule->set = tmp->set; 3679 rule->rulenum = tmp->rulenum; 3680 rule->cmd_len = tmp->cmd_len; 3681 rule->act_ofs = tmp->act_ofs; 3682 rule->next_rule = (struct ip_fw *)tmp->next_rule; 3683 rule->cmd_len = tmp->cmd_len; 3684 rule->id = 0; /* XXX see if is ok = 0 */ 3685 rule->pcnt = tmp->pcnt; 3686 rule->bcnt = tmp->bcnt; 3687 rule->timestamp = tmp->timestamp; 3688 3689 free (tmp, M_TEMP); 3690 return 0; 3691 } 3692 3693 /* 3694 * Named object api 3695 * 3696 */ 3697 3698 void 3699 ipfw_init_srv(struct ip_fw_chain *ch) 3700 { 3701 3702 ch->srvmap = ipfw_objhash_create(IPFW_OBJECTS_DEFAULT); 3703 ch->srvstate = malloc(sizeof(void *) * IPFW_OBJECTS_DEFAULT, 3704 M_IPFW, M_WAITOK | M_ZERO); 3705 } 3706 3707 void 3708 ipfw_destroy_srv(struct ip_fw_chain *ch) 3709 { 3710 3711 free(ch->srvstate, M_IPFW); 3712 ipfw_objhash_destroy(ch->srvmap); 3713 } 3714 3715 /* 3716 * Allocate new bitmask which can be used to enlarge/shrink 3717 * named instance index. 3718 */ 3719 void 3720 ipfw_objhash_bitmap_alloc(uint32_t items, void **idx, int *pblocks) 3721 { 3722 size_t size; 3723 int max_blocks; 3724 u_long *idx_mask; 3725 3726 KASSERT((items % BLOCK_ITEMS) == 0, 3727 ("bitmask size needs to power of 2 and greater or equal to %zu", 3728 BLOCK_ITEMS)); 3729 3730 max_blocks = items / BLOCK_ITEMS; 3731 size = items / 8; 3732 idx_mask = malloc(size * IPFW_MAX_SETS, M_IPFW, M_WAITOK); 3733 /* Mark all as free */ 3734 memset(idx_mask, 0xFF, size * IPFW_MAX_SETS); 3735 *idx_mask &= ~(u_long)1; /* Skip index 0 */ 3736 3737 *idx = idx_mask; 3738 *pblocks = max_blocks; 3739 } 3740 3741 /* 3742 * Copy current bitmask index to new one. 3743 */ 3744 void 3745 ipfw_objhash_bitmap_merge(struct namedobj_instance *ni, void **idx, int *blocks) 3746 { 3747 int old_blocks, new_blocks; 3748 u_long *old_idx, *new_idx; 3749 int i; 3750 3751 old_idx = ni->idx_mask; 3752 old_blocks = ni->max_blocks; 3753 new_idx = *idx; 3754 new_blocks = *blocks; 3755 3756 for (i = 0; i < IPFW_MAX_SETS; i++) { 3757 memcpy(&new_idx[new_blocks * i], &old_idx[old_blocks * i], 3758 old_blocks * sizeof(u_long)); 3759 } 3760 } 3761 3762 /* 3763 * Swaps current @ni index with new one. 3764 */ 3765 void 3766 ipfw_objhash_bitmap_swap(struct namedobj_instance *ni, void **idx, int *blocks) 3767 { 3768 int old_blocks; 3769 u_long *old_idx; 3770 3771 old_idx = ni->idx_mask; 3772 old_blocks = ni->max_blocks; 3773 3774 ni->idx_mask = *idx; 3775 ni->max_blocks = *blocks; 3776 3777 /* Save old values */ 3778 *idx = old_idx; 3779 *blocks = old_blocks; 3780 } 3781 3782 void 3783 ipfw_objhash_bitmap_free(void *idx, int blocks) 3784 { 3785 3786 free(idx, M_IPFW); 3787 } 3788 3789 /* 3790 * Creates named hash instance. 3791 * Must be called without holding any locks. 3792 * Return pointer to new instance. 3793 */ 3794 struct namedobj_instance * 3795 ipfw_objhash_create(uint32_t items) 3796 { 3797 struct namedobj_instance *ni; 3798 int i; 3799 size_t size; 3800 3801 size = sizeof(struct namedobj_instance) + 3802 sizeof(struct namedobjects_head) * NAMEDOBJ_HASH_SIZE + 3803 sizeof(struct namedobjects_head) * NAMEDOBJ_HASH_SIZE; 3804 3805 ni = malloc(size, M_IPFW, M_WAITOK | M_ZERO); 3806 ni->nn_size = NAMEDOBJ_HASH_SIZE; 3807 ni->nv_size = NAMEDOBJ_HASH_SIZE; 3808 3809 ni->names = (struct namedobjects_head *)(ni +1); 3810 ni->values = &ni->names[ni->nn_size]; 3811 3812 for (i = 0; i < ni->nn_size; i++) 3813 TAILQ_INIT(&ni->names[i]); 3814 3815 for (i = 0; i < ni->nv_size; i++) 3816 TAILQ_INIT(&ni->values[i]); 3817 3818 /* Set default hashing/comparison functions */ 3819 ni->hash_f = objhash_hash_name; 3820 ni->cmp_f = objhash_cmp_name; 3821 3822 /* Allocate bitmask separately due to possible resize */ 3823 ipfw_objhash_bitmap_alloc(items, (void*)&ni->idx_mask, &ni->max_blocks); 3824 3825 return (ni); 3826 } 3827 3828 void 3829 ipfw_objhash_destroy(struct namedobj_instance *ni) 3830 { 3831 3832 free(ni->idx_mask, M_IPFW); 3833 free(ni, M_IPFW); 3834 } 3835 3836 void 3837 ipfw_objhash_set_funcs(struct namedobj_instance *ni, objhash_hash_f *hash_f, 3838 objhash_cmp_f *cmp_f) 3839 { 3840 3841 ni->hash_f = hash_f; 3842 ni->cmp_f = cmp_f; 3843 } 3844 3845 static uint32_t 3846 objhash_hash_name(struct namedobj_instance *ni, void *name, uint32_t set) 3847 { 3848 3849 return (fnv_32_str((char *)name, FNV1_32_INIT)); 3850 } 3851 3852 static int 3853 objhash_cmp_name(struct named_object *no, void *name, uint32_t set) 3854 { 3855 3856 if ((strcmp(no->name, (char *)name) == 0) && (no->set == set)) 3857 return (0); 3858 3859 return (1); 3860 } 3861 3862 static uint32_t 3863 objhash_hash_idx(struct namedobj_instance *ni, uint32_t val) 3864 { 3865 uint32_t v; 3866 3867 v = val % (ni->nv_size - 1); 3868 3869 return (v); 3870 } 3871 3872 struct named_object * 3873 ipfw_objhash_lookup_name(struct namedobj_instance *ni, uint32_t set, char *name) 3874 { 3875 struct named_object *no; 3876 uint32_t hash; 3877 3878 hash = ni->hash_f(ni, name, set) % ni->nn_size; 3879 3880 TAILQ_FOREACH(no, &ni->names[hash], nn_next) { 3881 if (ni->cmp_f(no, name, set) == 0) 3882 return (no); 3883 } 3884 3885 return (NULL); 3886 } 3887 3888 /* 3889 * Find named object by name, considering also its TLV type. 3890 */ 3891 struct named_object * 3892 ipfw_objhash_lookup_name_type(struct namedobj_instance *ni, uint32_t set, 3893 uint32_t type, char *name) 3894 { 3895 struct named_object *no; 3896 uint32_t hash; 3897 3898 hash = ni->hash_f(ni, name, set) % ni->nn_size; 3899 3900 TAILQ_FOREACH(no, &ni->names[hash], nn_next) { 3901 if (ni->cmp_f(no, name, set) == 0 && no->etlv == type) 3902 return (no); 3903 } 3904 3905 return (NULL); 3906 } 3907 3908 struct named_object * 3909 ipfw_objhash_lookup_kidx(struct namedobj_instance *ni, uint16_t kidx) 3910 { 3911 struct named_object *no; 3912 uint32_t hash; 3913 3914 hash = objhash_hash_idx(ni, kidx); 3915 3916 TAILQ_FOREACH(no, &ni->values[hash], nv_next) { 3917 if (no->kidx == kidx) 3918 return (no); 3919 } 3920 3921 return (NULL); 3922 } 3923 3924 int 3925 ipfw_objhash_same_name(struct namedobj_instance *ni, struct named_object *a, 3926 struct named_object *b) 3927 { 3928 3929 if ((strcmp(a->name, b->name) == 0) && a->set == b->set) 3930 return (1); 3931 3932 return (0); 3933 } 3934 3935 void 3936 ipfw_objhash_add(struct namedobj_instance *ni, struct named_object *no) 3937 { 3938 uint32_t hash; 3939 3940 hash = ni->hash_f(ni, no->name, no->set) % ni->nn_size; 3941 TAILQ_INSERT_HEAD(&ni->names[hash], no, nn_next); 3942 3943 hash = objhash_hash_idx(ni, no->kidx); 3944 TAILQ_INSERT_HEAD(&ni->values[hash], no, nv_next); 3945 3946 ni->count++; 3947 } 3948 3949 void 3950 ipfw_objhash_del(struct namedobj_instance *ni, struct named_object *no) 3951 { 3952 uint32_t hash; 3953 3954 hash = ni->hash_f(ni, no->name, no->set) % ni->nn_size; 3955 TAILQ_REMOVE(&ni->names[hash], no, nn_next); 3956 3957 hash = objhash_hash_idx(ni, no->kidx); 3958 TAILQ_REMOVE(&ni->values[hash], no, nv_next); 3959 3960 ni->count--; 3961 } 3962 3963 uint32_t 3964 ipfw_objhash_count(struct namedobj_instance *ni) 3965 { 3966 3967 return (ni->count); 3968 } 3969 3970 /* 3971 * Runs @func for each found named object. 3972 * It is safe to delete objects from callback 3973 */ 3974 void 3975 ipfw_objhash_foreach(struct namedobj_instance *ni, objhash_cb_t *f, void *arg) 3976 { 3977 struct named_object *no, *no_tmp; 3978 int i; 3979 3980 for (i = 0; i < ni->nn_size; i++) { 3981 TAILQ_FOREACH_SAFE(no, &ni->names[i], nn_next, no_tmp) 3982 f(ni, no, arg); 3983 } 3984 } 3985 3986 /* 3987 * Removes index from given set. 3988 * Returns 0 on success. 3989 */ 3990 int 3991 ipfw_objhash_free_idx(struct namedobj_instance *ni, uint16_t idx) 3992 { 3993 u_long *mask; 3994 int i, v; 3995 3996 i = idx / BLOCK_ITEMS; 3997 v = idx % BLOCK_ITEMS; 3998 3999 if (i >= ni->max_blocks) 4000 return (1); 4001 4002 mask = &ni->idx_mask[i]; 4003 4004 if ((*mask & ((u_long)1 << v)) != 0) 4005 return (1); 4006 4007 /* Mark as free */ 4008 *mask |= (u_long)1 << v; 4009 4010 /* Update free offset */ 4011 if (ni->free_off[0] > i) 4012 ni->free_off[0] = i; 4013 4014 return (0); 4015 } 4016 4017 /* 4018 * Allocate new index in given instance and stores in in @pidx. 4019 * Returns 0 on success. 4020 */ 4021 int 4022 ipfw_objhash_alloc_idx(void *n, uint16_t *pidx) 4023 { 4024 struct namedobj_instance *ni; 4025 u_long *mask; 4026 int i, off, v; 4027 4028 ni = (struct namedobj_instance *)n; 4029 4030 off = ni->free_off[0]; 4031 mask = &ni->idx_mask[off]; 4032 4033 for (i = off; i < ni->max_blocks; i++, mask++) { 4034 if ((v = ffsl(*mask)) == 0) 4035 continue; 4036 4037 /* Mark as busy */ 4038 *mask &= ~ ((u_long)1 << (v - 1)); 4039 4040 ni->free_off[0] = i; 4041 4042 v = BLOCK_ITEMS * i + v - 1; 4043 4044 *pidx = v; 4045 return (0); 4046 } 4047 4048 return (1); 4049 } 4050 4051 /* end of file */ 4052