1 /* 2 * Copyright (c) 2014 - 2018 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 <net/ipfw3/ip_fw3.h> 64 #include <net/ipfw3_basic/ip_fw3_table.h> 65 #include <net/ipfw3_basic/ip_fw3_state.h> 66 #include <net/ipfw3_basic/ip_fw3_sync.h> 67 #include <net/ipfw3_basic/ip_fw3_basic.h> 68 #include <net/ipfw3_nat/ip_fw3_nat.h> 69 #include <net/dummynet3/ip_dummynet3.h> 70 71 #include "ipfw3.h" 72 #include "ipfw3basic.h" 73 #include "ipfw3log.h" 74 #include "ipfw3set.h" 75 #include "ipfw3table.h" 76 #include "ipfw3dummynet.h" 77 #include "ipfw3state.h" 78 #include "ipfw3sync.h" 79 #include "ipfw3nat.h" 80 81 #define MAX_ARGS 32 82 #define WHITESP " \t\f\v\n\r" 83 #define IPFW3_LIB_PATH "/usr/lib/libipfw3%s.so" 84 85 int fw3_socket = -1; /* main RAW socket */ 86 int do_acct, /* Show packet/byte count */ 87 do_time, /* Show time stamps */ 88 do_quiet = 1, /* Be quiet , default is quiet*/ 89 do_force, /* Don't ask for confirmation */ 90 do_pipe, /* this cmd refers to a pipe */ 91 do_nat, /* Nat configuration. */ 92 do_sort, /* field to sort results (0 = no) */ 93 do_expired, /* display expired dynamic rules */ 94 do_compact, /* show rules in compact mode */ 95 show_sets, /* display rule sets */ 96 verbose; 97 98 struct ipfw3_keyword keywords[KEYWORD_SIZE]; 99 struct ipfw3_mapping mappings[MAPPING_SIZE]; 100 101 int 102 match_token(struct char_int_map *table, char *string) 103 { 104 while (table->key) { 105 if (strcmp(table->key, string) == 0) { 106 return table->val; 107 } 108 table++; 109 } 110 return 0; 111 } 112 113 void 114 module_get(char *modules_str, int len) 115 { 116 if (do_get_x(IP_FW_MODULE, modules_str, &len) < 0) 117 errx(EX_USAGE, "ipfw3 not loaded."); 118 } 119 120 void 121 module_list(int ac, char *av[]) 122 { 123 void *module_str = NULL; 124 int len = 1024; 125 if ((module_str = realloc(module_str, len)) == NULL) 126 err(EX_OSERR, "realloc"); 127 128 module_get(module_str, len); 129 printf("%s\n", (char *)module_str); 130 } 131 132 void 133 module_load(void) 134 { 135 const char *error; 136 init_module mod_init_func; 137 void *module_lib; 138 char module_lib_file[50]; 139 void *module_str = NULL; 140 int len = 1024; 141 142 if ((module_str = realloc(module_str, len)) == NULL) 143 err(EX_OSERR, "realloc"); 144 145 module_get(module_str, len); 146 147 const char s[2] = ","; 148 char *token; 149 token = strtok(module_str, s); 150 while (token != NULL) { 151 sprintf(module_lib_file, IPFW3_LIB_PATH, token); 152 token = strtok(NULL, s); 153 module_lib = dlopen(module_lib_file, RTLD_LAZY); 154 if (!module_lib) { 155 fprintf(stderr, "Couldn't open %s: %s\n", 156 module_lib_file, dlerror()); 157 exit(EX_SOFTWARE); 158 } 159 mod_init_func = dlsym(module_lib, "load_module"); 160 if ((error = dlerror())) 161 { 162 fprintf(stderr, "Couldn't find init function: %s\n", error); 163 exit(EX_SOFTWARE); 164 } 165 (*mod_init_func)((register_func)register_ipfw_func, 166 (register_keyword)register_ipfw_keyword); 167 } 168 } 169 170 void 171 register_ipfw_keyword(int module, int opcode, char *word, int type) 172 { 173 struct ipfw3_keyword *tmp; 174 175 tmp=keywords; 176 for (;;) { 177 if (tmp->type == NONE) { 178 strcpy(tmp->word, word); 179 tmp->module = module; 180 tmp->opcode = opcode; 181 tmp->type = type; 182 break; 183 } else { 184 if (strcmp(tmp->word, word) == 0) 185 errx(EX_USAGE, "keyword `%s' exists", word); 186 else 187 tmp++; 188 } 189 } 190 } 191 192 void 193 register_ipfw_func(int module, int opcode, parser_func parser, shower_func shower) 194 { 195 struct ipfw3_mapping *tmp; 196 197 tmp = mappings; 198 while (1) { 199 if (tmp->type == NONE) { 200 tmp->module = module; 201 tmp->opcode = opcode; 202 tmp->parser = parser; 203 tmp->shower = shower; 204 tmp->type = IN_USE; 205 break; 206 } else { 207 if (tmp->opcode == opcode && tmp->module == module) { 208 errx(EX_USAGE, "func `%d' of module `%d' exists", 209 opcode, module); 210 break; 211 } else { 212 tmp++; 213 } 214 } 215 } 216 } 217 218 /* 219 * this func need to check whether 'or' need to be printed, 220 * when the filter is the first filter with 'or' when dont print 221 * when not first and same as previous, then print or and no filter name 222 * when not first but different from previous, print name without 'or' 223 * show_or = 1: show or and ignore filter name 224 * show_or = 0: show filter name ignore or 225 */ 226 void prev_show_chk(ipfw_insn *cmd, uint8_t *prev_module, uint8_t *prev_opcode, 227 int *show_or) 228 { 229 if (cmd->len & F_OR) { 230 if (*prev_module == 0 && *prev_opcode == 0) { 231 /* first cmd with 'or' flag */ 232 *show_or = 0; 233 *prev_module = cmd->module; 234 *prev_opcode = cmd->opcode; 235 } else if (cmd->module == *prev_module && 236 cmd->opcode == *prev_opcode) { 237 /* cmd same as previous, same module and opcode */ 238 *show_or = 1; 239 } else { 240 /* cmd different from prev*/ 241 *show_or = 0; 242 *prev_module = cmd->module; 243 *prev_opcode = cmd->opcode; 244 245 } 246 } else { 247 *show_or = 0; 248 *prev_module = 0; 249 *prev_opcode = 0; 250 } 251 } 252 253 /* 254 * word can be: proto from to other 255 * proto show proto 256 * from show from 257 * to show to 258 * other show all other filters 259 */ 260 int show_filter(ipfw_insn *cmd, char *word, int type) 261 { 262 struct ipfw3_keyword *k; 263 struct ipfw3_mapping *m; 264 shower_func fn; 265 int i, j, show_or; 266 uint8_t prev_module, prev_opcode; 267 268 k = keywords; 269 m = mappings; 270 for (i = 1; i < KEYWORD_SIZE; i++, k++) { 271 if (k->type == type) { 272 if (k->module == cmd->module && 273 k->opcode == cmd->opcode) { 274 for (j = 1; j < MAPPING_SIZE; j++, m++) { 275 if (m->type == IN_USE && 276 k->module == m->module && 277 k->opcode == m->opcode) { 278 prev_show_chk(cmd, &prev_module, 279 &prev_opcode, &show_or); 280 if (cmd->len & F_NOT) 281 printf(" not"); 282 283 fn = m->shower; 284 (*fn)(cmd, show_or); 285 return 1; 286 } 287 } 288 } 289 } 290 } 291 return 0; 292 } 293 294 void 295 help(void) 296 { 297 fprintf(stderr, "usage: ipfw3 [options]\n" 298 " ipfw3 add [rulenum] [set id] action filters\n" 299 " ipfw3 delete [rulenum]\n" 300 " ipfw3 flush\n" 301 " ipfw3 list [rulenum]\n" 302 " ipfw3 show [rulenum]\n" 303 " ipfw3 zero [rulenum]\n" 304 " ipfw3 set [show|enable|disable]\n" 305 " ipfw3 module\n" 306 " ipfw3 [enable|disable]\n" 307 " ipfw3 log [reset|off|on]\n" 308 " ipfw3 nat [config|show|delete]\n" 309 " ipfw3 pipe [config|show|delete]\n" 310 " ipfw3 state [add|delete|list|show]\n" 311 " ipfw3 nat [config|show]\n" 312 "\nsee ipfw3 manpage for details\n"); 313 exit(EX_USAGE); 314 } 315 316 void 317 rule_delete(int ac, char *av[]) 318 { 319 int error, rulenum; 320 321 NEXT_ARG; 322 323 while (ac && isdigit(**av)) { 324 rulenum = atoi(*av); 325 error = do_set_x(IP_FW_DEL, &rulenum, sizeof(int)); 326 if (error) { 327 err(EX_OSERR, "do_get_x(IP_FW_DEL)"); 328 } 329 NEXT_ARG; 330 } 331 } 332 333 /* 334 * helper function, updates the pointer to cmd with the length 335 * of the current command, and also cleans up the first word of 336 * the new command in case it has been clobbered before. 337 */ 338 ipfw_insn* 339 next_cmd(ipfw_insn *cmd) 340 { 341 cmd += F_LEN(cmd); 342 bzero(cmd, sizeof(*cmd)); 343 return cmd; 344 } 345 346 /* 347 * Parse arguments and assemble the microinstructions which make up a rule. 348 * Rules are added into the 'rulebuf' and then copied in the correct order 349 * into the actual rule. 350 * 351 * 352 */ 353 void 354 rule_add(int ac, char *av[], uint8_t insert) 355 { 356 /* 357 * rules are added into the 'rulebuf' and then copied in 358 * the correct order into the actual rule. 359 * Some things that need to go out of order (prob, action etc.) 360 * go into actbuf[]. 361 */ 362 static uint32_t rulebuf[IPFW_RULE_SIZE_MAX]; 363 static uint32_t actbuf[IPFW_RULE_SIZE_MAX]; 364 static uint32_t othbuf[IPFW_RULE_SIZE_MAX]; 365 static uint32_t cmdbuf[IPFW_RULE_SIZE_MAX]; 366 367 ipfw_insn *src, *dst, *cmd, *action, *other; 368 ipfw_insn *prev; 369 char *prev_av; 370 ipfw_insn *the_comment = NULL; 371 struct ipfw_ioc_rule *rule; 372 struct ipfw3_keyword *key; 373 struct ipfw3_mapping *map; 374 parser_func fn; 375 int i, j; 376 377 bzero(actbuf, sizeof(actbuf)); /* actions go here */ 378 bzero(othbuf, sizeof(actbuf)); /* others */ 379 bzero(cmdbuf, sizeof(cmdbuf)); /* filters */ 380 bzero(rulebuf, sizeof(rulebuf)); 381 382 rule = (struct ipfw_ioc_rule *)rulebuf; 383 cmd = (ipfw_insn *)cmdbuf; 384 action = (ipfw_insn *)actbuf; 385 other = (ipfw_insn *)othbuf; 386 387 rule->insert = insert; 388 389 NEED2("need more parameters"); 390 NEXT_ARG; 391 392 /* [rule N] -- Rule number optional */ 393 if (ac && isdigit(**av)) { 394 rule->rulenum = atoi(*av); 395 NEXT_ARG; 396 } 397 398 /* [set N] -- set number (0..30), optional */ 399 if (ac > 1 && !strncmp(*av, "set", strlen(*av))) { 400 int set = strtoul(av[1], NULL, 10); 401 if (set < 0 || set > 30) 402 errx(EX_DATAERR, "illegal set %s", av[1]); 403 rule->set = set; 404 av += 2; ac -= 2; 405 } 406 407 /* 408 * parse before 409 */ 410 for (;;) { 411 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) { 412 if (key->type == BEFORE && 413 strcmp(key->word, *av) == 0) { 414 for (j = 0, map = mappings; 415 j < MAPPING_SIZE; j++, map++) { 416 if (map->type == IN_USE && 417 map->module == key->module && 418 map->opcode == key->opcode ) { 419 fn = map->parser; 420 (*fn)(&other, &ac, &av); 421 break; 422 } 423 } 424 break; 425 } 426 } 427 if (i >= KEYWORD_SIZE) { 428 break; 429 } else if (F_LEN(other) > 0) { 430 if (other->module == MODULE_BASIC_ID && 431 other->opcode == O_BASIC_CHECK_STATE) { 432 other = next_cmd(other); 433 goto done; 434 } 435 other = next_cmd(other); 436 } 437 } 438 439 /* 440 * parse actions 441 * 442 * only accept 1 action 443 */ 444 NEED1("missing action"); 445 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) { 446 if (ac > 0 && key->type == ACTION && 447 strcmp(key->word, *av) == 0) { 448 for (j = 0, map = mappings; 449 j < MAPPING_SIZE; j++, map++) { 450 if (map->type == IN_USE && 451 map->module == key->module && 452 map->opcode == key->opcode) { 453 fn = map->parser; 454 (*fn)(&action, &ac, &av); 455 break; 456 } 457 } 458 break; 459 } 460 } 461 if (F_LEN(action) > 0) 462 action = next_cmd(action); 463 464 /* 465 * parse protocol 466 */ 467 if (strcmp(*av, "proto") == 0){ 468 NEXT_ARG; 469 } 470 471 NEED1("missing protocol"); 472 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) { 473 if (key->type == PROTO && 474 strcmp(key->word, "proto") == 0) { 475 for (j = 0, map = mappings; 476 j < MAPPING_SIZE; j++, map++) { 477 if (map->type == IN_USE && 478 map->module == key->module && 479 map->opcode == key->opcode ) { 480 fn = map->parser; 481 (*fn)(&cmd, &ac, &av); 482 break; 483 } 484 } 485 break; 486 } 487 } 488 if (F_LEN(cmd) > 0) 489 cmd = next_cmd(cmd); 490 491 /* 492 * other filters 493 */ 494 while (ac > 0) { 495 char *s, *cur; /* current filter */ 496 ipfw_insn_u32 *cmd32; /* alias for cmd */ 497 498 s = *av; 499 cmd32 = (ipfw_insn_u32 *)cmd; 500 if (strcmp(*av, "or") == 0) { 501 if (prev == NULL) 502 errx(EX_USAGE, "'or' should" 503 "between two filters\n"); 504 prev->len |= F_OR; 505 cmd->len = F_OR; 506 *av = prev_av; 507 } 508 if (strcmp(*av, "not") == 0) { 509 if (cmd->len & F_NOT) 510 errx(EX_USAGE, "double \"not\" not allowed\n"); 511 cmd->len = F_NOT; 512 NEXT_ARG; 513 continue; 514 } 515 cur = *av; 516 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) { 517 if ((key->type == FILTER || 518 key->type == AFTER || 519 key->type == FROM || 520 key->type == TO) && 521 strcmp(key->word, cur) == 0) { 522 for (j = 0, map = mappings; 523 j< MAPPING_SIZE; j++, map++) { 524 if (map->type == IN_USE && 525 map->module == key->module && 526 map->opcode == key->opcode ) { 527 fn = map->parser; 528 (*fn)(&cmd, &ac, &av); 529 break; 530 } 531 } 532 break; 533 } else if (i == KEYWORD_SIZE - 1) { 534 errx(EX_USAGE, "bad command `%s'", cur); 535 } 536 } 537 if (i >= KEYWORD_SIZE) { 538 break; 539 } else if (F_LEN(cmd) > 0) { 540 prev = cmd; 541 prev_av = cur; 542 cmd = next_cmd(cmd); 543 } 544 } 545 546 done: 547 if (ac>0) 548 errx(EX_USAGE, "bad command `%s'", *av); 549 550 /* 551 * Now copy stuff into the rule. 552 * [filters][others][action][comment] 553 */ 554 dst = (ipfw_insn *)rule->cmd; 555 /* 556 * copy all filters, except comment 557 */ 558 src = (ipfw_insn *)cmdbuf; 559 for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) { 560 /* pick comment out */ 561 i = F_LEN(src); 562 if (src->module == MODULE_BASIC_ID && 563 src->opcode == O_BASIC_COMMENT) { 564 the_comment=src; 565 } else { 566 bcopy(src, dst, i * sizeof(u_int32_t)); 567 dst = (ipfw_insn *)((uint32_t *)dst + i); 568 } 569 } 570 571 /* 572 * start action section, it begin with others 573 */ 574 rule->act_ofs = (uint32_t *)dst - (uint32_t *)(rule->cmd); 575 576 /* 577 * copy all other others 578 */ 579 for (src = (ipfw_insn *)othbuf; src != other; src += i) { 580 i = F_LEN(src); 581 bcopy(src, dst, i * sizeof(u_int32_t)); 582 dst = (ipfw_insn *)((uint32_t *)dst + i); 583 } 584 585 /* copy the action to the end of rule */ 586 src = (ipfw_insn *)actbuf; 587 i = F_LEN(src); 588 bcopy(src, dst, i * sizeof(u_int32_t)); 589 dst = (ipfw_insn *)((uint32_t *)dst + i); 590 591 /* 592 * comment place behind the action 593 */ 594 if (the_comment != NULL) { 595 i = F_LEN(the_comment); 596 bcopy(the_comment, dst, i * sizeof(u_int32_t)); 597 dst = (ipfw_insn *)((uint32_t *)dst + i); 598 } 599 600 rule->cmd_len = (u_int32_t *)dst - (u_int32_t *)(rule->cmd); 601 i = (void *)dst - (void *)rule; 602 if (do_set_x(IP_FW_ADD, (void *)rule, i) == -1) { 603 err(EX_UNAVAILABLE, "setsockopt(%s)", "IP_FW_ADD"); 604 } 605 if (!do_quiet) 606 rule_show(rule, 10, 10); 607 } 608 609 void 610 rule_zero(int ac, char *av[]) 611 { 612 int rulenum; 613 int failed = EX_OK; 614 615 NEXT_ARG; 616 617 if (!ac) { 618 /* clear all entries */ 619 if (do_set_x(IP_FW_ZERO, NULL, 0) < 0) 620 err(EX_UNAVAILABLE, "do_set_x(IP_FW_ZERO)"); 621 if (!do_quiet) 622 printf("Accounting cleared.\n"); 623 return; 624 } 625 626 while (ac) { 627 /* Rule number */ 628 if (isdigit(**av)) { 629 rulenum = atoi(*av); 630 NEXT_ARG; 631 if (do_set_x(IP_FW_ZERO, &rulenum, sizeof rulenum)) { 632 warn("rule %u: do_set_x(IP_FW_ZERO)", rulenum); 633 failed = EX_UNAVAILABLE; 634 } else if (!do_quiet) 635 printf("Entry %d cleared\n", rulenum); 636 } else { 637 errx(EX_USAGE, "invalid rule number ``%s''", *av); 638 } 639 } 640 if (failed != EX_OK) 641 exit(failed); 642 } 643 644 void 645 rule_flush(void) 646 { 647 int cmd = IP_FW_FLUSH; 648 if (do_pipe) { 649 cmd = IP_DUMMYNET_FLUSH; 650 } 651 if (!do_force) { 652 int c; 653 654 printf("Are you sure? [yn] "); 655 fflush(stdout); 656 do { 657 c = toupper(getc(stdin)); 658 while (c != '\n' && getc(stdin) != '\n') 659 if (feof(stdin)) 660 return; /* and do not flush */ 661 } while (c != 'Y' && c != 'N'); 662 if (c == 'N') /* user said no */ 663 return; 664 } 665 if (do_set_x(cmd, NULL, 0) < 0 ) { 666 if (do_pipe) 667 errx(EX_USAGE, "pipe/queue in use"); 668 else 669 errx(EX_USAGE, "do_set_x(IP_FW_FLUSH) failed"); 670 } 671 if (!do_quiet) { 672 printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules"); 673 } 674 } 675 676 void 677 rule_list(int ac, char *av[]) 678 { 679 struct ipfw_ioc_rule *rule; 680 681 void *data = NULL; 682 int bcwidth, nbytes, pcwidth, width; 683 int nalloc = 1024; 684 int the_rule_num = 0; 685 int total_len; 686 687 NEXT_ARG; 688 689 /* get rules or pipes from kernel, resizing array as necessary */ 690 nbytes = nalloc; 691 692 while (nbytes >= nalloc) { 693 nalloc = nalloc * 2 ; 694 nbytes = nalloc; 695 if ((data = realloc(data, nbytes)) == NULL) 696 err(EX_OSERR, "realloc"); 697 if (do_get_x(IP_FW_GET, data, &nbytes) < 0) 698 err(EX_OSERR, "do_get_x(IP_FW_GET)"); 699 } 700 701 /* 702 * Count static rules. 703 */ 704 rule = data; 705 bcwidth = pcwidth = 0; 706 if (do_acct) { 707 total_len = 0; 708 for (rule = data; rule != NULL; rule = (void *)rule + IOC_RULESIZE(rule)) { 709 /* packet counter */ 710 width = snprintf(NULL, 0, "%ju", (uintmax_t)rule->pcnt); 711 if (width > pcwidth) 712 pcwidth = width; 713 714 /* byte counter */ 715 width = snprintf(NULL, 0, "%ju", (uintmax_t)rule->bcnt); 716 if (width > bcwidth) 717 bcwidth = width; 718 719 total_len += IOC_RULESIZE(rule); 720 if (total_len == nbytes) { 721 break; 722 } 723 } 724 } 725 726 727 if (ac == 1) { 728 the_rule_num = atoi(*av); 729 } 730 731 total_len = 0; 732 for (rule = data; rule != NULL; rule = (void *)rule + IOC_RULESIZE(rule)) { 733 if(the_rule_num == 0 || rule->rulenum == the_rule_num) { 734 rule_show(rule, pcwidth, bcwidth); 735 } 736 total_len += IOC_RULESIZE(rule); 737 if (total_len == nbytes) { 738 break; 739 } 740 } 741 742 } 743 744 void 745 rule_show(struct ipfw_ioc_rule *rule, int pcwidth, int bcwidth) 746 { 747 static int twidth = 0; 748 ipfw_insn *cmd; 749 int l; 750 751 u_int32_t set_disable = rule->sets; 752 753 if (set_disable & (1 << rule->set)) { /* disabled */ 754 if (!show_sets) 755 return; 756 else 757 printf("# DISABLED "); 758 } 759 if (do_compact) { 760 printf("%u", rule->rulenum); 761 } else { 762 printf("%05u", rule->rulenum); 763 } 764 765 if (do_acct) { 766 if (do_compact) { 767 printf(" %ju %ju", (uintmax_t)rule->pcnt, 768 (uintmax_t)rule->bcnt); 769 } else { 770 printf(" %*ju %*ju", pcwidth, (uintmax_t)rule->pcnt, 771 bcwidth, (uintmax_t)rule->bcnt); 772 } 773 } 774 775 if (do_time == 1) { 776 char timestr[30]; 777 778 if (twidth == 0) { 779 strcpy(timestr, ctime((time_t *)&twidth)); 780 *strchr(timestr, '\n') = '\0'; 781 twidth = strlen(timestr); 782 } 783 if (rule->timestamp) { 784 time_t t = _long_to_time(rule->timestamp); 785 786 strcpy(timestr, ctime(&t)); 787 *strchr(timestr, '\n') = '\0'; 788 printf(" %s", timestr); 789 } else { 790 printf(" %*s", twidth, " "); 791 } 792 } else if (do_time == 2) { 793 printf( " %10u", rule->timestamp); 794 } 795 796 if (show_sets) 797 printf(" set %d", rule->set); 798 799 800 struct ipfw3_keyword *k; 801 struct ipfw3_mapping *m; 802 shower_func fn, comment_fn = NULL; 803 ipfw_insn *comment_cmd; 804 int i, j, changed; 805 806 /* 807 * show others and actions 808 */ 809 for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule); 810 l > 0; l -= F_LEN(cmd), 811 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) { 812 k = keywords; 813 m = mappings; 814 for (i = 1; i< KEYWORD_SIZE; i++, k++) { 815 if ( k->module == cmd->module && k->opcode == cmd->opcode ) { 816 for (j = 1; j< MAPPING_SIZE; j++, m++) { 817 if (m->type == IN_USE && 818 m->module == cmd->module && 819 m->opcode == cmd->opcode) { 820 if (cmd->module == MODULE_BASIC_ID && 821 cmd->opcode == O_BASIC_COMMENT) { 822 comment_fn = m->shower; 823 comment_cmd = cmd; 824 } else { 825 fn = m->shower; 826 (*fn)(cmd, 0); 827 } 828 if (cmd->module == MODULE_BASIC_ID && 829 cmd->opcode == 830 O_BASIC_CHECK_STATE) { 831 goto done; 832 } 833 break; 834 } 835 } 836 break; 837 } 838 } 839 } 840 841 /* 842 * show proto 843 */ 844 changed=0; 845 for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd), 846 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) { 847 changed = show_filter(cmd, "proto", PROTO); 848 } 849 if (!changed && !do_quiet) 850 printf(" ip"); 851 852 /* 853 * show from 854 */ 855 changed = 0; 856 for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd), 857 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) { 858 changed = show_filter(cmd, "from", FROM); 859 } 860 if (!changed && !do_quiet) 861 printf(" from any"); 862 863 /* 864 * show to 865 */ 866 changed = 0; 867 for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd), 868 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) { 869 changed = show_filter(cmd, "to", TO); 870 } 871 if (!changed && !do_quiet) 872 printf(" to any"); 873 874 /* 875 * show other filters 876 */ 877 l = rule->act_ofs; 878 cmd = rule->cmd; 879 m = mappings; 880 for ( ; l > 0; ) { 881 show_filter(cmd, "other", FILTER); 882 l -= F_LEN(cmd); 883 cmd=(ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd)); 884 } 885 886 /* show the comment in the end */ 887 if (comment_fn != NULL) { 888 (*comment_fn)(comment_cmd, 0); 889 } 890 done: 891 printf("\n"); 892 } 893 894 /* 895 * do_set_x - extended version of do_set 896 * insert a x_header in the beginning of the rule buf 897 * and call setsockopt() with IP_FW_X. 898 */ 899 int 900 do_set_x(int optname, void *rule, int optlen) 901 { 902 int len, *newbuf, retval; 903 ip_fw_x_header *x_header; 904 905 if (fw3_socket < 0) 906 err(EX_UNAVAILABLE, "socket not avaialble"); 907 908 len = optlen + sizeof(ip_fw_x_header); 909 newbuf = malloc(len); 910 if (newbuf == NULL) 911 err(EX_OSERR, "malloc newbuf in do_set_x"); 912 913 bzero(newbuf, len); 914 x_header = (ip_fw_x_header *)newbuf; 915 x_header->opcode = optname; 916 /* copy the rule into the newbuf, just after the x_header*/ 917 bcopy(rule, ++x_header, optlen); 918 retval = setsockopt(fw3_socket, IPPROTO_IP, IP_FW_X, newbuf, len); 919 free(newbuf); 920 return retval; 921 } 922 923 /* 924 * same as do_set_x 925 */ 926 int 927 do_get_x(int optname, void *rule, int *optlen) 928 { 929 int len, *newbuf, retval; 930 ip_fw_x_header *x_header; 931 932 if (fw3_socket < 0) 933 err(EX_UNAVAILABLE, "socket not avaialble"); 934 935 len = *optlen + sizeof(ip_fw_x_header); 936 newbuf = malloc(len); 937 if (newbuf == NULL) 938 err(EX_OSERR, "malloc newbuf in do_get_x"); 939 940 bzero(newbuf, len); 941 x_header = (ip_fw_x_header *)newbuf; 942 x_header->opcode = optname; 943 /* copy the rule into the newbuf, just after the x_header*/ 944 bcopy(rule, ++x_header, *optlen); 945 retval = getsockopt(fw3_socket, IPPROTO_IP, IP_FW_X, newbuf, &len); 946 bcopy(newbuf, rule, len); 947 free(newbuf); 948 *optlen = len; 949 return retval; 950 } 951 952 int 953 ipfw3_main(int ac, char **av) 954 { 955 int ch; 956 957 if (ac == 1) 958 help(); 959 960 /* Set the force flag for non-interactive processes */ 961 do_force = !isatty(STDIN_FILENO); 962 963 optind = optreset = 1; 964 while ((ch = getopt(ac, av, "hs:acefStTv")) != -1) 965 switch (ch) { 966 case 'h': /* help */ 967 help(); 968 break; /* NOTREACHED */ 969 970 case 's': /* sort */ 971 do_sort = atoi(optarg); 972 break; 973 case 'a': 974 do_acct = 1; 975 break; 976 case 'c': 977 do_compact = 1; 978 break; 979 case 'e': 980 do_expired = 1; 981 break; 982 case 'f': 983 do_force = 1; 984 break; 985 case 'S': 986 show_sets = 1; 987 break; 988 case 't': 989 do_time = 1; 990 break; 991 case 'T': 992 do_time = 2; 993 break; 994 case 'v': 995 do_quiet = 0; 996 verbose++; 997 break; 998 default: 999 help(); 1000 } 1001 1002 ac -= optind; 1003 av += optind; 1004 NEED1("bad arguments, for usage summary ``ipfw3''"); 1005 1006 /* 1007 * optional: pipe or queue or nat 1008 */ 1009 do_nat = 0; 1010 do_pipe = 0; 1011 if (!strncmp(*av, "nat", strlen(*av))) 1012 do_nat = 1; 1013 else if (!strncmp(*av, "pipe", strlen(*av))) { 1014 do_pipe = 1; 1015 } else if (!strncmp(*av, "queue", strlen(*av))) { 1016 do_pipe = 2; 1017 } 1018 NEED1("missing command"); 1019 1020 /* 1021 * for pipes and queues and nat we normally say 'pipe NN config' 1022 * but the code is easier to parse as 'pipe config NN' 1023 * so we swap the two arguments. 1024 */ 1025 if ((do_pipe || do_nat) && ac > 2 && isdigit(*(av[1]))) { 1026 char *p = av[1]; 1027 av[1] = av[2]; 1028 av[2] = p; 1029 } 1030 1031 if (!strncmp(*av, "add", strlen(*av))) { 1032 module_load(); 1033 rule_add(ac, av, 0); 1034 } else if (!strncmp(*av, "insert", strlen(*av))) { 1035 module_load(); 1036 rule_add(ac, av, 1); 1037 } else if (!strncmp(*av, "delete", strlen(*av))) { 1038 rule_delete(ac, av); 1039 } else if (!strncmp(*av, "flush", strlen(*av))) { 1040 rule_flush(); 1041 } else if (!strncmp(*av, "list", strlen(*av))) { 1042 module_load(); 1043 rule_list(ac, av); 1044 } else if (!strncmp(*av, "show", strlen(*av))) { 1045 do_acct++; 1046 module_load(); 1047 rule_list(ac, av); 1048 } else if (!strncmp(*av, "zero", strlen(*av))) { 1049 rule_zero(ac, av); 1050 } else if (!strncmp(*av, "set", strlen(*av))) { 1051 set_main(ac, av); 1052 } else if (!strncmp(*av, "module", strlen(*av))) { 1053 NEXT_ARG; 1054 if (!strncmp(*av, "list", strlen(*av))) { 1055 module_list(ac, av); 1056 } else { 1057 errx(EX_USAGE, "bad ipfw3 module command `%s'", *av); 1058 } 1059 } else if (!strncmp(*av, "log", strlen(*av))) { 1060 NEXT_ARG; 1061 log_main(ac, av); 1062 } else if (!strncmp(*av, "nat", strlen(*av))) { 1063 NEXT_ARG; 1064 nat_main(ac, av); 1065 } else if (!strncmp(*av, "pipe", strlen(*av)) || 1066 !strncmp(*av, "queue", strlen(*av))) { 1067 NEXT_ARG; 1068 dummynet_main(ac, av); 1069 } else if (!strncmp(*av, "state", strlen(*av))) { 1070 NEXT_ARG; 1071 state_main(ac, av); 1072 } else if (!strncmp(*av, "table", strlen(*av))) { 1073 if (ac > 2 && isdigit(*(av[1]))) { 1074 char *p = av[1]; 1075 av[1] = av[2]; 1076 av[2] = p; 1077 } 1078 NEXT_ARG; 1079 table_main(ac, av); 1080 } else if (!strncmp(*av, "sync", strlen(*av))) { 1081 NEXT_ARG; 1082 sync_main(ac, av); 1083 } else { 1084 errx(EX_USAGE, "bad ipfw3 command `%s'", *av); 1085 } 1086 return 0; 1087 } 1088 1089 void 1090 ipfw3_readfile(int ac, char *av[]) 1091 { 1092 char buf[BUFSIZ]; 1093 char *a, *p, *args[MAX_ARGS], *cmd = NULL; 1094 char linename[17]; 1095 int i=0, lineno=0, qflag=0, pflag=0, status; 1096 FILE *f = NULL; 1097 pid_t preproc = 0; 1098 int c; 1099 1100 while ((c = getopt(ac, av, "D:U:p:q")) != -1) { 1101 switch (c) { 1102 case 'D': 1103 if (!pflag) 1104 errx(EX_USAGE, "-D requires -p"); 1105 if (i > MAX_ARGS - 2) 1106 errx(EX_USAGE, "too many -D or -U options"); 1107 args[i++] = "-D"; 1108 args[i++] = optarg; 1109 break; 1110 1111 case 'U': 1112 if (!pflag) 1113 errx(EX_USAGE, "-U requires -p"); 1114 if (i > MAX_ARGS - 2) 1115 errx(EX_USAGE, "too many -D or -U options"); 1116 args[i++] = "-U"; 1117 args[i++] = optarg; 1118 break; 1119 1120 case 'p': 1121 pflag = 1; 1122 cmd = optarg; 1123 args[0] = cmd; 1124 i = 1; 1125 break; 1126 1127 case 'q': 1128 qflag = 1; 1129 break; 1130 1131 default: 1132 errx(EX_USAGE, "bad arguments, for usage" 1133 " summary ``ipfw''"); 1134 } 1135 } 1136 1137 av += optind; 1138 ac -= optind; 1139 if (ac != 1) 1140 errx(EX_USAGE, "extraneous filename arguments"); 1141 1142 if ((f = fopen(av[0], "r")) == NULL) 1143 err(EX_UNAVAILABLE, "fopen: %s", av[0]); 1144 1145 if (pflag) { 1146 /* pipe through preprocessor (cpp or m4) */ 1147 int pipedes[2]; 1148 1149 args[i] = NULL; 1150 1151 if (pipe(pipedes) == -1) 1152 err(EX_OSERR, "cannot create pipe"); 1153 1154 switch ((preproc = fork())) { 1155 case -1: 1156 err(EX_OSERR, "cannot fork"); 1157 1158 case 0: 1159 /* child */ 1160 if (dup2(fileno(f), 0) == -1 || 1161 dup2(pipedes[1], 1) == -1) { 1162 err(EX_OSERR, "dup2()"); 1163 } 1164 fclose(f); 1165 close(pipedes[1]); 1166 close(pipedes[0]); 1167 execvp(cmd, args); 1168 err(EX_OSERR, "execvp(%s) failed", cmd); 1169 1170 default: 1171 /* parent */ 1172 fclose(f); 1173 close(pipedes[1]); 1174 if ((f = fdopen(pipedes[0], "r")) == NULL) { 1175 int savederrno = errno; 1176 1177 kill(preproc, SIGTERM); 1178 errno = savederrno; 1179 err(EX_OSERR, "fdopen()"); 1180 } 1181 } 1182 } 1183 1184 while (fgets(buf, BUFSIZ, f)) { 1185 lineno++; 1186 sprintf(linename, "Line %d", lineno); 1187 args[0] = linename; 1188 1189 if (*buf == '#') 1190 continue; 1191 if ((p = strchr(buf, '#')) != NULL) 1192 *p = '\0'; 1193 i = 1; 1194 if (qflag) 1195 args[i++] = "-q"; 1196 for (a = strtok(buf, WHITESP); a && i < MAX_ARGS; 1197 a = strtok(NULL, WHITESP), i++) { 1198 args[i] = a; 1199 } 1200 1201 if (i == (qflag? 2: 1)) 1202 continue; 1203 if (i == MAX_ARGS) 1204 errx(EX_USAGE, "%s: too many arguments", linename); 1205 1206 args[i] = NULL; 1207 ipfw3_main(i, args); 1208 } 1209 fclose(f); 1210 if (pflag) { 1211 if (waitpid(preproc, &status, 0) == -1) 1212 errx(EX_OSERR, "waitpid()"); 1213 if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK) 1214 errx(EX_UNAVAILABLE, "preprocessor exited with status %d", 1215 WEXITSTATUS(status)); 1216 else if (WIFSIGNALED(status)) 1217 errx(EX_UNAVAILABLE, "preprocessor exited with signal %d", 1218 WTERMSIG(status)); 1219 } 1220 } 1221 1222 int 1223 main(int ac, char *av[]) 1224 { 1225 fw3_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 1226 if (fw3_socket < 0) 1227 err(EX_UNAVAILABLE, "socket"); 1228 1229 memset(keywords, 0, LEN_FW3_KEYWORD * KEYWORD_SIZE); 1230 memset(mappings, 0, LEN_FW3_MAPPING * MAPPING_SIZE); 1231 1232 prepare_default_funcs(); 1233 1234 if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) 1235 ipfw3_readfile(ac, av); 1236 else 1237 ipfw3_main(ac, av); 1238 return EX_OK; 1239 } 1240