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