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