ip_fw_sockopt.c revision 201732
1/*- 2 * Copyright (c) 2002-2009 Luigi Rizzo, Universita` di Pisa 3 * 4 * Supported by: Valeria Paoli 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: head/sys/netinet/ipfw/ip_fw_sockopt.c 201732 2010-01-07 10:08:05Z luigi $"); 30 31/* 32 * Sockopt support for ipfw. The routines here implement 33 * the upper half of the ipfw code. 34 */ 35 36#if !defined(KLD_MODULE) 37#include "opt_ipfw.h" 38#include "opt_ipdivert.h" 39#include "opt_ipdn.h" 40#include "opt_inet.h" 41#ifndef INET 42#error IPFIREWALL requires INET. 43#endif /* INET */ 44#endif 45#include "opt_inet6.h" 46#include "opt_ipsec.h" 47 48#include <sys/param.h> 49#include <sys/systm.h> 50#include <sys/malloc.h> 51#include <sys/mbuf.h> /* struct m_tag used by nested headers */ 52#include <sys/kernel.h> 53#include <sys/lock.h> 54#include <sys/priv.h> 55#include <sys/proc.h> 56#include <sys/rwlock.h> 57#include <sys/socket.h> 58#include <sys/socketvar.h> 59#include <sys/sysctl.h> 60#include <sys/syslog.h> 61#include <net/if.h> 62#include <net/route.h> 63#include <net/vnet.h> 64 65#include <netinet/in.h> 66#include <netinet/ip_var.h> /* hooks */ 67#include <netinet/ip_fw.h> 68#include <netinet/ipfw/ip_fw_private.h> 69 70#ifdef MAC 71#include <security/mac/mac_framework.h> 72#endif 73 74MALLOC_DEFINE(M_IPFW, "IpFw/IpAcct", "IpFw/IpAcct chain's"); 75 76/* 77 * static variables followed by global ones (none in this file) 78 */ 79 80/* 81 * Find the smallest rule >= key, id. 82 * We could use bsearch but it is so simple that we code it directly 83 */ 84int 85ipfw_find_rule(struct ip_fw_chain *chain, uint32_t key, uint32_t id) 86{ 87 int i, lo, hi; 88 struct ip_fw *r; 89 90 for (lo = 0, hi = chain->n_rules - 1; lo < hi;) { 91 i = (lo + hi) / 2; 92 r = chain->map[i]; 93 if (r->rulenum < key) 94 lo = i + 1; /* continue from the next one */ 95 else if (r->rulenum > key) 96 hi = i; /* this might be good */ 97 else if (r->id < id) 98 lo = i + 1; /* continue from the next one */ 99 else /* r->id >= id */ 100 hi = i; /* this might be good */ 101 }; 102 return hi; 103} 104 105/* 106 * allocate a new map, returns the chain locked. extra is the number 107 * of entries to add or delete. 108 */ 109static struct ip_fw ** 110get_map(struct ip_fw_chain *chain, int extra, int locked) 111{ 112 113 for (;;) { 114 struct ip_fw **map; 115 int i; 116 117 i = chain->n_rules + extra; 118 map = malloc(i * sizeof(struct ip_fw *), M_IPFW, M_WAITOK); 119 if (map == NULL) { 120 printf("%s: cannot allocate map\n", __FUNCTION__); 121 return NULL; 122 } 123 if (!locked) 124 IPFW_UH_WLOCK(chain); 125 if (i >= chain->n_rules + extra) /* good */ 126 return map; 127 /* otherwise we lost the race, free and retry */ 128 if (!locked) 129 IPFW_UH_WUNLOCK(chain); 130 free(map, M_IPFW); 131 } 132} 133 134/* 135 * swap the maps. It is supposed to be called with IPFW_UH_WLOCK 136 */ 137static struct ip_fw ** 138swap_map(struct ip_fw_chain *chain, struct ip_fw **new_map, int new_len) 139{ 140 struct ip_fw **old_map; 141 142 IPFW_WLOCK(chain); 143 chain->id++; 144 chain->n_rules = new_len; 145 old_map = chain->map; 146 chain->map = new_map; 147 IPFW_WUNLOCK(chain); 148 return old_map; 149} 150 151/* 152 * Add a new rule to the list. Copy the rule into a malloc'ed area, then 153 * possibly create a rule number and add the rule to the list. 154 * Update the rule_number in the input struct so the caller knows it as well. 155 * XXX DO NOT USE FOR THE DEFAULT RULE. 156 * Must be called without IPFW_UH held 157 */ 158int 159ipfw_add_rule(struct ip_fw_chain *chain, struct ip_fw *input_rule) 160{ 161 struct ip_fw *rule; 162 int i, l, insert_before; 163 struct ip_fw **map; /* the new array of pointers */ 164 165 if (chain->rules == NULL || input_rule->rulenum > IPFW_DEFAULT_RULE-1) 166 return (EINVAL); 167 168 l = RULESIZE(input_rule); 169 rule = malloc(l, M_IPFW, M_WAITOK | M_ZERO); 170 if (rule == NULL) 171 return (ENOSPC); 172 /* get_map returns with IPFW_UH_WLOCK if successful */ 173 map = get_map(chain, 1, 0 /* not locked */); 174 if (map == NULL) { 175 free(rule, M_IPFW); 176 return ENOSPC; 177 } 178 179 bcopy(input_rule, rule, l); 180 /* clear fields not settable from userland */ 181 rule->x_next = NULL; 182 rule->next_rule = NULL; 183 rule->pcnt = 0; 184 rule->bcnt = 0; 185 rule->timestamp = 0; 186 187 if (V_autoinc_step < 1) 188 V_autoinc_step = 1; 189 else if (V_autoinc_step > 1000) 190 V_autoinc_step = 1000; 191 /* find the insertion point, we will insert before */ 192 insert_before = rule->rulenum ? rule->rulenum + 1 : IPFW_DEFAULT_RULE; 193 i = ipfw_find_rule(chain, insert_before, 0); 194 /* duplicate first part */ 195 if (i > 0) 196 bcopy(chain->map, map, i * sizeof(struct ip_fw *)); 197 map[i] = rule; 198 /* duplicate remaining part, we always have the default rule */ 199 bcopy(chain->map + i, map + i + 1, 200 sizeof(struct ip_fw *) *(chain->n_rules - i)); 201 if (rule->rulenum == 0) { 202 /* write back the number */ 203 rule->rulenum = i > 0 ? map[i-1]->rulenum : 0; 204 if (rule->rulenum < IPFW_DEFAULT_RULE - V_autoinc_step) 205 rule->rulenum += V_autoinc_step; 206 input_rule->rulenum = rule->rulenum; 207 } 208 209 rule->id = chain->id + 1; 210 map = swap_map(chain, map, chain->n_rules + 1); 211 chain->static_len += l; 212 IPFW_UH_WUNLOCK(chain); 213 if (map) 214 free(map, M_IPFW); 215 return (0); 216} 217 218/* 219 * Reclaim storage associated with a list of rules. This is 220 * typically the list created using remove_rule. 221 * A NULL pointer on input is handled correctly. 222 */ 223void 224ipfw_reap_rules(struct ip_fw *head) 225{ 226 struct ip_fw *rule; 227 228 while ((rule = head) != NULL) { 229 head = head->x_next; 230 free(rule, M_IPFW); 231 } 232} 233 234/** 235 * Remove all rules with given number, and also do set manipulation. 236 * Assumes chain != NULL && *chain != NULL. 237 * 238 * The argument is an u_int32_t. The low 16 bit are the rule or set number, 239 * the next 8 bits are the new set, the top 8 bits are the command: 240 * 241 * 0 delete rules with given number 242 * 1 delete rules with given set number 243 * 2 move rules with given number to new set 244 * 3 move rules with given set number to new set 245 * 4 swap sets with given numbers 246 * 5 delete rules with given number and with given set number 247 */ 248static int 249del_entry(struct ip_fw_chain *chain, u_int32_t arg) 250{ 251 struct ip_fw *rule; 252 uint32_t rulenum; /* rule or old_set */ 253 uint8_t cmd, new_set; 254 int start, end = 0, i, ofs, n; 255 struct ip_fw **map = NULL; 256 int error = 0; 257 258 rulenum = arg & 0xffff; 259 cmd = (arg >> 24) & 0xff; 260 new_set = (arg >> 16) & 0xff; 261 262 if (cmd > 5 || new_set > RESVD_SET) 263 return EINVAL; 264 if (cmd == 0 || cmd == 2 || cmd == 5) { 265 if (rulenum >= IPFW_DEFAULT_RULE) 266 return EINVAL; 267 } else { 268 if (rulenum > RESVD_SET) /* old_set */ 269 return EINVAL; 270 } 271 272 IPFW_UH_WLOCK(chain); /* prevent conflicts among the writers */ 273 chain->reap = NULL; /* prepare for deletions */ 274 275 switch (cmd) { 276 case 0: /* delete rules with given number (0 is special means all) */ 277 case 1: /* delete all rules with given set number, rule->set == rulenum */ 278 case 5: /* delete rules with given number and with given set number. 279 * rulenum - given rule number; 280 * new_set - given set number. 281 */ 282 /* locate first rule to delete (start), the one after the 283 * last one (end), and count how many rules to delete (n) 284 */ 285 n = 0; 286 if (cmd == 1) { /* look for a specific set, must scan all */ 287 for (start = -1, i = 0; i < chain->n_rules; i++) { 288 if (chain->map[start]->set != rulenum) 289 continue; 290 if (start < 0) 291 start = i; 292 end = i; 293 n++; 294 } 295 end++; /* first non-matching */ 296 } else { 297 start = ipfw_find_rule(chain, rulenum, 0); 298 for (end = start; end < chain->n_rules; end++) { 299 rule = chain->map[end]; 300 if (rulenum > 0 && rule->rulenum != rulenum) 301 break; 302 if (rule->set != RESVD_SET && 303 (cmd == 0 || rule->set == new_set) ) 304 n++; 305 } 306 } 307 if (n == 0 && arg == 0) 308 break; /* special case, flush on empty ruleset */ 309 /* allocate the map, if needed */ 310 if (n > 0) 311 map = get_map(chain, -n, 1 /* locked */); 312 if (n == 0 || map == NULL) { 313 error = EINVAL; 314 break; 315 } 316 /* copy the initial part of the map */ 317 if (start > 0) 318 bcopy(chain->map, map, start * sizeof(struct ip_fw *)); 319 /* copy active rules between start and end */ 320 for (i = ofs = start; i < end; i++) { 321 rule = chain->map[i]; 322 if (!(rule->set != RESVD_SET && 323 (cmd == 0 || rule->set == new_set) )) 324 map[ofs++] = chain->map[i]; 325 } 326 /* finally the tail */ 327 bcopy(chain->map + end, map + ofs, 328 (chain->n_rules - end) * sizeof(struct ip_fw *)); 329 map = swap_map(chain, map, chain->n_rules - n); 330 /* now remove the rules deleted */ 331 for (i = start; i < end; i++) { 332 rule = map[i]; 333 if (rule->set != RESVD_SET && 334 (cmd == 0 || rule->set == new_set) ) { 335 int l = RULESIZE(rule); 336 337 chain->static_len -= l; 338 ipfw_remove_dyn_children(rule); 339 rule->x_next = chain->reap; 340 chain->reap = rule; 341 } 342 } 343 break; 344 345 case 2: /* move rules with given number to new set */ 346 IPFW_UH_WLOCK(chain); 347 for (i = 0; i < chain->n_rules; i++) { 348 rule = chain->map[i]; 349 if (rule->rulenum == rulenum) 350 rule->set = new_set; 351 } 352 IPFW_UH_WUNLOCK(chain); 353 break; 354 355 case 3: /* move rules with given set number to new set */ 356 IPFW_UH_WLOCK(chain); 357 for (i = 0; i < chain->n_rules; i++) { 358 rule = chain->map[i]; 359 if (rule->set == rulenum) 360 rule->set = new_set; 361 } 362 IPFW_UH_WUNLOCK(chain); 363 break; 364 365 case 4: /* swap two sets */ 366 IPFW_UH_WLOCK(chain); 367 for (i = 0; i < chain->n_rules; i++) { 368 rule = chain->map[i]; 369 if (rule->set == rulenum) 370 rule->set = new_set; 371 else if (rule->set == new_set) 372 rule->set = rulenum; 373 } 374 IPFW_UH_WUNLOCK(chain); 375 break; 376 } 377 rule = chain->reap; 378 chain->reap = NULL; 379 IPFW_UH_WUNLOCK(chain); 380 ipfw_reap_rules(rule); 381 if (map) 382 free(map, M_IPFW); 383 return error; 384} 385 386/* 387 * Clear counters for a specific rule. 388 * Normally run under IPFW_UH_RLOCK, but these are idempotent ops 389 * so we only care that rules do not disappear. 390 */ 391static void 392clear_counters(struct ip_fw *rule, int log_only) 393{ 394 ipfw_insn_log *l = (ipfw_insn_log *)ACTION_PTR(rule); 395 396 if (log_only == 0) { 397 rule->bcnt = rule->pcnt = 0; 398 rule->timestamp = 0; 399 } 400 if (l->o.opcode == O_LOG) 401 l->log_left = l->max_log; 402} 403 404/** 405 * Reset some or all counters on firewall rules. 406 * The argument `arg' is an u_int32_t. The low 16 bit are the rule number, 407 * the next 8 bits are the set number, the top 8 bits are the command: 408 * 0 work with rules from all set's; 409 * 1 work with rules only from specified set. 410 * Specified rule number is zero if we want to clear all entries. 411 * log_only is 1 if we only want to reset logs, zero otherwise. 412 */ 413static int 414zero_entry(struct ip_fw_chain *chain, u_int32_t arg, int log_only) 415{ 416 struct ip_fw *rule; 417 char *msg; 418 int i; 419 420 uint16_t rulenum = arg & 0xffff; 421 uint8_t set = (arg >> 16) & 0xff; 422 uint8_t cmd = (arg >> 24) & 0xff; 423 424 if (cmd > 1) 425 return (EINVAL); 426 if (cmd == 1 && set > RESVD_SET) 427 return (EINVAL); 428 429 IPFW_UH_RLOCK(chain); 430 if (rulenum == 0) { 431 V_norule_counter = 0; 432 for (i = 0; i < chain->n_rules; i++) { 433 rule = chain->map[i]; 434 /* Skip rules not in our set. */ 435 if (cmd == 1 && rule->set != set) 436 continue; 437 clear_counters(rule, log_only); 438 } 439 msg = log_only ? "All logging counts reset" : 440 "Accounting cleared"; 441 } else { 442 int cleared = 0; 443 for (i = 0; i < chain->n_rules; i++) { 444 rule = chain->map[i]; 445 if (rule->rulenum == rulenum) { 446 if (cmd == 0 || rule->set == set) 447 clear_counters(rule, log_only); 448 cleared = 1; 449 } 450 if (rule->rulenum > rulenum) 451 break; 452 } 453 if (!cleared) { /* we did not find any matching rules */ 454 IPFW_WUNLOCK(chain); 455 return (EINVAL); 456 } 457 msg = log_only ? "logging count reset" : "cleared"; 458 } 459 IPFW_UH_RUNLOCK(chain); 460 461 if (V_fw_verbose) { 462 int lev = LOG_SECURITY | LOG_NOTICE; 463 464 if (rulenum) 465 log(lev, "ipfw: Entry %d %s.\n", rulenum, msg); 466 else 467 log(lev, "ipfw: %s.\n", msg); 468 } 469 return (0); 470} 471 472/* 473 * Check validity of the structure before insert. 474 * Rules are simple, so this mostly need to check rule sizes. 475 */ 476static int 477check_ipfw_struct(struct ip_fw *rule, int size) 478{ 479 int l, cmdlen = 0; 480 int have_action=0; 481 ipfw_insn *cmd; 482 483 if (size < sizeof(*rule)) { 484 printf("ipfw: rule too short\n"); 485 return (EINVAL); 486 } 487 /* first, check for valid size */ 488 l = RULESIZE(rule); 489 if (l != size) { 490 printf("ipfw: size mismatch (have %d want %d)\n", size, l); 491 return (EINVAL); 492 } 493 if (rule->act_ofs >= rule->cmd_len) { 494 printf("ipfw: bogus action offset (%u > %u)\n", 495 rule->act_ofs, rule->cmd_len - 1); 496 return (EINVAL); 497 } 498 /* 499 * Now go for the individual checks. Very simple ones, basically only 500 * instruction sizes. 501 */ 502 for (l = rule->cmd_len, cmd = rule->cmd ; 503 l > 0 ; l -= cmdlen, cmd += cmdlen) { 504 cmdlen = F_LEN(cmd); 505 if (cmdlen > l) { 506 printf("ipfw: opcode %d size truncated\n", 507 cmd->opcode); 508 return EINVAL; 509 } 510 switch (cmd->opcode) { 511 case O_PROBE_STATE: 512 case O_KEEP_STATE: 513 case O_PROTO: 514 case O_IP_SRC_ME: 515 case O_IP_DST_ME: 516 case O_LAYER2: 517 case O_IN: 518 case O_FRAG: 519 case O_DIVERTED: 520 case O_IPOPT: 521 case O_IPTOS: 522 case O_IPPRECEDENCE: 523 case O_IPVER: 524 case O_TCPWIN: 525 case O_TCPFLAGS: 526 case O_TCPOPTS: 527 case O_ESTAB: 528 case O_VERREVPATH: 529 case O_VERSRCREACH: 530 case O_ANTISPOOF: 531 case O_IPSEC: 532#ifdef INET6 533 case O_IP6_SRC_ME: 534 case O_IP6_DST_ME: 535 case O_EXT_HDR: 536 case O_IP6: 537#endif 538 case O_IP4: 539 case O_TAG: 540 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 541 goto bad_size; 542 break; 543 544 case O_FIB: 545 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 546 goto bad_size; 547 if (cmd->arg1 >= rt_numfibs) { 548 printf("ipfw: invalid fib number %d\n", 549 cmd->arg1); 550 return EINVAL; 551 } 552 break; 553 554 case O_SETFIB: 555 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 556 goto bad_size; 557 if (cmd->arg1 >= rt_numfibs) { 558 printf("ipfw: invalid fib number %d\n", 559 cmd->arg1); 560 return EINVAL; 561 } 562 goto check_action; 563 564 case O_UID: 565 case O_GID: 566 case O_JAIL: 567 case O_IP_SRC: 568 case O_IP_DST: 569 case O_TCPSEQ: 570 case O_TCPACK: 571 case O_PROB: 572 case O_ICMPTYPE: 573 if (cmdlen != F_INSN_SIZE(ipfw_insn_u32)) 574 goto bad_size; 575 break; 576 577 case O_LIMIT: 578 if (cmdlen != F_INSN_SIZE(ipfw_insn_limit)) 579 goto bad_size; 580 break; 581 582 case O_LOG: 583 if (cmdlen != F_INSN_SIZE(ipfw_insn_log)) 584 goto bad_size; 585 586 ((ipfw_insn_log *)cmd)->log_left = 587 ((ipfw_insn_log *)cmd)->max_log; 588 589 break; 590 591 case O_IP_SRC_MASK: 592 case O_IP_DST_MASK: 593 /* only odd command lengths */ 594 if ( !(cmdlen & 1) || cmdlen > 31) 595 goto bad_size; 596 break; 597 598 case O_IP_SRC_SET: 599 case O_IP_DST_SET: 600 if (cmd->arg1 == 0 || cmd->arg1 > 256) { 601 printf("ipfw: invalid set size %d\n", 602 cmd->arg1); 603 return EINVAL; 604 } 605 if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 606 (cmd->arg1+31)/32 ) 607 goto bad_size; 608 break; 609 610 case O_IP_SRC_LOOKUP: 611 case O_IP_DST_LOOKUP: 612 if (cmd->arg1 >= IPFW_TABLES_MAX) { 613 printf("ipfw: invalid table number %d\n", 614 cmd->arg1); 615 return (EINVAL); 616 } 617 if (cmdlen != F_INSN_SIZE(ipfw_insn) && 618 cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 1 && 619 cmdlen != F_INSN_SIZE(ipfw_insn_u32)) 620 goto bad_size; 621 break; 622 623 case O_MACADDR2: 624 if (cmdlen != F_INSN_SIZE(ipfw_insn_mac)) 625 goto bad_size; 626 break; 627 628 case O_NOP: 629 case O_IPID: 630 case O_IPTTL: 631 case O_IPLEN: 632 case O_TCPDATALEN: 633 case O_TAGGED: 634 if (cmdlen < 1 || cmdlen > 31) 635 goto bad_size; 636 break; 637 638 case O_MAC_TYPE: 639 case O_IP_SRCPORT: 640 case O_IP_DSTPORT: /* XXX artificial limit, 30 port pairs */ 641 if (cmdlen < 2 || cmdlen > 31) 642 goto bad_size; 643 break; 644 645 case O_RECV: 646 case O_XMIT: 647 case O_VIA: 648 if (cmdlen != F_INSN_SIZE(ipfw_insn_if)) 649 goto bad_size; 650 break; 651 652 case O_ALTQ: 653 if (cmdlen != F_INSN_SIZE(ipfw_insn_altq)) 654 goto bad_size; 655 break; 656 657 case O_PIPE: 658 case O_QUEUE: 659 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 660 goto bad_size; 661 goto check_action; 662 663 case O_FORWARD_IP: 664#ifdef IPFIREWALL_FORWARD 665 if (cmdlen != F_INSN_SIZE(ipfw_insn_sa)) 666 goto bad_size; 667 goto check_action; 668#else 669 return EINVAL; 670#endif 671 672 case O_DIVERT: 673 case O_TEE: 674 if (ip_divert_ptr == NULL) 675 return EINVAL; 676 else 677 goto check_size; 678 case O_NETGRAPH: 679 case O_NGTEE: 680 if (ng_ipfw_input_p == NULL) 681 return EINVAL; 682 else 683 goto check_size; 684 case O_NAT: 685 if (!IPFW_NAT_LOADED) 686 return EINVAL; 687 if (cmdlen != F_INSN_SIZE(ipfw_insn_nat)) 688 goto bad_size; 689 goto check_action; 690 case O_FORWARD_MAC: /* XXX not implemented yet */ 691 case O_CHECK_STATE: 692 case O_COUNT: 693 case O_ACCEPT: 694 case O_DENY: 695 case O_REJECT: 696#ifdef INET6 697 case O_UNREACH6: 698#endif 699 case O_SKIPTO: 700 case O_REASS: 701check_size: 702 if (cmdlen != F_INSN_SIZE(ipfw_insn)) 703 goto bad_size; 704check_action: 705 if (have_action) { 706 printf("ipfw: opcode %d, multiple actions" 707 " not allowed\n", 708 cmd->opcode); 709 return EINVAL; 710 } 711 have_action = 1; 712 if (l != cmdlen) { 713 printf("ipfw: opcode %d, action must be" 714 " last opcode\n", 715 cmd->opcode); 716 return EINVAL; 717 } 718 break; 719#ifdef INET6 720 case O_IP6_SRC: 721 case O_IP6_DST: 722 if (cmdlen != F_INSN_SIZE(struct in6_addr) + 723 F_INSN_SIZE(ipfw_insn)) 724 goto bad_size; 725 break; 726 727 case O_FLOW6ID: 728 if (cmdlen != F_INSN_SIZE(ipfw_insn_u32) + 729 ((ipfw_insn_u32 *)cmd)->o.arg1) 730 goto bad_size; 731 break; 732 733 case O_IP6_SRC_MASK: 734 case O_IP6_DST_MASK: 735 if ( !(cmdlen & 1) || cmdlen > 127) 736 goto bad_size; 737 break; 738 case O_ICMP6TYPE: 739 if( cmdlen != F_INSN_SIZE( ipfw_insn_icmp6 ) ) 740 goto bad_size; 741 break; 742#endif 743 744 default: 745 switch (cmd->opcode) { 746#ifndef INET6 747 case O_IP6_SRC_ME: 748 case O_IP6_DST_ME: 749 case O_EXT_HDR: 750 case O_IP6: 751 case O_UNREACH6: 752 case O_IP6_SRC: 753 case O_IP6_DST: 754 case O_FLOW6ID: 755 case O_IP6_SRC_MASK: 756 case O_IP6_DST_MASK: 757 case O_ICMP6TYPE: 758 printf("ipfw: no IPv6 support in kernel\n"); 759 return EPROTONOSUPPORT; 760#endif 761 default: 762 printf("ipfw: opcode %d, unknown opcode\n", 763 cmd->opcode); 764 return EINVAL; 765 } 766 } 767 } 768 if (have_action == 0) { 769 printf("ipfw: missing action\n"); 770 return EINVAL; 771 } 772 return 0; 773 774bad_size: 775 printf("ipfw: opcode %d size %d wrong\n", 776 cmd->opcode, cmdlen); 777 return EINVAL; 778} 779 780/* 781 * Copy the static and dynamic rules to the supplied buffer 782 * and return the amount of space actually used. 783 * Must be run under IPFW_UH_RLOCK 784 */ 785static size_t 786ipfw_getrules(struct ip_fw_chain *chain, void *buf, size_t space) 787{ 788 char *bp = buf; 789 char *ep = bp + space; 790 struct ip_fw *rule, *dst; 791 int l, i; 792 time_t boot_seconds; 793 794 boot_seconds = boottime.tv_sec; 795 for (i = 0; i < chain->n_rules; i++) { 796 rule = chain->map[i]; 797 l = RULESIZE(rule); 798 if (bp + l > ep) { /* should not happen */ 799 printf("overflow dumping static rules\n"); 800 break; 801 } 802 dst = (struct ip_fw *)bp; 803 bcopy(rule, dst, l); 804 /* 805 * XXX HACK. Store the disable mask in the "next" 806 * pointer in a wild attempt to keep the ABI the same. 807 * Why do we do this on EVERY rule? 808 */ 809 bcopy(&V_set_disable, &dst->next_rule, sizeof(V_set_disable)); 810 if (dst->timestamp) 811 dst->timestamp += boot_seconds; 812 bp += l; 813 } 814 ipfw_get_dynamic(&bp, ep); /* protected by the dynamic lock */ 815 return (bp - (char *)buf); 816} 817 818 819/** 820 * {set|get}sockopt parser. 821 */ 822int 823ipfw_ctl(struct sockopt *sopt) 824{ 825#define RULE_MAXSIZE (256*sizeof(u_int32_t)) 826 int error; 827 size_t size; 828 struct ip_fw *buf, *rule; 829 struct ip_fw_chain *chain; 830 u_int32_t rulenum[2]; 831 832 error = priv_check(sopt->sopt_td, PRIV_NETINET_IPFW); 833 if (error) 834 return (error); 835 836 /* 837 * Disallow modifications in really-really secure mode, but still allow 838 * the logging counters to be reset. 839 */ 840 if (sopt->sopt_name == IP_FW_ADD || 841 (sopt->sopt_dir == SOPT_SET && sopt->sopt_name != IP_FW_RESETLOG)) { 842 error = securelevel_ge(sopt->sopt_td->td_ucred, 3); 843 if (error) 844 return (error); 845 } 846 847 chain = &V_layer3_chain; 848 error = 0; 849 850 switch (sopt->sopt_name) { 851 case IP_FW_GET: 852 /* 853 * pass up a copy of the current rules. Static rules 854 * come first (the last of which has number IPFW_DEFAULT_RULE), 855 * followed by a possibly empty list of dynamic rule. 856 * The last dynamic rule has NULL in the "next" field. 857 * 858 * Note that the calculated size is used to bound the 859 * amount of data returned to the user. The rule set may 860 * change between calculating the size and returning the 861 * data in which case we'll just return what fits. 862 */ 863 for (;;) { 864 int len = 0, want; 865 866 size = chain->static_len; 867 size += ipfw_dyn_len(); 868 if (size >= sopt->sopt_valsize) 869 break; 870 buf = malloc(size, M_TEMP, M_WAITOK); 871 if (buf == NULL) 872 break; 873 IPFW_UH_RLOCK(chain); 874 /* check again how much space we need */ 875 want = chain->static_len + ipfw_dyn_len(); 876 if (size >= want) 877 len = ipfw_getrules(chain, buf, size); 878 IPFW_UH_RUNLOCK(chain); 879 if (size >= want) 880 error = sooptcopyout(sopt, buf, len); 881 free(buf, M_TEMP); 882 if (size >= want) 883 break; 884 } 885 break; 886 887 case IP_FW_FLUSH: 888 /* locking is done within del_entry() */ 889 error = del_entry(chain, 0); /* special case, rule=0, cmd=0 means all */ 890 break; 891 892 case IP_FW_ADD: 893 rule = malloc(RULE_MAXSIZE, M_TEMP, M_WAITOK); 894 error = sooptcopyin(sopt, rule, RULE_MAXSIZE, 895 sizeof(struct ip_fw) ); 896 if (error == 0) 897 error = check_ipfw_struct(rule, sopt->sopt_valsize); 898 if (error == 0) { 899 /* locking is done within ipfw_add_rule() */ 900 error = ipfw_add_rule(chain, rule); 901 size = RULESIZE(rule); 902 if (!error && sopt->sopt_dir == SOPT_GET) 903 error = sooptcopyout(sopt, rule, size); 904 } 905 free(rule, M_TEMP); 906 break; 907 908 case IP_FW_DEL: 909 /* 910 * IP_FW_DEL is used for deleting single rules or sets, 911 * and (ab)used to atomically manipulate sets. Argument size 912 * is used to distinguish between the two: 913 * sizeof(u_int32_t) 914 * delete single rule or set of rules, 915 * or reassign rules (or sets) to a different set. 916 * 2*sizeof(u_int32_t) 917 * atomic disable/enable sets. 918 * first u_int32_t contains sets to be disabled, 919 * second u_int32_t contains sets to be enabled. 920 */ 921 error = sooptcopyin(sopt, rulenum, 922 2*sizeof(u_int32_t), sizeof(u_int32_t)); 923 if (error) 924 break; 925 size = sopt->sopt_valsize; 926 if (size == sizeof(u_int32_t) && rulenum[0] != 0) { 927 /* delete or reassign, locking done in del_entry() */ 928 error = del_entry(chain, rulenum[0]); 929 } else if (size == 2*sizeof(u_int32_t)) { /* set enable/disable */ 930 IPFW_UH_WLOCK(chain); 931 V_set_disable = 932 (V_set_disable | rulenum[0]) & ~rulenum[1] & 933 ~(1<<RESVD_SET); /* set RESVD_SET always enabled */ 934 IPFW_UH_WUNLOCK(chain); 935 } else 936 error = EINVAL; 937 break; 938 939 case IP_FW_ZERO: 940 case IP_FW_RESETLOG: /* argument is an u_int_32, the rule number */ 941 rulenum[0] = 0; 942 if (sopt->sopt_val != 0) { 943 error = sooptcopyin(sopt, rulenum, 944 sizeof(u_int32_t), sizeof(u_int32_t)); 945 if (error) 946 break; 947 } 948 error = zero_entry(chain, rulenum[0], 949 sopt->sopt_name == IP_FW_RESETLOG); 950 break; 951 952 /*--- TABLE manipulations are protected by the IPFW_LOCK ---*/ 953 case IP_FW_TABLE_ADD: 954 { 955 ipfw_table_entry ent; 956 957 error = sooptcopyin(sopt, &ent, 958 sizeof(ent), sizeof(ent)); 959 if (error) 960 break; 961 error = ipfw_add_table_entry(chain, ent.tbl, 962 ent.addr, ent.masklen, ent.value); 963 } 964 break; 965 966 case IP_FW_TABLE_DEL: 967 { 968 ipfw_table_entry ent; 969 970 error = sooptcopyin(sopt, &ent, 971 sizeof(ent), sizeof(ent)); 972 if (error) 973 break; 974 error = ipfw_del_table_entry(chain, ent.tbl, 975 ent.addr, ent.masklen); 976 } 977 break; 978 979 case IP_FW_TABLE_FLUSH: 980 { 981 u_int16_t tbl; 982 983 error = sooptcopyin(sopt, &tbl, 984 sizeof(tbl), sizeof(tbl)); 985 if (error) 986 break; 987 IPFW_WLOCK(chain); 988 error = ipfw_flush_table(chain, tbl); 989 IPFW_WUNLOCK(chain); 990 } 991 break; 992 993 case IP_FW_TABLE_GETSIZE: 994 { 995 u_int32_t tbl, cnt; 996 997 if ((error = sooptcopyin(sopt, &tbl, sizeof(tbl), 998 sizeof(tbl)))) 999 break; 1000 IPFW_RLOCK(chain); 1001 error = ipfw_count_table(chain, tbl, &cnt); 1002 IPFW_RUNLOCK(chain); 1003 if (error) 1004 break; 1005 error = sooptcopyout(sopt, &cnt, sizeof(cnt)); 1006 } 1007 break; 1008 1009 case IP_FW_TABLE_LIST: 1010 { 1011 ipfw_table *tbl; 1012 1013 if (sopt->sopt_valsize < sizeof(*tbl)) { 1014 error = EINVAL; 1015 break; 1016 } 1017 size = sopt->sopt_valsize; 1018 tbl = malloc(size, M_TEMP, M_WAITOK); 1019 error = sooptcopyin(sopt, tbl, size, sizeof(*tbl)); 1020 if (error) { 1021 free(tbl, M_TEMP); 1022 break; 1023 } 1024 tbl->size = (size - sizeof(*tbl)) / 1025 sizeof(ipfw_table_entry); 1026 IPFW_RLOCK(chain); 1027 error = ipfw_dump_table(chain, tbl); 1028 IPFW_RUNLOCK(chain); 1029 if (error) { 1030 free(tbl, M_TEMP); 1031 break; 1032 } 1033 error = sooptcopyout(sopt, tbl, size); 1034 free(tbl, M_TEMP); 1035 } 1036 break; 1037 1038 /*--- NAT operations are protected by the IPFW_LOCK ---*/ 1039 case IP_FW_NAT_CFG: 1040 if (IPFW_NAT_LOADED) 1041 error = ipfw_nat_cfg_ptr(sopt); 1042 else { 1043 printf("IP_FW_NAT_CFG: %s\n", 1044 "ipfw_nat not present, please load it"); 1045 error = EINVAL; 1046 } 1047 break; 1048 1049 case IP_FW_NAT_DEL: 1050 if (IPFW_NAT_LOADED) 1051 error = ipfw_nat_del_ptr(sopt); 1052 else { 1053 printf("IP_FW_NAT_DEL: %s\n", 1054 "ipfw_nat not present, please load it"); 1055 error = EINVAL; 1056 } 1057 break; 1058 1059 case IP_FW_NAT_GET_CONFIG: 1060 if (IPFW_NAT_LOADED) 1061 error = ipfw_nat_get_cfg_ptr(sopt); 1062 else { 1063 printf("IP_FW_NAT_GET_CFG: %s\n", 1064 "ipfw_nat not present, please load it"); 1065 error = EINVAL; 1066 } 1067 break; 1068 1069 case IP_FW_NAT_GET_LOG: 1070 if (IPFW_NAT_LOADED) 1071 error = ipfw_nat_get_log_ptr(sopt); 1072 else { 1073 printf("IP_FW_NAT_GET_LOG: %s\n", 1074 "ipfw_nat not present, please load it"); 1075 error = EINVAL; 1076 } 1077 break; 1078 1079 default: 1080 printf("ipfw: ipfw_ctl invalid option %d\n", sopt->sopt_name); 1081 error = EINVAL; 1082 } 1083 1084 return (error); 1085#undef RULE_MAXSIZE 1086} 1087/* end of file */ 1088