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