1 /* 2 * Copyright (c) 2002 Luigi Rizzo 3 * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp 4 * Copyright (c) 1994 Ugen J.S.Antsilevich 5 * 6 * Idea and grammar partially left from: 7 * Copyright (c) 1993 Daniel Boulet 8 * 9 * Redistribution and use in source forms, with and without modification, 10 * are permitted provided that this entire comment appears intact. 11 * 12 * Redistribution in binary form may occur without any restrictions. 13 * Obviously, it would be nice if you gave credit where credit is due 14 * but requiring it would be too onerous. 15 * 16 * This software is provided ``AS IS'' without any warranties of any kind. 17 * 18 * NEW command line interface for IP firewall facility 19 * 20 * $FreeBSD: src/sbin/ipfw/ipfw2.c,v 1.4.2.13 2003/05/27 22:21:11 gshapiro Exp $ 21 */ 22 23 #include <sys/param.h> 24 #include <sys/mbuf.h> 25 #include <sys/socket.h> 26 #include <sys/sockio.h> 27 #include <sys/sysctl.h> 28 #include <sys/time.h> 29 #include <sys/wait.h> 30 31 #include <arpa/inet.h> 32 #include <ctype.h> 33 #include <dlfcn.h> 34 #include <err.h> 35 #include <errno.h> 36 #include <grp.h> 37 #include <limits.h> 38 #include <netdb.h> 39 #include <pwd.h> 40 #include <sysexits.h> 41 #include <signal.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <stdarg.h> 45 #include <string.h> 46 #include <timeconv.h> 47 #include <unistd.h> 48 49 #include <netinet/in.h> 50 #include <netinet/in_systm.h> 51 #include <netinet/ip.h> 52 #include <netinet/ip_icmp.h> 53 #include <netinet/tcp.h> 54 #include <net/if.h> 55 #include <net/if_dl.h> 56 #include <net/route.h> 57 #include <net/ethernet.h> 58 59 60 #include "../../sys/net/ipfw3/ip_fw3.h" 61 #include "../../sys/net/ipfw3/ip_fw3_table.h" 62 #include "../../sys/net/dummynet3/ip_dummynet3.h" 63 #include "../../sys/net/libalias/alias.h" 64 #include "../../sys/net/ipfw3_basic/ip_fw3_basic.h" 65 #include "../../sys/net/ipfw3_nat/ip_fw3_nat.h" 66 #include "ipfw.h" 67 68 69 #define KEYWORD_SIZE 256 70 #define MAPPING_SIZE 256 71 72 #define MAX_KEYWORD_LEN 20 73 #define MAX_ARGS 32 74 #define WHITESP " \t\f\v\n\r" 75 #define IPFW_LIB_PATH "/usr/lib/libipfw3%s.so" 76 #define IP_MASK_ALL 0xffffffff 77 #define NAT_BUF_LEN 1024 78 /* 79 * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines 80 * This is only used in this code. 81 */ 82 #define IPPROTO_ETHERTYPE 0x1000 83 84 /* 85 * This macro returns the size of a struct sockaddr when passed 86 * through a routing socket. Basically we round up sa_len to 87 * a multiple of sizeof(long), with a minimum of sizeof(long). 88 * The check for a NULL pointer is just a convenience, probably never used. 89 * The case sa_len == 0 should only apply to empty structures. 90 */ 91 #define SA_SIZE(sa) \ 92 ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \ 93 sizeof(long) : \ 94 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) ) 95 96 /* 97 * show_rules() prints the body of an ipfw rule. 98 * Because the standard rule has at least proto src_ip dst_ip, we use 99 * a helper function to produce these entries if not provided explicitly. 100 * The first argument is the list of fields we have, the second is 101 * the list of fields we want to be printed. 102 * 103 * Special cases if we have provided a MAC header: 104 * + if the rule does not contain IP addresses/ports, do not print them; 105 * + if the rule does not contain an IP proto, print "all" instead of "ip"; 106 * 107 */ 108 #define HAVE_PROTO 0x0001 109 #define HAVE_SRCIP 0x0002 110 #define HAVE_DSTIP 0x0004 111 #define HAVE_MAC 0x0008 112 #define HAVE_MACTYPE 0x0010 113 #define HAVE_OPTIONS 0x8000 114 115 #define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP) 116 117 /* 118 * Definition of a port range, and macros to deal with values. 119 * FORMAT: HI 16-bits == first port in range, 0 == all ports. 120 * LO 16-bits == number of ports in range 121 * NOTES: - Port values are not stored in network byte order. 122 */ 123 124 #define port_range u_long 125 126 #define GETLOPORT(x) ((x) >> 0x10) 127 #define GETNUMPORTS(x) ((x) & 0x0000ffff) 128 #define GETHIPORT(x) (GETLOPORT((x)) + GETNUMPORTS((x))) 129 130 /* Set y to be the low-port value in port_range variable x. */ 131 #define SETLOPORT(x, y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10)) 132 133 /* Set y to be the number of ports in port_range variable x. */ 134 #define SETNUMPORTS(x, y) ((x) = ((x) & 0xffff0000) | (y)) 135 136 #define INC_ARGCV() do { \ 137 (*_av)++; \ 138 (*_ac)--; \ 139 av = *_av; \ 140 ac = *_ac; \ 141 } while (0) 142 143 144 int ipfw_socket = -1; /* main RAW socket */ 145 int do_resolv, /* Would try to resolve all */ 146 do_acct, /* Show packet/byte count */ 147 do_time, /* Show time stamps */ 148 do_quiet = 1, /* Be quiet , default is quiet*/ 149 do_force, /* Don't ask for confirmation */ 150 do_pipe, /* this cmd refers to a pipe */ 151 do_nat, /* Nat configuration. */ 152 do_sort, /* field to sort results (0 = no) */ 153 do_dynamic, /* display dynamic rules */ 154 do_expired, /* display expired dynamic rules */ 155 do_compact, /* show rules in compact mode */ 156 show_sets, /* display rule sets */ 157 verbose; 158 159 enum tokens { 160 TOK_NULL=0, 161 162 TOK_IP, 163 TOK_IF, 164 TOK_ALOG, 165 TOK_DENY_INC, 166 TOK_SAME_PORTS, 167 TOK_UNREG_ONLY, 168 TOK_RESET_ADDR, 169 TOK_ALIAS_REV, 170 TOK_PROXY_ONLY, 171 TOK_REDIR_ADDR, 172 TOK_REDIR_PORT, 173 TOK_REDIR_PROTO, 174 175 TOK_PIPE, 176 TOK_QUEUE, 177 TOK_PLR, 178 TOK_NOERROR, 179 TOK_BUCKETS, 180 TOK_DSTIP, 181 TOK_SRCIP, 182 TOK_DSTPORT, 183 TOK_SRCPORT, 184 TOK_ALL, 185 TOK_MASK, 186 TOK_BW, 187 TOK_DELAY, 188 TOK_RED, 189 TOK_GRED, 190 TOK_DROPTAIL, 191 TOK_PROTO, 192 TOK_WEIGHT, 193 }; 194 195 struct char_int_map dummynet_params[] = { 196 { "plr", TOK_PLR }, 197 { "noerror", TOK_NOERROR }, 198 { "buckets", TOK_BUCKETS }, 199 { "dst-ip", TOK_DSTIP }, 200 { "src-ip", TOK_SRCIP }, 201 { "dst-port", TOK_DSTPORT }, 202 { "src-port", TOK_SRCPORT }, 203 { "proto", TOK_PROTO }, 204 { "weight", TOK_WEIGHT }, 205 { "all", TOK_ALL }, 206 { "mask", TOK_MASK }, 207 { "droptail", TOK_DROPTAIL }, 208 { "red", TOK_RED }, 209 { "gred", TOK_GRED }, 210 { "bw", TOK_BW }, 211 { "bandwidth", TOK_BW }, 212 { "delay", TOK_DELAY }, 213 { "pipe", TOK_PIPE }, 214 { "queue", TOK_QUEUE }, 215 { "dummynet-params", TOK_NULL }, 216 { NULL, 0 } 217 }; 218 219 struct char_int_map nat_params[] = { 220 { "ip", TOK_IP }, 221 { "if", TOK_IF }, 222 { "log", TOK_ALOG }, 223 { "deny_in", TOK_DENY_INC }, 224 { "same_ports", TOK_SAME_PORTS }, 225 { "unreg_only", TOK_UNREG_ONLY }, 226 { "reset", TOK_RESET_ADDR }, 227 { "reverse", TOK_ALIAS_REV }, 228 { "proxy_only", TOK_PROXY_ONLY }, 229 { "redirect_addr", TOK_REDIR_ADDR }, 230 { "redirect_port", TOK_REDIR_PORT }, 231 { "redirect_proto", TOK_REDIR_PROTO }, 232 { NULL, 0 }, 233 }; 234 235 struct ipfw_keyword { 236 int type; 237 char word[MAX_KEYWORD_LEN]; 238 int module; 239 int opcode; 240 }; 241 242 struct ipfw_mapping { 243 int type; 244 int module; 245 int opcode; 246 parser_func parser; 247 shower_func shower; 248 }; 249 250 struct ipfw_keyword keywords[KEYWORD_SIZE]; 251 struct ipfw_mapping mappings[MAPPING_SIZE]; 252 253 static int 254 match_token(struct char_int_map *table, char *string) 255 { 256 while (table->key) { 257 if (strcmp(table->key, string) == 0) { 258 return table->val; 259 } 260 table++; 261 } 262 return 0; 263 } 264 265 static void 266 get_modules(char *modules_str, int len) 267 { 268 if (do_get_x(IP_FW_MODULE, modules_str, &len) < 0) 269 errx(EX_USAGE, "ipfw3 not loaded."); 270 } 271 272 static void 273 list_modules(int ac, char *av[]) 274 { 275 void *module_str = NULL; 276 int len = 1024; 277 if ((module_str = realloc(module_str, len)) == NULL) 278 err(EX_OSERR, "realloc"); 279 280 get_modules(module_str, len); 281 printf("%s", (char *)module_str); 282 } 283 void 284 parse_accept(ipfw_insn **cmd, int *ac, char **av[]) 285 { 286 (*cmd)->opcode = O_BASIC_ACCEPT; 287 (*cmd)->module = MODULE_BASIC_ID; 288 (*cmd)->len = (*cmd)->len|LEN_OF_IPFWINSN; 289 NEXT_ARG1; 290 if (!strncmp(**av, "log", strlen(**av))) { 291 (*cmd)->arg3 = 1; 292 NEXT_ARG1; 293 if (isdigit(***av)) { 294 (*cmd)->arg1 = strtoul(**av, NULL, 10); 295 NEXT_ARG1; 296 } 297 } 298 } 299 300 void 301 parse_deny(ipfw_insn **cmd, int *ac, char **av[]) 302 { 303 (*cmd)->opcode = O_BASIC_DENY; 304 (*cmd)->module = MODULE_BASIC_ID; 305 (*cmd)->len = (*cmd)->len|LEN_OF_IPFWINSN; 306 NEXT_ARG1; 307 if (!strncmp(**av, "log", strlen(**av))) { 308 (*cmd)->arg3 = 1; 309 NEXT_ARG1; 310 if (isdigit(***av)) { 311 (*cmd)->arg1 = strtoul(**av, NULL, 10); 312 NEXT_ARG1; 313 } 314 } 315 } 316 317 void 318 show_accept(ipfw_insn *cmd, int show_or) 319 { 320 printf(" allow"); 321 if (cmd->arg3) { 322 printf(" log %d", cmd->arg1); 323 } 324 } 325 326 void 327 show_deny(ipfw_insn *cmd, int show_or) 328 { 329 printf(" deny"); 330 if (cmd->arg3) { 331 printf(" log %d", cmd->arg1); 332 } 333 } 334 335 static void 336 load_modules(void) 337 { 338 const char *error; 339 init_module mod_init_func; 340 void *module_lib; 341 char module_lib_file[50]; 342 void *module_str = NULL; 343 int len = 1024; 344 345 if ((module_str = realloc(module_str, len)) == NULL) 346 err(EX_OSERR, "realloc"); 347 348 get_modules(module_str, len); 349 350 const char s[2] = ","; 351 char *token; 352 token = strtok(module_str, s); 353 while (token != NULL) { 354 sprintf(module_lib_file, IPFW_LIB_PATH, token); 355 token = strtok(NULL, s); 356 module_lib = dlopen(module_lib_file, RTLD_LAZY); 357 if (!module_lib) { 358 fprintf(stderr, "Couldn't open %s: %s\n", 359 module_lib_file, dlerror()); 360 exit(EX_SOFTWARE); 361 } 362 mod_init_func = dlsym(module_lib, "load_module"); 363 if ((error = dlerror())) 364 { 365 fprintf(stderr, "Couldn't find init function: %s\n", error); 366 exit(EX_SOFTWARE); 367 } 368 (*mod_init_func)((register_func)register_ipfw_func, 369 (register_keyword)register_ipfw_keyword); 370 } 371 } 372 373 void 374 prepare_default_funcs(void) 375 { 376 /* register allow*/ 377 register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_ACCEPT, "allow", ACTION); 378 register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_ACCEPT, "accept", ACTION); 379 register_ipfw_func(MODULE_BASIC_ID, O_BASIC_ACCEPT, 380 (parser_func)parse_accept, (shower_func)show_accept); 381 /* register deny*/ 382 register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_DENY, "deny", ACTION); 383 register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_DENY, "reject", ACTION); 384 register_ipfw_func(MODULE_BASIC_ID, O_BASIC_DENY, 385 (parser_func)parse_deny, (shower_func)show_deny); 386 } 387 388 void 389 register_ipfw_keyword(int module, int opcode, char *word, int type) 390 { 391 struct ipfw_keyword *tmp; 392 393 tmp=keywords; 394 for(;;) { 395 if (tmp->type == NONE) { 396 strcpy(tmp->word, word); 397 tmp->module = module; 398 tmp->opcode = opcode; 399 tmp->type = type; 400 break; 401 } else { 402 if (strcmp(tmp->word, word) == 0) 403 errx(EX_USAGE, "keyword `%s' exists", word); 404 else 405 tmp++; 406 } 407 } 408 } 409 410 void 411 register_ipfw_func(int module, int opcode, parser_func parser, shower_func shower) 412 { 413 struct ipfw_mapping *tmp; 414 415 tmp = mappings; 416 while (1) { 417 if (tmp->type == NONE) { 418 tmp->module = module; 419 tmp->opcode = opcode; 420 tmp->parser = parser; 421 tmp->shower = shower; 422 tmp->type = IN_USE; 423 break; 424 } else { 425 if (tmp->opcode == opcode && tmp->module == module) { 426 errx(EX_USAGE, "func `%d' of module `%d' exists", 427 opcode, module); 428 break; 429 } else { 430 tmp++; 431 } 432 } 433 } 434 } 435 436 /* 437 * this func need to check whether 'or' need to be printed, 438 * when the filter is the first filter with 'or' when dont print 439 * when not first and same as previous, then print or and no filter name 440 * when not first but different from previous, print name without 'or' 441 * show_or = 1: show or and ignore filter name 442 * show_or = 0: show filter name ignore or 443 */ 444 void prev_show_chk(ipfw_insn *cmd, uint8_t *prev_module, uint8_t *prev_opcode, 445 int *show_or) 446 { 447 if (cmd->len & F_OR) { 448 if (*prev_module == 0 && *prev_opcode == 0) { 449 /* first cmd with 'or' flag */ 450 *show_or = 0; 451 *prev_module = cmd->module; 452 *prev_opcode = cmd->opcode; 453 } else if (cmd->module == *prev_module && 454 cmd->opcode == *prev_opcode) { 455 /* cmd same as previous, same module and opcode */ 456 *show_or = 1; 457 } else { 458 /* cmd different from prev*/ 459 *show_or = 0; 460 *prev_module = cmd->module; 461 *prev_opcode = cmd->opcode; 462 463 } 464 } else { 465 *show_or = 0; 466 *prev_module = 0; 467 *prev_opcode = 0; 468 } 469 } 470 471 /* 472 * word can be: proto from to other 473 * proto show proto 474 * from show from 475 * to show to 476 * other show all other filters 477 */ 478 int show_filter(ipfw_insn *cmd, char *word, int type) 479 { 480 struct ipfw_keyword *k; 481 struct ipfw_mapping *m; 482 shower_func fn; 483 int i, j, show_or; 484 uint8_t prev_module, prev_opcode; 485 486 k = keywords; 487 m = mappings; 488 for (i = 1; i < KEYWORD_SIZE; i++, k++) { 489 if (k->type == type) { 490 if (k->module == cmd->module && 491 k->opcode == cmd->opcode) { 492 for (j = 1; j < MAPPING_SIZE; j++, m++) { 493 if (m->type == IN_USE && 494 k->module == m->module && 495 k->opcode == m->opcode) { 496 prev_show_chk(cmd, &prev_module, 497 &prev_opcode, &show_or); 498 if (cmd->len & F_NOT) 499 printf(" not"); 500 501 fn = m->shower; 502 (*fn)(cmd, show_or); 503 return 1; 504 } 505 } 506 } 507 } 508 } 509 return 0; 510 } 511 512 static void 513 show_rules(struct ipfw_ioc_rule *rule, int pcwidth, int bcwidth) 514 { 515 static int twidth = 0; 516 ipfw_insn *cmd; 517 int l; 518 519 u_int32_t set_disable = rule->set_disable; 520 521 if (set_disable & (1 << rule->set)) { /* disabled */ 522 if (!show_sets) 523 return; 524 else 525 printf("# DISABLED "); 526 } 527 printf("%05u ", rule->rulenum); 528 529 if (do_acct) 530 printf("%*ju %*ju ", pcwidth, (uintmax_t)rule->pcnt, bcwidth, 531 (uintmax_t)rule->bcnt); 532 533 if (do_time == 1) { 534 char timestr[30]; 535 536 if (twidth == 0) { 537 strcpy(timestr, ctime((time_t *)&twidth)); 538 *strchr(timestr, '\n') = '\0'; 539 twidth = strlen(timestr); 540 } 541 if (rule->timestamp) { 542 time_t t = _long_to_time(rule->timestamp); 543 544 strcpy(timestr, ctime(&t)); 545 *strchr(timestr, '\n') = '\0'; 546 printf("%s ", timestr); 547 } else { 548 printf("%*s ", twidth, " "); 549 } 550 } else if (do_time == 2) { 551 printf( "%10u ", rule->timestamp); 552 } 553 554 if (show_sets) 555 printf("set %d ", rule->set); 556 557 558 struct ipfw_keyword *k; 559 struct ipfw_mapping *m; 560 shower_func fn, comment_fn = NULL; 561 ipfw_insn *comment_cmd; 562 int i, j, changed; 563 564 /* 565 * show others and actions 566 */ 567 for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule); 568 l > 0; l -= F_LEN(cmd), 569 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) { 570 k = keywords; 571 m = mappings; 572 for (i = 1; i< KEYWORD_SIZE; i++, k++) { 573 if ( k->module == cmd->module && k->opcode == cmd->opcode ) { 574 for (j = 1; j< MAPPING_SIZE; j++, m++) { 575 if (m->type == IN_USE && 576 m->module == cmd->module && 577 m->opcode == cmd->opcode) { 578 if (cmd->module == MODULE_BASIC_ID && 579 cmd->opcode == O_BASIC_COMMENT) { 580 comment_fn = m->shower; 581 comment_cmd = cmd; 582 } else { 583 fn = m->shower; 584 (*fn)(cmd, 0); 585 } 586 if (cmd->module == MODULE_BASIC_ID && 587 cmd->opcode == 588 O_BASIC_CHECK_STATE) { 589 goto done; 590 } 591 break; 592 } 593 } 594 break; 595 } 596 } 597 } 598 599 /* 600 * show proto 601 */ 602 changed=0; 603 for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd), 604 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) { 605 changed = show_filter(cmd, "proto", PROTO); 606 } 607 if (!changed && !do_quiet) 608 printf(" ip"); 609 610 /* 611 * show from 612 */ 613 changed = 0; 614 for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd), 615 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) { 616 changed = show_filter(cmd, "from", FROM); 617 } 618 if (!changed && !do_quiet) 619 printf(" from any"); 620 621 /* 622 * show to 623 */ 624 changed = 0; 625 for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd), 626 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) { 627 changed = show_filter(cmd, "to", TO); 628 } 629 if (!changed && !do_quiet) 630 printf(" to any"); 631 632 /* 633 * show other filters 634 */ 635 for (l = rule->act_ofs, cmd = rule->cmd, m = mappings; 636 l > 0; l -= F_LEN(cmd), 637 cmd=(ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) { 638 show_filter(cmd, "other", FILTER); 639 } 640 641 /* show the comment in the end */ 642 if (comment_fn != NULL) { 643 (*comment_fn)(comment_cmd, 0); 644 } 645 done: 646 printf("\n"); 647 } 648 649 static void 650 show_states(struct ipfw_ioc_state *d, int pcwidth, int bcwidth) 651 { 652 struct protoent *pe; 653 struct in_addr a; 654 655 printf("%05u ", d->rulenum); 656 if (do_acct) { 657 printf("%*ju %*ju ", pcwidth, (uintmax_t)d->pcnt, 658 bcwidth, (uintmax_t)d->bcnt); 659 } 660 661 if (do_time == 1) { 662 /* state->timestamp */ 663 char timestr[30]; 664 time_t t = _long_to_time(d->timestamp); 665 strcpy(timestr, ctime(&t)); 666 *strchr(timestr, '\n') = '\0'; 667 printf(" (%s", timestr); 668 669 /* state->lifetime */ 670 printf(" %ds", d->lifetime); 671 672 /* state->expiry */ 673 if (d->expiry !=0) { 674 t = _long_to_time(d->expiry); 675 strcpy(timestr, ctime(&t)); 676 *strchr(timestr, '\n') = '\0'; 677 printf(" %s)", timestr); 678 } else { 679 printf(" 0)"); 680 } 681 682 } else if (do_time == 2) { 683 printf("(%u %ds %u) ", d->timestamp, d->lifetime, d->expiry); 684 } 685 686 if ((pe = getprotobynumber(d->flow_id.proto)) != NULL) 687 printf(" %s", pe->p_name); 688 else 689 printf(" proto %u", d->flow_id.proto); 690 691 a.s_addr = htonl(d->flow_id.src_ip); 692 printf(" %s %d", inet_ntoa(a), d->flow_id.src_port); 693 694 a.s_addr = htonl(d->flow_id.dst_ip); 695 printf(" <-> %s %d", inet_ntoa(a), d->flow_id.dst_port); 696 printf(" CPU %d", d->cpuid); 697 printf("\n"); 698 } 699 700 int 701 sort_q(const void *pa, const void *pb) 702 { 703 int rev = (do_sort < 0); 704 int field = rev ? -do_sort : do_sort; 705 long long res = 0; 706 const struct dn_ioc_flowqueue *a = pa; 707 const struct dn_ioc_flowqueue *b = pb; 708 709 switch(field) { 710 case 1: /* pkts */ 711 res = a->len - b->len; 712 break; 713 case 2: /* bytes */ 714 res = a->len_bytes - b->len_bytes; 715 break; 716 717 case 3: /* tot pkts */ 718 res = a->tot_pkts - b->tot_pkts; 719 break; 720 721 case 4: /* tot bytes */ 722 res = a->tot_bytes - b->tot_bytes; 723 break; 724 } 725 if (res < 0) 726 res = -1; 727 if (res > 0) 728 res = 1; 729 return (int)(rev ? res : -res); 730 } 731 732 static void 733 show_queues(struct dn_ioc_flowset *fs, struct dn_ioc_flowqueue *q) 734 { 735 int l; 736 737 printf("mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n", 738 fs->flow_mask.u.ip.proto, 739 fs->flow_mask.u.ip.src_ip, fs->flow_mask.u.ip.src_port, 740 fs->flow_mask.u.ip.dst_ip, fs->flow_mask.u.ip.dst_port); 741 if (fs->rq_elements == 0) 742 return; 743 744 printf("BKT Prot ___Source IP/port____ " 745 "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n"); 746 if (do_sort != 0) 747 heapsort(q, fs->rq_elements, sizeof(*q), sort_q); 748 for (l = 0; l < fs->rq_elements; l++) { 749 struct in_addr ina; 750 struct protoent *pe; 751 752 ina.s_addr = htonl(q[l].id.u.ip.src_ip); 753 printf("%3d ", q[l].hash_slot); 754 pe = getprotobynumber(q[l].id.u.ip.proto); 755 if (pe) 756 printf("%-4s ", pe->p_name); 757 else 758 printf("%4u ", q[l].id.u.ip.proto); 759 printf("%15s/%-5d ", 760 inet_ntoa(ina), q[l].id.u.ip.src_port); 761 ina.s_addr = htonl(q[l].id.u.ip.dst_ip); 762 printf("%15s/%-5d ", 763 inet_ntoa(ina), q[l].id.u.ip.dst_port); 764 printf("%4ju %8ju %2u %4u %3u\n", 765 (uintmax_t)q[l].tot_pkts, (uintmax_t)q[l].tot_bytes, 766 q[l].len, q[l].len_bytes, q[l].drops); 767 if (verbose) 768 printf(" S %20ju F %20ju\n", 769 (uintmax_t)q[l].S, (uintmax_t)q[l].F); 770 } 771 } 772 773 static void 774 show_flowset_parms(struct dn_ioc_flowset *fs, char *prefix) 775 { 776 char qs[30]; 777 char plr[30]; 778 char red[90]; /* Display RED parameters */ 779 int l; 780 781 l = fs->qsize; 782 if (fs->flags_fs & DN_QSIZE_IS_BYTES) { 783 if (l >= 8192) 784 sprintf(qs, "%d KB", l / 1024); 785 else 786 sprintf(qs, "%d B", l); 787 } else 788 sprintf(qs, "%3d sl.", l); 789 if (fs->plr) 790 sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff)); 791 else 792 plr[0] = '\0'; 793 if (fs->flags_fs & DN_IS_RED) /* RED parameters */ 794 sprintf(red, 795 "\n\t %cRED w_q %f min_th %d max_th %d max_p %f", 796 (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ', 797 1.0 * fs->w_q / (double)(1 << SCALE_RED), 798 SCALE_VAL(fs->min_th), 799 SCALE_VAL(fs->max_th), 800 1.0 * fs->max_p / (double)(1 << SCALE_RED)); 801 else 802 sprintf(red, "droptail"); 803 804 printf("%s %s%s %d queues (%d buckets) %s\n", 805 prefix, qs, plr, fs->rq_elements, fs->rq_size, red); 806 } 807 808 static void 809 show_pipes(void *data, int nbytes, int ac, char *av[]) 810 { 811 u_long rulenum; 812 void *next = data; 813 struct dn_ioc_pipe *p = (struct dn_ioc_pipe *)data; 814 struct dn_ioc_flowset *fs; 815 struct dn_ioc_flowqueue *q; 816 int l; 817 818 if (ac > 0) 819 rulenum = strtoul(*av++, NULL, 10); 820 else 821 rulenum = 0; 822 for (; nbytes >= sizeof(*p); p = (struct dn_ioc_pipe *)next) { 823 double b = p->bandwidth; 824 char buf[30]; 825 char prefix[80]; 826 827 if (p->fs.fs_type != DN_IS_PIPE) 828 break; /* done with pipes, now queues */ 829 830 /* 831 * compute length, as pipe have variable size 832 */ 833 l = sizeof(*p) + p->fs.rq_elements * sizeof(*q); 834 next = (void *)p + l; 835 nbytes -= l; 836 837 if (rulenum != 0 && rulenum != p->pipe_nr) 838 continue; 839 840 /* 841 * Print rate 842 */ 843 if (b == 0) 844 sprintf(buf, "unlimited"); 845 else if (b >= 1000000) 846 sprintf(buf, "%7.3f Mbit/s", b/1000000); 847 else if (b >= 1000) 848 sprintf(buf, "%7.3f Kbit/s", b/1000); 849 else 850 sprintf(buf, "%7.3f bit/s ", b); 851 852 sprintf(prefix, "%05d: %s %4d ms ", 853 p->pipe_nr, buf, p->delay); 854 show_flowset_parms(&p->fs, prefix); 855 if (verbose) 856 printf(" V %20ju\n", (uintmax_t)p->V >> MY_M); 857 858 q = (struct dn_ioc_flowqueue *)(p+1); 859 show_queues(&p->fs, q); 860 } 861 862 for (fs = next; nbytes >= sizeof(*fs); fs = next) { 863 char prefix[80]; 864 865 if (fs->fs_type != DN_IS_QUEUE) 866 break; 867 l = sizeof(*fs) + fs->rq_elements * sizeof(*q); 868 next = (void *)fs + l; 869 nbytes -= l; 870 q = (struct dn_ioc_flowqueue *)(fs+1); 871 sprintf(prefix, "q%05d: weight %d pipe %d ", 872 fs->fs_nr, fs->weight, fs->parent_nr); 873 show_flowset_parms(fs, prefix); 874 show_queues(fs, q); 875 } 876 } 877 878 /* 879 * This one handles all set-related commands 880 * ipfw set { show | enable | disable } 881 * ipfw set swap X Y 882 * ipfw set move X to Y 883 * ipfw set move rule X to Y 884 */ 885 static void 886 sets_handler(int ac, char *av[]) 887 { 888 u_int32_t set_disable, masks[2]; 889 u_int16_t rulenum; 890 u_int8_t cmd, new_set; 891 int i, nbytes; 892 893 NEXT_ARG; 894 if (!ac) 895 errx(EX_USAGE, "set needs command"); 896 if (!strncmp(*av, "show", strlen(*av)) ) { 897 void *data = NULL; 898 char *msg; 899 int nalloc=1000; 900 nbytes = nalloc; 901 902 while (nbytes >= nalloc) { 903 nalloc = nalloc * 2+321; 904 nbytes = nalloc; 905 if (data == NULL) { 906 if ((data = malloc(nbytes)) == NULL) { 907 err(EX_OSERR, "malloc"); 908 } 909 } else if ((data = realloc(data, nbytes)) == NULL) { 910 err(EX_OSERR, "realloc"); 911 } 912 if (do_get_x(IP_FW_GET, data, &nbytes) < 0) { 913 err(EX_OSERR, "getsockopt(IP_FW_GET)"); 914 } 915 } 916 set_disable = ((struct ipfw_ioc_rule *)data)->set_disable; 917 for (i = 0, msg = "disable" ; i < 31; i++) 918 if ( (set_disable & (1<<i))) { 919 printf("%s %d", msg, i); 920 msg = ""; 921 } 922 msg = (set_disable) ? " enable" : "enable"; 923 for (i = 0; i < 31; i++) 924 if ( !(set_disable & (1<<i))) { 925 printf("%s %d", msg, i); 926 msg = ""; 927 } 928 printf("\n"); 929 } else if (!strncmp(*av, "swap", strlen(*av))) { 930 NEXT_ARG; 931 if (ac != 2) 932 errx(EX_USAGE, "set swap needs 2 set numbers\n"); 933 rulenum = atoi(av[0]); 934 new_set = atoi(av[1]); 935 if (!isdigit(*(av[0])) || rulenum > 30) 936 errx(EX_DATAERR, "invalid set number %s\n", av[0]); 937 if (!isdigit(*(av[1])) || new_set > 30) 938 errx(EX_DATAERR, "invalid set number %s\n", av[1]); 939 masks[0] = (4 << 24) | (new_set << 16) | (rulenum); 940 i = do_set_x(IP_FW_DEL, masks, sizeof(u_int32_t)); 941 } else if (!strncmp(*av, "move", strlen(*av))) { 942 NEXT_ARG; 943 if (ac && !strncmp(*av, "rule", strlen(*av))) { 944 cmd = 2; 945 NEXT_ARG; 946 } else 947 cmd = 3; 948 if (ac != 3 || strncmp(av[1], "to", strlen(*av))) 949 errx(EX_USAGE, "syntax: set move [rule] X to Y\n"); 950 rulenum = atoi(av[0]); 951 new_set = atoi(av[2]); 952 if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > 30) || 953 (cmd == 2 && rulenum == 65535) ) 954 errx(EX_DATAERR, "invalid source number %s\n", av[0]); 955 if (!isdigit(*(av[2])) || new_set > 30) 956 errx(EX_DATAERR, "invalid dest. set %s\n", av[1]); 957 masks[0] = (cmd << 24) | (new_set << 16) | (rulenum); 958 i = do_set_x(IP_FW_DEL, masks, sizeof(u_int32_t)); 959 } else if (!strncmp(*av, "disable", strlen(*av)) || 960 !strncmp(*av, "enable", strlen(*av)) ) { 961 int which = !strncmp(*av, "enable", strlen(*av)) ? 1 : 0; 962 963 NEXT_ARG; 964 masks[0] = masks[1] = 0; 965 966 while (ac) { 967 if (isdigit(**av)) { 968 i = atoi(*av); 969 if (i < 0 || i > 30) 970 errx(EX_DATAERR, "invalid set number %d\n", i); 971 masks[which] |= (1<<i); 972 } else if (!strncmp(*av, "disable", strlen(*av))) 973 which = 0; 974 else if (!strncmp(*av, "enable", strlen(*av))) 975 which = 1; 976 else 977 errx(EX_DATAERR, "invalid set command %s\n", *av); 978 NEXT_ARG; 979 } 980 if ( (masks[0] & masks[1]) != 0 ) 981 errx(EX_DATAERR, "cannot enable and disable the same set\n"); 982 i = do_set_x(IP_FW_DEL, masks, sizeof(masks)); 983 if (i) 984 warn("set enable/disable: setsockopt(IP_FW_DEL)"); 985 } else 986 errx(EX_USAGE, "invalid set command %s\n", *av); 987 } 988 989 static void 990 add_state(int ac, char *av[]) 991 { 992 struct ipfw_ioc_state ioc_state; 993 ioc_state.expiry = 0; 994 ioc_state.lifetime = 0; 995 NEXT_ARG; 996 if (strcmp(*av, "rulenum") == 0) { 997 NEXT_ARG; 998 ioc_state.rulenum = atoi(*av); 999 } else { 1000 errx(EX_USAGE, "ipfw state add rule"); 1001 } 1002 NEXT_ARG; 1003 struct protoent *pe; 1004 pe = getprotobyname(*av); 1005 ioc_state.flow_id.proto = pe->p_proto; 1006 1007 NEXT_ARG; 1008 ioc_state.flow_id.src_ip = inet_addr(*av); 1009 1010 NEXT_ARG; 1011 ioc_state.flow_id.src_port = atoi(*av); 1012 1013 NEXT_ARG; 1014 ioc_state.flow_id.dst_ip = inet_addr(*av); 1015 1016 NEXT_ARG; 1017 ioc_state.flow_id.dst_port = atoi(*av); 1018 1019 NEXT_ARG; 1020 if (strcmp(*av, "live") == 0) { 1021 NEXT_ARG; 1022 ioc_state.lifetime = atoi(*av); 1023 NEXT_ARG; 1024 } 1025 1026 if (strcmp(*av, "expiry") == 0) { 1027 NEXT_ARG; 1028 ioc_state.expiry = strtoul(*av, NULL, 10); 1029 printf("ioc_state.expiry=%d\n", ioc_state.expiry); 1030 } 1031 1032 if (do_set_x(IP_FW_STATE_ADD, &ioc_state, sizeof(struct ipfw_ioc_state)) < 0 ) { 1033 err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_ADD)"); 1034 } 1035 if (!do_quiet) { 1036 printf("Flushed all states.\n"); 1037 } 1038 } 1039 1040 static void 1041 delete_state(int ac, char *av[]) 1042 { 1043 int rulenum; 1044 NEXT_ARG; 1045 if (ac == 1 && isdigit(**av)) 1046 rulenum = atoi(*av); 1047 if (do_set_x(IP_FW_STATE_DEL, &rulenum, sizeof(int)) < 0 ) 1048 err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_DEL)"); 1049 if (!do_quiet) 1050 printf("Flushed all states.\n"); 1051 } 1052 1053 static void 1054 flush_state(int ac, char *av[]) 1055 { 1056 if (!do_force) { 1057 int c; 1058 1059 printf("Are you sure? [yn] "); 1060 fflush(stdout); 1061 do { 1062 c = toupper(getc(stdin)); 1063 while (c != '\n' && getc(stdin) != '\n') 1064 if (feof(stdin)) 1065 return; /* and do not flush */ 1066 } while (c != 'Y' && c != 'N'); 1067 if (c == 'N') /* user said no */ 1068 return; 1069 } 1070 if (do_set_x(IP_FW_STATE_FLUSH, NULL, 0) < 0 ) 1071 err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_FLUSH)"); 1072 if (!do_quiet) 1073 printf("Flushed all states.\n"); 1074 } 1075 1076 static int 1077 lookup_host (char *host, struct in_addr *ipaddr) 1078 { 1079 struct hostent *he; 1080 1081 if (!inet_aton(host, ipaddr)) { 1082 if ((he = gethostbyname(host)) == NULL) 1083 return(-1); 1084 *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 1085 } 1086 return(0); 1087 } 1088 1089 static void 1090 table_append(int ac, char *av[]) 1091 { 1092 struct ipfw_ioc_table tbl; 1093 char *p; 1094 int size; 1095 1096 NEXT_ARG; 1097 if (isdigit(**av)) 1098 tbl.id = atoi(*av); 1099 else 1100 errx(EX_USAGE, "table id `%s' invalid", *av); 1101 1102 if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1) 1103 errx(EX_USAGE, "table id `%d' invalid", tbl.id); 1104 1105 NEXT_ARG; 1106 if (strcmp(*av, "ip") == 0) 1107 tbl.type = 1; 1108 else if (strcmp(*av, "mac") == 0) 1109 tbl.type = 2; 1110 else 1111 errx(EX_USAGE, "table type `%s' not supported", *av); 1112 1113 NEXT_ARG; 1114 if (tbl.type == 1) { /* table type ipv4 */ 1115 struct ipfw_ioc_table_ip_entry ip_ent; 1116 if (!ac) 1117 errx(EX_USAGE, "IP address required"); 1118 1119 p = strchr(*av, '/'); 1120 if (p) { 1121 *p++ = '\0'; 1122 ip_ent.masklen = atoi(p); 1123 if (ip_ent.masklen > 32) 1124 errx(EX_DATAERR, "bad width ``%s''", p); 1125 } else { 1126 ip_ent.masklen = 32; 1127 } 1128 1129 if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0) 1130 errx(EX_NOHOST, "hostname ``%s'' unknown", *av); 1131 1132 tbl.ip_ent[0] = ip_ent; 1133 size = sizeof(tbl) + sizeof(ip_ent); 1134 } else if (tbl.type == 2) { /* table type mac */ 1135 struct ipfw_ioc_table_mac_entry mac_ent; 1136 if (!ac) 1137 errx(EX_USAGE, "MAC address required"); 1138 1139 mac_ent.addr = *ether_aton(*av); 1140 tbl.mac_ent[0] = mac_ent; 1141 size = sizeof(tbl) + sizeof(mac_ent); 1142 } 1143 if (do_set_x(IP_FW_TABLE_APPEND, &tbl, size) < 0 ) 1144 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_APPEND) " 1145 "table `%d' append `%s' failed", tbl.id, *av); 1146 } 1147 1148 static void 1149 table_remove(int ac, char *av[]) 1150 { 1151 struct ipfw_ioc_table tbl; 1152 struct ipfw_ioc_table_ip_entry ip_ent; 1153 char *p; 1154 int size; 1155 1156 NEXT_ARG; 1157 if (isdigit(**av)) 1158 tbl.id = atoi(*av); 1159 else 1160 errx(EX_USAGE, "table id `%s' invalid", *av); 1161 1162 if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1) 1163 errx(EX_USAGE, "table id `%d' invalid", tbl.id); 1164 1165 NEXT_ARG; 1166 if (strcmp(*av, "ip") == 0) 1167 tbl.type = 1; 1168 else if (strcmp(*av, "mac") == 0) 1169 tbl.type = 2; 1170 else 1171 errx(EX_USAGE, "table type `%s' not supported", *av); 1172 1173 NEXT_ARG; 1174 if (!ac) 1175 errx(EX_USAGE, "IP address required"); 1176 p = strchr(*av, '/'); 1177 if (p) { 1178 *p++ = '\0'; 1179 ip_ent.masklen = atoi(p); 1180 if (ip_ent.masklen > 32) 1181 errx(EX_DATAERR, "bad width ``%s''", p); 1182 } else { 1183 ip_ent.masklen = 32; 1184 } 1185 1186 if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0) 1187 errx(EX_NOHOST, "hostname ``%s'' unknown", *av); 1188 1189 tbl.ip_ent[0] = ip_ent; 1190 size = sizeof(tbl) + sizeof(ip_ent); 1191 if (do_set_x(IP_FW_TABLE_REMOVE, &tbl, size) < 0 ) { 1192 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_REMOVE) " 1193 "table `%d' append `%s' failed", tbl.id, *av); 1194 } 1195 } 1196 1197 static void 1198 table_flush(int ac, char *av[]) 1199 { 1200 struct ipfw_ioc_table ioc_table; 1201 struct ipfw_ioc_table *t = &ioc_table; 1202 1203 NEXT_ARG; 1204 if (isdigit(**av)) { 1205 t->id = atoi(*av); 1206 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1) 1207 errx(EX_USAGE, "table id `%d' invalid", t->id); 1208 } else { 1209 errx(EX_USAGE, "table id `%s' invalid", *av); 1210 } 1211 if (do_set_x(IP_FW_TABLE_FLUSH, t, sizeof(struct ipfw_ioc_table)) < 0 ) 1212 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_FLUSH) " 1213 "table `%s' flush failed", *av); 1214 } 1215 1216 static void 1217 table_list(int ac, char *av[]) 1218 { 1219 struct ipfw_ioc_table *ioc_table; 1220 int i, count, nbytes, nalloc = 1024; 1221 void *data = NULL; 1222 NEXT_ARG; 1223 if (strcmp(*av, "list") == 0) { 1224 nbytes = nalloc; 1225 while (nbytes >= nalloc) { 1226 nalloc = nalloc * 2 ; 1227 nbytes = nalloc; 1228 if ((data = realloc(data, nbytes)) == NULL) 1229 err(EX_OSERR, "realloc"); 1230 if (do_get_x(IP_FW_TABLE_LIST, data, &nbytes) < 0) 1231 err(EX_OSERR, "do_get_x(IP_FW_TABLE_LIST)"); 1232 } 1233 ioc_table = (struct ipfw_ioc_table *)data; 1234 count = nbytes / sizeof(struct ipfw_ioc_table); 1235 for (i = 0; i < count; i++, ioc_table++) { 1236 if (ioc_table->type > 0) { 1237 printf("table %d",ioc_table->id); 1238 if (ioc_table->type == 1) 1239 printf(" type ip"); 1240 else if (ioc_table->type == 2) 1241 printf(" type mac"); 1242 printf(" count %d",ioc_table->count); 1243 if (strlen(ioc_table->name) > 0) 1244 printf(" name %s",ioc_table->name); 1245 printf("\n"); 1246 1247 } 1248 } 1249 } else { 1250 errx(EX_USAGE, "ipfw3 table `%s' delete invalid", *av); 1251 } 1252 } 1253 1254 void 1255 print_table(struct ipfw_ioc_table * tbl) 1256 { 1257 int i; 1258 if (tbl->type == 0) 1259 errx(EX_USAGE, "table %d is not in use", tbl->id); 1260 1261 printf("table %d", tbl->id); 1262 if (tbl->type == 1) 1263 printf(" type ip"); 1264 else if (tbl->type == 2) 1265 printf(" type mac"); 1266 1267 printf(" count %d", tbl->count); 1268 if (strlen(tbl->name) > 0) 1269 printf(" name %s", tbl->name); 1270 1271 printf("\n"); 1272 1273 if (tbl->type == 1) { 1274 struct ipfw_ioc_table_ip_entry *ip_ent; 1275 ip_ent = tbl->ip_ent; 1276 for (i = 0; i < tbl->count; i++) { 1277 printf("%s", inet_ntoa(*(struct in_addr *)&ip_ent->addr)); 1278 printf("/%d ", ip_ent->masklen); 1279 printf("\n"); 1280 ip_ent++; 1281 } 1282 } else if (tbl->type == 2) { 1283 struct ipfw_ioc_table_mac_entry *mac_ent; 1284 mac_ent = tbl->mac_ent; 1285 for (i = 0; i < tbl->count; i++) { 1286 printf("%s", ether_ntoa(&mac_ent->addr)); 1287 printf("\n"); 1288 mac_ent++; 1289 } 1290 } 1291 } 1292 1293 static void 1294 table_show(int ac, char *av[]) 1295 { 1296 int nbytes, nalloc = 1024; 1297 void *data = NULL; 1298 NEXT_ARG; 1299 if (isdigit(**av)) { 1300 nbytes = nalloc; 1301 while (nbytes >= nalloc) { 1302 nalloc = nalloc * 2 + 256; 1303 nbytes = nalloc; 1304 if (data == NULL) { 1305 if ((data = malloc(nbytes)) == NULL) { 1306 err(EX_OSERR, "malloc"); 1307 } 1308 } else if ((data = realloc(data, nbytes)) == NULL) { 1309 err(EX_OSERR, "realloc"); 1310 } 1311 /* store table id in the header of data */ 1312 int *head = (int *)data; 1313 *head = atoi(*av); 1314 if (*head < 0 || *head > IPFW_TABLES_MAX - 1) 1315 errx(EX_USAGE, "table id `%d' invalid", *head); 1316 if (do_get_x(IP_FW_TABLE_SHOW, data, &nbytes) < 0) 1317 err(EX_OSERR, "do_get_x(IP_FW_TABLE_LIST)"); 1318 struct ipfw_ioc_table *tbl; 1319 tbl = (struct ipfw_ioc_table *)data; 1320 print_table(tbl); 1321 } 1322 } else { 1323 errx(EX_USAGE, "ipfw3 table `%s' show invalid", *av); 1324 } 1325 } 1326 1327 static void 1328 table_create(int ac, char *av[]) 1329 { 1330 struct ipfw_ioc_table ioc_table; 1331 struct ipfw_ioc_table *t = &ioc_table; 1332 1333 NEXT_ARG; 1334 if (ac < 2) 1335 errx(EX_USAGE, "table parameters invalid"); 1336 if (isdigit(**av)) { 1337 t->id = atoi(*av); 1338 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1) 1339 errx(EX_USAGE, "table id `%d' invalid", t->id); 1340 } else { 1341 errx(EX_USAGE, "table id `%s' invalid", *av); 1342 } 1343 NEXT_ARG; 1344 if (strcmp(*av, "ip") == 0) 1345 t->type = 1; 1346 else if (strcmp(*av, "mac") == 0) 1347 t->type = 2; 1348 else 1349 errx(EX_USAGE, "table type `%s' not supported", *av); 1350 1351 NEXT_ARG; 1352 memset(t->name, 0, IPFW_TABLE_NAME_LEN); 1353 if (ac == 2 && strcmp(*av, "name") == 0) { 1354 NEXT_ARG; 1355 if (strlen(*av) < IPFW_TABLE_NAME_LEN) { 1356 strncpy(t->name, *av, strlen(*av)); 1357 } else { 1358 errx(EX_USAGE, "table name `%s' too long", *av); 1359 } 1360 } else if (ac == 1) { 1361 errx(EX_USAGE, "table `%s' invalid", *av); 1362 } 1363 1364 if (do_set_x(IP_FW_TABLE_CREATE, t, sizeof(struct ipfw_ioc_table)) < 0) 1365 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_CREATE) " 1366 "table `%d' in use", t->id); 1367 } 1368 1369 static void 1370 table_delete(int ac, char *av[]) 1371 { 1372 struct ipfw_ioc_table ioc_table; 1373 struct ipfw_ioc_table *t = &ioc_table; 1374 1375 NEXT_ARG; 1376 if (isdigit(**av)) { 1377 t->id = atoi(*av); 1378 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1) 1379 errx(EX_USAGE, "table id `%d' invalid", t->id); 1380 } else { 1381 errx(EX_USAGE, "table id `%s' invalid", *av); 1382 } 1383 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1) 1384 errx(EX_USAGE, "table id `%d' invalid", t->id); 1385 1386 if (do_set_x(IP_FW_TABLE_DELETE, t, sizeof(struct ipfw_ioc_table)) < 0) 1387 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_DELETE) " 1388 "table `%s' delete failed", *av); 1389 } 1390 1391 static void 1392 table_test(int ac, char *av[]) 1393 { 1394 struct ipfw_ioc_table tbl; 1395 int size; 1396 1397 NEXT_ARG; 1398 if (isdigit(**av)) 1399 tbl.id = atoi(*av); 1400 else 1401 errx(EX_USAGE, "table id `%s' invalid", *av); 1402 1403 if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1) 1404 errx(EX_USAGE, "table id `%d' invalid", tbl.id); 1405 1406 NEXT_ARG; 1407 if (strcmp(*av, "ip") == 0) 1408 tbl.type = 1; 1409 else if (strcmp(*av, "mac") == 0) 1410 tbl.type = 2; 1411 else 1412 errx(EX_USAGE, "table type `%s' not supported", *av); 1413 1414 NEXT_ARG; 1415 if (tbl.type == 1) { /* table type ipv4 */ 1416 struct ipfw_ioc_table_ip_entry ip_ent; 1417 if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0) 1418 errx(EX_NOHOST, "hostname ``%s'' unknown", *av); 1419 1420 tbl.ip_ent[0] = ip_ent; 1421 size = sizeof(tbl) + sizeof(ip_ent); 1422 } else if (tbl.type == 2) { /* table type mac */ 1423 struct ipfw_ioc_table_mac_entry mac_ent; 1424 if (!ac) 1425 errx(EX_USAGE, "MAC address required"); 1426 1427 mac_ent.addr = *ether_aton(*av); 1428 tbl.mac_ent[0] = mac_ent; 1429 size = sizeof(tbl) + sizeof(mac_ent); 1430 } 1431 if (do_set_x(IP_FW_TABLE_TEST, &tbl, size) < 0 ) { 1432 printf("NO, %s not exists in table %d\n", *av, tbl.id); 1433 } else { 1434 printf("YES, %s exists in table %d\n", *av, tbl.id); 1435 } 1436 } 1437 1438 static void 1439 table_rename(int ac, char *av[]) 1440 { 1441 struct ipfw_ioc_table tbl; 1442 int size; 1443 1444 bzero(&tbl, sizeof(tbl)); 1445 NEXT_ARG; 1446 if (isdigit(**av)) 1447 tbl.id = atoi(*av); 1448 else 1449 errx(EX_USAGE, "table id `%s' invalid", *av); 1450 1451 if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1) 1452 errx(EX_USAGE, "table id `%d' invalid", tbl.id); 1453 1454 NEXT_ARG; 1455 strlcpy(tbl.name, *av, IPFW_TABLE_NAME_LEN); 1456 size = sizeof(tbl); 1457 if (do_set_x(IP_FW_TABLE_RENAME, &tbl, size) < 0 ) 1458 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_RENAME) " 1459 "table `%d' not in use", tbl.id); 1460 } 1461 1462 static void 1463 list(int ac, char *av[]) 1464 { 1465 struct ipfw_ioc_state *dynrules, *d; 1466 struct ipfw_ioc_rule *r; 1467 1468 u_long rnum; 1469 void *data = NULL; 1470 int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width; 1471 int exitval = EX_OK, lac; 1472 char **lav, *endptr; 1473 int seen = 0; 1474 int nalloc = 1024; 1475 1476 NEXT_ARG; 1477 1478 /* get rules or pipes from kernel, resizing array as necessary */ 1479 nbytes = nalloc; 1480 1481 while (nbytes >= nalloc) { 1482 nalloc = nalloc * 2 ; 1483 nbytes = nalloc; 1484 if ((data = realloc(data, nbytes)) == NULL) 1485 err(EX_OSERR, "realloc"); 1486 if (do_get_x(IP_FW_GET, data, &nbytes) < 0) 1487 err(EX_OSERR, "do_get_x(IP_FW_GET)"); 1488 } 1489 1490 /* 1491 * Count static rules. 1492 */ 1493 r = data; 1494 nstat = r->static_count; 1495 1496 /* 1497 * Count dynamic rules. This is easier as they have 1498 * fixed size. 1499 */ 1500 dynrules = (struct ipfw_ioc_state *)((void *)r + r->static_len); 1501 ndyn = (nbytes - r->static_len) / sizeof(*dynrules); 1502 1503 /* if showing stats, figure out column widths ahead of time */ 1504 bcwidth = pcwidth = 0; 1505 if (do_acct) { 1506 for (n = 0, r = data; n < nstat; 1507 n++, r = (void *)r + IOC_RULESIZE(r)) { 1508 /* packet counter */ 1509 width = snprintf(NULL, 0, "%ju", (uintmax_t)r->pcnt); 1510 if (width > pcwidth) 1511 pcwidth = width; 1512 1513 /* byte counter */ 1514 width = snprintf(NULL, 0, "%ju", (uintmax_t)r->bcnt); 1515 if (width > bcwidth) 1516 bcwidth = width; 1517 } 1518 } 1519 if (do_dynamic && ndyn) { 1520 for (n = 0, d = dynrules; n < ndyn; n++, d++) { 1521 width = snprintf(NULL, 0, "%ju", (uintmax_t)d->pcnt); 1522 if (width > pcwidth) 1523 pcwidth = width; 1524 1525 width = snprintf(NULL, 0, "%ju", (uintmax_t)d->bcnt); 1526 if (width > bcwidth) 1527 bcwidth = width; 1528 } 1529 } 1530 1531 /* if no rule numbers were specified, list all rules */ 1532 if (ac == 0) { 1533 if (do_dynamic != 2) { 1534 for (n = 0, r = data; n < nstat; n++, 1535 r = (void *)r + IOC_RULESIZE(r)) { 1536 show_rules(r, pcwidth, bcwidth); 1537 } 1538 } 1539 if (do_dynamic && ndyn) { 1540 if (do_dynamic != 2) { 1541 printf("## States (%d):\n", ndyn); 1542 } 1543 for (n = 0, d = dynrules; n < ndyn; n++, d++) 1544 show_states(d, pcwidth, bcwidth); 1545 } 1546 goto done; 1547 } 1548 1549 /* display specific rules requested on command line */ 1550 1551 if (do_dynamic != 2) { 1552 for (lac = ac, lav = av; lac != 0; lac--) { 1553 /* convert command line rule # */ 1554 rnum = strtoul(*lav++, &endptr, 10); 1555 if (*endptr) { 1556 exitval = EX_USAGE; 1557 warnx("invalid rule number: %s", *(lav - 1)); 1558 continue; 1559 } 1560 for (n = seen = 0, r = data; n < nstat; 1561 n++, r = (void *)r + IOC_RULESIZE(r) ) { 1562 if (r->rulenum > rnum) 1563 break; 1564 if (r->rulenum == rnum) { 1565 show_rules(r, pcwidth, bcwidth); 1566 seen = 1; 1567 } 1568 } 1569 if (!seen) { 1570 /* give precedence to other error(s) */ 1571 if (exitval == EX_OK) 1572 exitval = EX_UNAVAILABLE; 1573 warnx("rule %lu does not exist", rnum); 1574 } 1575 } 1576 } 1577 1578 if (do_dynamic && ndyn) { 1579 if (do_dynamic != 2) { 1580 printf("## States (%d):\n", ndyn); 1581 } 1582 for (lac = ac, lav = av; lac != 0; lac--) { 1583 rnum = strtoul(*lav++, &endptr, 10); 1584 if (*endptr) 1585 /* already warned */ 1586 continue; 1587 for (n = 0, d = dynrules; n < ndyn; n++, d++) { 1588 if (d->rulenum > rnum) 1589 break; 1590 if (d->rulenum == rnum) 1591 show_states(d, pcwidth, bcwidth); 1592 } 1593 } 1594 } 1595 1596 ac = 0; 1597 1598 done: 1599 free(data); 1600 1601 if (exitval != EX_OK) 1602 exit(exitval); 1603 } 1604 1605 static void 1606 show_dummynet(int ac, char *av[]) 1607 { 1608 void *data = NULL; 1609 int nbytes; 1610 int nalloc = 1024; /* start somewhere... */ 1611 1612 NEXT_ARG; 1613 1614 nbytes = nalloc; 1615 while (nbytes >= nalloc) { 1616 nalloc = nalloc * 2 + 200; 1617 nbytes = nalloc; 1618 if ((data = realloc(data, nbytes)) == NULL) 1619 err(EX_OSERR, "realloc"); 1620 if (do_get_x(IP_DUMMYNET_GET, data, &nbytes) < 0) { 1621 err(EX_OSERR, "do_get_x(IP_%s_GET)", 1622 do_pipe ? "DUMMYNET" : "FW"); 1623 } 1624 } 1625 1626 show_pipes(data, nbytes, ac, av); 1627 free(data); 1628 } 1629 1630 static void 1631 help(void) 1632 { 1633 fprintf(stderr, "usage: ipfw [options]\n" 1634 " ipfw add [rulenum] [set id] action filters\n" 1635 " ipfw delete [rulenum]\n" 1636 " ipfw flush\n" 1637 " ipfw list [rulenum]\n" 1638 " ipfw show [rulenum]\n" 1639 " ipfw zero [rulenum]\n" 1640 " ipfw set [show|enable|disable]\n" 1641 " ipfw module\n" 1642 " ipfw [enable|disable]\n" 1643 " ipfw log [reset|off|on]\n" 1644 " ipfw nat [config|show|delete]\n" 1645 " ipfw pipe [config|show|delete]\n" 1646 " ipfw state [add|delete|list|show]" 1647 "\nsee ipfw manpage for details\n"); 1648 exit(EX_USAGE); 1649 } 1650 1651 static void 1652 delete_nat_config(int ac, char *av[]) 1653 { 1654 NEXT_ARG; 1655 int i = 0; 1656 if (ac > 0) { 1657 i = atoi(*av); 1658 } 1659 if (do_set_x(IP_FW_NAT_DEL, &i, sizeof(i)) == -1) 1660 errx(EX_USAGE, "NAT %d in use or not exists", i); 1661 } 1662 1663 static void 1664 delete_rules(int ac, char *av[]) 1665 { 1666 struct dn_ioc_pipe pipe; 1667 u_int32_t rulenum; 1668 int exitval = EX_OK; 1669 int do_set = 0; 1670 int i; 1671 1672 memset(&pipe, 0, sizeof pipe); 1673 1674 NEXT_ARG; 1675 if (ac > 0 && !strncmp(*av, "set", strlen(*av))) { 1676 do_set = 1; /* delete set */ 1677 NEXT_ARG; 1678 } 1679 1680 /* Rule number */ 1681 while (ac && isdigit(**av)) { 1682 i = atoi(*av); 1683 NEXT_ARG; 1684 if (do_pipe) { 1685 if (do_pipe == 1) 1686 pipe.pipe_nr = i; 1687 else 1688 pipe.fs.fs_nr = i; 1689 1690 i = do_set_x(IP_DUMMYNET_DEL, &pipe, sizeof pipe); 1691 if (i) { 1692 exitval = 1; 1693 warn("rule %u: setsockopt(IP_DUMMYNET_DEL)", 1694 do_pipe == 1 ? pipe.pipe_nr : pipe.fs.fs_nr); 1695 } 1696 } else { 1697 rulenum = (i & 0xffff) | (do_set << 24); 1698 i = do_set_x(IP_FW_DEL, &rulenum, sizeof rulenum); 1699 if (i) { 1700 exitval = EX_UNAVAILABLE; 1701 warn("rule %u: setsockopt(IP_FW_DEL)", 1702 rulenum); 1703 } 1704 } 1705 } 1706 if (exitval != EX_OK) 1707 exit(exitval); 1708 } 1709 1710 1711 static unsigned long 1712 getbw(const char *str, u_short *flags, int kb) 1713 { 1714 unsigned long val; 1715 int inbytes = 0; 1716 char *end; 1717 1718 val = strtoul(str, &end, 0); 1719 if (*end == 'k' || *end == 'K') { 1720 ++end; 1721 val *= kb; 1722 } else if (*end == 'm' || *end == 'M') { 1723 ++end; 1724 val *= kb * kb; 1725 } 1726 1727 /* 1728 * Deal with bits or bytes or b(bits) or B(bytes). If there is no 1729 * trailer assume bits. 1730 */ 1731 if (strncasecmp(end, "bit", 3) == 0) { 1732 ; 1733 } else if (strncasecmp(end, "byte", 4) == 0) { 1734 inbytes = 1; 1735 } else if (*end == 'b') { 1736 ; 1737 } else if (*end == 'B') { 1738 inbytes = 1; 1739 } 1740 1741 /* 1742 * Return in bits if flags is NULL, else flag bits 1743 * or bytes in flags and return the unconverted value. 1744 */ 1745 if (inbytes && flags) 1746 *flags |= DN_QSIZE_IS_BYTES; 1747 else if (inbytes && flags == NULL) 1748 val *= 8; 1749 1750 return(val); 1751 } 1752 1753 /* 1754 * config dummynet pipe/queue 1755 */ 1756 static void 1757 config_dummynet(int ac, char **av) 1758 { 1759 struct dn_ioc_pipe pipe; 1760 u_int32_t a; 1761 void *par = NULL; 1762 int i; 1763 char *end; 1764 1765 NEXT_ARG; 1766 memset(&pipe, 0, sizeof pipe); 1767 /* Pipe number */ 1768 if (ac && isdigit(**av)) { 1769 i = atoi(*av); 1770 NEXT_ARG; 1771 if (do_pipe == 1) 1772 pipe.pipe_nr = i; 1773 else 1774 pipe.fs.fs_nr = i; 1775 } 1776 1777 while (ac > 0) { 1778 double d; 1779 1780 int tok = match_token(dummynet_params, *av); 1781 NEXT_ARG; 1782 1783 switch(tok) { 1784 case TOK_NOERROR: 1785 pipe.fs.flags_fs |= DN_NOERROR; 1786 break; 1787 1788 case TOK_PLR: 1789 NEED1("plr needs argument 0..1\n"); 1790 d = strtod(av[0], NULL); 1791 if (d > 1) 1792 d = 1; 1793 else if (d < 0) 1794 d = 0; 1795 pipe.fs.plr = (int)(d*0x7fffffff); 1796 NEXT_ARG; 1797 break; 1798 1799 case TOK_QUEUE: 1800 NEED1("queue needs queue size\n"); 1801 end = NULL; 1802 pipe.fs.qsize = getbw(av[0], &pipe.fs.flags_fs, 1024); 1803 NEXT_ARG; 1804 break; 1805 1806 case TOK_BUCKETS: 1807 NEED1("buckets needs argument\n"); 1808 pipe.fs.rq_size = strtoul(av[0], NULL, 0); 1809 NEXT_ARG; 1810 break; 1811 1812 case TOK_MASK: 1813 NEED1("mask needs mask specifier\n"); 1814 /* 1815 * per-flow queue, mask is dst_ip, dst_port, 1816 * src_ip, src_port, proto measured in bits 1817 */ 1818 par = NULL; 1819 1820 pipe.fs.flow_mask.type = ETHERTYPE_IP; 1821 pipe.fs.flow_mask.u.ip.dst_ip = 0; 1822 pipe.fs.flow_mask.u.ip.src_ip = 0; 1823 pipe.fs.flow_mask.u.ip.dst_port = 0; 1824 pipe.fs.flow_mask.u.ip.src_port = 0; 1825 pipe.fs.flow_mask.u.ip.proto = 0; 1826 end = NULL; 1827 1828 while (ac >= 1) { 1829 u_int32_t *p32 = NULL; 1830 u_int16_t *p16 = NULL; 1831 1832 tok = match_token(dummynet_params, *av); 1833 NEXT_ARG; 1834 switch(tok) { 1835 case TOK_ALL: 1836 /* 1837 * special case, all bits significant 1838 */ 1839 pipe.fs.flow_mask.u.ip.dst_ip = ~0; 1840 pipe.fs.flow_mask.u.ip.src_ip = ~0; 1841 pipe.fs.flow_mask.u.ip.dst_port = ~0; 1842 pipe.fs.flow_mask.u.ip.src_port = ~0; 1843 pipe.fs.flow_mask.u.ip.proto = ~0; 1844 pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK; 1845 goto end_mask; 1846 1847 case TOK_DSTIP: 1848 p32 = &pipe.fs.flow_mask.u.ip.dst_ip; 1849 break; 1850 1851 case TOK_SRCIP: 1852 p32 = &pipe.fs.flow_mask.u.ip.src_ip; 1853 break; 1854 1855 case TOK_DSTPORT: 1856 p16 = &pipe.fs.flow_mask.u.ip.dst_port; 1857 break; 1858 1859 case TOK_SRCPORT: 1860 p16 = &pipe.fs.flow_mask.u.ip.src_port; 1861 break; 1862 1863 case TOK_PROTO: 1864 break; 1865 1866 default: 1867 NEXT_ARG; 1868 goto end_mask; 1869 } 1870 if (ac < 1) 1871 errx(EX_USAGE, "mask: value missing"); 1872 if (*av[0] == '/') { 1873 a = strtoul(av[0]+1, &end, 0); 1874 a = (a == 32) ? ~0 : (1 << a) - 1; 1875 } else 1876 a = strtoul(av[0], &end, 0); 1877 if (p32 != NULL) 1878 *p32 = a; 1879 else if (p16 != NULL) { 1880 if (a > 65535) 1881 errx(EX_DATAERR, 1882 "mask: must be 16 bit"); 1883 *p16 = (u_int16_t)a; 1884 } else { 1885 if (a > 255) 1886 errx(EX_DATAERR, 1887 "mask: must be 8 bit"); 1888 pipe.fs.flow_mask.u.ip.proto = (uint8_t)a; 1889 } 1890 if (a != 0) 1891 pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK; 1892 NEXT_ARG; 1893 } /* end while, config masks */ 1894 1895 end_mask: 1896 break; 1897 1898 case TOK_RED: 1899 case TOK_GRED: 1900 NEED1("red/gred needs w_q/min_th/max_th/max_p\n"); 1901 pipe.fs.flags_fs |= DN_IS_RED; 1902 if (tok == TOK_GRED) 1903 pipe.fs.flags_fs |= DN_IS_GENTLE_RED; 1904 /* 1905 * the format for parameters is w_q/min_th/max_th/max_p 1906 */ 1907 if ((end = strsep(&av[0], "/"))) { 1908 double w_q = strtod(end, NULL); 1909 if (w_q > 1 || w_q <= 0) 1910 errx(EX_DATAERR, "0 < w_q <= 1"); 1911 pipe.fs.w_q = (int) (w_q * (1 << SCALE_RED)); 1912 } 1913 if ((end = strsep(&av[0], "/"))) { 1914 pipe.fs.min_th = strtoul(end, &end, 0); 1915 if (*end == 'K' || *end == 'k') 1916 pipe.fs.min_th *= 1024; 1917 } 1918 if ((end = strsep(&av[0], "/"))) { 1919 pipe.fs.max_th = strtoul(end, &end, 0); 1920 if (*end == 'K' || *end == 'k') 1921 pipe.fs.max_th *= 1024; 1922 } 1923 if ((end = strsep(&av[0], "/"))) { 1924 double max_p = strtod(end, NULL); 1925 if (max_p > 1 || max_p <= 0) 1926 errx(EX_DATAERR, "0 < max_p <= 1"); 1927 pipe.fs.max_p = (int)(max_p * (1 << SCALE_RED)); 1928 } 1929 NEXT_ARG; 1930 break; 1931 1932 case TOK_DROPTAIL: 1933 pipe.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED); 1934 break; 1935 1936 case TOK_BW: 1937 NEED1("bw needs bandwidth\n"); 1938 if (do_pipe != 1) 1939 errx(EX_DATAERR, "bandwidth only valid for pipes"); 1940 /* 1941 * set bandwidth value 1942 */ 1943 pipe.bandwidth = getbw(av[0], NULL, 1000); 1944 if (pipe.bandwidth < 0) 1945 errx(EX_DATAERR, "bandwidth too large"); 1946 NEXT_ARG; 1947 break; 1948 1949 case TOK_DELAY: 1950 if (do_pipe != 1) 1951 errx(EX_DATAERR, "delay only valid for pipes"); 1952 NEED1("delay needs argument 0..10000ms\n"); 1953 pipe.delay = strtoul(av[0], NULL, 0); 1954 NEXT_ARG; 1955 break; 1956 1957 case TOK_WEIGHT: 1958 if (do_pipe == 1) 1959 errx(EX_DATAERR, "weight only valid for queues"); 1960 NEED1("weight needs argument 0..100\n"); 1961 pipe.fs.weight = strtoul(av[0], &end, 0); 1962 NEXT_ARG; 1963 break; 1964 1965 case TOK_PIPE: 1966 if (do_pipe == 1) 1967 errx(EX_DATAERR, "pipe only valid for queues"); 1968 NEED1("pipe needs pipe_number\n"); 1969 pipe.fs.parent_nr = strtoul(av[0], &end, 0); 1970 NEXT_ARG; 1971 break; 1972 1973 default: 1974 errx(EX_DATAERR, "unrecognised option ``%s''", *av); 1975 } 1976 } 1977 if (do_pipe == 1) { 1978 if (pipe.pipe_nr == 0) 1979 errx(EX_DATAERR, "pipe_nr must be > 0"); 1980 if (pipe.delay > 10000) 1981 errx(EX_DATAERR, "delay must be < 10000"); 1982 } else { /* do_pipe == 2, queue */ 1983 if (pipe.fs.parent_nr == 0) 1984 errx(EX_DATAERR, "pipe must be > 0"); 1985 if (pipe.fs.weight >100) 1986 errx(EX_DATAERR, "weight must be <= 100"); 1987 } 1988 if (pipe.fs.flags_fs & DN_QSIZE_IS_BYTES) { 1989 if (pipe.fs.qsize > 1024*1024) 1990 errx(EX_DATAERR, "queue size must be < 1MB"); 1991 } else { 1992 if (pipe.fs.qsize > 100) 1993 errx(EX_DATAERR, "2 <= queue size <= 100"); 1994 } 1995 if (pipe.fs.flags_fs & DN_IS_RED) { 1996 size_t len; 1997 int lookup_depth, avg_pkt_size; 1998 double s, idle, weight, w_q; 1999 int clock_hz; 2000 int t; 2001 2002 if (pipe.fs.min_th >= pipe.fs.max_th) 2003 errx(EX_DATAERR, "min_th %d must be < than max_th %d", 2004 pipe.fs.min_th, pipe.fs.max_th); 2005 if (pipe.fs.max_th == 0) 2006 errx(EX_DATAERR, "max_th must be > 0"); 2007 2008 len = sizeof(int); 2009 if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth", 2010 &lookup_depth, &len, NULL, 0) == -1) 2011 2012 errx(1, "sysctlbyname(\"%s\")", 2013 "net.inet.ip.dummynet.red_lookup_depth"); 2014 if (lookup_depth == 0) 2015 errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth" 2016 " must be greater than zero"); 2017 2018 len = sizeof(int); 2019 if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size", 2020 &avg_pkt_size, &len, NULL, 0) == -1) 2021 2022 errx(1, "sysctlbyname(\"%s\")", 2023 "net.inet.ip.dummynet.red_avg_pkt_size"); 2024 if (avg_pkt_size == 0) 2025 errx(EX_DATAERR, 2026 "net.inet.ip.dummynet.red_avg_pkt_size must" 2027 " be greater than zero"); 2028 2029 len = sizeof(clock_hz); 2030 if (sysctlbyname("net.inet.ip.dummynet.hz", &clock_hz, &len, 2031 NULL, 0) == -1) { 2032 errx(1, "sysctlbyname(\"%s\")", 2033 "net.inet.ip.dummynet.hz"); 2034 } 2035 2036 /* 2037 * Ticks needed for sending a medium-sized packet. 2038 * Unfortunately, when we are configuring a WF2Q+ queue, we 2039 * do not have bandwidth information, because that is stored 2040 * in the parent pipe, and also we have multiple queues 2041 * competing for it. So we set s=0, which is not very 2042 * correct. But on the other hand, why do we want RED with 2043 * WF2Q+ ? 2044 */ 2045 if (pipe.bandwidth == 0) /* this is a WF2Q+ queue */ 2046 s = 0; 2047 else 2048 s = clock_hz * avg_pkt_size * 8 / pipe.bandwidth; 2049 2050 /* 2051 * max idle time (in ticks) before avg queue size becomes 0. 2052 * NOTA: (3/w_q) is approx the value x so that 2053 * (1-w_q)^x < 10^-3. 2054 */ 2055 w_q = ((double)pipe.fs.w_q) / (1 << SCALE_RED); 2056 idle = s * 3. / w_q; 2057 pipe.fs.lookup_step = (int)idle / lookup_depth; 2058 if (!pipe.fs.lookup_step) 2059 pipe.fs.lookup_step = 1; 2060 weight = 1 - w_q; 2061 for (t = pipe.fs.lookup_step; t > 0; --t) 2062 weight *= weight; 2063 pipe.fs.lookup_weight = (int)(weight * (1 << SCALE_RED)); 2064 } 2065 i = do_set_x(IP_DUMMYNET_CONFIGURE, &pipe, sizeof pipe); 2066 if (i) 2067 err(1, "do_set_x(%s)", "IP_DUMMYNET_CONFIGURE"); 2068 } 2069 2070 /* 2071 * helper function, updates the pointer to cmd with the length 2072 * of the current command, and also cleans up the first word of 2073 * the new command in case it has been clobbered before. 2074 */ 2075 static ipfw_insn* 2076 next_cmd(ipfw_insn *cmd) 2077 { 2078 cmd += F_LEN(cmd); 2079 bzero(cmd, sizeof(*cmd)); 2080 return cmd; 2081 } 2082 2083 /* 2084 * Parse arguments and assemble the microinstructions which make up a rule. 2085 * Rules are added into the 'rulebuf' and then copied in the correct order 2086 * into the actual rule. 2087 * 2088 * 2089 */ 2090 static void 2091 add(int ac, char *av[]) 2092 { 2093 /* 2094 * rules are added into the 'rulebuf' and then copied in 2095 * the correct order into the actual rule. 2096 * Some things that need to go out of order (prob, action etc.) 2097 * go into actbuf[]. 2098 */ 2099 static uint32_t rulebuf[IPFW_RULE_SIZE_MAX]; 2100 static uint32_t actbuf[IPFW_RULE_SIZE_MAX]; 2101 static uint32_t othbuf[IPFW_RULE_SIZE_MAX]; 2102 static uint32_t cmdbuf[IPFW_RULE_SIZE_MAX]; 2103 2104 ipfw_insn *src, *dst, *cmd, *action, *other; 2105 ipfw_insn *prev; 2106 char *prev_av; 2107 ipfw_insn *the_comment = NULL; 2108 struct ipfw_ioc_rule *rule; 2109 struct ipfw_keyword *key; 2110 struct ipfw_mapping *map; 2111 parser_func fn; 2112 int i, j; 2113 2114 bzero(actbuf, sizeof(actbuf)); /* actions go here */ 2115 bzero(othbuf, sizeof(actbuf)); /* others */ 2116 bzero(cmdbuf, sizeof(cmdbuf)); /* filters */ 2117 bzero(rulebuf, sizeof(rulebuf)); 2118 2119 rule = (struct ipfw_ioc_rule *)rulebuf; 2120 cmd = (ipfw_insn *)cmdbuf; 2121 action = (ipfw_insn *)actbuf; 2122 other = (ipfw_insn *)othbuf; 2123 2124 NEED2("need more parameters"); 2125 NEXT_ARG; 2126 2127 /* [rule N] -- Rule number optional */ 2128 if (ac && isdigit(**av)) { 2129 rule->rulenum = atoi(*av); 2130 NEXT_ARG; 2131 } 2132 2133 /* [set N] -- set number (0..30), optional */ 2134 if (ac > 1 && !strncmp(*av, "set", strlen(*av))) { 2135 int set = strtoul(av[1], NULL, 10); 2136 if (set < 0 || set > 30) 2137 errx(EX_DATAERR, "illegal set %s", av[1]); 2138 rule->set = set; 2139 av += 2; ac -= 2; 2140 } 2141 2142 /* 2143 * parse before 2144 */ 2145 for (;;) { 2146 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) { 2147 if (key->type == BEFORE && 2148 strcmp(key->word, *av) == 0) { 2149 for (j = 0, map = mappings; 2150 j < MAPPING_SIZE; j++, map++) { 2151 if (map->type == IN_USE && 2152 map->module == key->module && 2153 map->opcode == key->opcode ) { 2154 fn = map->parser; 2155 (*fn)(&other, &ac, &av); 2156 break; 2157 } 2158 } 2159 break; 2160 } 2161 } 2162 if (i >= KEYWORD_SIZE) { 2163 break; 2164 } else if (F_LEN(other) > 0) { 2165 if (other->module == MODULE_BASIC_ID && 2166 other->opcode == O_BASIC_CHECK_STATE) { 2167 other = next_cmd(other); 2168 goto done; 2169 } 2170 other = next_cmd(other); 2171 } 2172 } 2173 2174 /* 2175 * parse actions 2176 * 2177 * only accept 1 action 2178 */ 2179 NEED1("missing action"); 2180 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) { 2181 if (ac > 0 && key->type == ACTION && 2182 strcmp(key->word, *av) == 0) { 2183 for (j = 0, map = mappings; j<MAPPING_SIZE; j++, map++) { 2184 if (map->type == IN_USE && 2185 map->module == key->module && 2186 map->opcode == key->opcode) { 2187 fn = map->parser; 2188 (*fn)(&action, &ac, &av); 2189 break; 2190 } 2191 } 2192 break; 2193 } 2194 } 2195 if (F_LEN(action) > 0) 2196 action = next_cmd(action); 2197 2198 /* 2199 * parse protocol 2200 */ 2201 if (strcmp(*av, "proto") == 0){ 2202 NEXT_ARG; 2203 } 2204 2205 NEED1("missing protocol"); 2206 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) { 2207 if (key->type == PROTO && 2208 strcmp(key->word, "proto") == 0) { 2209 for (j = 0, map = mappings; j<MAPPING_SIZE; j++, map++) { 2210 if (map->type == IN_USE && 2211 map->module == key->module && 2212 map->opcode == key->opcode ) { 2213 fn = map->parser; 2214 (*fn)(&cmd, &ac, &av); 2215 break; 2216 } 2217 } 2218 break; 2219 } 2220 } 2221 if (F_LEN(cmd) > 0) 2222 cmd = next_cmd(cmd); 2223 2224 /* 2225 * other filters 2226 */ 2227 while (ac > 0) { 2228 char *s, *cur; /* current filter */ 2229 ipfw_insn_u32 *cmd32; /* alias for cmd */ 2230 2231 s = *av; 2232 cmd32 = (ipfw_insn_u32 *)cmd; 2233 if (strcmp(*av, "or") == 0) { 2234 if (prev == NULL) 2235 errx(EX_USAGE, "'or' should" 2236 "between two filters\n"); 2237 prev->len |= F_OR; 2238 cmd->len = F_OR; 2239 *av = prev_av; 2240 } 2241 if (strcmp(*av, "not") == 0) { 2242 if (cmd->len & F_NOT) 2243 errx(EX_USAGE, "double \"not\" not allowed\n"); 2244 cmd->len = F_NOT; 2245 NEXT_ARG; 2246 continue; 2247 } 2248 cur = *av; 2249 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) { 2250 if ((key->type == FILTER || 2251 key->type == AFTER || 2252 key->type == FROM || 2253 key->type == TO) && 2254 strcmp(key->word, cur) == 0) { 2255 for (j = 0, map = mappings; 2256 j< MAPPING_SIZE; j++, map++) { 2257 if (map->type == IN_USE && 2258 map->module == key->module && 2259 map->opcode == key->opcode ) { 2260 fn = map->parser; 2261 (*fn)(&cmd, &ac, &av); 2262 break; 2263 } 2264 } 2265 break; 2266 } else if (i == KEYWORD_SIZE - 1) { 2267 errx(EX_USAGE, "bad command `%s'", cur); 2268 } 2269 } 2270 if (i >= KEYWORD_SIZE) { 2271 break; 2272 } else if (F_LEN(cmd) > 0) { 2273 prev = cmd; 2274 prev_av = cur; 2275 cmd = next_cmd(cmd); 2276 } 2277 } 2278 2279 done: 2280 if (ac>0) 2281 errx(EX_USAGE, "bad command `%s'", *av); 2282 2283 /* 2284 * Now copy stuff into the rule. 2285 * [filters][others][action][comment] 2286 */ 2287 dst = (ipfw_insn *)rule->cmd; 2288 /* 2289 * copy all filters, except comment 2290 */ 2291 src = (ipfw_insn *)cmdbuf; 2292 for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) { 2293 /* pick comment out */ 2294 i = F_LEN(src); 2295 if (src->module == MODULE_BASIC_ID && src->opcode == O_BASIC_COMMENT) { 2296 the_comment=src; 2297 } else { 2298 bcopy(src, dst, i * sizeof(u_int32_t)); 2299 dst = (ipfw_insn *)((uint32_t *)dst + i); 2300 } 2301 } 2302 2303 /* 2304 * start action section, it begin with others 2305 */ 2306 rule->act_ofs = (uint32_t *)dst - (uint32_t *)(rule->cmd); 2307 2308 /* 2309 * copy all other others 2310 */ 2311 for (src = (ipfw_insn *)othbuf; src != other; src += i) { 2312 i = F_LEN(src); 2313 bcopy(src, dst, i * sizeof(u_int32_t)); 2314 dst = (ipfw_insn *)((uint32_t *)dst + i); 2315 } 2316 2317 /* copy the action to the end of rule */ 2318 src = (ipfw_insn *)actbuf; 2319 i = F_LEN(src); 2320 bcopy(src, dst, i * sizeof(u_int32_t)); 2321 dst = (ipfw_insn *)((uint32_t *)dst + i); 2322 2323 /* 2324 * comment place behind the action 2325 */ 2326 if (the_comment != NULL) { 2327 i = F_LEN(the_comment); 2328 bcopy(the_comment, dst, i * sizeof(u_int32_t)); 2329 dst = (ipfw_insn *)((uint32_t *)dst + i); 2330 } 2331 2332 rule->cmd_len = (u_int32_t *)dst - (u_int32_t *)(rule->cmd); 2333 i = (void *)dst - (void *)rule; 2334 if (do_set_x(IP_FW_ADD, (void *)rule, i) == -1) { 2335 err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD"); 2336 } 2337 if (!do_quiet) 2338 show_rules(rule, 10, 10); 2339 } 2340 2341 static void 2342 zero(int ac, char *av[]) 2343 { 2344 int rulenum; 2345 int failed = EX_OK; 2346 2347 NEXT_ARG; 2348 2349 if (!ac) { 2350 /* clear all entries */ 2351 if (do_set_x(IP_FW_ZERO, NULL, 0) < 0) 2352 err(EX_UNAVAILABLE, "do_set_x(IP_FW_ZERO)"); 2353 if (!do_quiet) 2354 printf("Accounting cleared.\n"); 2355 return; 2356 } 2357 2358 while (ac) { 2359 /* Rule number */ 2360 if (isdigit(**av)) { 2361 rulenum = atoi(*av); 2362 NEXT_ARG; 2363 if (do_set_x(IP_FW_ZERO, &rulenum, sizeof rulenum)) { 2364 warn("rule %u: do_set_x(IP_FW_ZERO)", rulenum); 2365 failed = EX_UNAVAILABLE; 2366 } else if (!do_quiet) 2367 printf("Entry %d cleared\n", rulenum); 2368 } else { 2369 errx(EX_USAGE, "invalid rule number ``%s''", *av); 2370 } 2371 } 2372 if (failed != EX_OK) 2373 exit(failed); 2374 } 2375 2376 static void 2377 resetlog(int ac, char *av[]) 2378 { 2379 int rulenum; 2380 int failed = EX_OK; 2381 2382 NEXT_ARG; 2383 2384 if (!ac) { 2385 /* clear all entries */ 2386 if (setsockopt(ipfw_socket, IPPROTO_IP, IP_FW_RESETLOG, NULL, 0) < 0) 2387 err(EX_UNAVAILABLE, "setsockopt(IP_FW_RESETLOG)"); 2388 if (!do_quiet) 2389 printf("Logging counts reset.\n"); 2390 2391 return; 2392 } 2393 2394 while (ac) { 2395 /* Rule number */ 2396 if (isdigit(**av)) { 2397 rulenum = atoi(*av); 2398 NEXT_ARG; 2399 if (setsockopt(ipfw_socket, IPPROTO_IP, 2400 IP_FW_RESETLOG, &rulenum, sizeof rulenum)) { 2401 warn("rule %u: setsockopt(IP_FW_RESETLOG)", rulenum); 2402 failed = EX_UNAVAILABLE; 2403 } else if (!do_quiet) 2404 printf("Entry %d logging count reset\n", rulenum); 2405 } else { 2406 errx(EX_DATAERR, "invalid rule number ``%s''", *av); 2407 } 2408 } 2409 if (failed != EX_OK) 2410 exit(failed); 2411 } 2412 2413 static void 2414 flush(void) 2415 { 2416 int cmd = IP_FW_FLUSH; 2417 if (do_pipe) { 2418 cmd = IP_DUMMYNET_FLUSH; 2419 } else if (do_nat) { 2420 cmd = IP_FW_NAT_FLUSH; 2421 } 2422 if (!do_force) { 2423 int c; 2424 2425 printf("Are you sure? [yn] "); 2426 fflush(stdout); 2427 do { 2428 c = toupper(getc(stdin)); 2429 while (c != '\n' && getc(stdin) != '\n') 2430 if (feof(stdin)) 2431 return; /* and do not flush */ 2432 } while (c != 'Y' && c != 'N'); 2433 if (c == 'N') /* user said no */ 2434 return; 2435 } 2436 if (do_set_x(cmd, NULL, 0) < 0 ) { 2437 if (do_pipe) 2438 errx(EX_USAGE, "pipe/queue in use"); 2439 else if (do_nat) 2440 errx(EX_USAGE, "NAT configuration in use"); 2441 else 2442 errx(EX_USAGE, "do_set_x(IP_FWFLUSH) failed"); 2443 } 2444 if (!do_quiet) { 2445 printf("Flushed all %s.\n", do_pipe ? "pipes": 2446 (do_nat?"nat configurations":"rules")); 2447 } 2448 } 2449 2450 static void 2451 str2addr(const char* str, struct in_addr* addr) 2452 { 2453 struct hostent* hp; 2454 2455 if (inet_aton (str, addr)) 2456 return; 2457 2458 hp = gethostbyname (str); 2459 if (!hp) 2460 errx (1, "unknown host %s", str); 2461 2462 memcpy (addr, hp->h_addr, sizeof (struct in_addr)); 2463 } 2464 2465 static int 2466 str2portrange(const char* str, const char* proto, port_range *portRange) 2467 { 2468 struct servent* sp; 2469 char* sep; 2470 char* end; 2471 u_short loPort, hiPort; 2472 2473 /* First see if this is a service, return corresponding port if so. */ 2474 sp = getservbyname (str, proto); 2475 if (sp) { 2476 SETLOPORT(*portRange, ntohs(sp->s_port)); 2477 SETNUMPORTS(*portRange, 1); 2478 return 0; 2479 } 2480 2481 /* Not a service, see if it's a single port or port range. */ 2482 sep = strchr (str, '-'); 2483 if (sep == NULL) { 2484 SETLOPORT(*portRange, strtol(str, &end, 10)); 2485 if (end != str) { 2486 /* Single port. */ 2487 SETNUMPORTS(*portRange, 1); 2488 return 0; 2489 } 2490 2491 /* Error in port range field. */ 2492 errx (EX_DATAERR, "%s/%s: unknown service", str, proto); 2493 } 2494 2495 /* Port range, get the values and sanity check. */ 2496 sscanf (str, "%hu-%hu", &loPort, &hiPort); 2497 SETLOPORT(*portRange, loPort); 2498 SETNUMPORTS(*portRange, 0); /* Error by default */ 2499 if (loPort <= hiPort) 2500 SETNUMPORTS(*portRange, hiPort - loPort + 1); 2501 2502 if (GETNUMPORTS(*portRange) == 0) 2503 errx (EX_DATAERR, "invalid port range %s", str); 2504 2505 return 0; 2506 } 2507 2508 static int 2509 str2proto(const char* str) 2510 { 2511 if (!strcmp (str, "tcp")) 2512 return IPPROTO_TCP; 2513 if (!strcmp (str, "udp")) 2514 return IPPROTO_UDP; 2515 errx (EX_DATAERR, "unknown protocol %s. Expected tcp or udp", str); 2516 } 2517 2518 static int 2519 str2addr_portrange (const char* str, struct in_addr* addr, 2520 char* proto, port_range *portRange) 2521 { 2522 char* ptr; 2523 2524 ptr = strchr (str, ':'); 2525 if (!ptr) 2526 errx (EX_DATAERR, "%s is missing port number", str); 2527 2528 *ptr = '\0'; 2529 ++ptr; 2530 2531 str2addr (str, addr); 2532 return str2portrange (ptr, proto, portRange); 2533 } 2534 2535 /* 2536 * Search for interface with name "ifn", and fill n accordingly: 2537 * 2538 * n->ip ip address of interface "ifn" 2539 * n->if_name copy of interface name "ifn" 2540 */ 2541 static void 2542 set_addr_dynamic(const char *ifn, struct cfg_nat *n) 2543 { 2544 struct if_msghdr *ifm; 2545 struct ifa_msghdr *ifam; 2546 struct sockaddr_dl *sdl; 2547 struct sockaddr_in *sin; 2548 char *buf, *lim, *next; 2549 size_t needed; 2550 int mib[6]; 2551 int ifIndex, ifMTU; 2552 2553 mib[0] = CTL_NET; 2554 mib[1] = PF_ROUTE; 2555 mib[2] = 0; 2556 mib[3] = AF_INET; 2557 mib[4] = NET_RT_IFLIST; 2558 mib[5] = 0; 2559 2560 /* 2561 * Get interface data. 2562 */ 2563 if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1) 2564 err(1, "iflist-sysctl-estimate"); 2565 if ((buf = malloc(needed)) == NULL) 2566 errx(1, "malloc failed"); 2567 if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1) 2568 err(1, "iflist-sysctl-get"); 2569 lim = buf + needed; 2570 /* 2571 * Loop through interfaces until one with 2572 * given name is found. This is done to 2573 * find correct interface index for routing 2574 * message processing. 2575 */ 2576 ifIndex = 0; 2577 next = buf; 2578 while (next < lim) { 2579 ifm = (struct if_msghdr *)next; 2580 next += ifm->ifm_msglen; 2581 if (ifm->ifm_version != RTM_VERSION) { 2582 if (verbose) 2583 warnx("routing message version %d " 2584 "not understood", ifm->ifm_version); 2585 continue; 2586 } 2587 if (ifm->ifm_type == RTM_IFINFO) { 2588 sdl = (struct sockaddr_dl *)(ifm + 1); 2589 if (strlen(ifn) == sdl->sdl_nlen && 2590 strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) { 2591 ifIndex = ifm->ifm_index; 2592 ifMTU = ifm->ifm_data.ifi_mtu; 2593 break; 2594 } 2595 } 2596 } 2597 if (!ifIndex) 2598 errx(1, "unknown interface name %s", ifn); 2599 /* 2600 * Get interface address. 2601 */ 2602 sin = NULL; 2603 while (next < lim) { 2604 ifam = (struct ifa_msghdr *)next; 2605 next += ifam->ifam_msglen; 2606 if (ifam->ifam_version != RTM_VERSION) { 2607 if (verbose) 2608 warnx("routing message version %d " 2609 "not understood", ifam->ifam_version); 2610 continue; 2611 } 2612 if (ifam->ifam_type != RTM_NEWADDR) 2613 break; 2614 if (ifam->ifam_addrs & RTA_IFA) { 2615 int i; 2616 char *cp = (char *)(ifam + 1); 2617 2618 for (i = 1; i < RTA_IFA; i <<= 1) { 2619 if (ifam->ifam_addrs & i) 2620 cp += SA_SIZE((struct sockaddr *)cp); 2621 } 2622 if (((struct sockaddr *)cp)->sa_family == AF_INET) { 2623 sin = (struct sockaddr_in *)cp; 2624 break; 2625 } 2626 } 2627 } 2628 if (sin == NULL) 2629 errx(1, "%s: cannot get interface address", ifn); 2630 2631 n->ip = sin->sin_addr; 2632 strncpy(n->if_name, ifn, IF_NAMESIZE); 2633 2634 free(buf); 2635 } 2636 2637 static int 2638 setup_redir_addr(char *spool_buf, int len, int *_ac, char ***_av) 2639 { 2640 struct cfg_redir *r; 2641 struct cfg_spool *tmp; 2642 char **av, *sep; 2643 char tmp_spool_buf[NAT_BUF_LEN]; 2644 int ac, i, space, lsnat; 2645 2646 i=0; 2647 av = *_av; 2648 ac = *_ac; 2649 space = 0; 2650 lsnat = 0; 2651 if (len >= SOF_REDIR) { 2652 r = (struct cfg_redir *)spool_buf; 2653 /* Skip cfg_redir at beginning of buf. */ 2654 spool_buf = &spool_buf[SOF_REDIR]; 2655 space = SOF_REDIR; 2656 len -= SOF_REDIR; 2657 } else { 2658 goto nospace; 2659 } 2660 2661 r->mode = REDIR_ADDR; 2662 /* Extract local address. */ 2663 if (ac == 0) 2664 errx(EX_DATAERR, "redirect_addr: missing local address"); 2665 2666 sep = strchr(*av, ','); 2667 if (sep) { /* LSNAT redirection syntax. */ 2668 r->laddr.s_addr = INADDR_NONE; 2669 /* Preserve av, copy spool servers to tmp_spool_buf. */ 2670 strncpy(tmp_spool_buf, *av, strlen(*av)+1); 2671 lsnat = 1; 2672 } else { 2673 str2addr(*av, &r->laddr); 2674 } 2675 INC_ARGCV(); 2676 2677 /* Extract public address. */ 2678 if (ac == 0) 2679 errx(EX_DATAERR, "redirect_addr: missing public address"); 2680 2681 str2addr(*av, &r->paddr); 2682 INC_ARGCV(); 2683 2684 /* Setup LSNAT server pool. */ 2685 if (sep) { 2686 sep = strtok(tmp_spool_buf, ", "); 2687 while (sep != NULL) { 2688 tmp = (struct cfg_spool *)spool_buf; 2689 if (len < SOF_SPOOL) 2690 goto nospace; 2691 2692 len -= SOF_SPOOL; 2693 space += SOF_SPOOL; 2694 str2addr(sep, &tmp->addr); 2695 tmp->port = ~0; 2696 r->spool_cnt++; 2697 /* Point to the next possible cfg_spool. */ 2698 spool_buf = &spool_buf[SOF_SPOOL]; 2699 sep = strtok(NULL, ", "); 2700 } 2701 } 2702 return(space); 2703 2704 nospace: 2705 errx(EX_DATAERR, "redirect_addr: buf is too small\n"); 2706 } 2707 2708 static int 2709 setup_redir_port(char *spool_buf, int len, int *_ac, char ***_av) 2710 { 2711 char **av, *sep, *protoName; 2712 char tmp_spool_buf[NAT_BUF_LEN]; 2713 int ac, space, lsnat; 2714 struct cfg_redir *r; 2715 struct cfg_spool *tmp; 2716 u_short numLocalPorts; 2717 port_range portRange; 2718 2719 av = *_av; 2720 ac = *_ac; 2721 space = 0; 2722 lsnat = 0; 2723 numLocalPorts = 0; 2724 2725 if (len >= SOF_REDIR) { 2726 r = (struct cfg_redir *)spool_buf; 2727 /* Skip cfg_redir at beginning of buf. */ 2728 spool_buf = &spool_buf[SOF_REDIR]; 2729 space = SOF_REDIR; 2730 len -= SOF_REDIR; 2731 } else { 2732 goto nospace; 2733 } 2734 2735 r->mode = REDIR_PORT; 2736 /* 2737 * Extract protocol. 2738 */ 2739 if (ac == 0) 2740 errx (EX_DATAERR, "redirect_port: missing protocol"); 2741 2742 r->proto = str2proto(*av); 2743 protoName = *av; 2744 INC_ARGCV(); 2745 2746 /* 2747 * Extract local address. 2748 */ 2749 if (ac == 0) 2750 errx (EX_DATAERR, "redirect_port: missing local address"); 2751 2752 sep = strchr(*av, ','); 2753 /* LSNAT redirection syntax. */ 2754 if (sep) { 2755 r->laddr.s_addr = INADDR_NONE; 2756 r->lport = ~0; 2757 numLocalPorts = 1; 2758 /* Preserve av, copy spool servers to tmp_spool_buf. */ 2759 strncpy(tmp_spool_buf, *av, strlen(*av)+1); 2760 lsnat = 1; 2761 } else { 2762 if (str2addr_portrange (*av, &r->laddr, protoName, &portRange) != 0) 2763 errx(EX_DATAERR, "redirect_port:" 2764 "invalid local port range"); 2765 2766 r->lport = GETLOPORT(portRange); 2767 numLocalPorts = GETNUMPORTS(portRange); 2768 } 2769 INC_ARGCV(); 2770 2771 /* 2772 * Extract public port and optionally address. 2773 */ 2774 if (ac == 0) 2775 errx (EX_DATAERR, "redirect_port: missing public port"); 2776 2777 sep = strchr (*av, ':'); 2778 if (sep) { 2779 if (str2addr_portrange (*av, &r->paddr, protoName, &portRange) != 0) 2780 errx(EX_DATAERR, "redirect_port:" 2781 "invalid public port range"); 2782 } else { 2783 r->paddr.s_addr = INADDR_ANY; 2784 if (str2portrange(*av, protoName, &portRange) != 0) 2785 errx(EX_DATAERR, "redirect_port:" 2786 "invalid public port range"); 2787 } 2788 2789 r->pport = GETLOPORT(portRange); 2790 r->pport_cnt = GETNUMPORTS(portRange); 2791 INC_ARGCV(); 2792 2793 /* 2794 * Extract remote address and optionally port. 2795 */ 2796 /* 2797 * NB: isalpha(**av) => we've to check that next parameter is really an 2798 * option for this redirect entry, else stop here processing arg[cv]. 2799 */ 2800 if (ac != 0 && !isalpha(**av)) { 2801 sep = strchr (*av, ':'); 2802 if (sep) { 2803 if (str2addr_portrange (*av, &r->raddr, 2804 protoName, &portRange) != 0) 2805 errx(EX_DATAERR, "redirect_port:" 2806 "invalid remote port range"); 2807 } else { 2808 SETLOPORT(portRange, 0); 2809 SETNUMPORTS(portRange, 1); 2810 str2addr (*av, &r->raddr); 2811 } 2812 INC_ARGCV(); 2813 } else { 2814 SETLOPORT(portRange, 0); 2815 SETNUMPORTS(portRange, 1); 2816 r->raddr.s_addr = INADDR_ANY; 2817 } 2818 r->rport = GETLOPORT(portRange); 2819 r->rport_cnt = GETNUMPORTS(portRange); 2820 2821 /* 2822 * Make sure port ranges match up, then add the redirect ports. 2823 */ 2824 if (numLocalPorts != r->pport_cnt) 2825 errx(EX_DATAERR, "redirect_port:" 2826 "port ranges must be equal in size"); 2827 2828 /* Remote port range is allowed to be '0' which means all ports. */ 2829 if (r->rport_cnt != numLocalPorts && 2830 (r->rport_cnt != 1 || r->rport != 0)) 2831 errx(EX_DATAERR, "redirect_port: remote port must" 2832 "be 0 or equal to local port range in size"); 2833 2834 /* 2835 * Setup LSNAT server pool. 2836 */ 2837 if (lsnat) { 2838 sep = strtok(tmp_spool_buf, ", "); 2839 while (sep != NULL) { 2840 tmp = (struct cfg_spool *)spool_buf; 2841 if (len < SOF_SPOOL) 2842 goto nospace; 2843 2844 len -= SOF_SPOOL; 2845 space += SOF_SPOOL; 2846 if (str2addr_portrange(sep, 2847 &tmp->addr, protoName, &portRange) != 0) 2848 errx(EX_DATAERR, "redirect_port:" 2849 "invalid local port range"); 2850 if (GETNUMPORTS(portRange) != 1) 2851 errx(EX_DATAERR, "redirect_port: local port" 2852 "must be single in this context"); 2853 tmp->port = GETLOPORT(portRange); 2854 r->spool_cnt++; 2855 /* Point to the next possible cfg_spool. */ 2856 spool_buf = &spool_buf[SOF_SPOOL]; 2857 sep = strtok(NULL, ", "); 2858 } 2859 } 2860 return (space); 2861 2862 nospace: 2863 errx(EX_DATAERR, "redirect_port: buf is too small\n"); 2864 } 2865 2866 static int 2867 setup_redir_proto(char *spool_buf, int len, int *_ac, char ***_av) 2868 { 2869 struct protoent *protoent; 2870 struct cfg_redir *r; 2871 int ac, i, space; 2872 char **av; 2873 2874 i=0; 2875 av = *_av; 2876 ac = *_ac; 2877 if (len >= SOF_REDIR) { 2878 r = (struct cfg_redir *)spool_buf; 2879 /* Skip cfg_redir at beginning of buf. */ 2880 spool_buf = &spool_buf[SOF_REDIR]; 2881 space = SOF_REDIR; 2882 len -= SOF_REDIR; 2883 } else { 2884 goto nospace; 2885 } 2886 r->mode = REDIR_PROTO; 2887 /* 2888 * Extract protocol. 2889 */ 2890 if (ac == 0) 2891 errx(EX_DATAERR, "redirect_proto: missing protocol"); 2892 2893 protoent = getprotobyname(*av); 2894 if (protoent == NULL) 2895 errx(EX_DATAERR, "redirect_proto: unknown protocol %s", *av); 2896 else 2897 r->proto = protoent->p_proto; 2898 2899 INC_ARGCV(); 2900 2901 /* 2902 * Extract local address. 2903 */ 2904 if (ac == 0) 2905 errx(EX_DATAERR, "redirect_proto: missing local address"); 2906 else 2907 str2addr(*av, &r->laddr); 2908 INC_ARGCV(); 2909 2910 /* 2911 * Extract optional public address. 2912 */ 2913 if (ac == 0) { 2914 r->paddr.s_addr = INADDR_ANY; 2915 r->raddr.s_addr = INADDR_ANY; 2916 } else { 2917 /* see above in setup_redir_port() */ 2918 if (!isalpha(**av)) { 2919 str2addr(*av, &r->paddr); 2920 INC_ARGCV(); 2921 2922 /* 2923 * Extract optional remote address. 2924 */ 2925 /* see above in setup_redir_port() */ 2926 if (ac != 0 && !isalpha(**av)) { 2927 str2addr(*av, &r->raddr); 2928 INC_ARGCV(); 2929 } 2930 } 2931 } 2932 return (space); 2933 2934 nospace: 2935 errx(EX_DATAERR, "redirect_proto: buf is too small\n"); 2936 } 2937 2938 static void 2939 show_nat_config(char *buf) { 2940 struct cfg_nat *n; 2941 struct cfg_redir *t; 2942 struct cfg_spool *s; 2943 struct protoent *p; 2944 int i, cnt, flag, off; 2945 2946 n = (struct cfg_nat *)buf; 2947 flag = 1; 2948 off = sizeof(*n); 2949 printf("ipfw nat %u config", n->id); 2950 if (strlen(n->if_name) != 0) 2951 printf(" if %s", n->if_name); 2952 else if (n->ip.s_addr != 0) 2953 printf(" ip %s", inet_ntoa(n->ip)); 2954 while (n->mode != 0) { 2955 if (n->mode & PKT_ALIAS_LOG) { 2956 printf(" log"); 2957 n->mode &= ~PKT_ALIAS_LOG; 2958 } else if (n->mode & PKT_ALIAS_DENY_INCOMING) { 2959 printf(" deny_in"); 2960 n->mode &= ~PKT_ALIAS_DENY_INCOMING; 2961 } else if (n->mode & PKT_ALIAS_SAME_PORTS) { 2962 printf(" same_ports"); 2963 n->mode &= ~PKT_ALIAS_SAME_PORTS; 2964 } else if (n->mode & PKT_ALIAS_UNREGISTERED_ONLY) { 2965 printf(" unreg_only"); 2966 n->mode &= ~PKT_ALIAS_UNREGISTERED_ONLY; 2967 } else if (n->mode & PKT_ALIAS_RESET_ON_ADDR_CHANGE) { 2968 printf(" reset"); 2969 n->mode &= ~PKT_ALIAS_RESET_ON_ADDR_CHANGE; 2970 } else if (n->mode & PKT_ALIAS_REVERSE) { 2971 printf(" reverse"); 2972 n->mode &= ~PKT_ALIAS_REVERSE; 2973 } else if (n->mode & PKT_ALIAS_PROXY_ONLY) { 2974 printf(" proxy_only"); 2975 n->mode &= ~PKT_ALIAS_PROXY_ONLY; 2976 } 2977 } 2978 /* Print all the redirect's data configuration. */ 2979 for (cnt = 0; cnt < n->redir_cnt; cnt++) { 2980 t = (struct cfg_redir *)&buf[off]; 2981 off += SOF_REDIR; 2982 switch (t->mode) { 2983 case REDIR_ADDR: 2984 printf(" redirect_addr"); 2985 if (t->spool_cnt == 0) 2986 printf(" %s", inet_ntoa(t->laddr)); 2987 else 2988 for (i = 0; i < t->spool_cnt; i++) { 2989 s = (struct cfg_spool *)&buf[off]; 2990 if (i) 2991 printf(", "); 2992 else 2993 printf(" "); 2994 printf("%s", inet_ntoa(s->addr)); 2995 off += SOF_SPOOL; 2996 } 2997 printf(" %s", inet_ntoa(t->paddr)); 2998 break; 2999 case REDIR_PORT: 3000 p = getprotobynumber(t->proto); 3001 printf(" redirect_port %s ", p->p_name); 3002 if (!t->spool_cnt) { 3003 printf("%s:%u", inet_ntoa(t->laddr), t->lport); 3004 if (t->pport_cnt > 1) 3005 printf("-%u", t->lport + t->pport_cnt - 1); 3006 } else 3007 for (i=0; i < t->spool_cnt; i++) { 3008 s = (struct cfg_spool *)&buf[off]; 3009 if (i) 3010 printf(", "); 3011 printf("%s:%u", inet_ntoa(s->addr), s->port); 3012 off += SOF_SPOOL; 3013 } 3014 3015 printf(" "); 3016 if (t->paddr.s_addr) 3017 printf("%s:", inet_ntoa(t->paddr)); 3018 printf("%u", t->pport); 3019 if (!t->spool_cnt && t->pport_cnt > 1) 3020 printf("-%u", t->pport + t->pport_cnt - 1); 3021 3022 if (t->raddr.s_addr) { 3023 printf(" %s", inet_ntoa(t->raddr)); 3024 if (t->rport) { 3025 printf(":%u", t->rport); 3026 if (!t->spool_cnt && t->rport_cnt > 1) 3027 printf("-%u", t->rport + 3028 t->rport_cnt - 1); 3029 } 3030 } 3031 break; 3032 case REDIR_PROTO: 3033 p = getprotobynumber(t->proto); 3034 printf(" redirect_proto %s %s", p->p_name, 3035 inet_ntoa(t->laddr)); 3036 if (t->paddr.s_addr != 0) { 3037 printf(" %s", inet_ntoa(t->paddr)); 3038 if (t->raddr.s_addr) 3039 printf(" %s", inet_ntoa(t->raddr)); 3040 } 3041 break; 3042 default: 3043 errx(EX_DATAERR, "unknown redir mode"); 3044 break; 3045 } 3046 } 3047 printf("\n"); 3048 } 3049 3050 3051 static void 3052 show_nat(int ac, char **av) { 3053 struct cfg_nat *n; 3054 struct cfg_redir *e; 3055 int i, nbytes, nalloc, size; 3056 int nat_cnt, redir_cnt, nat_id; 3057 uint8_t *data; 3058 3059 nalloc = 1024; 3060 size = 0; 3061 data = NULL; 3062 3063 NEXT_ARG; 3064 3065 if (ac == 0) 3066 nat_id = 0; 3067 else 3068 nat_id = strtoul(*av, NULL, 10); 3069 3070 nbytes = nalloc; 3071 while (nbytes >= nalloc) { 3072 nalloc = nalloc * 2; 3073 nbytes = nalloc; 3074 if ((data = realloc(data, nbytes)) == NULL) { 3075 err(EX_OSERR, "realloc"); 3076 } 3077 if (do_get_x(IP_FW_NAT_GET, data, &nbytes) < 0) { 3078 err(EX_OSERR, "do_get_x(IP_FW_NAT_GET)"); 3079 } 3080 } 3081 3082 if (nbytes == 0) { 3083 exit(EX_OK); 3084 } 3085 3086 nat_cnt = *((int *)data); 3087 for (i = sizeof(nat_cnt); nat_cnt; nat_cnt--) { 3088 n = (struct cfg_nat *)&data[i]; 3089 if (n->id >= 0 && n->id <= IPFW_DEFAULT_RULE) { 3090 if (nat_id == 0 || n->id == nat_id) 3091 show_nat_config(&data[i]); 3092 } 3093 i += sizeof(struct cfg_nat); 3094 for (redir_cnt = 0; redir_cnt < n->redir_cnt; redir_cnt++) { 3095 e = (struct cfg_redir *)&data[i]; 3096 i += sizeof(struct cfg_redir) + 3097 e->spool_cnt * sizeof(struct cfg_spool); 3098 } 3099 } 3100 } 3101 3102 int 3103 get_kern_boottime(void) 3104 { 3105 struct timeval boottime; 3106 size_t size; 3107 int mib[2]; 3108 mib[0] = CTL_KERN; 3109 mib[1] = KERN_BOOTTIME; 3110 size = sizeof(boottime); 3111 if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 && 3112 boottime.tv_sec != 0) { 3113 return boottime.tv_sec; 3114 } 3115 return -1; 3116 } 3117 3118 void 3119 show_nat_state(int ac, char **av) 3120 { 3121 int nbytes, nalloc; 3122 int nat_id; 3123 uint8_t *data; 3124 3125 nalloc = 1024; 3126 data = NULL; 3127 3128 NEXT_ARG; 3129 if (ac == 0) 3130 nat_id = 0; 3131 else 3132 nat_id = strtoul(*av, NULL, 10); 3133 3134 nbytes = nalloc; 3135 while (nbytes >= nalloc) { 3136 nalloc = nalloc * 2; 3137 nbytes = nalloc; 3138 if ((data = realloc(data, nbytes)) == NULL) { 3139 err(EX_OSERR, "realloc"); 3140 } 3141 memcpy(data, &nat_id, sizeof(int)); 3142 if (do_get_x(IP_FW_NAT_LOG, data, &nbytes) < 0) { 3143 err(EX_OSERR, "do_get_x(IP_FW_NAT_GET_STATE)"); 3144 } 3145 } 3146 if (nbytes == 0) 3147 exit(EX_OK); 3148 struct ipfw_ioc_nat_state *nat_state; 3149 nat_state =(struct ipfw_ioc_nat_state *)data; 3150 int count = nbytes / sizeof( struct ipfw_ioc_nat_state); 3151 int i, uptime_sec; 3152 uptime_sec = get_kern_boottime(); 3153 for (i = 0; i < count; i ++) { 3154 struct protoent *pe = getprotobynumber(nat_state->link_type); 3155 printf("%s ", pe->p_name); 3156 printf("%s:%hu => ",inet_ntoa(nat_state->src_addr), 3157 htons(nat_state->src_port)); 3158 printf("%s:%hu",inet_ntoa(nat_state->alias_addr), 3159 htons(nat_state->alias_port)); 3160 printf(" -> %s:%hu ",inet_ntoa(nat_state->dst_addr), 3161 htons(nat_state->dst_port)); 3162 if (do_time == 1) { 3163 char timestr[30]; 3164 time_t t = _long_to_time(uptime_sec + nat_state->timestamp); 3165 strcpy(timestr, ctime(&t)); 3166 *strchr(timestr, '\n') = '\0'; 3167 printf("%s ", timestr); 3168 } else if (do_time == 2) { 3169 printf( "%10u ", uptime_sec + nat_state->timestamp); 3170 } 3171 printf("\n"); 3172 nat_state++; 3173 } 3174 } 3175 3176 /* 3177 * do_set_x - extended version og do_set 3178 * insert a x_header in the beginning of the rule buf 3179 * and call setsockopt() with IP_FW_X. 3180 */ 3181 int 3182 do_set_x(int optname, void *rule, int optlen) 3183 { 3184 int len, *newbuf; 3185 3186 ip_fw_x_header *x_header; 3187 if (ipfw_socket < 0) 3188 err(EX_UNAVAILABLE, "socket not avaialble"); 3189 len = optlen + sizeof(ip_fw_x_header); 3190 newbuf = malloc(len); 3191 if (newbuf == NULL) 3192 err(EX_OSERR, "malloc newbuf in do_set_x"); 3193 bzero(newbuf, len); 3194 x_header = (ip_fw_x_header *)newbuf; 3195 x_header->opcode = optname; 3196 /* copy the rule into the newbuf, just after the x_header*/ 3197 bcopy(rule, ++x_header, optlen); 3198 return setsockopt(ipfw_socket, IPPROTO_IP, IP_FW_X, newbuf, len); 3199 } 3200 3201 /* 3202 * same as do_set_x 3203 */ 3204 int 3205 do_get_x(int optname, void *rule, int *optlen) 3206 { 3207 int len, *newbuf, retval; 3208 3209 ip_fw_x_header *x_header; 3210 if (ipfw_socket < 0) 3211 err(EX_UNAVAILABLE, "socket not avaialble"); 3212 len = *optlen + sizeof(ip_fw_x_header); 3213 newbuf = malloc(len); 3214 if (newbuf == NULL) 3215 err(EX_OSERR, "malloc newbuf in do_get_x"); 3216 bzero(newbuf, len); 3217 x_header = (ip_fw_x_header *)newbuf; 3218 x_header->opcode = optname; 3219 /* copy the rule into the newbuf, just after the x_header*/ 3220 bcopy(rule, ++x_header, *optlen); 3221 retval = getsockopt(ipfw_socket, IPPROTO_IP, IP_FW_X, newbuf, &len); 3222 bcopy(newbuf, rule, len); 3223 *optlen=len; 3224 return retval; 3225 } 3226 3227 static void 3228 config_nat(int ac, char **av) 3229 { 3230 struct cfg_nat *n; /* Nat instance configuration. */ 3231 int i, len, off, tok; 3232 char *id, buf[NAT_BUF_LEN]; /* Buffer for serialized data. */ 3233 3234 len = NAT_BUF_LEN; 3235 /* Offset in buf: save space for n at the beginning. */ 3236 off = sizeof(struct cfg_nat); 3237 memset(buf, 0, sizeof(buf)); 3238 n = (struct cfg_nat *)buf; 3239 3240 NEXT_ARG; 3241 /* Nat id. */ 3242 if (ac && isdigit(**av)) { 3243 id = *av; 3244 i = atoi(*av); 3245 NEXT_ARG; 3246 n->id = i; 3247 } else 3248 errx(EX_DATAERR, "missing nat id"); 3249 if (ac == 0) 3250 errx(EX_DATAERR, "missing option"); 3251 3252 while (ac > 0) { 3253 tok = match_token(nat_params, *av); 3254 NEXT_ARG; 3255 switch (tok) { 3256 case TOK_IP: 3257 if (ac == 0) 3258 errx(EX_DATAERR, "missing option"); 3259 if (!inet_aton(av[0], &(n->ip))) 3260 errx(EX_DATAERR, "bad ip address ``%s''", 3261 av[0]); 3262 NEXT_ARG; 3263 break; 3264 case TOK_IF: 3265 if (ac == 0) 3266 errx(EX_DATAERR, "missing option"); 3267 set_addr_dynamic(av[0], n); 3268 NEXT_ARG; 3269 break; 3270 case TOK_ALOG: 3271 n->mode |= PKT_ALIAS_LOG; 3272 break; 3273 case TOK_DENY_INC: 3274 n->mode |= PKT_ALIAS_DENY_INCOMING; 3275 break; 3276 case TOK_SAME_PORTS: 3277 n->mode |= PKT_ALIAS_SAME_PORTS; 3278 break; 3279 case TOK_UNREG_ONLY: 3280 n->mode |= PKT_ALIAS_UNREGISTERED_ONLY; 3281 break; 3282 case TOK_RESET_ADDR: 3283 n->mode |= PKT_ALIAS_RESET_ON_ADDR_CHANGE; 3284 break; 3285 case TOK_ALIAS_REV: 3286 n->mode |= PKT_ALIAS_REVERSE; 3287 break; 3288 case TOK_PROXY_ONLY: 3289 n->mode |= PKT_ALIAS_PROXY_ONLY; 3290 break; 3291 /* 3292 * All the setup_redir_* functions work directly in the final 3293 * buffer, see above for details. 3294 */ 3295 case TOK_REDIR_ADDR: 3296 case TOK_REDIR_PORT: 3297 case TOK_REDIR_PROTO: 3298 switch (tok) { 3299 case TOK_REDIR_ADDR: 3300 i = setup_redir_addr(&buf[off], len, &ac, &av); 3301 break; 3302 case TOK_REDIR_PORT: 3303 i = setup_redir_port(&buf[off], len, &ac, &av); 3304 break; 3305 case TOK_REDIR_PROTO: 3306 i = setup_redir_proto(&buf[off], len, &ac, &av); 3307 break; 3308 } 3309 n->redir_cnt++; 3310 off += i; 3311 len -= i; 3312 break; 3313 default: 3314 errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]); 3315 } 3316 } 3317 i = do_set_x(IP_FW_NAT_CFG, buf, off); 3318 if (i) 3319 err(1, "do_set_x(%s)", "IP_FW_NAT_CFG"); 3320 3321 /* After every modification, we show the resultant rule. */ 3322 int _ac = 2; 3323 char *_av[] = {"config", id}; 3324 show_nat(_ac, _av); 3325 } 3326 3327 3328 static int 3329 ipfw_main(int ac, char **av) 3330 { 3331 int ch; 3332 3333 if (ac == 1) 3334 help(); 3335 3336 /* Set the force flag for non-interactive processes */ 3337 do_force = !isatty(STDIN_FILENO); 3338 3339 optind = optreset = 1; 3340 while ((ch = getopt(ac, av, "hs:acdDefNStTv")) != -1) 3341 switch (ch) { 3342 case 'h': /* help */ 3343 help(); 3344 break; /* NOTREACHED */ 3345 3346 case 's': /* sort */ 3347 do_sort = atoi(optarg); 3348 break; 3349 case 'a': 3350 do_acct = 1; 3351 break; 3352 case 'c': 3353 do_compact = 1; 3354 break; 3355 case 'd': 3356 do_dynamic = 1; 3357 break; 3358 case 'D': 3359 do_dynamic = 2; 3360 break; 3361 case 'e': 3362 do_expired = 1; 3363 break; 3364 case 'f': 3365 do_force = 1; 3366 break; 3367 case 'N': 3368 do_resolv = 1; 3369 break; 3370 case 'S': 3371 show_sets = 1; 3372 break; 3373 case 't': 3374 do_time = 1; 3375 break; 3376 case 'T': 3377 do_time = 2; 3378 break; 3379 case 'v': 3380 do_quiet = 0; 3381 verbose++; 3382 break; 3383 default: 3384 help(); 3385 } 3386 3387 ac -= optind; 3388 av += optind; 3389 NEED1("bad arguments, for usage summary ``ipfw''"); 3390 3391 /* 3392 * optional: pipe or queue or nat 3393 */ 3394 do_nat = 0; 3395 do_pipe = 0; 3396 if (!strncmp(*av, "nat", strlen(*av))) 3397 do_nat = 1; 3398 else if (!strncmp(*av, "pipe", strlen(*av))) { 3399 do_pipe = 1; 3400 } else if (!strncmp(*av, "queue", strlen(*av))) { 3401 do_pipe = 2; 3402 } 3403 NEED1("missing command"); 3404 3405 /* 3406 * for pipes and queues and nat we normally say 'pipe NN config' 3407 * but the code is easier to parse as 'pipe config NN' 3408 * so we swap the two arguments. 3409 */ 3410 if ((do_pipe || do_nat) && ac > 2 && isdigit(*(av[1]))) { 3411 char *p = av[1]; 3412 av[1] = av[2]; 3413 av[2] = p; 3414 } 3415 3416 if (!strncmp(*av, "add", strlen(*av))) { 3417 load_modules(); 3418 add(ac, av); 3419 } else if (!strncmp(*av, "delete", strlen(*av))) { 3420 delete_rules(ac, av); 3421 } else if (!strncmp(*av, "flush", strlen(*av))) { 3422 flush(); 3423 } else if (!strncmp(*av, "list", strlen(*av))) { 3424 load_modules(); 3425 list(ac, av); 3426 } else if (!strncmp(*av, "show", strlen(*av))) { 3427 do_acct++; 3428 load_modules(); 3429 list(ac, av); 3430 } else if (!strncmp(*av, "zero", strlen(*av))) { 3431 zero(ac, av); 3432 } else if (!strncmp(*av, "set", strlen(*av))) { 3433 sets_handler(ac, av); 3434 } else if (!strncmp(*av, "module", strlen(*av))) { 3435 NEXT_ARG; 3436 if (!strncmp(*av, "show", strlen(*av)) || 3437 !strncmp(*av, "show", strlen(*av))) { 3438 list_modules(ac, av); 3439 } else { 3440 errx(EX_USAGE, "bad ipfw module command `%s'", *av); 3441 } 3442 } else if (!strncmp(*av, "resetlog", strlen(*av))) { 3443 resetlog(ac, av); 3444 } else if (!strncmp(*av, "log", strlen(*av))) { 3445 NEXT_ARG; 3446 if (!strncmp(*av, "reset", strlen(*av))) { 3447 resetlog(ac, av); 3448 } else if (!strncmp(*av, "off", strlen(*av))) { 3449 3450 } else if (!strncmp(*av, "on", strlen(*av))) { 3451 3452 } else { 3453 errx(EX_USAGE, "bad command `%s'", *av); 3454 } 3455 } else if (!strncmp(*av, "nat", strlen(*av))) { 3456 NEXT_ARG; 3457 if (!strncmp(*av, "config", strlen(*av))) { 3458 config_nat(ac, av); 3459 } else if (!strncmp(*av, "flush", strlen(*av))) { 3460 flush(); 3461 } else if (!strncmp(*av, "show", strlen(*av)) || 3462 !strncmp(*av, "list", strlen(*av))) { 3463 if (ac > 2 && isdigit(*(av[1]))) { 3464 char *p = av[1]; 3465 av[1] = av[2]; 3466 av[2] = p; 3467 } 3468 NEXT_ARG; 3469 if (!strncmp(*av, "config", strlen(*av))) { 3470 show_nat(ac, av); 3471 } else if (!strncmp(*av, "state", strlen(*av))) { 3472 show_nat_state(ac,av); 3473 } else { 3474 errx(EX_USAGE, 3475 "bad nat show command `%s'", *av); 3476 } 3477 } else if (!strncmp(*av, "delete", strlen(*av))) { 3478 delete_nat_config(ac, av); 3479 } else { 3480 errx(EX_USAGE, "bad ipfw nat command `%s'", *av); 3481 } 3482 } else if (!strncmp(*av, "pipe", strlen(*av)) || 3483 !strncmp(*av, "queue", strlen(*av))) { 3484 NEXT_ARG; 3485 if (!strncmp(*av, "config", strlen(*av))) { 3486 config_dummynet(ac, av); 3487 } else if (!strncmp(*av, "flush", strlen(*av))) { 3488 flush(); 3489 } else if (!strncmp(*av, "show", strlen(*av))) { 3490 show_dummynet(ac, av); 3491 } else { 3492 errx(EX_USAGE, "bad ipfw pipe command `%s'", *av); 3493 } 3494 } else if (!strncmp(*av, "state", strlen(*av))) { 3495 NEXT_ARG; 3496 if (!strncmp(*av, "add", strlen(*av))) { 3497 add_state(ac, av); 3498 } else if (!strncmp(*av, "delete", strlen(*av))) { 3499 delete_state(ac, av); 3500 } else if (!strncmp(*av, "flush", strlen(*av))) { 3501 flush_state(ac, av); 3502 } else if (!strncmp(*av, "list", strlen(*av))) { 3503 do_dynamic = 2; 3504 list(ac, av); 3505 } else if (!strncmp(*av, "show", strlen(*av))) { 3506 do_acct = 1; 3507 do_dynamic =2; 3508 list(ac, av); 3509 } else { 3510 errx(EX_USAGE, "bad ipfw state command `%s'", *av); 3511 } 3512 } else if (!strncmp(*av, "table", strlen(*av))) { 3513 if (ac > 2 && isdigit(*(av[1]))) { 3514 char *p = av[1]; 3515 av[1] = av[2]; 3516 av[2] = p; 3517 } 3518 NEXT_ARG; 3519 if (!strncmp(*av, "append", strlen(*av))) { 3520 table_append(ac, av); 3521 } else if (!strncmp(*av, "remove", strlen(*av))) { 3522 table_remove(ac, av); 3523 } else if (!strncmp(*av, "flush", strlen(*av))) { 3524 table_flush(ac, av); 3525 } else if (!strncmp(*av, "list", strlen(*av))) { 3526 table_list(ac, av); 3527 } else if (!strncmp(*av, "show", strlen(*av))) { 3528 table_show(ac, av); 3529 } else if (!strncmp(*av, "type", strlen(*av))) { 3530 table_create(ac, av); 3531 } else if (!strncmp(*av, "delete", strlen(*av))) { 3532 table_delete(ac, av); 3533 } else if (!strncmp(*av, "test", strlen(*av))) { 3534 table_test(ac,av); 3535 } else if (!strncmp(*av, "name", strlen(*av))) { 3536 table_rename(ac, av); 3537 } else { 3538 errx(EX_USAGE, "bad ipfw table command `%s'", *av); 3539 } 3540 3541 } else { 3542 errx(EX_USAGE, "bad ipfw command `%s'", *av); 3543 } 3544 return 0; 3545 } 3546 3547 static void 3548 ipfw_readfile(int ac, char *av[]) 3549 { 3550 char buf[BUFSIZ]; 3551 char *a, *p, *args[MAX_ARGS], *cmd = NULL; 3552 char linename[10]; 3553 int i=0, lineno=0, qflag=0, pflag=0, status; 3554 FILE *f = NULL; 3555 pid_t preproc = 0; 3556 int c; 3557 3558 while ((c = getopt(ac, av, "D:U:p:q")) != -1) { 3559 switch (c) { 3560 case 'D': 3561 if (!pflag) 3562 errx(EX_USAGE, "-D requires -p"); 3563 if (i > MAX_ARGS - 2) 3564 errx(EX_USAGE, "too many -D or -U options"); 3565 args[i++] = "-D"; 3566 args[i++] = optarg; 3567 break; 3568 3569 case 'U': 3570 if (!pflag) 3571 errx(EX_USAGE, "-U requires -p"); 3572 if (i > MAX_ARGS - 2) 3573 errx(EX_USAGE, "too many -D or -U options"); 3574 args[i++] = "-U"; 3575 args[i++] = optarg; 3576 break; 3577 3578 case 'p': 3579 pflag = 1; 3580 cmd = optarg; 3581 args[0] = cmd; 3582 i = 1; 3583 break; 3584 3585 case 'q': 3586 qflag = 1; 3587 break; 3588 3589 default: 3590 errx(EX_USAGE, "bad arguments, for usage" 3591 " summary ``ipfw''"); 3592 } 3593 } 3594 3595 av += optind; 3596 ac -= optind; 3597 if (ac != 1) 3598 errx(EX_USAGE, "extraneous filename arguments"); 3599 3600 if ((f = fopen(av[0], "r")) == NULL) 3601 err(EX_UNAVAILABLE, "fopen: %s", av[0]); 3602 3603 if (pflag) { 3604 /* pipe through preprocessor (cpp or m4) */ 3605 int pipedes[2]; 3606 3607 args[i] = NULL; 3608 3609 if (pipe(pipedes) == -1) 3610 err(EX_OSERR, "cannot create pipe"); 3611 3612 switch ((preproc = fork())) { 3613 case -1: 3614 err(EX_OSERR, "cannot fork"); 3615 3616 case 0: 3617 /* child */ 3618 if (dup2(fileno(f), 0) == -1 || 3619 dup2(pipedes[1], 1) == -1) { 3620 err(EX_OSERR, "dup2()"); 3621 } 3622 fclose(f); 3623 close(pipedes[1]); 3624 close(pipedes[0]); 3625 execvp(cmd, args); 3626 err(EX_OSERR, "execvp(%s) failed", cmd); 3627 3628 default: 3629 /* parent */ 3630 fclose(f); 3631 close(pipedes[1]); 3632 if ((f = fdopen(pipedes[0], "r")) == NULL) { 3633 int savederrno = errno; 3634 3635 kill(preproc, SIGTERM); 3636 errno = savederrno; 3637 err(EX_OSERR, "fdopen()"); 3638 } 3639 } 3640 } 3641 3642 while (fgets(buf, BUFSIZ, f)) { 3643 lineno++; 3644 sprintf(linename, "Line %d", lineno); 3645 args[0] = linename; 3646 3647 if (*buf == '#') 3648 continue; 3649 if ((p = strchr(buf, '#')) != NULL) 3650 *p = '\0'; 3651 i = 1; 3652 if (qflag) 3653 args[i++] = "-q"; 3654 for (a = strtok(buf, WHITESP); a && i < MAX_ARGS; 3655 a = strtok(NULL, WHITESP), i++) { 3656 args[i] = a; 3657 } 3658 3659 if (i == (qflag? 2: 1)) 3660 continue; 3661 if (i == MAX_ARGS) 3662 errx(EX_USAGE, "%s: too many arguments", linename); 3663 3664 args[i] = NULL; 3665 ipfw_main(i, args); 3666 } 3667 fclose(f); 3668 if (pflag) { 3669 if (waitpid(preproc, &status, 0) == -1) 3670 errx(EX_OSERR, "waitpid()"); 3671 if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK) 3672 errx(EX_UNAVAILABLE, "preprocessor exited with status %d", 3673 WEXITSTATUS(status)); 3674 else if (WIFSIGNALED(status)) 3675 errx(EX_UNAVAILABLE, "preprocessor exited with signal %d", 3676 WTERMSIG(status)); 3677 } 3678 } 3679 3680 int 3681 main(int ac, char *av[]) 3682 { 3683 ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 3684 if (ipfw_socket < 0) 3685 err(EX_UNAVAILABLE, "socket"); 3686 3687 memset(keywords, 0, sizeof(struct ipfw_keyword) * KEYWORD_SIZE); 3688 memset(mappings, 0, sizeof(struct ipfw_mapping) * MAPPING_SIZE); 3689 3690 prepare_default_funcs(); 3691 3692 if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) 3693 ipfw_readfile(ac, av); 3694 else 3695 ipfw_main(ac, av); 3696 return EX_OK; 3697 } 3698