1 /* 2 * Copyright (c) 2014 - 2016 The DragonFly Project. All rights reserved. 3 * 4 * This code is derived from software contributed to The DragonFly Project 5 * by Bill Yuan <bycn82@dragonflybsd.org> 6 * 7 * Copyright (c) 2002 Luigi Rizzo 8 * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp 9 * Copyright (c) 1994 Ugen J.S.Antsilevich 10 * 11 * Idea and grammar partially left from: 12 * Copyright (c) 1993 Daniel Boulet 13 * 14 * 15 * Redistribution and use in source forms, with and without modification, 16 * are permitted provided that this entire comment appears intact. 17 * 18 * Redistribution in binary form may occur without any restrictions. 19 * Obviously, it would be nice if you gave credit where credit is due 20 * but requiring it would be too onerous. 21 * 22 * This software is provided ``AS IS'' without any warranties of any kind. 23 * 24 */ 25 26 #include <sys/param.h> 27 #include <sys/mbuf.h> 28 #include <sys/socket.h> 29 #include <sys/sockio.h> 30 #include <sys/sysctl.h> 31 #include <sys/time.h> 32 #include <sys/wait.h> 33 34 #include <arpa/inet.h> 35 #include <ctype.h> 36 #include <dlfcn.h> 37 #include <err.h> 38 #include <errno.h> 39 #include <grp.h> 40 #include <limits.h> 41 #include <netdb.h> 42 #include <pwd.h> 43 #include <sysexits.h> 44 #include <signal.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <stdarg.h> 48 #include <string.h> 49 #include <timeconv.h> 50 #include <unistd.h> 51 52 #include <netinet/in.h> 53 #include <netinet/in_systm.h> 54 #include <netinet/ip.h> 55 #include <netinet/ip_icmp.h> 56 #include <netinet/tcp.h> 57 #include <net/if.h> 58 #include <net/if_dl.h> 59 #include <net/route.h> 60 #include <net/ethernet.h> 61 62 63 #include "../../sys/net/ipfw3/ip_fw3.h" 64 #include "../../sys/net/ipfw3/ip_fw3_table.h" 65 #include "../../sys/net/ipfw3/ip_fw3_sync.h" 66 #include "../../sys/net/dummynet3/ip_dummynet3.h" 67 #include "../../sys/net/libalias/alias.h" 68 #include "../../sys/net/ipfw3_basic/ip_fw3_basic.h" 69 #include "../../sys/net/ipfw3_nat/ip_fw3_nat.h" 70 71 #include "ipfw3.h" 72 #include "ipfw3sync.h" 73 #include "ipfw3nat.h" 74 75 76 #define KEYWORD_SIZE 256 77 #define MAPPING_SIZE 256 78 79 #define MAX_KEYWORD_LEN 20 80 #define MAX_ARGS 32 81 #define WHITESP " \t\f\v\n\r" 82 #define IPFW_LIB_PATH "/usr/lib/libipfw3%s.so" 83 #define IP_MASK_ALL 0xffffffff 84 /* 85 * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines 86 * This is only used in this code. 87 */ 88 #define IPPROTO_ETHERTYPE 0x1000 89 90 /* 91 * show_rules() prints the body of an ipfw rule. 92 * Because the standard rule has at least proto src_ip dst_ip, we use 93 * a helper function to produce these entries if not provided explicitly. 94 * The first argument is the list of fields we have, the second is 95 * the list of fields we want to be printed. 96 * 97 * Special cases if we have provided a MAC header: 98 * + if the rule does not contain IP addresses/ports, do not print them; 99 * + if the rule does not contain an IP proto, print "all" instead of "ip"; 100 * 101 */ 102 #define HAVE_PROTO 0x0001 103 #define HAVE_SRCIP 0x0002 104 #define HAVE_DSTIP 0x0004 105 #define HAVE_MAC 0x0008 106 #define HAVE_MACTYPE 0x0010 107 #define HAVE_OPTIONS 0x8000 108 109 #define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP) 110 111 112 int ipfw_socket = -1; /* main RAW socket */ 113 int do_resolv, /* Would try to resolve all */ 114 do_acct, /* Show packet/byte count */ 115 do_time, /* Show time stamps */ 116 do_quiet = 1, /* Be quiet , default is quiet*/ 117 do_force, /* Don't ask for confirmation */ 118 do_pipe, /* this cmd refers to a pipe */ 119 do_nat, /* Nat configuration. */ 120 do_sort, /* field to sort results (0 = no) */ 121 do_dynamic, /* display dynamic rules */ 122 do_expired, /* display expired dynamic rules */ 123 do_compact, /* show rules in compact mode */ 124 show_sets, /* display rule sets */ 125 verbose; 126 127 struct char_int_map dummynet_params[] = { 128 { "plr", TOK_PLR }, 129 { "noerror", TOK_NOERROR }, 130 { "buckets", TOK_BUCKETS }, 131 { "dst-ip", TOK_DSTIP }, 132 { "src-ip", TOK_SRCIP }, 133 { "dst-port", TOK_DSTPORT }, 134 { "src-port", TOK_SRCPORT }, 135 { "proto", TOK_PROTO }, 136 { "weight", TOK_WEIGHT }, 137 { "all", TOK_ALL }, 138 { "mask", TOK_MASK }, 139 { "droptail", TOK_DROPTAIL }, 140 { "red", TOK_RED }, 141 { "gred", TOK_GRED }, 142 { "bw", TOK_BW }, 143 { "bandwidth", TOK_BW }, 144 { "delay", TOK_DELAY }, 145 { "pipe", TOK_PIPE }, 146 { "queue", TOK_QUEUE }, 147 { "dummynet-params", TOK_NULL }, 148 { NULL, 0 } 149 }; 150 151 struct ipfw_keyword { 152 int type; 153 char word[MAX_KEYWORD_LEN]; 154 int module; 155 int opcode; 156 }; 157 158 struct ipfw_mapping { 159 int type; 160 int module; 161 int opcode; 162 parser_func parser; 163 shower_func shower; 164 }; 165 166 struct ipfw_keyword keywords[KEYWORD_SIZE]; 167 struct ipfw_mapping mappings[MAPPING_SIZE]; 168 169 int 170 match_token(struct char_int_map *table, char *string) 171 { 172 while (table->key) { 173 if (strcmp(table->key, string) == 0) { 174 return table->val; 175 } 176 table++; 177 } 178 return 0; 179 } 180 181 static void 182 get_modules(char *modules_str, int len) 183 { 184 if (do_get_x(IP_FW_MODULE, modules_str, &len) < 0) 185 errx(EX_USAGE, "ipfw3 not loaded."); 186 } 187 188 static void 189 list_modules(int ac, char *av[]) 190 { 191 void *module_str = NULL; 192 int len = 1024; 193 if ((module_str = realloc(module_str, len)) == NULL) 194 err(EX_OSERR, "realloc"); 195 196 get_modules(module_str, len); 197 printf("%s", (char *)module_str); 198 } 199 void 200 parse_accept(ipfw_insn **cmd, int *ac, char **av[]) 201 { 202 (*cmd)->opcode = O_BASIC_ACCEPT; 203 (*cmd)->module = MODULE_BASIC_ID; 204 (*cmd)->len = (*cmd)->len|LEN_OF_IPFWINSN; 205 NEXT_ARG1; 206 if (!strncmp(**av, "log", strlen(**av))) { 207 (*cmd)->arg3 = 1; 208 NEXT_ARG1; 209 if (isdigit(***av)) { 210 (*cmd)->arg1 = strtoul(**av, NULL, 10); 211 NEXT_ARG1; 212 } 213 } 214 } 215 216 void 217 parse_deny(ipfw_insn **cmd, int *ac, char **av[]) 218 { 219 (*cmd)->opcode = O_BASIC_DENY; 220 (*cmd)->module = MODULE_BASIC_ID; 221 (*cmd)->len = (*cmd)->len|LEN_OF_IPFWINSN; 222 NEXT_ARG1; 223 if (!strncmp(**av, "log", strlen(**av))) { 224 (*cmd)->arg3 = 1; 225 NEXT_ARG1; 226 if (isdigit(***av)) { 227 (*cmd)->arg1 = strtoul(**av, NULL, 10); 228 NEXT_ARG1; 229 } 230 } 231 } 232 233 void 234 show_accept(ipfw_insn *cmd, int show_or) 235 { 236 printf(" allow"); 237 if (cmd->arg3) { 238 printf(" log %d", cmd->arg1); 239 } 240 } 241 242 void 243 show_deny(ipfw_insn *cmd, int show_or) 244 { 245 printf(" deny"); 246 if (cmd->arg3) { 247 printf(" log %d", cmd->arg1); 248 } 249 } 250 251 static void 252 load_modules(void) 253 { 254 const char *error; 255 init_module mod_init_func; 256 void *module_lib; 257 char module_lib_file[50]; 258 void *module_str = NULL; 259 int len = 1024; 260 261 if ((module_str = realloc(module_str, len)) == NULL) 262 err(EX_OSERR, "realloc"); 263 264 get_modules(module_str, len); 265 266 const char s[2] = ","; 267 char *token; 268 token = strtok(module_str, s); 269 while (token != NULL) { 270 sprintf(module_lib_file, IPFW_LIB_PATH, token); 271 token = strtok(NULL, s); 272 module_lib = dlopen(module_lib_file, RTLD_LAZY); 273 if (!module_lib) { 274 fprintf(stderr, "Couldn't open %s: %s\n", 275 module_lib_file, dlerror()); 276 exit(EX_SOFTWARE); 277 } 278 mod_init_func = dlsym(module_lib, "load_module"); 279 if ((error = dlerror())) 280 { 281 fprintf(stderr, "Couldn't find init function: %s\n", error); 282 exit(EX_SOFTWARE); 283 } 284 (*mod_init_func)((register_func)register_ipfw_func, 285 (register_keyword)register_ipfw_keyword); 286 } 287 } 288 289 void 290 prepare_default_funcs(void) 291 { 292 /* register allow*/ 293 register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_ACCEPT, "allow", ACTION); 294 register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_ACCEPT, "accept", ACTION); 295 register_ipfw_func(MODULE_BASIC_ID, O_BASIC_ACCEPT, 296 (parser_func)parse_accept, (shower_func)show_accept); 297 /* register deny*/ 298 register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_DENY, "deny", ACTION); 299 register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_DENY, "reject", ACTION); 300 register_ipfw_func(MODULE_BASIC_ID, O_BASIC_DENY, 301 (parser_func)parse_deny, (shower_func)show_deny); 302 } 303 304 void 305 register_ipfw_keyword(int module, int opcode, char *word, int type) 306 { 307 struct ipfw_keyword *tmp; 308 309 tmp=keywords; 310 for(;;) { 311 if (tmp->type == NONE) { 312 strcpy(tmp->word, word); 313 tmp->module = module; 314 tmp->opcode = opcode; 315 tmp->type = type; 316 break; 317 } else { 318 if (strcmp(tmp->word, word) == 0) 319 errx(EX_USAGE, "keyword `%s' exists", word); 320 else 321 tmp++; 322 } 323 } 324 } 325 326 void 327 register_ipfw_func(int module, int opcode, parser_func parser, shower_func shower) 328 { 329 struct ipfw_mapping *tmp; 330 331 tmp = mappings; 332 while (1) { 333 if (tmp->type == NONE) { 334 tmp->module = module; 335 tmp->opcode = opcode; 336 tmp->parser = parser; 337 tmp->shower = shower; 338 tmp->type = IN_USE; 339 break; 340 } else { 341 if (tmp->opcode == opcode && tmp->module == module) { 342 errx(EX_USAGE, "func `%d' of module `%d' exists", 343 opcode, module); 344 break; 345 } else { 346 tmp++; 347 } 348 } 349 } 350 } 351 352 /* 353 * this func need to check whether 'or' need to be printed, 354 * when the filter is the first filter with 'or' when dont print 355 * when not first and same as previous, then print or and no filter name 356 * when not first but different from previous, print name without 'or' 357 * show_or = 1: show or and ignore filter name 358 * show_or = 0: show filter name ignore or 359 */ 360 void prev_show_chk(ipfw_insn *cmd, uint8_t *prev_module, uint8_t *prev_opcode, 361 int *show_or) 362 { 363 if (cmd->len & F_OR) { 364 if (*prev_module == 0 && *prev_opcode == 0) { 365 /* first cmd with 'or' flag */ 366 *show_or = 0; 367 *prev_module = cmd->module; 368 *prev_opcode = cmd->opcode; 369 } else if (cmd->module == *prev_module && 370 cmd->opcode == *prev_opcode) { 371 /* cmd same as previous, same module and opcode */ 372 *show_or = 1; 373 } else { 374 /* cmd different from prev*/ 375 *show_or = 0; 376 *prev_module = cmd->module; 377 *prev_opcode = cmd->opcode; 378 379 } 380 } else { 381 *show_or = 0; 382 *prev_module = 0; 383 *prev_opcode = 0; 384 } 385 } 386 387 /* 388 * word can be: proto from to other 389 * proto show proto 390 * from show from 391 * to show to 392 * other show all other filters 393 */ 394 int show_filter(ipfw_insn *cmd, char *word, int type) 395 { 396 struct ipfw_keyword *k; 397 struct ipfw_mapping *m; 398 shower_func fn; 399 int i, j, show_or; 400 uint8_t prev_module, prev_opcode; 401 402 k = keywords; 403 m = mappings; 404 for (i = 1; i < KEYWORD_SIZE; i++, k++) { 405 if (k->type == type) { 406 if (k->module == cmd->module && 407 k->opcode == cmd->opcode) { 408 for (j = 1; j < MAPPING_SIZE; j++, m++) { 409 if (m->type == IN_USE && 410 k->module == m->module && 411 k->opcode == m->opcode) { 412 prev_show_chk(cmd, &prev_module, 413 &prev_opcode, &show_or); 414 if (cmd->len & F_NOT) 415 printf(" not"); 416 417 fn = m->shower; 418 (*fn)(cmd, show_or); 419 return 1; 420 } 421 } 422 } 423 } 424 } 425 return 0; 426 } 427 428 static void 429 show_rules(struct ipfw_ioc_rule *rule, int pcwidth, int bcwidth) 430 { 431 static int twidth = 0; 432 ipfw_insn *cmd; 433 int l; 434 435 u_int32_t set_disable = rule->set_disable; 436 437 if (set_disable & (1 << rule->set)) { /* disabled */ 438 if (!show_sets) 439 return; 440 else 441 printf("# DISABLED "); 442 } 443 printf("%05u ", rule->rulenum); 444 445 if (do_acct) 446 printf("%*ju %*ju ", pcwidth, (uintmax_t)rule->pcnt, bcwidth, 447 (uintmax_t)rule->bcnt); 448 449 if (do_time == 1) { 450 char timestr[30]; 451 452 if (twidth == 0) { 453 strcpy(timestr, ctime((time_t *)&twidth)); 454 *strchr(timestr, '\n') = '\0'; 455 twidth = strlen(timestr); 456 } 457 if (rule->timestamp) { 458 time_t t = _long_to_time(rule->timestamp); 459 460 strcpy(timestr, ctime(&t)); 461 *strchr(timestr, '\n') = '\0'; 462 printf("%s ", timestr); 463 } else { 464 printf("%*s ", twidth, " "); 465 } 466 } else if (do_time == 2) { 467 printf( "%10u ", rule->timestamp); 468 } 469 470 if (show_sets) 471 printf("set %d ", rule->set); 472 473 474 struct ipfw_keyword *k; 475 struct ipfw_mapping *m; 476 shower_func fn, comment_fn = NULL; 477 ipfw_insn *comment_cmd; 478 int i, j, changed; 479 480 /* 481 * show others and actions 482 */ 483 for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule); 484 l > 0; l -= F_LEN(cmd), 485 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) { 486 k = keywords; 487 m = mappings; 488 for (i = 1; i< KEYWORD_SIZE; i++, k++) { 489 if ( k->module == cmd->module && k->opcode == cmd->opcode ) { 490 for (j = 1; j< MAPPING_SIZE; j++, m++) { 491 if (m->type == IN_USE && 492 m->module == cmd->module && 493 m->opcode == cmd->opcode) { 494 if (cmd->module == MODULE_BASIC_ID && 495 cmd->opcode == O_BASIC_COMMENT) { 496 comment_fn = m->shower; 497 comment_cmd = cmd; 498 } else { 499 fn = m->shower; 500 (*fn)(cmd, 0); 501 } 502 if (cmd->module == MODULE_BASIC_ID && 503 cmd->opcode == 504 O_BASIC_CHECK_STATE) { 505 goto done; 506 } 507 break; 508 } 509 } 510 break; 511 } 512 } 513 } 514 515 /* 516 * show proto 517 */ 518 changed=0; 519 for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd), 520 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) { 521 changed = show_filter(cmd, "proto", PROTO); 522 } 523 if (!changed && !do_quiet) 524 printf(" ip"); 525 526 /* 527 * show from 528 */ 529 changed = 0; 530 for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd), 531 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) { 532 changed = show_filter(cmd, "from", FROM); 533 } 534 if (!changed && !do_quiet) 535 printf(" from any"); 536 537 /* 538 * show to 539 */ 540 changed = 0; 541 for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd), 542 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) { 543 changed = show_filter(cmd, "to", TO); 544 } 545 if (!changed && !do_quiet) 546 printf(" to any"); 547 548 /* 549 * show other filters 550 */ 551 for (l = rule->act_ofs, cmd = rule->cmd, m = mappings; 552 l > 0; l -= F_LEN(cmd), 553 cmd=(ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) { 554 show_filter(cmd, "other", FILTER); 555 } 556 557 /* show the comment in the end */ 558 if (comment_fn != NULL) { 559 (*comment_fn)(comment_cmd, 0); 560 } 561 done: 562 printf("\n"); 563 } 564 565 static void 566 show_states(struct ipfw_ioc_state *d, int pcwidth, int bcwidth) 567 { 568 struct protoent *pe; 569 struct in_addr a; 570 571 printf("%05u ", d->rulenum); 572 if (do_acct) { 573 printf("%*ju %*ju ", pcwidth, (uintmax_t)d->pcnt, 574 bcwidth, (uintmax_t)d->bcnt); 575 } 576 577 if (do_time == 1) { 578 /* state->timestamp */ 579 char timestr[30]; 580 time_t t = _long_to_time(d->timestamp); 581 strcpy(timestr, ctime(&t)); 582 *strchr(timestr, '\n') = '\0'; 583 printf(" (%s", timestr); 584 585 /* state->lifetime */ 586 printf(" %ds", d->lifetime); 587 588 /* state->expiry */ 589 if (d->expiry !=0) { 590 t = _long_to_time(d->expiry); 591 strcpy(timestr, ctime(&t)); 592 *strchr(timestr, '\n') = '\0'; 593 printf(" %s)", timestr); 594 } else { 595 printf(" 0)"); 596 } 597 598 } else if (do_time == 2) { 599 printf("(%u %ds %u) ", d->timestamp, d->lifetime, d->expiry); 600 } 601 602 if ((pe = getprotobynumber(d->flow_id.proto)) != NULL) 603 printf(" %s", pe->p_name); 604 else 605 printf(" proto %u", d->flow_id.proto); 606 607 a.s_addr = htonl(d->flow_id.src_ip); 608 printf(" %s %d", inet_ntoa(a), d->flow_id.src_port); 609 610 a.s_addr = htonl(d->flow_id.dst_ip); 611 printf(" <-> %s %d", inet_ntoa(a), d->flow_id.dst_port); 612 printf(" CPU %d", d->cpuid); 613 printf("\n"); 614 } 615 616 int 617 sort_q(const void *pa, const void *pb) 618 { 619 int rev = (do_sort < 0); 620 int field = rev ? -do_sort : do_sort; 621 long long res = 0; 622 const struct dn_ioc_flowqueue *a = pa; 623 const struct dn_ioc_flowqueue *b = pb; 624 625 switch(field) { 626 case 1: /* pkts */ 627 res = a->len - b->len; 628 break; 629 case 2: /* bytes */ 630 res = a->len_bytes - b->len_bytes; 631 break; 632 633 case 3: /* tot pkts */ 634 res = a->tot_pkts - b->tot_pkts; 635 break; 636 637 case 4: /* tot bytes */ 638 res = a->tot_bytes - b->tot_bytes; 639 break; 640 } 641 if (res < 0) 642 res = -1; 643 if (res > 0) 644 res = 1; 645 return (int)(rev ? res : -res); 646 } 647 648 static void 649 show_queues(struct dn_ioc_flowset *fs, struct dn_ioc_flowqueue *q) 650 { 651 int l; 652 653 printf("mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n", 654 fs->flow_mask.u.ip.proto, 655 fs->flow_mask.u.ip.src_ip, fs->flow_mask.u.ip.src_port, 656 fs->flow_mask.u.ip.dst_ip, fs->flow_mask.u.ip.dst_port); 657 if (fs->rq_elements == 0) 658 return; 659 660 printf("BKT Prot ___Source IP/port____ " 661 "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n"); 662 if (do_sort != 0) 663 heapsort(q, fs->rq_elements, sizeof(*q), sort_q); 664 for (l = 0; l < fs->rq_elements; l++) { 665 struct in_addr ina; 666 struct protoent *pe; 667 668 ina.s_addr = htonl(q[l].id.u.ip.src_ip); 669 printf("%3d ", q[l].hash_slot); 670 pe = getprotobynumber(q[l].id.u.ip.proto); 671 if (pe) 672 printf("%-4s ", pe->p_name); 673 else 674 printf("%4u ", q[l].id.u.ip.proto); 675 printf("%15s/%-5d ", 676 inet_ntoa(ina), q[l].id.u.ip.src_port); 677 ina.s_addr = htonl(q[l].id.u.ip.dst_ip); 678 printf("%15s/%-5d ", 679 inet_ntoa(ina), q[l].id.u.ip.dst_port); 680 printf("%4ju %8ju %2u %4u %3u\n", 681 (uintmax_t)q[l].tot_pkts, (uintmax_t)q[l].tot_bytes, 682 q[l].len, q[l].len_bytes, q[l].drops); 683 if (verbose) 684 printf(" S %20ju F %20ju\n", 685 (uintmax_t)q[l].S, (uintmax_t)q[l].F); 686 } 687 } 688 689 static void 690 show_flowset_parms(struct dn_ioc_flowset *fs, char *prefix) 691 { 692 char qs[30]; 693 char plr[30]; 694 char red[90]; /* Display RED parameters */ 695 int l; 696 697 l = fs->qsize; 698 if (fs->flags_fs & DN_QSIZE_IS_BYTES) { 699 if (l >= 8192) 700 sprintf(qs, "%d KB", l / 1024); 701 else 702 sprintf(qs, "%d B", l); 703 } else 704 sprintf(qs, "%3d sl.", l); 705 if (fs->plr) 706 sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff)); 707 else 708 plr[0] = '\0'; 709 if (fs->flags_fs & DN_IS_RED) /* RED parameters */ 710 sprintf(red, 711 "\n\t %cRED w_q %f min_th %d max_th %d max_p %f", 712 (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ', 713 1.0 * fs->w_q / (double)(1 << SCALE_RED), 714 SCALE_VAL(fs->min_th), 715 SCALE_VAL(fs->max_th), 716 1.0 * fs->max_p / (double)(1 << SCALE_RED)); 717 else 718 sprintf(red, "droptail"); 719 720 printf("%s %s%s %d queues (%d buckets) %s\n", 721 prefix, qs, plr, fs->rq_elements, fs->rq_size, red); 722 } 723 724 static void 725 show_pipes(void *data, int nbytes, int ac, char *av[]) 726 { 727 u_long rulenum; 728 void *next = data; 729 struct dn_ioc_pipe *p = (struct dn_ioc_pipe *)data; 730 struct dn_ioc_flowset *fs; 731 struct dn_ioc_flowqueue *q; 732 int l; 733 734 if (ac > 0) 735 rulenum = strtoul(*av++, NULL, 10); 736 else 737 rulenum = 0; 738 for (; nbytes >= sizeof(*p); p = (struct dn_ioc_pipe *)next) { 739 double b = p->bandwidth; 740 char buf[30]; 741 char prefix[80]; 742 743 if (p->fs.fs_type != DN_IS_PIPE) 744 break; /* done with pipes, now queues */ 745 746 /* 747 * compute length, as pipe have variable size 748 */ 749 l = sizeof(*p) + p->fs.rq_elements * sizeof(*q); 750 next = (void *)p + l; 751 nbytes -= l; 752 753 if (rulenum != 0 && rulenum != p->pipe_nr) 754 continue; 755 756 /* 757 * Print rate 758 */ 759 if (b == 0) 760 sprintf(buf, "unlimited"); 761 else if (b >= 1000000) 762 sprintf(buf, "%7.3f Mbit/s", b/1000000); 763 else if (b >= 1000) 764 sprintf(buf, "%7.3f Kbit/s", b/1000); 765 else 766 sprintf(buf, "%7.3f bit/s ", b); 767 768 sprintf(prefix, "%05d: %s %4d ms ", 769 p->pipe_nr, buf, p->delay); 770 show_flowset_parms(&p->fs, prefix); 771 if (verbose) 772 printf(" V %20ju\n", (uintmax_t)p->V >> MY_M); 773 774 q = (struct dn_ioc_flowqueue *)(p+1); 775 show_queues(&p->fs, q); 776 } 777 778 for (fs = next; nbytes >= sizeof(*fs); fs = next) { 779 char prefix[80]; 780 781 if (fs->fs_type != DN_IS_QUEUE) 782 break; 783 l = sizeof(*fs) + fs->rq_elements * sizeof(*q); 784 next = (void *)fs + l; 785 nbytes -= l; 786 q = (struct dn_ioc_flowqueue *)(fs+1); 787 sprintf(prefix, "q%05d: weight %d pipe %d ", 788 fs->fs_nr, fs->weight, fs->parent_nr); 789 show_flowset_parms(fs, prefix); 790 show_queues(fs, q); 791 } 792 } 793 794 /* 795 * This one handles all set-related commands 796 * ipfw set { show | enable | disable } 797 * ipfw set swap X Y 798 * ipfw set move X to Y 799 * ipfw set move rule X to Y 800 */ 801 static void 802 sets_handler(int ac, char *av[]) 803 { 804 u_int32_t set_disable, masks[2]; 805 u_int16_t rulenum; 806 u_int8_t cmd, new_set; 807 int i, nbytes; 808 809 NEXT_ARG; 810 if (!ac) 811 errx(EX_USAGE, "set needs command"); 812 if (!strncmp(*av, "show", strlen(*av)) ) { 813 void *data = NULL; 814 char *msg; 815 int nalloc=1000; 816 nbytes = nalloc; 817 818 while (nbytes >= nalloc) { 819 nalloc = nalloc * 2+321; 820 nbytes = nalloc; 821 if (data == NULL) { 822 if ((data = malloc(nbytes)) == NULL) { 823 err(EX_OSERR, "malloc"); 824 } 825 } else if ((data = realloc(data, nbytes)) == NULL) { 826 err(EX_OSERR, "realloc"); 827 } 828 if (do_get_x(IP_FW_GET, data, &nbytes) < 0) { 829 err(EX_OSERR, "getsockopt(IP_FW_GET)"); 830 } 831 } 832 set_disable = ((struct ipfw_ioc_rule *)data)->set_disable; 833 for (i = 0, msg = "disable" ; i < 31; i++) 834 if ( (set_disable & (1<<i))) { 835 printf("%s %d", msg, i); 836 msg = ""; 837 } 838 msg = (set_disable) ? " enable" : "enable"; 839 for (i = 0; i < 31; i++) 840 if ( !(set_disable & (1<<i))) { 841 printf("%s %d", msg, i); 842 msg = ""; 843 } 844 printf("\n"); 845 } else if (!strncmp(*av, "swap", strlen(*av))) { 846 NEXT_ARG; 847 if (ac != 2) 848 errx(EX_USAGE, "set swap needs 2 set numbers\n"); 849 rulenum = atoi(av[0]); 850 new_set = atoi(av[1]); 851 if (!isdigit(*(av[0])) || rulenum > 30) 852 errx(EX_DATAERR, "invalid set number %s\n", av[0]); 853 if (!isdigit(*(av[1])) || new_set > 30) 854 errx(EX_DATAERR, "invalid set number %s\n", av[1]); 855 masks[0] = (4 << 24) | (new_set << 16) | (rulenum); 856 i = do_set_x(IP_FW_DEL, masks, sizeof(u_int32_t)); 857 } else if (!strncmp(*av, "move", strlen(*av))) { 858 NEXT_ARG; 859 if (ac && !strncmp(*av, "rule", strlen(*av))) { 860 cmd = 2; 861 NEXT_ARG; 862 } else 863 cmd = 3; 864 if (ac != 3 || strncmp(av[1], "to", strlen(*av))) 865 errx(EX_USAGE, "syntax: set move [rule] X to Y\n"); 866 rulenum = atoi(av[0]); 867 new_set = atoi(av[2]); 868 if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > 30) || 869 (cmd == 2 && rulenum == 65535) ) 870 errx(EX_DATAERR, "invalid source number %s\n", av[0]); 871 if (!isdigit(*(av[2])) || new_set > 30) 872 errx(EX_DATAERR, "invalid dest. set %s\n", av[1]); 873 masks[0] = (cmd << 24) | (new_set << 16) | (rulenum); 874 i = do_set_x(IP_FW_DEL, masks, sizeof(u_int32_t)); 875 } else if (!strncmp(*av, "disable", strlen(*av)) || 876 !strncmp(*av, "enable", strlen(*av)) ) { 877 int which = !strncmp(*av, "enable", strlen(*av)) ? 1 : 0; 878 879 NEXT_ARG; 880 masks[0] = masks[1] = 0; 881 882 while (ac) { 883 if (isdigit(**av)) { 884 i = atoi(*av); 885 if (i < 0 || i > 30) 886 errx(EX_DATAERR, "invalid set number %d\n", i); 887 masks[which] |= (1<<i); 888 } else if (!strncmp(*av, "disable", strlen(*av))) 889 which = 0; 890 else if (!strncmp(*av, "enable", strlen(*av))) 891 which = 1; 892 else 893 errx(EX_DATAERR, "invalid set command %s\n", *av); 894 NEXT_ARG; 895 } 896 if ( (masks[0] & masks[1]) != 0 ) 897 errx(EX_DATAERR, "cannot enable and disable the same set\n"); 898 i = do_set_x(IP_FW_DEL, masks, sizeof(masks)); 899 if (i) 900 warn("set enable/disable: setsockopt(IP_FW_DEL)"); 901 } else 902 errx(EX_USAGE, "invalid set command %s\n", *av); 903 } 904 905 static void 906 add_state(int ac, char *av[]) 907 { 908 struct ipfw_ioc_state ioc_state; 909 ioc_state.expiry = 0; 910 ioc_state.lifetime = 0; 911 NEXT_ARG; 912 if (strcmp(*av, "rulenum") == 0) { 913 NEXT_ARG; 914 ioc_state.rulenum = atoi(*av); 915 } else { 916 errx(EX_USAGE, "ipfw state add rule"); 917 } 918 NEXT_ARG; 919 struct protoent *pe; 920 pe = getprotobyname(*av); 921 ioc_state.flow_id.proto = pe->p_proto; 922 923 NEXT_ARG; 924 ioc_state.flow_id.src_ip = inet_addr(*av); 925 926 NEXT_ARG; 927 ioc_state.flow_id.src_port = atoi(*av); 928 929 NEXT_ARG; 930 ioc_state.flow_id.dst_ip = inet_addr(*av); 931 932 NEXT_ARG; 933 ioc_state.flow_id.dst_port = atoi(*av); 934 935 NEXT_ARG; 936 if (strcmp(*av, "live") == 0) { 937 NEXT_ARG; 938 ioc_state.lifetime = atoi(*av); 939 NEXT_ARG; 940 } 941 942 if (strcmp(*av, "expiry") == 0) { 943 NEXT_ARG; 944 ioc_state.expiry = strtoul(*av, NULL, 10); 945 printf("ioc_state.expiry=%d\n", ioc_state.expiry); 946 } 947 948 if (do_set_x(IP_FW_STATE_ADD, &ioc_state, sizeof(struct ipfw_ioc_state)) < 0 ) { 949 err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_ADD)"); 950 } 951 if (!do_quiet) { 952 printf("Flushed all states.\n"); 953 } 954 } 955 956 static void 957 delete_state(int ac, char *av[]) 958 { 959 int rulenum; 960 NEXT_ARG; 961 if (ac == 1 && isdigit(**av)) 962 rulenum = atoi(*av); 963 if (do_set_x(IP_FW_STATE_DEL, &rulenum, sizeof(int)) < 0 ) 964 err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_DEL)"); 965 if (!do_quiet) 966 printf("Flushed all states.\n"); 967 } 968 969 static void 970 flush_state(int ac, char *av[]) 971 { 972 if (!do_force) { 973 int c; 974 975 printf("Are you sure? [yn] "); 976 fflush(stdout); 977 do { 978 c = toupper(getc(stdin)); 979 while (c != '\n' && getc(stdin) != '\n') 980 if (feof(stdin)) 981 return; /* and do not flush */ 982 } while (c != 'Y' && c != 'N'); 983 if (c == 'N') /* user said no */ 984 return; 985 } 986 if (do_set_x(IP_FW_STATE_FLUSH, NULL, 0) < 0 ) 987 err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_FLUSH)"); 988 if (!do_quiet) 989 printf("Flushed all states.\n"); 990 } 991 992 static int 993 lookup_host (char *host, struct in_addr *ipaddr) 994 { 995 struct hostent *he; 996 997 if (!inet_aton(host, ipaddr)) { 998 if ((he = gethostbyname(host)) == NULL) 999 return(-1); 1000 *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 1001 } 1002 return(0); 1003 } 1004 1005 static void 1006 table_append(int ac, char *av[]) 1007 { 1008 struct ipfw_ioc_table tbl; 1009 char *p; 1010 int size; 1011 1012 NEXT_ARG; 1013 if (isdigit(**av)) 1014 tbl.id = atoi(*av); 1015 else 1016 errx(EX_USAGE, "table id `%s' invalid", *av); 1017 1018 if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1) 1019 errx(EX_USAGE, "table id `%d' invalid", tbl.id); 1020 1021 NEXT_ARG; 1022 if (strcmp(*av, "ip") == 0) 1023 tbl.type = 1; 1024 else if (strcmp(*av, "mac") == 0) 1025 tbl.type = 2; 1026 else 1027 errx(EX_USAGE, "table type `%s' not supported", *av); 1028 1029 NEXT_ARG; 1030 if (tbl.type == 1) { /* table type ipv4 */ 1031 struct ipfw_ioc_table_ip_entry ip_ent; 1032 if (!ac) 1033 errx(EX_USAGE, "IP address required"); 1034 1035 p = strchr(*av, '/'); 1036 if (p) { 1037 *p++ = '\0'; 1038 ip_ent.masklen = atoi(p); 1039 if (ip_ent.masklen > 32) 1040 errx(EX_DATAERR, "bad width ``%s''", p); 1041 } else { 1042 ip_ent.masklen = 32; 1043 } 1044 1045 if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0) 1046 errx(EX_NOHOST, "hostname ``%s'' unknown", *av); 1047 1048 tbl.ip_ent[0] = ip_ent; 1049 size = sizeof(tbl) + sizeof(ip_ent); 1050 } else if (tbl.type == 2) { /* table type mac */ 1051 struct ipfw_ioc_table_mac_entry mac_ent; 1052 if (!ac) 1053 errx(EX_USAGE, "MAC address required"); 1054 1055 mac_ent.addr = *ether_aton(*av); 1056 tbl.mac_ent[0] = mac_ent; 1057 size = sizeof(tbl) + sizeof(mac_ent); 1058 } 1059 if (do_set_x(IP_FW_TABLE_APPEND, &tbl, size) < 0 ) 1060 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_APPEND) " 1061 "table `%d' append `%s' failed", tbl.id, *av); 1062 } 1063 1064 static void 1065 table_remove(int ac, char *av[]) 1066 { 1067 struct ipfw_ioc_table tbl; 1068 struct ipfw_ioc_table_ip_entry ip_ent; 1069 char *p; 1070 int size; 1071 1072 NEXT_ARG; 1073 if (isdigit(**av)) 1074 tbl.id = atoi(*av); 1075 else 1076 errx(EX_USAGE, "table id `%s' invalid", *av); 1077 1078 if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1) 1079 errx(EX_USAGE, "table id `%d' invalid", tbl.id); 1080 1081 NEXT_ARG; 1082 if (strcmp(*av, "ip") == 0) 1083 tbl.type = 1; 1084 else if (strcmp(*av, "mac") == 0) 1085 tbl.type = 2; 1086 else 1087 errx(EX_USAGE, "table type `%s' not supported", *av); 1088 1089 NEXT_ARG; 1090 if (!ac) 1091 errx(EX_USAGE, "IP address required"); 1092 p = strchr(*av, '/'); 1093 if (p) { 1094 *p++ = '\0'; 1095 ip_ent.masklen = atoi(p); 1096 if (ip_ent.masklen > 32) 1097 errx(EX_DATAERR, "bad width ``%s''", p); 1098 } else { 1099 ip_ent.masklen = 32; 1100 } 1101 1102 if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0) 1103 errx(EX_NOHOST, "hostname ``%s'' unknown", *av); 1104 1105 tbl.ip_ent[0] = ip_ent; 1106 size = sizeof(tbl) + sizeof(ip_ent); 1107 if (do_set_x(IP_FW_TABLE_REMOVE, &tbl, size) < 0 ) { 1108 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_REMOVE) " 1109 "table `%d' append `%s' failed", tbl.id, *av); 1110 } 1111 } 1112 1113 static void 1114 table_flush(int ac, char *av[]) 1115 { 1116 struct ipfw_ioc_table ioc_table; 1117 struct ipfw_ioc_table *t = &ioc_table; 1118 1119 NEXT_ARG; 1120 if (isdigit(**av)) { 1121 t->id = atoi(*av); 1122 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1) 1123 errx(EX_USAGE, "table id `%d' invalid", t->id); 1124 } else { 1125 errx(EX_USAGE, "table id `%s' invalid", *av); 1126 } 1127 if (do_set_x(IP_FW_TABLE_FLUSH, t, sizeof(struct ipfw_ioc_table)) < 0 ) 1128 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_FLUSH) " 1129 "table `%s' flush failed", *av); 1130 } 1131 1132 static void 1133 table_list(int ac, char *av[]) 1134 { 1135 struct ipfw_ioc_table *ioc_table; 1136 int i, count, nbytes, nalloc = 1024; 1137 void *data = NULL; 1138 NEXT_ARG; 1139 if (strcmp(*av, "list") == 0) { 1140 nbytes = nalloc; 1141 while (nbytes >= nalloc) { 1142 nalloc = nalloc * 2 ; 1143 nbytes = nalloc; 1144 if ((data = realloc(data, nbytes)) == NULL) 1145 err(EX_OSERR, "realloc"); 1146 if (do_get_x(IP_FW_TABLE_LIST, data, &nbytes) < 0) 1147 err(EX_OSERR, "do_get_x(IP_FW_TABLE_LIST)"); 1148 } 1149 ioc_table = (struct ipfw_ioc_table *)data; 1150 count = nbytes / sizeof(struct ipfw_ioc_table); 1151 for (i = 0; i < count; i++, ioc_table++) { 1152 if (ioc_table->type > 0) { 1153 printf("table %d",ioc_table->id); 1154 if (ioc_table->type == 1) 1155 printf(" type ip"); 1156 else if (ioc_table->type == 2) 1157 printf(" type mac"); 1158 printf(" count %d",ioc_table->count); 1159 if (strlen(ioc_table->name) > 0) 1160 printf(" name %s",ioc_table->name); 1161 printf("\n"); 1162 1163 } 1164 } 1165 } else { 1166 errx(EX_USAGE, "ipfw3 table `%s' delete invalid", *av); 1167 } 1168 } 1169 1170 void 1171 print_table(struct ipfw_ioc_table * tbl) 1172 { 1173 int i; 1174 if (tbl->type == 0) 1175 errx(EX_USAGE, "table %d is not in use", tbl->id); 1176 1177 printf("table %d", tbl->id); 1178 if (tbl->type == 1) 1179 printf(" type ip"); 1180 else if (tbl->type == 2) 1181 printf(" type mac"); 1182 1183 printf(" count %d", tbl->count); 1184 if (strlen(tbl->name) > 0) 1185 printf(" name %s", tbl->name); 1186 1187 printf("\n"); 1188 1189 if (tbl->type == 1) { 1190 struct ipfw_ioc_table_ip_entry *ip_ent; 1191 ip_ent = tbl->ip_ent; 1192 for (i = 0; i < tbl->count; i++) { 1193 printf("%s", inet_ntoa(*(struct in_addr *)&ip_ent->addr)); 1194 printf("/%d ", ip_ent->masklen); 1195 printf("\n"); 1196 ip_ent++; 1197 } 1198 } else if (tbl->type == 2) { 1199 struct ipfw_ioc_table_mac_entry *mac_ent; 1200 mac_ent = tbl->mac_ent; 1201 for (i = 0; i < tbl->count; i++) { 1202 printf("%s", ether_ntoa(&mac_ent->addr)); 1203 printf("\n"); 1204 mac_ent++; 1205 } 1206 } 1207 } 1208 1209 static void 1210 table_show(int ac, char *av[]) 1211 { 1212 int nbytes, nalloc = 1024; 1213 void *data = NULL; 1214 NEXT_ARG; 1215 if (isdigit(**av)) { 1216 nbytes = nalloc; 1217 while (nbytes >= nalloc) { 1218 nalloc = nalloc * 2 + 256; 1219 nbytes = nalloc; 1220 if (data == NULL) { 1221 if ((data = malloc(nbytes)) == NULL) { 1222 err(EX_OSERR, "malloc"); 1223 } 1224 } else if ((data = realloc(data, nbytes)) == NULL) { 1225 err(EX_OSERR, "realloc"); 1226 } 1227 /* store table id in the header of data */ 1228 int *head = (int *)data; 1229 *head = atoi(*av); 1230 if (*head < 0 || *head > IPFW_TABLES_MAX - 1) 1231 errx(EX_USAGE, "table id `%d' invalid", *head); 1232 if (do_get_x(IP_FW_TABLE_SHOW, data, &nbytes) < 0) 1233 err(EX_OSERR, "do_get_x(IP_FW_TABLE_LIST)"); 1234 struct ipfw_ioc_table *tbl; 1235 tbl = (struct ipfw_ioc_table *)data; 1236 print_table(tbl); 1237 } 1238 } else { 1239 errx(EX_USAGE, "ipfw3 table `%s' show invalid", *av); 1240 } 1241 } 1242 1243 static void 1244 table_create(int ac, char *av[]) 1245 { 1246 struct ipfw_ioc_table ioc_table; 1247 struct ipfw_ioc_table *t = &ioc_table; 1248 1249 NEXT_ARG; 1250 if (ac < 2) 1251 errx(EX_USAGE, "table parameters invalid"); 1252 if (isdigit(**av)) { 1253 t->id = atoi(*av); 1254 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1) 1255 errx(EX_USAGE, "table id `%d' invalid", t->id); 1256 } else { 1257 errx(EX_USAGE, "table id `%s' invalid", *av); 1258 } 1259 NEXT_ARG; 1260 if (strcmp(*av, "ip") == 0) 1261 t->type = 1; 1262 else if (strcmp(*av, "mac") == 0) 1263 t->type = 2; 1264 else 1265 errx(EX_USAGE, "table type `%s' not supported", *av); 1266 1267 NEXT_ARG; 1268 memset(t->name, 0, IPFW_TABLE_NAME_LEN); 1269 if (ac == 2 && strcmp(*av, "name") == 0) { 1270 NEXT_ARG; 1271 if (strlen(*av) < IPFW_TABLE_NAME_LEN) { 1272 strncpy(t->name, *av, strlen(*av)); 1273 } else { 1274 errx(EX_USAGE, "table name `%s' too long", *av); 1275 } 1276 } else if (ac == 1) { 1277 errx(EX_USAGE, "table `%s' invalid", *av); 1278 } 1279 1280 if (do_set_x(IP_FW_TABLE_CREATE, t, sizeof(struct ipfw_ioc_table)) < 0) 1281 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_CREATE) " 1282 "table `%d' in use", t->id); 1283 } 1284 1285 static void 1286 table_delete(int ac, char *av[]) 1287 { 1288 struct ipfw_ioc_table ioc_table; 1289 struct ipfw_ioc_table *t = &ioc_table; 1290 1291 NEXT_ARG; 1292 if (isdigit(**av)) { 1293 t->id = atoi(*av); 1294 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1) 1295 errx(EX_USAGE, "table id `%d' invalid", t->id); 1296 } else { 1297 errx(EX_USAGE, "table id `%s' invalid", *av); 1298 } 1299 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1) 1300 errx(EX_USAGE, "table id `%d' invalid", t->id); 1301 1302 if (do_set_x(IP_FW_TABLE_DELETE, t, sizeof(struct ipfw_ioc_table)) < 0) 1303 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_DELETE) " 1304 "table `%s' delete failed", *av); 1305 } 1306 1307 static void 1308 table_test(int ac, char *av[]) 1309 { 1310 struct ipfw_ioc_table tbl; 1311 int size; 1312 1313 NEXT_ARG; 1314 if (isdigit(**av)) 1315 tbl.id = atoi(*av); 1316 else 1317 errx(EX_USAGE, "table id `%s' invalid", *av); 1318 1319 if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1) 1320 errx(EX_USAGE, "table id `%d' invalid", tbl.id); 1321 1322 NEXT_ARG; 1323 if (strcmp(*av, "ip") == 0) 1324 tbl.type = 1; 1325 else if (strcmp(*av, "mac") == 0) 1326 tbl.type = 2; 1327 else 1328 errx(EX_USAGE, "table type `%s' not supported", *av); 1329 1330 NEXT_ARG; 1331 if (tbl.type == 1) { /* table type ipv4 */ 1332 struct ipfw_ioc_table_ip_entry ip_ent; 1333 if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0) 1334 errx(EX_NOHOST, "hostname ``%s'' unknown", *av); 1335 1336 tbl.ip_ent[0] = ip_ent; 1337 size = sizeof(tbl) + sizeof(ip_ent); 1338 } else if (tbl.type == 2) { /* table type mac */ 1339 struct ipfw_ioc_table_mac_entry mac_ent; 1340 if (!ac) 1341 errx(EX_USAGE, "MAC address required"); 1342 1343 mac_ent.addr = *ether_aton(*av); 1344 tbl.mac_ent[0] = mac_ent; 1345 size = sizeof(tbl) + sizeof(mac_ent); 1346 } 1347 if (do_set_x(IP_FW_TABLE_TEST, &tbl, size) < 0 ) { 1348 printf("NO, %s not exists in table %d\n", *av, tbl.id); 1349 } else { 1350 printf("YES, %s exists in table %d\n", *av, tbl.id); 1351 } 1352 } 1353 1354 static void 1355 table_rename(int ac, char *av[]) 1356 { 1357 struct ipfw_ioc_table tbl; 1358 int size; 1359 1360 bzero(&tbl, sizeof(tbl)); 1361 NEXT_ARG; 1362 if (isdigit(**av)) 1363 tbl.id = atoi(*av); 1364 else 1365 errx(EX_USAGE, "table id `%s' invalid", *av); 1366 1367 if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1) 1368 errx(EX_USAGE, "table id `%d' invalid", tbl.id); 1369 1370 NEXT_ARG; 1371 strlcpy(tbl.name, *av, IPFW_TABLE_NAME_LEN); 1372 size = sizeof(tbl); 1373 if (do_set_x(IP_FW_TABLE_RENAME, &tbl, size) < 0 ) 1374 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_RENAME) " 1375 "table `%d' not in use", tbl.id); 1376 } 1377 1378 static void 1379 list(int ac, char *av[]) 1380 { 1381 struct ipfw_ioc_state *dynrules, *d; 1382 struct ipfw_ioc_rule *r; 1383 1384 u_long rnum; 1385 void *data = NULL; 1386 int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width; 1387 int exitval = EX_OK, lac; 1388 char **lav, *endptr; 1389 int seen = 0; 1390 int nalloc = 1024; 1391 1392 NEXT_ARG; 1393 1394 /* get rules or pipes from kernel, resizing array as necessary */ 1395 nbytes = nalloc; 1396 1397 while (nbytes >= nalloc) { 1398 nalloc = nalloc * 2 ; 1399 nbytes = nalloc; 1400 if ((data = realloc(data, nbytes)) == NULL) 1401 err(EX_OSERR, "realloc"); 1402 if (do_get_x(IP_FW_GET, data, &nbytes) < 0) 1403 err(EX_OSERR, "do_get_x(IP_FW_GET)"); 1404 } 1405 1406 /* 1407 * Count static rules. 1408 */ 1409 r = data; 1410 nstat = r->static_count; 1411 1412 /* 1413 * Count dynamic rules. This is easier as they have 1414 * fixed size. 1415 */ 1416 dynrules = (struct ipfw_ioc_state *)((void *)r + r->static_len); 1417 ndyn = (nbytes - r->static_len) / sizeof(*dynrules); 1418 1419 /* if showing stats, figure out column widths ahead of time */ 1420 bcwidth = pcwidth = 0; 1421 if (do_acct) { 1422 for (n = 0, r = data; n < nstat; 1423 n++, r = (void *)r + IOC_RULESIZE(r)) { 1424 /* packet counter */ 1425 width = snprintf(NULL, 0, "%ju", (uintmax_t)r->pcnt); 1426 if (width > pcwidth) 1427 pcwidth = width; 1428 1429 /* byte counter */ 1430 width = snprintf(NULL, 0, "%ju", (uintmax_t)r->bcnt); 1431 if (width > bcwidth) 1432 bcwidth = width; 1433 } 1434 } 1435 if (do_dynamic && ndyn) { 1436 for (n = 0, d = dynrules; n < ndyn; n++, d++) { 1437 width = snprintf(NULL, 0, "%ju", (uintmax_t)d->pcnt); 1438 if (width > pcwidth) 1439 pcwidth = width; 1440 1441 width = snprintf(NULL, 0, "%ju", (uintmax_t)d->bcnt); 1442 if (width > bcwidth) 1443 bcwidth = width; 1444 } 1445 } 1446 1447 /* if no rule numbers were specified, list all rules */ 1448 if (ac == 0) { 1449 if (do_dynamic != 2) { 1450 for (n = 0, r = data; n < nstat; n++, 1451 r = (void *)r + IOC_RULESIZE(r)) { 1452 show_rules(r, pcwidth, bcwidth); 1453 } 1454 } 1455 if (do_dynamic && ndyn) { 1456 if (do_dynamic != 2) { 1457 printf("## States (%d):\n", ndyn); 1458 } 1459 for (n = 0, d = dynrules; n < ndyn; n++, d++) 1460 show_states(d, pcwidth, bcwidth); 1461 } 1462 goto done; 1463 } 1464 1465 /* display specific rules requested on command line */ 1466 1467 if (do_dynamic != 2) { 1468 for (lac = ac, lav = av; lac != 0; lac--) { 1469 /* convert command line rule # */ 1470 rnum = strtoul(*lav++, &endptr, 10); 1471 if (*endptr) { 1472 exitval = EX_USAGE; 1473 warnx("invalid rule number: %s", *(lav - 1)); 1474 continue; 1475 } 1476 for (n = seen = 0, r = data; n < nstat; 1477 n++, r = (void *)r + IOC_RULESIZE(r) ) { 1478 if (r->rulenum > rnum) 1479 break; 1480 if (r->rulenum == rnum) { 1481 show_rules(r, pcwidth, bcwidth); 1482 seen = 1; 1483 } 1484 } 1485 if (!seen) { 1486 /* give precedence to other error(s) */ 1487 if (exitval == EX_OK) 1488 exitval = EX_UNAVAILABLE; 1489 warnx("rule %lu does not exist", rnum); 1490 } 1491 } 1492 } 1493 1494 if (do_dynamic && ndyn) { 1495 if (do_dynamic != 2) { 1496 printf("## States (%d):\n", ndyn); 1497 } 1498 for (lac = ac, lav = av; lac != 0; lac--) { 1499 rnum = strtoul(*lav++, &endptr, 10); 1500 if (*endptr) 1501 /* already warned */ 1502 continue; 1503 for (n = 0, d = dynrules; n < ndyn; n++, d++) { 1504 if (d->rulenum > rnum) 1505 break; 1506 if (d->rulenum == rnum) 1507 show_states(d, pcwidth, bcwidth); 1508 } 1509 } 1510 } 1511 1512 ac = 0; 1513 1514 done: 1515 free(data); 1516 1517 if (exitval != EX_OK) 1518 exit(exitval); 1519 } 1520 1521 static void 1522 show_dummynet(int ac, char *av[]) 1523 { 1524 void *data = NULL; 1525 int nbytes; 1526 int nalloc = 1024; /* start somewhere... */ 1527 1528 NEXT_ARG; 1529 1530 nbytes = nalloc; 1531 while (nbytes >= nalloc) { 1532 nalloc = nalloc * 2 + 200; 1533 nbytes = nalloc; 1534 if ((data = realloc(data, nbytes)) == NULL) 1535 err(EX_OSERR, "realloc"); 1536 if (do_get_x(IP_DUMMYNET_GET, data, &nbytes) < 0) { 1537 err(EX_OSERR, "do_get_x(IP_%s_GET)", 1538 do_pipe ? "DUMMYNET" : "FW"); 1539 } 1540 } 1541 1542 show_pipes(data, nbytes, ac, av); 1543 free(data); 1544 } 1545 1546 static void 1547 help(void) 1548 { 1549 fprintf(stderr, "usage: ipfw [options]\n" 1550 " ipfw add [rulenum] [set id] action filters\n" 1551 " ipfw delete [rulenum]\n" 1552 " ipfw flush\n" 1553 " ipfw list [rulenum]\n" 1554 " ipfw show [rulenum]\n" 1555 " ipfw zero [rulenum]\n" 1556 " ipfw set [show|enable|disable]\n" 1557 " ipfw module\n" 1558 " ipfw [enable|disable]\n" 1559 " ipfw log [reset|off|on]\n" 1560 " ipfw nat [config|show|delete]\n" 1561 " ipfw pipe [config|show|delete]\n" 1562 " ipfw state [add|delete|list|show]" 1563 "\nsee ipfw manpage for details\n"); 1564 exit(EX_USAGE); 1565 } 1566 1567 1568 static void 1569 delete_rules(int ac, char *av[]) 1570 { 1571 struct dn_ioc_pipe pipe; 1572 u_int32_t rulenum; 1573 int exitval = EX_OK; 1574 int do_set = 0; 1575 int i; 1576 1577 memset(&pipe, 0, sizeof pipe); 1578 1579 NEXT_ARG; 1580 if (ac > 0 && !strncmp(*av, "set", strlen(*av))) { 1581 do_set = 1; /* delete set */ 1582 NEXT_ARG; 1583 } 1584 1585 /* Rule number */ 1586 while (ac && isdigit(**av)) { 1587 i = atoi(*av); 1588 NEXT_ARG; 1589 if (do_pipe) { 1590 if (do_pipe == 1) 1591 pipe.pipe_nr = i; 1592 else 1593 pipe.fs.fs_nr = i; 1594 1595 i = do_set_x(IP_DUMMYNET_DEL, &pipe, sizeof pipe); 1596 if (i) { 1597 exitval = 1; 1598 warn("rule %u: setsockopt(IP_DUMMYNET_DEL)", 1599 do_pipe == 1 ? pipe.pipe_nr : 1600 pipe.fs.fs_nr); 1601 } 1602 } else { 1603 rulenum = (i & 0xffff) | (do_set << 24); 1604 i = do_set_x(IP_FW_DEL, &rulenum, sizeof rulenum); 1605 if (i) { 1606 exitval = EX_UNAVAILABLE; 1607 warn("rule %u: setsockopt(IP_FW_DEL)", 1608 rulenum); 1609 } 1610 } 1611 } 1612 if (exitval != EX_OK) 1613 exit(exitval); 1614 } 1615 1616 1617 static unsigned long 1618 getbw(const char *str, u_short *flags, int kb) 1619 { 1620 unsigned long val; 1621 int inbytes = 0; 1622 char *end; 1623 1624 val = strtoul(str, &end, 0); 1625 if (*end == 'k' || *end == 'K') { 1626 ++end; 1627 val *= kb; 1628 } else if (*end == 'm' || *end == 'M') { 1629 ++end; 1630 val *= kb * kb; 1631 } 1632 1633 /* 1634 * Deal with bits or bytes or b(bits) or B(bytes). If there is no 1635 * trailer assume bits. 1636 */ 1637 if (strncasecmp(end, "bit", 3) == 0) { 1638 ; 1639 } else if (strncasecmp(end, "byte", 4) == 0) { 1640 inbytes = 1; 1641 } else if (*end == 'b') { 1642 ; 1643 } else if (*end == 'B') { 1644 inbytes = 1; 1645 } 1646 1647 /* 1648 * Return in bits if flags is NULL, else flag bits 1649 * or bytes in flags and return the unconverted value. 1650 */ 1651 if (inbytes && flags) 1652 *flags |= DN_QSIZE_IS_BYTES; 1653 else if (inbytes && flags == NULL) 1654 val *= 8; 1655 1656 return(val); 1657 } 1658 1659 /* 1660 * config dummynet pipe/queue 1661 */ 1662 static void 1663 config_dummynet(int ac, char **av) 1664 { 1665 struct dn_ioc_pipe pipe; 1666 u_int32_t a; 1667 void *par = NULL; 1668 int i; 1669 char *end; 1670 1671 NEXT_ARG; 1672 memset(&pipe, 0, sizeof pipe); 1673 /* Pipe number */ 1674 if (ac && isdigit(**av)) { 1675 i = atoi(*av); 1676 NEXT_ARG; 1677 if (do_pipe == 1) 1678 pipe.pipe_nr = i; 1679 else 1680 pipe.fs.fs_nr = i; 1681 } 1682 1683 while (ac > 0) { 1684 double d; 1685 1686 int tok = match_token(dummynet_params, *av); 1687 NEXT_ARG; 1688 1689 switch(tok) { 1690 case TOK_NOERROR: 1691 pipe.fs.flags_fs |= DN_NOERROR; 1692 break; 1693 1694 case TOK_PLR: 1695 NEED1("plr needs argument 0..1\n"); 1696 d = strtod(av[0], NULL); 1697 if (d > 1) 1698 d = 1; 1699 else if (d < 0) 1700 d = 0; 1701 pipe.fs.plr = (int)(d*0x7fffffff); 1702 NEXT_ARG; 1703 break; 1704 1705 case TOK_QUEUE: 1706 NEED1("queue needs queue size\n"); 1707 end = NULL; 1708 pipe.fs.qsize = getbw(av[0], &pipe.fs.flags_fs, 1024); 1709 NEXT_ARG; 1710 break; 1711 1712 case TOK_BUCKETS: 1713 NEED1("buckets needs argument\n"); 1714 pipe.fs.rq_size = strtoul(av[0], NULL, 0); 1715 NEXT_ARG; 1716 break; 1717 1718 case TOK_MASK: 1719 NEED1("mask needs mask specifier\n"); 1720 /* 1721 * per-flow queue, mask is dst_ip, dst_port, 1722 * src_ip, src_port, proto measured in bits 1723 */ 1724 par = NULL; 1725 1726 pipe.fs.flow_mask.type = ETHERTYPE_IP; 1727 pipe.fs.flow_mask.u.ip.dst_ip = 0; 1728 pipe.fs.flow_mask.u.ip.src_ip = 0; 1729 pipe.fs.flow_mask.u.ip.dst_port = 0; 1730 pipe.fs.flow_mask.u.ip.src_port = 0; 1731 pipe.fs.flow_mask.u.ip.proto = 0; 1732 end = NULL; 1733 1734 while (ac >= 1) { 1735 u_int32_t *p32 = NULL; 1736 u_int16_t *p16 = NULL; 1737 1738 tok = match_token(dummynet_params, *av); 1739 NEXT_ARG; 1740 switch(tok) { 1741 case TOK_ALL: 1742 /* 1743 * special case, all bits significant 1744 */ 1745 pipe.fs.flow_mask.u.ip.dst_ip = ~0; 1746 pipe.fs.flow_mask.u.ip.src_ip = ~0; 1747 pipe.fs.flow_mask.u.ip.dst_port = ~0; 1748 pipe.fs.flow_mask.u.ip.src_port = ~0; 1749 pipe.fs.flow_mask.u.ip.proto = ~0; 1750 pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK; 1751 goto end_mask; 1752 1753 case TOK_DSTIP: 1754 p32 = &pipe.fs.flow_mask.u.ip.dst_ip; 1755 break; 1756 1757 case TOK_SRCIP: 1758 p32 = &pipe.fs.flow_mask.u.ip.src_ip; 1759 break; 1760 1761 case TOK_DSTPORT: 1762 p16 = &pipe.fs.flow_mask.u.ip.dst_port; 1763 break; 1764 1765 case TOK_SRCPORT: 1766 p16 = &pipe.fs.flow_mask.u.ip.src_port; 1767 break; 1768 1769 case TOK_PROTO: 1770 break; 1771 1772 default: 1773 NEXT_ARG; 1774 goto end_mask; 1775 } 1776 if (ac < 1) 1777 errx(EX_USAGE, "mask: value missing"); 1778 if (*av[0] == '/') { 1779 a = strtoul(av[0]+1, &end, 0); 1780 a = (a == 32) ? ~0 : (1 << a) - 1; 1781 } else 1782 a = strtoul(av[0], &end, 0); 1783 if (p32 != NULL) 1784 *p32 = a; 1785 else if (p16 != NULL) { 1786 if (a > 65535) 1787 errx(EX_DATAERR, 1788 "mask: must be 16 bit"); 1789 *p16 = (u_int16_t)a; 1790 } else { 1791 if (a > 255) 1792 errx(EX_DATAERR, 1793 "mask: must be 8 bit"); 1794 pipe.fs.flow_mask.u.ip.proto = 1795 (uint8_t)a; 1796 } 1797 if (a != 0) 1798 pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK; 1799 NEXT_ARG; 1800 } /* end while, config masks */ 1801 1802 end_mask: 1803 break; 1804 1805 case TOK_RED: 1806 case TOK_GRED: 1807 NEED1("red/gred needs w_q/min_th/max_th/max_p\n"); 1808 pipe.fs.flags_fs |= DN_IS_RED; 1809 if (tok == TOK_GRED) 1810 pipe.fs.flags_fs |= DN_IS_GENTLE_RED; 1811 /* 1812 * the format for parameters is w_q/min_th/max_th/max_p 1813 */ 1814 if ((end = strsep(&av[0], "/"))) { 1815 double w_q = strtod(end, NULL); 1816 if (w_q > 1 || w_q <= 0) 1817 errx(EX_DATAERR, "0 < w_q <= 1"); 1818 pipe.fs.w_q = (int) (w_q * (1 << SCALE_RED)); 1819 } 1820 if ((end = strsep(&av[0], "/"))) { 1821 pipe.fs.min_th = strtoul(end, &end, 0); 1822 if (*end == 'K' || *end == 'k') 1823 pipe.fs.min_th *= 1024; 1824 } 1825 if ((end = strsep(&av[0], "/"))) { 1826 pipe.fs.max_th = strtoul(end, &end, 0); 1827 if (*end == 'K' || *end == 'k') 1828 pipe.fs.max_th *= 1024; 1829 } 1830 if ((end = strsep(&av[0], "/"))) { 1831 double max_p = strtod(end, NULL); 1832 if (max_p > 1 || max_p <= 0) 1833 errx(EX_DATAERR, "0 < max_p <= 1"); 1834 pipe.fs.max_p = (int)(max_p * (1 << SCALE_RED)); 1835 } 1836 NEXT_ARG; 1837 break; 1838 1839 case TOK_DROPTAIL: 1840 pipe.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED); 1841 break; 1842 1843 case TOK_BW: 1844 NEED1("bw needs bandwidth\n"); 1845 if (do_pipe != 1) 1846 errx(EX_DATAERR, 1847 "bandwidth only valid for pipes"); 1848 /* 1849 * set bandwidth value 1850 */ 1851 pipe.bandwidth = getbw(av[0], NULL, 1000); 1852 if (pipe.bandwidth < 0) 1853 errx(EX_DATAERR, "bandwidth too large"); 1854 NEXT_ARG; 1855 break; 1856 1857 case TOK_DELAY: 1858 if (do_pipe != 1) 1859 errx(EX_DATAERR, "delay only valid for pipes"); 1860 NEED1("delay needs argument 0..10000ms\n"); 1861 pipe.delay = strtoul(av[0], NULL, 0); 1862 NEXT_ARG; 1863 break; 1864 1865 case TOK_WEIGHT: 1866 if (do_pipe == 1) 1867 errx(EX_DATAERR, 1868 "weight only valid for queues"); 1869 NEED1("weight needs argument 0..100\n"); 1870 pipe.fs.weight = strtoul(av[0], &end, 0); 1871 NEXT_ARG; 1872 break; 1873 1874 case TOK_PIPE: 1875 if (do_pipe == 1) 1876 errx(EX_DATAERR, "pipe only valid for queues"); 1877 NEED1("pipe needs pipe_number\n"); 1878 pipe.fs.parent_nr = strtoul(av[0], &end, 0); 1879 NEXT_ARG; 1880 break; 1881 1882 default: 1883 errx(EX_DATAERR, "unrecognised option ``%s''", *av); 1884 } 1885 } 1886 if (do_pipe == 1) { 1887 if (pipe.pipe_nr == 0) 1888 errx(EX_DATAERR, "pipe_nr must be > 0"); 1889 if (pipe.delay > 10000) 1890 errx(EX_DATAERR, "delay must be < 10000"); 1891 } else { /* do_pipe == 2, queue */ 1892 if (pipe.fs.parent_nr == 0) 1893 errx(EX_DATAERR, "pipe must be > 0"); 1894 if (pipe.fs.weight >100) 1895 errx(EX_DATAERR, "weight must be <= 100"); 1896 } 1897 if (pipe.fs.flags_fs & DN_QSIZE_IS_BYTES) { 1898 if (pipe.fs.qsize > 1024*1024) 1899 errx(EX_DATAERR, "queue size must be < 1MB"); 1900 } else { 1901 if (pipe.fs.qsize > 100) 1902 errx(EX_DATAERR, "2 <= queue size <= 100"); 1903 } 1904 if (pipe.fs.flags_fs & DN_IS_RED) { 1905 size_t len; 1906 int lookup_depth, avg_pkt_size; 1907 double s, idle, weight, w_q; 1908 int clock_hz; 1909 int t; 1910 1911 if (pipe.fs.min_th >= pipe.fs.max_th) 1912 errx(EX_DATAERR, "min_th %d must be < than max_th %d", 1913 pipe.fs.min_th, pipe.fs.max_th); 1914 if (pipe.fs.max_th == 0) 1915 errx(EX_DATAERR, "max_th must be > 0"); 1916 1917 len = sizeof(int); 1918 if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth", 1919 &lookup_depth, &len, NULL, 0) == -1) 1920 1921 errx(1, "sysctlbyname(\"%s\")", 1922 "net.inet.ip.dummynet.red_lookup_depth"); 1923 if (lookup_depth == 0) 1924 errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth" 1925 " must be greater than zero"); 1926 1927 len = sizeof(int); 1928 if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size", 1929 &avg_pkt_size, &len, NULL, 0) == -1) 1930 1931 errx(1, "sysctlbyname(\"%s\")", 1932 "net.inet.ip.dummynet.red_avg_pkt_size"); 1933 if (avg_pkt_size == 0) 1934 errx(EX_DATAERR, 1935 "net.inet.ip.dummynet.red_avg_pkt_size must" 1936 " be greater than zero"); 1937 1938 len = sizeof(clock_hz); 1939 if (sysctlbyname("net.inet.ip.dummynet.hz", &clock_hz, &len, 1940 NULL, 0) == -1) { 1941 errx(1, "sysctlbyname(\"%s\")", 1942 "net.inet.ip.dummynet.hz"); 1943 } 1944 1945 /* 1946 * Ticks needed for sending a medium-sized packet. 1947 * Unfortunately, when we are configuring a WF2Q+ queue, we 1948 * do not have bandwidth information, because that is stored 1949 * in the parent pipe, and also we have multiple queues 1950 * competing for it. So we set s=0, which is not very 1951 * correct. But on the other hand, why do we want RED with 1952 * WF2Q+ ? 1953 */ 1954 if (pipe.bandwidth == 0) /* this is a WF2Q+ queue */ 1955 s = 0; 1956 else 1957 s = clock_hz * avg_pkt_size * 8 / pipe.bandwidth; 1958 1959 /* 1960 * max idle time (in ticks) before avg queue size becomes 0. 1961 * NOTA: (3/w_q) is approx the value x so that 1962 * (1-w_q)^x < 10^-3. 1963 */ 1964 w_q = ((double)pipe.fs.w_q) / (1 << SCALE_RED); 1965 idle = s * 3. / w_q; 1966 pipe.fs.lookup_step = (int)idle / lookup_depth; 1967 if (!pipe.fs.lookup_step) 1968 pipe.fs.lookup_step = 1; 1969 weight = 1 - w_q; 1970 for (t = pipe.fs.lookup_step; t > 0; --t) 1971 weight *= weight; 1972 pipe.fs.lookup_weight = (int)(weight * (1 << SCALE_RED)); 1973 } 1974 i = do_set_x(IP_DUMMYNET_CONFIGURE, &pipe, sizeof pipe); 1975 if (i) 1976 err(1, "do_set_x(%s)", "IP_DUMMYNET_CONFIGURE"); 1977 } 1978 1979 /* 1980 * helper function, updates the pointer to cmd with the length 1981 * of the current command, and also cleans up the first word of 1982 * the new command in case it has been clobbered before. 1983 */ 1984 static ipfw_insn* 1985 next_cmd(ipfw_insn *cmd) 1986 { 1987 cmd += F_LEN(cmd); 1988 bzero(cmd, sizeof(*cmd)); 1989 return cmd; 1990 } 1991 1992 /* 1993 * Parse arguments and assemble the microinstructions which make up a rule. 1994 * Rules are added into the 'rulebuf' and then copied in the correct order 1995 * into the actual rule. 1996 * 1997 * 1998 */ 1999 static void 2000 add(int ac, char *av[]) 2001 { 2002 /* 2003 * rules are added into the 'rulebuf' and then copied in 2004 * the correct order into the actual rule. 2005 * Some things that need to go out of order (prob, action etc.) 2006 * go into actbuf[]. 2007 */ 2008 static uint32_t rulebuf[IPFW_RULE_SIZE_MAX]; 2009 static uint32_t actbuf[IPFW_RULE_SIZE_MAX]; 2010 static uint32_t othbuf[IPFW_RULE_SIZE_MAX]; 2011 static uint32_t cmdbuf[IPFW_RULE_SIZE_MAX]; 2012 2013 ipfw_insn *src, *dst, *cmd, *action, *other; 2014 ipfw_insn *prev; 2015 char *prev_av; 2016 ipfw_insn *the_comment = NULL; 2017 struct ipfw_ioc_rule *rule; 2018 struct ipfw_keyword *key; 2019 struct ipfw_mapping *map; 2020 parser_func fn; 2021 int i, j; 2022 2023 bzero(actbuf, sizeof(actbuf)); /* actions go here */ 2024 bzero(othbuf, sizeof(actbuf)); /* others */ 2025 bzero(cmdbuf, sizeof(cmdbuf)); /* filters */ 2026 bzero(rulebuf, sizeof(rulebuf)); 2027 2028 rule = (struct ipfw_ioc_rule *)rulebuf; 2029 cmd = (ipfw_insn *)cmdbuf; 2030 action = (ipfw_insn *)actbuf; 2031 other = (ipfw_insn *)othbuf; 2032 2033 NEED2("need more parameters"); 2034 NEXT_ARG; 2035 2036 /* [rule N] -- Rule number optional */ 2037 if (ac && isdigit(**av)) { 2038 rule->rulenum = atoi(*av); 2039 NEXT_ARG; 2040 } 2041 2042 /* [set N] -- set number (0..30), optional */ 2043 if (ac > 1 && !strncmp(*av, "set", strlen(*av))) { 2044 int set = strtoul(av[1], NULL, 10); 2045 if (set < 0 || set > 30) 2046 errx(EX_DATAERR, "illegal set %s", av[1]); 2047 rule->set = set; 2048 av += 2; ac -= 2; 2049 } 2050 2051 /* 2052 * parse before 2053 */ 2054 for (;;) { 2055 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) { 2056 if (key->type == BEFORE && 2057 strcmp(key->word, *av) == 0) { 2058 for (j = 0, map = mappings; 2059 j < MAPPING_SIZE; j++, map++) { 2060 if (map->type == IN_USE && 2061 map->module == key->module && 2062 map->opcode == key->opcode ) { 2063 fn = map->parser; 2064 (*fn)(&other, &ac, &av); 2065 break; 2066 } 2067 } 2068 break; 2069 } 2070 } 2071 if (i >= KEYWORD_SIZE) { 2072 break; 2073 } else if (F_LEN(other) > 0) { 2074 if (other->module == MODULE_BASIC_ID && 2075 other->opcode == O_BASIC_CHECK_STATE) { 2076 other = next_cmd(other); 2077 goto done; 2078 } 2079 other = next_cmd(other); 2080 } 2081 } 2082 2083 /* 2084 * parse actions 2085 * 2086 * only accept 1 action 2087 */ 2088 NEED1("missing action"); 2089 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) { 2090 if (ac > 0 && key->type == ACTION && 2091 strcmp(key->word, *av) == 0) { 2092 for (j = 0, map = mappings; 2093 j < MAPPING_SIZE; j++, map++) { 2094 if (map->type == IN_USE && 2095 map->module == key->module && 2096 map->opcode == key->opcode) { 2097 fn = map->parser; 2098 (*fn)(&action, &ac, &av); 2099 break; 2100 } 2101 } 2102 break; 2103 } 2104 } 2105 if (F_LEN(action) > 0) 2106 action = next_cmd(action); 2107 2108 /* 2109 * parse protocol 2110 */ 2111 if (strcmp(*av, "proto") == 0){ 2112 NEXT_ARG; 2113 } 2114 2115 NEED1("missing protocol"); 2116 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) { 2117 if (key->type == PROTO && 2118 strcmp(key->word, "proto") == 0) { 2119 for (j = 0, map = mappings; 2120 j < MAPPING_SIZE; j++, map++) { 2121 if (map->type == IN_USE && 2122 map->module == key->module && 2123 map->opcode == key->opcode ) { 2124 fn = map->parser; 2125 (*fn)(&cmd, &ac, &av); 2126 break; 2127 } 2128 } 2129 break; 2130 } 2131 } 2132 if (F_LEN(cmd) > 0) 2133 cmd = next_cmd(cmd); 2134 2135 /* 2136 * other filters 2137 */ 2138 while (ac > 0) { 2139 char *s, *cur; /* current filter */ 2140 ipfw_insn_u32 *cmd32; /* alias for cmd */ 2141 2142 s = *av; 2143 cmd32 = (ipfw_insn_u32 *)cmd; 2144 if (strcmp(*av, "or") == 0) { 2145 if (prev == NULL) 2146 errx(EX_USAGE, "'or' should" 2147 "between two filters\n"); 2148 prev->len |= F_OR; 2149 cmd->len = F_OR; 2150 *av = prev_av; 2151 } 2152 if (strcmp(*av, "not") == 0) { 2153 if (cmd->len & F_NOT) 2154 errx(EX_USAGE, "double \"not\" not allowed\n"); 2155 cmd->len = F_NOT; 2156 NEXT_ARG; 2157 continue; 2158 } 2159 cur = *av; 2160 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) { 2161 if ((key->type == FILTER || 2162 key->type == AFTER || 2163 key->type == FROM || 2164 key->type == TO) && 2165 strcmp(key->word, cur) == 0) { 2166 for (j = 0, map = mappings; 2167 j< MAPPING_SIZE; j++, map++) { 2168 if (map->type == IN_USE && 2169 map->module == key->module && 2170 map->opcode == key->opcode ) { 2171 fn = map->parser; 2172 (*fn)(&cmd, &ac, &av); 2173 break; 2174 } 2175 } 2176 break; 2177 } else if (i == KEYWORD_SIZE - 1) { 2178 errx(EX_USAGE, "bad command `%s'", cur); 2179 } 2180 } 2181 if (i >= KEYWORD_SIZE) { 2182 break; 2183 } else if (F_LEN(cmd) > 0) { 2184 prev = cmd; 2185 prev_av = cur; 2186 cmd = next_cmd(cmd); 2187 } 2188 } 2189 2190 done: 2191 if (ac>0) 2192 errx(EX_USAGE, "bad command `%s'", *av); 2193 2194 /* 2195 * Now copy stuff into the rule. 2196 * [filters][others][action][comment] 2197 */ 2198 dst = (ipfw_insn *)rule->cmd; 2199 /* 2200 * copy all filters, except comment 2201 */ 2202 src = (ipfw_insn *)cmdbuf; 2203 for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) { 2204 /* pick comment out */ 2205 i = F_LEN(src); 2206 if (src->module == MODULE_BASIC_ID && 2207 src->opcode == O_BASIC_COMMENT) { 2208 the_comment=src; 2209 } else { 2210 bcopy(src, dst, i * sizeof(u_int32_t)); 2211 dst = (ipfw_insn *)((uint32_t *)dst + i); 2212 } 2213 } 2214 2215 /* 2216 * start action section, it begin with others 2217 */ 2218 rule->act_ofs = (uint32_t *)dst - (uint32_t *)(rule->cmd); 2219 2220 /* 2221 * copy all other others 2222 */ 2223 for (src = (ipfw_insn *)othbuf; src != other; src += i) { 2224 i = F_LEN(src); 2225 bcopy(src, dst, i * sizeof(u_int32_t)); 2226 dst = (ipfw_insn *)((uint32_t *)dst + i); 2227 } 2228 2229 /* copy the action to the end of rule */ 2230 src = (ipfw_insn *)actbuf; 2231 i = F_LEN(src); 2232 bcopy(src, dst, i * sizeof(u_int32_t)); 2233 dst = (ipfw_insn *)((uint32_t *)dst + i); 2234 2235 /* 2236 * comment place behind the action 2237 */ 2238 if (the_comment != NULL) { 2239 i = F_LEN(the_comment); 2240 bcopy(the_comment, dst, i * sizeof(u_int32_t)); 2241 dst = (ipfw_insn *)((uint32_t *)dst + i); 2242 } 2243 2244 rule->cmd_len = (u_int32_t *)dst - (u_int32_t *)(rule->cmd); 2245 i = (void *)dst - (void *)rule; 2246 if (do_set_x(IP_FW_ADD, (void *)rule, i) == -1) { 2247 err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD"); 2248 } 2249 if (!do_quiet) 2250 show_rules(rule, 10, 10); 2251 } 2252 2253 static void 2254 zero(int ac, char *av[]) 2255 { 2256 int rulenum; 2257 int failed = EX_OK; 2258 2259 NEXT_ARG; 2260 2261 if (!ac) { 2262 /* clear all entries */ 2263 if (do_set_x(IP_FW_ZERO, NULL, 0) < 0) 2264 err(EX_UNAVAILABLE, "do_set_x(IP_FW_ZERO)"); 2265 if (!do_quiet) 2266 printf("Accounting cleared.\n"); 2267 return; 2268 } 2269 2270 while (ac) { 2271 /* Rule number */ 2272 if (isdigit(**av)) { 2273 rulenum = atoi(*av); 2274 NEXT_ARG; 2275 if (do_set_x(IP_FW_ZERO, &rulenum, sizeof rulenum)) { 2276 warn("rule %u: do_set_x(IP_FW_ZERO)", rulenum); 2277 failed = EX_UNAVAILABLE; 2278 } else if (!do_quiet) 2279 printf("Entry %d cleared\n", rulenum); 2280 } else { 2281 errx(EX_USAGE, "invalid rule number ``%s''", *av); 2282 } 2283 } 2284 if (failed != EX_OK) 2285 exit(failed); 2286 } 2287 2288 static void 2289 resetlog(int ac, char *av[]) 2290 { 2291 int rulenum; 2292 int failed = EX_OK; 2293 2294 NEXT_ARG; 2295 2296 if (!ac) { 2297 /* clear all entries */ 2298 if (setsockopt(ipfw_socket, IPPROTO_IP, 2299 IP_FW_RESETLOG, NULL, 0) < 0) 2300 err(EX_UNAVAILABLE, "setsockopt(IP_FW_RESETLOG)"); 2301 if (!do_quiet) 2302 printf("Logging counts reset.\n"); 2303 2304 return; 2305 } 2306 2307 while (ac) { 2308 /* Rule number */ 2309 if (isdigit(**av)) { 2310 rulenum = atoi(*av); 2311 NEXT_ARG; 2312 if (setsockopt(ipfw_socket, IPPROTO_IP, 2313 IP_FW_RESETLOG, &rulenum, sizeof rulenum)) { 2314 warn("rule %u: setsockopt(IP_FW_RESETLOG)", 2315 rulenum); 2316 failed = EX_UNAVAILABLE; 2317 } else if (!do_quiet) 2318 printf("Entry %d logging count reset\n", 2319 rulenum); 2320 } else { 2321 errx(EX_DATAERR, "invalid rule number ``%s''", *av); 2322 } 2323 } 2324 if (failed != EX_OK) 2325 exit(failed); 2326 } 2327 2328 static void 2329 flush(void) 2330 { 2331 int cmd = IP_FW_FLUSH; 2332 if (do_pipe) { 2333 cmd = IP_DUMMYNET_FLUSH; 2334 } 2335 if (!do_force) { 2336 int c; 2337 2338 printf("Are you sure? [yn] "); 2339 fflush(stdout); 2340 do { 2341 c = toupper(getc(stdin)); 2342 while (c != '\n' && getc(stdin) != '\n') 2343 if (feof(stdin)) 2344 return; /* and do not flush */ 2345 } while (c != 'Y' && c != 'N'); 2346 if (c == 'N') /* user said no */ 2347 return; 2348 } 2349 if (do_set_x(cmd, NULL, 0) < 0 ) { 2350 if (do_pipe) 2351 errx(EX_USAGE, "pipe/queue in use"); 2352 else 2353 errx(EX_USAGE, "do_set_x(IP_FW_FLUSH) failed"); 2354 } 2355 if (!do_quiet) { 2356 printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules"); 2357 } 2358 } 2359 2360 /* 2361 * do_set_x - extended version og do_set 2362 * insert a x_header in the beginning of the rule buf 2363 * and call setsockopt() with IP_FW_X. 2364 */ 2365 int 2366 do_set_x(int optname, void *rule, int optlen) 2367 { 2368 int len, *newbuf; 2369 2370 ip_fw_x_header *x_header; 2371 if (ipfw_socket < 0) 2372 err(EX_UNAVAILABLE, "socket not avaialble"); 2373 len = optlen + sizeof(ip_fw_x_header); 2374 newbuf = malloc(len); 2375 if (newbuf == NULL) 2376 err(EX_OSERR, "malloc newbuf in do_set_x"); 2377 bzero(newbuf, len); 2378 x_header = (ip_fw_x_header *)newbuf; 2379 x_header->opcode = optname; 2380 /* copy the rule into the newbuf, just after the x_header*/ 2381 bcopy(rule, ++x_header, optlen); 2382 return setsockopt(ipfw_socket, IPPROTO_IP, IP_FW_X, newbuf, len); 2383 } 2384 2385 /* 2386 * same as do_set_x 2387 */ 2388 int 2389 do_get_x(int optname, void *rule, int *optlen) 2390 { 2391 int len, *newbuf, retval; 2392 2393 ip_fw_x_header *x_header; 2394 if (ipfw_socket < 0) 2395 err(EX_UNAVAILABLE, "socket not avaialble"); 2396 len = *optlen + sizeof(ip_fw_x_header); 2397 newbuf = malloc(len); 2398 if (newbuf == NULL) 2399 err(EX_OSERR, "malloc newbuf in do_get_x"); 2400 bzero(newbuf, len); 2401 x_header = (ip_fw_x_header *)newbuf; 2402 x_header->opcode = optname; 2403 /* copy the rule into the newbuf, just after the x_header*/ 2404 bcopy(rule, ++x_header, *optlen); 2405 retval = getsockopt(ipfw_socket, IPPROTO_IP, IP_FW_X, newbuf, &len); 2406 bcopy(newbuf, rule, len); 2407 *optlen=len; 2408 return retval; 2409 } 2410 2411 static int 2412 ipfw_main(int ac, char **av) 2413 { 2414 int ch; 2415 2416 if (ac == 1) 2417 help(); 2418 2419 /* Set the force flag for non-interactive processes */ 2420 do_force = !isatty(STDIN_FILENO); 2421 2422 optind = optreset = 1; 2423 while ((ch = getopt(ac, av, "hs:acdDefNStTv")) != -1) 2424 switch (ch) { 2425 case 'h': /* help */ 2426 help(); 2427 break; /* NOTREACHED */ 2428 2429 case 's': /* sort */ 2430 do_sort = atoi(optarg); 2431 break; 2432 case 'a': 2433 do_acct = 1; 2434 break; 2435 case 'c': 2436 do_compact = 1; 2437 break; 2438 case 'd': 2439 do_dynamic = 1; 2440 break; 2441 case 'D': 2442 do_dynamic = 2; 2443 break; 2444 case 'e': 2445 do_expired = 1; 2446 break; 2447 case 'f': 2448 do_force = 1; 2449 break; 2450 case 'N': 2451 do_resolv = 1; 2452 break; 2453 case 'S': 2454 show_sets = 1; 2455 break; 2456 case 't': 2457 do_time = 1; 2458 break; 2459 case 'T': 2460 do_time = 2; 2461 break; 2462 case 'v': 2463 do_quiet = 0; 2464 verbose++; 2465 break; 2466 default: 2467 help(); 2468 } 2469 2470 ac -= optind; 2471 av += optind; 2472 NEED1("bad arguments, for usage summary ``ipfw''"); 2473 2474 /* 2475 * optional: pipe or queue or nat 2476 */ 2477 do_nat = 0; 2478 do_pipe = 0; 2479 if (!strncmp(*av, "nat", strlen(*av))) 2480 do_nat = 1; 2481 else if (!strncmp(*av, "pipe", strlen(*av))) { 2482 do_pipe = 1; 2483 } else if (!strncmp(*av, "queue", strlen(*av))) { 2484 do_pipe = 2; 2485 } 2486 NEED1("missing command"); 2487 2488 /* 2489 * for pipes and queues and nat we normally say 'pipe NN config' 2490 * but the code is easier to parse as 'pipe config NN' 2491 * so we swap the two arguments. 2492 */ 2493 if ((do_pipe || do_nat) && ac > 2 && isdigit(*(av[1]))) { 2494 char *p = av[1]; 2495 av[1] = av[2]; 2496 av[2] = p; 2497 } 2498 2499 if (!strncmp(*av, "add", strlen(*av))) { 2500 load_modules(); 2501 add(ac, av); 2502 } else if (!strncmp(*av, "delete", strlen(*av))) { 2503 delete_rules(ac, av); 2504 } else if (!strncmp(*av, "flush", strlen(*av))) { 2505 flush(); 2506 } else if (!strncmp(*av, "list", strlen(*av))) { 2507 load_modules(); 2508 list(ac, av); 2509 } else if (!strncmp(*av, "show", strlen(*av))) { 2510 do_acct++; 2511 load_modules(); 2512 list(ac, av); 2513 } else if (!strncmp(*av, "zero", strlen(*av))) { 2514 zero(ac, av); 2515 } else if (!strncmp(*av, "set", strlen(*av))) { 2516 sets_handler(ac, av); 2517 } else if (!strncmp(*av, "module", strlen(*av))) { 2518 NEXT_ARG; 2519 if (!strncmp(*av, "show", strlen(*av)) || 2520 !strncmp(*av, "show", strlen(*av))) { 2521 list_modules(ac, av); 2522 } else { 2523 errx(EX_USAGE, "bad ipfw module command `%s'", *av); 2524 } 2525 } else if (!strncmp(*av, "resetlog", strlen(*av))) { 2526 resetlog(ac, av); 2527 } else if (!strncmp(*av, "log", strlen(*av))) { 2528 NEXT_ARG; 2529 if (!strncmp(*av, "reset", strlen(*av))) { 2530 resetlog(ac, av); 2531 } else if (!strncmp(*av, "off", strlen(*av))) { 2532 2533 } else if (!strncmp(*av, "on", strlen(*av))) { 2534 2535 } else { 2536 errx(EX_USAGE, "bad command `%s'", *av); 2537 } 2538 } else if (!strncmp(*av, "nat", strlen(*av))) { 2539 NEXT_ARG; 2540 nat_main(ac, av); 2541 } else if (!strncmp(*av, "pipe", strlen(*av)) || 2542 !strncmp(*av, "queue", strlen(*av))) { 2543 NEXT_ARG; 2544 if (!strncmp(*av, "config", strlen(*av))) { 2545 config_dummynet(ac, av); 2546 } else if (!strncmp(*av, "flush", strlen(*av))) { 2547 flush(); 2548 } else if (!strncmp(*av, "show", strlen(*av))) { 2549 show_dummynet(ac, av); 2550 } else { 2551 errx(EX_USAGE, "bad ipfw pipe command `%s'", *av); 2552 } 2553 } else if (!strncmp(*av, "state", strlen(*av))) { 2554 NEXT_ARG; 2555 if (!strncmp(*av, "add", strlen(*av))) { 2556 add_state(ac, av); 2557 } else if (!strncmp(*av, "delete", strlen(*av))) { 2558 delete_state(ac, av); 2559 } else if (!strncmp(*av, "flush", strlen(*av))) { 2560 flush_state(ac, av); 2561 } else if (!strncmp(*av, "list", strlen(*av))) { 2562 do_dynamic = 2; 2563 list(ac, av); 2564 } else if (!strncmp(*av, "show", strlen(*av))) { 2565 do_acct = 1; 2566 do_dynamic =2; 2567 list(ac, av); 2568 } else { 2569 errx(EX_USAGE, "bad ipfw state command `%s'", *av); 2570 } 2571 } else if (!strncmp(*av, "table", strlen(*av))) { 2572 if (ac > 2 && isdigit(*(av[1]))) { 2573 char *p = av[1]; 2574 av[1] = av[2]; 2575 av[2] = p; 2576 } 2577 NEXT_ARG; 2578 if (!strncmp(*av, "append", strlen(*av))) { 2579 table_append(ac, av); 2580 } else if (!strncmp(*av, "remove", strlen(*av))) { 2581 table_remove(ac, av); 2582 } else if (!strncmp(*av, "flush", strlen(*av))) { 2583 table_flush(ac, av); 2584 } else if (!strncmp(*av, "list", strlen(*av))) { 2585 table_list(ac, av); 2586 } else if (!strncmp(*av, "show", strlen(*av))) { 2587 table_show(ac, av); 2588 } else if (!strncmp(*av, "type", strlen(*av))) { 2589 table_create(ac, av); 2590 } else if (!strncmp(*av, "delete", strlen(*av))) { 2591 table_delete(ac, av); 2592 } else if (!strncmp(*av, "test", strlen(*av))) { 2593 table_test(ac,av); 2594 } else if (!strncmp(*av, "name", strlen(*av))) { 2595 table_rename(ac, av); 2596 } else { 2597 errx(EX_USAGE, "bad ipfw table command `%s'", *av); 2598 } 2599 } else if (!strncmp(*av, "sync", strlen(*av))) { 2600 NEXT_ARG; 2601 if (!strncmp(*av, "edge", strlen(*av))) { 2602 sync_config_edge(ac, av); 2603 } else if (!strncmp(*av, "centre", strlen(*av))) { 2604 sync_config_centre(ac, av); 2605 } else if (!strncmp(*av, "show", strlen(*av))) { 2606 NEXT_ARG; 2607 if (!strncmp(*av, "config", strlen(*av))) { 2608 sync_show_config(ac, av); 2609 } else if (!strncmp(*av, "status", strlen(*av))) { 2610 sync_show_status(ac, av); 2611 } else { 2612 errx(EX_USAGE, "bad show command `%s'", *av); 2613 } 2614 } else if (!strncmp(*av, "start", strlen(*av))) { 2615 NEXT_ARG; 2616 if (!strncmp(*av, "edge", strlen(*av))) { 2617 sync_edge_start(ac, av); 2618 } else if (!strncmp(*av, "centre", strlen(*av))) { 2619 sync_centre_start(ac, av); 2620 } 2621 } else if (!strncmp(*av, "stop", strlen(*av))) { 2622 NEXT_ARG; 2623 if (!strncmp(*av, "edge", strlen(*av))) { 2624 sync_edge_stop(ac, av); 2625 } else if (!strncmp(*av, "centre", strlen(*av))) { 2626 sync_centre_stop(ac, av); 2627 } 2628 } else if (!strncmp(*av, "clear", strlen(*av))) { 2629 NEXT_ARG; 2630 if (!strncmp(*av, "edge", strlen(*av))) { 2631 sync_edge_clear(ac, av); 2632 } else if (!strncmp(*av, "centre", strlen(*av))) { 2633 sync_centre_clear(ac, av); 2634 } 2635 } else if (!strncmp(*av, "test", strlen(*av))) { 2636 NEXT_ARG; 2637 if (!strncmp(*av, "edge", strlen(*av))) { 2638 sync_edge_test(ac, av); 2639 } else if (!strncmp(*av, "centre", strlen(*av))) { 2640 sync_centre_test(ac, av); 2641 } 2642 } else { 2643 errx(EX_USAGE, "bad ipfw sync command `%s'", *av); 2644 } 2645 } else { 2646 errx(EX_USAGE, "bad ipfw command `%s'", *av); 2647 } 2648 return 0; 2649 } 2650 2651 static void 2652 ipfw_readfile(int ac, char *av[]) 2653 { 2654 char buf[BUFSIZ]; 2655 char *a, *p, *args[MAX_ARGS], *cmd = NULL; 2656 char linename[10]; 2657 int i=0, lineno=0, qflag=0, pflag=0, status; 2658 FILE *f = NULL; 2659 pid_t preproc = 0; 2660 int c; 2661 2662 while ((c = getopt(ac, av, "D:U:p:q")) != -1) { 2663 switch (c) { 2664 case 'D': 2665 if (!pflag) 2666 errx(EX_USAGE, "-D requires -p"); 2667 if (i > MAX_ARGS - 2) 2668 errx(EX_USAGE, "too many -D or -U options"); 2669 args[i++] = "-D"; 2670 args[i++] = optarg; 2671 break; 2672 2673 case 'U': 2674 if (!pflag) 2675 errx(EX_USAGE, "-U requires -p"); 2676 if (i > MAX_ARGS - 2) 2677 errx(EX_USAGE, "too many -D or -U options"); 2678 args[i++] = "-U"; 2679 args[i++] = optarg; 2680 break; 2681 2682 case 'p': 2683 pflag = 1; 2684 cmd = optarg; 2685 args[0] = cmd; 2686 i = 1; 2687 break; 2688 2689 case 'q': 2690 qflag = 1; 2691 break; 2692 2693 default: 2694 errx(EX_USAGE, "bad arguments, for usage" 2695 " summary ``ipfw''"); 2696 } 2697 } 2698 2699 av += optind; 2700 ac -= optind; 2701 if (ac != 1) 2702 errx(EX_USAGE, "extraneous filename arguments"); 2703 2704 if ((f = fopen(av[0], "r")) == NULL) 2705 err(EX_UNAVAILABLE, "fopen: %s", av[0]); 2706 2707 if (pflag) { 2708 /* pipe through preprocessor (cpp or m4) */ 2709 int pipedes[2]; 2710 2711 args[i] = NULL; 2712 2713 if (pipe(pipedes) == -1) 2714 err(EX_OSERR, "cannot create pipe"); 2715 2716 switch ((preproc = fork())) { 2717 case -1: 2718 err(EX_OSERR, "cannot fork"); 2719 2720 case 0: 2721 /* child */ 2722 if (dup2(fileno(f), 0) == -1 || 2723 dup2(pipedes[1], 1) == -1) { 2724 err(EX_OSERR, "dup2()"); 2725 } 2726 fclose(f); 2727 close(pipedes[1]); 2728 close(pipedes[0]); 2729 execvp(cmd, args); 2730 err(EX_OSERR, "execvp(%s) failed", cmd); 2731 2732 default: 2733 /* parent */ 2734 fclose(f); 2735 close(pipedes[1]); 2736 if ((f = fdopen(pipedes[0], "r")) == NULL) { 2737 int savederrno = errno; 2738 2739 kill(preproc, SIGTERM); 2740 errno = savederrno; 2741 err(EX_OSERR, "fdopen()"); 2742 } 2743 } 2744 } 2745 2746 while (fgets(buf, BUFSIZ, f)) { 2747 lineno++; 2748 sprintf(linename, "Line %d", lineno); 2749 args[0] = linename; 2750 2751 if (*buf == '#') 2752 continue; 2753 if ((p = strchr(buf, '#')) != NULL) 2754 *p = '\0'; 2755 i = 1; 2756 if (qflag) 2757 args[i++] = "-q"; 2758 for (a = strtok(buf, WHITESP); a && i < MAX_ARGS; 2759 a = strtok(NULL, WHITESP), i++) { 2760 args[i] = a; 2761 } 2762 2763 if (i == (qflag? 2: 1)) 2764 continue; 2765 if (i == MAX_ARGS) 2766 errx(EX_USAGE, "%s: too many arguments", linename); 2767 2768 args[i] = NULL; 2769 ipfw_main(i, args); 2770 } 2771 fclose(f); 2772 if (pflag) { 2773 if (waitpid(preproc, &status, 0) == -1) 2774 errx(EX_OSERR, "waitpid()"); 2775 if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK) 2776 errx(EX_UNAVAILABLE, "preprocessor exited with status %d", 2777 WEXITSTATUS(status)); 2778 else if (WIFSIGNALED(status)) 2779 errx(EX_UNAVAILABLE, "preprocessor exited with signal %d", 2780 WTERMSIG(status)); 2781 } 2782 } 2783 2784 int 2785 main(int ac, char *av[]) 2786 { 2787 ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 2788 if (ipfw_socket < 0) 2789 err(EX_UNAVAILABLE, "socket"); 2790 2791 memset(keywords, 0, sizeof(struct ipfw_keyword) * KEYWORD_SIZE); 2792 memset(mappings, 0, sizeof(struct ipfw_mapping) * MAPPING_SIZE); 2793 2794 prepare_default_funcs(); 2795 2796 if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) 2797 ipfw_readfile(ac, av); 2798 else 2799 ipfw_main(ac, av); 2800 return EX_OK; 2801 } 2802