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