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