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[]) 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 NEED2("need more parameters"); 388 NEXT_ARG; 389 390 /* [rule N] -- Rule number optional */ 391 if (ac && isdigit(**av)) { 392 rule->rulenum = atoi(*av); 393 NEXT_ARG; 394 } 395 396 /* [set N] -- set number (0..30), optional */ 397 if (ac > 1 && !strncmp(*av, "set", strlen(*av))) { 398 int set = strtoul(av[1], NULL, 10); 399 if (set < 0 || set > 30) 400 errx(EX_DATAERR, "illegal set %s", av[1]); 401 rule->set = set; 402 av += 2; ac -= 2; 403 } 404 405 /* 406 * parse before 407 */ 408 for (;;) { 409 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) { 410 if (key->type == BEFORE && 411 strcmp(key->word, *av) == 0) { 412 for (j = 0, map = mappings; 413 j < MAPPING_SIZE; j++, map++) { 414 if (map->type == IN_USE && 415 map->module == key->module && 416 map->opcode == key->opcode ) { 417 fn = map->parser; 418 (*fn)(&other, &ac, &av); 419 break; 420 } 421 } 422 break; 423 } 424 } 425 if (i >= KEYWORD_SIZE) { 426 break; 427 } else if (F_LEN(other) > 0) { 428 if (other->module == MODULE_BASIC_ID && 429 other->opcode == O_BASIC_CHECK_STATE) { 430 other = next_cmd(other); 431 goto done; 432 } 433 other = next_cmd(other); 434 } 435 } 436 437 /* 438 * parse actions 439 * 440 * only accept 1 action 441 */ 442 NEED1("missing action"); 443 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) { 444 if (ac > 0 && key->type == ACTION && 445 strcmp(key->word, *av) == 0) { 446 for (j = 0, map = mappings; 447 j < MAPPING_SIZE; j++, map++) { 448 if (map->type == IN_USE && 449 map->module == key->module && 450 map->opcode == key->opcode) { 451 fn = map->parser; 452 (*fn)(&action, &ac, &av); 453 break; 454 } 455 } 456 break; 457 } 458 } 459 if (F_LEN(action) > 0) 460 action = next_cmd(action); 461 462 /* 463 * parse protocol 464 */ 465 if (strcmp(*av, "proto") == 0){ 466 NEXT_ARG; 467 } 468 469 NEED1("missing protocol"); 470 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) { 471 if (key->type == PROTO && 472 strcmp(key->word, "proto") == 0) { 473 for (j = 0, map = mappings; 474 j < MAPPING_SIZE; j++, map++) { 475 if (map->type == IN_USE && 476 map->module == key->module && 477 map->opcode == key->opcode ) { 478 fn = map->parser; 479 (*fn)(&cmd, &ac, &av); 480 break; 481 } 482 } 483 break; 484 } 485 } 486 if (F_LEN(cmd) > 0) 487 cmd = next_cmd(cmd); 488 489 /* 490 * other filters 491 */ 492 while (ac > 0) { 493 char *s, *cur; /* current filter */ 494 ipfw_insn_u32 *cmd32; /* alias for cmd */ 495 496 s = *av; 497 cmd32 = (ipfw_insn_u32 *)cmd; 498 if (strcmp(*av, "or") == 0) { 499 if (prev == NULL) 500 errx(EX_USAGE, "'or' should" 501 "between two filters\n"); 502 prev->len |= F_OR; 503 cmd->len = F_OR; 504 *av = prev_av; 505 } 506 if (strcmp(*av, "not") == 0) { 507 if (cmd->len & F_NOT) 508 errx(EX_USAGE, "double \"not\" not allowed\n"); 509 cmd->len = F_NOT; 510 NEXT_ARG; 511 continue; 512 } 513 cur = *av; 514 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) { 515 if ((key->type == FILTER || 516 key->type == AFTER || 517 key->type == FROM || 518 key->type == TO) && 519 strcmp(key->word, cur) == 0) { 520 for (j = 0, map = mappings; 521 j< MAPPING_SIZE; j++, map++) { 522 if (map->type == IN_USE && 523 map->module == key->module && 524 map->opcode == key->opcode ) { 525 fn = map->parser; 526 (*fn)(&cmd, &ac, &av); 527 break; 528 } 529 } 530 break; 531 } else if (i == KEYWORD_SIZE - 1) { 532 errx(EX_USAGE, "bad command `%s'", cur); 533 } 534 } 535 if (i >= KEYWORD_SIZE) { 536 break; 537 } else if (F_LEN(cmd) > 0) { 538 prev = cmd; 539 prev_av = cur; 540 cmd = next_cmd(cmd); 541 } 542 } 543 544 done: 545 if (ac>0) 546 errx(EX_USAGE, "bad command `%s'", *av); 547 548 /* 549 * Now copy stuff into the rule. 550 * [filters][others][action][comment] 551 */ 552 dst = (ipfw_insn *)rule->cmd; 553 /* 554 * copy all filters, except comment 555 */ 556 src = (ipfw_insn *)cmdbuf; 557 for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) { 558 /* pick comment out */ 559 i = F_LEN(src); 560 if (src->module == MODULE_BASIC_ID && 561 src->opcode == O_BASIC_COMMENT) { 562 the_comment=src; 563 } else { 564 bcopy(src, dst, i * sizeof(u_int32_t)); 565 dst = (ipfw_insn *)((uint32_t *)dst + i); 566 } 567 } 568 569 /* 570 * start action section, it begin with others 571 */ 572 rule->act_ofs = (uint32_t *)dst - (uint32_t *)(rule->cmd); 573 574 /* 575 * copy all other others 576 */ 577 for (src = (ipfw_insn *)othbuf; src != other; src += i) { 578 i = F_LEN(src); 579 bcopy(src, dst, i * sizeof(u_int32_t)); 580 dst = (ipfw_insn *)((uint32_t *)dst + i); 581 } 582 583 /* copy the action to the end of rule */ 584 src = (ipfw_insn *)actbuf; 585 i = F_LEN(src); 586 bcopy(src, dst, i * sizeof(u_int32_t)); 587 dst = (ipfw_insn *)((uint32_t *)dst + i); 588 589 /* 590 * comment place behind the action 591 */ 592 if (the_comment != NULL) { 593 i = F_LEN(the_comment); 594 bcopy(the_comment, dst, i * sizeof(u_int32_t)); 595 dst = (ipfw_insn *)((uint32_t *)dst + i); 596 } 597 598 rule->cmd_len = (u_int32_t *)dst - (u_int32_t *)(rule->cmd); 599 i = (void *)dst - (void *)rule; 600 if (do_set_x(IP_FW_ADD, (void *)rule, i) == -1) { 601 err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD"); 602 } 603 if (!do_quiet) 604 rule_show(rule, 10, 10); 605 } 606 607 void 608 rule_zero(int ac, char *av[]) 609 { 610 int rulenum; 611 int failed = EX_OK; 612 613 NEXT_ARG; 614 615 if (!ac) { 616 /* clear all entries */ 617 if (do_set_x(IP_FW_ZERO, NULL, 0) < 0) 618 err(EX_UNAVAILABLE, "do_set_x(IP_FW_ZERO)"); 619 if (!do_quiet) 620 printf("Accounting cleared.\n"); 621 return; 622 } 623 624 while (ac) { 625 /* Rule number */ 626 if (isdigit(**av)) { 627 rulenum = atoi(*av); 628 NEXT_ARG; 629 if (do_set_x(IP_FW_ZERO, &rulenum, sizeof rulenum)) { 630 warn("rule %u: do_set_x(IP_FW_ZERO)", rulenum); 631 failed = EX_UNAVAILABLE; 632 } else if (!do_quiet) 633 printf("Entry %d cleared\n", rulenum); 634 } else { 635 errx(EX_USAGE, "invalid rule number ``%s''", *av); 636 } 637 } 638 if (failed != EX_OK) 639 exit(failed); 640 } 641 642 void 643 rule_flush(void) 644 { 645 int cmd = IP_FW_FLUSH; 646 if (do_pipe) { 647 cmd = IP_DUMMYNET_FLUSH; 648 } 649 if (!do_force) { 650 int c; 651 652 printf("Are you sure? [yn] "); 653 fflush(stdout); 654 do { 655 c = toupper(getc(stdin)); 656 while (c != '\n' && getc(stdin) != '\n') 657 if (feof(stdin)) 658 return; /* and do not flush */ 659 } while (c != 'Y' && c != 'N'); 660 if (c == 'N') /* user said no */ 661 return; 662 } 663 if (do_set_x(cmd, NULL, 0) < 0 ) { 664 if (do_pipe) 665 errx(EX_USAGE, "pipe/queue in use"); 666 else 667 errx(EX_USAGE, "do_set_x(IP_FW_FLUSH) failed"); 668 } 669 if (!do_quiet) { 670 printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules"); 671 } 672 } 673 674 void 675 rule_list(int ac, char *av[]) 676 { 677 struct ipfw_ioc_rule *rule; 678 679 void *data = NULL; 680 int bcwidth, nbytes, pcwidth, width; 681 int nalloc = 1024; 682 int the_rule_num = 0; 683 int total_len; 684 685 NEXT_ARG; 686 687 /* get rules or pipes from kernel, resizing array as necessary */ 688 nbytes = nalloc; 689 690 while (nbytes >= nalloc) { 691 nalloc = nalloc * 2 ; 692 nbytes = nalloc; 693 if ((data = realloc(data, nbytes)) == NULL) 694 err(EX_OSERR, "realloc"); 695 if (do_get_x(IP_FW_GET, data, &nbytes) < 0) 696 err(EX_OSERR, "do_get_x(IP_FW_GET)"); 697 } 698 699 /* 700 * Count static rules. 701 */ 702 rule = data; 703 bcwidth = pcwidth = 0; 704 if (do_acct) { 705 total_len = 0; 706 for (rule = data; rule != NULL; rule = (void *)rule + IOC_RULESIZE(rule)) { 707 /* packet counter */ 708 width = snprintf(NULL, 0, "%ju", (uintmax_t)rule->pcnt); 709 if (width > pcwidth) 710 pcwidth = width; 711 712 /* byte counter */ 713 width = snprintf(NULL, 0, "%ju", (uintmax_t)rule->bcnt); 714 if (width > bcwidth) 715 bcwidth = width; 716 717 total_len += IOC_RULESIZE(rule); 718 if (total_len == nbytes) { 719 break; 720 } 721 } 722 } 723 724 725 if (ac == 1) { 726 the_rule_num = atoi(*av); 727 } 728 729 total_len = 0; 730 for (rule = data; rule != NULL; rule = (void *)rule + IOC_RULESIZE(rule)) { 731 if(the_rule_num == 0 || rule->rulenum == the_rule_num) { 732 rule_show(rule, pcwidth, bcwidth); 733 } 734 total_len += IOC_RULESIZE(rule); 735 if (total_len == nbytes) { 736 break; 737 } 738 } 739 740 } 741 742 void 743 rule_show(struct ipfw_ioc_rule *rule, int pcwidth, int bcwidth) 744 { 745 static int twidth = 0; 746 ipfw_insn *cmd; 747 int l; 748 749 u_int32_t set_disable = rule->sets; 750 751 if (set_disable & (1 << rule->set)) { /* disabled */ 752 if (!show_sets) 753 return; 754 else 755 printf("# DISABLED "); 756 } 757 if (do_compact) { 758 printf("%u", rule->rulenum); 759 } else { 760 printf("%05u", rule->rulenum); 761 } 762 763 if (do_acct) { 764 if (do_compact) { 765 printf(" %ju %ju", (uintmax_t)rule->pcnt, 766 (uintmax_t)rule->bcnt); 767 } else { 768 printf(" %*ju %*ju", pcwidth, (uintmax_t)rule->pcnt, 769 bcwidth, (uintmax_t)rule->bcnt); 770 } 771 } 772 773 if (do_time == 1) { 774 char timestr[30]; 775 776 if (twidth == 0) { 777 strcpy(timestr, ctime((time_t *)&twidth)); 778 *strchr(timestr, '\n') = '\0'; 779 twidth = strlen(timestr); 780 } 781 if (rule->timestamp) { 782 time_t t = _long_to_time(rule->timestamp); 783 784 strcpy(timestr, ctime(&t)); 785 *strchr(timestr, '\n') = '\0'; 786 printf(" %s", timestr); 787 } else { 788 printf(" %*s", twidth, " "); 789 } 790 } else if (do_time == 2) { 791 printf( " %10u", rule->timestamp); 792 } 793 794 if (show_sets) 795 printf(" set %d", rule->set); 796 797 798 struct ipfw3_keyword *k; 799 struct ipfw3_mapping *m; 800 shower_func fn, comment_fn = NULL; 801 ipfw_insn *comment_cmd; 802 int i, j, changed; 803 804 /* 805 * show others and actions 806 */ 807 for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule); 808 l > 0; l -= F_LEN(cmd), 809 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) { 810 k = keywords; 811 m = mappings; 812 for (i = 1; i< KEYWORD_SIZE; i++, k++) { 813 if ( k->module == cmd->module && k->opcode == cmd->opcode ) { 814 for (j = 1; j< MAPPING_SIZE; j++, m++) { 815 if (m->type == IN_USE && 816 m->module == cmd->module && 817 m->opcode == cmd->opcode) { 818 if (cmd->module == MODULE_BASIC_ID && 819 cmd->opcode == O_BASIC_COMMENT) { 820 comment_fn = m->shower; 821 comment_cmd = cmd; 822 } else { 823 fn = m->shower; 824 (*fn)(cmd, 0); 825 } 826 if (cmd->module == MODULE_BASIC_ID && 827 cmd->opcode == 828 O_BASIC_CHECK_STATE) { 829 goto done; 830 } 831 break; 832 } 833 } 834 break; 835 } 836 } 837 } 838 839 /* 840 * show proto 841 */ 842 changed=0; 843 for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd), 844 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) { 845 changed = show_filter(cmd, "proto", PROTO); 846 } 847 if (!changed && !do_quiet) 848 printf(" ip"); 849 850 /* 851 * show from 852 */ 853 changed = 0; 854 for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd), 855 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) { 856 changed = show_filter(cmd, "from", FROM); 857 } 858 if (!changed && !do_quiet) 859 printf(" from any"); 860 861 /* 862 * show to 863 */ 864 changed = 0; 865 for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd), 866 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) { 867 changed = show_filter(cmd, "to", TO); 868 } 869 if (!changed && !do_quiet) 870 printf(" to any"); 871 872 /* 873 * show other filters 874 */ 875 l = rule->act_ofs; 876 cmd = rule->cmd; 877 m = mappings; 878 for ( ; l > 0; ) { 879 show_filter(cmd, "other", FILTER); 880 l -= F_LEN(cmd); 881 cmd=(ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd)); 882 } 883 884 /* show the comment in the end */ 885 if (comment_fn != NULL) { 886 (*comment_fn)(comment_cmd, 0); 887 } 888 done: 889 printf("\n"); 890 } 891 892 /* 893 * do_set_x - extended version og do_set 894 * insert a x_header in the beginning of the rule buf 895 * and call setsockopt() with IP_FW_X. 896 */ 897 int 898 do_set_x(int optname, void *rule, int optlen) 899 { 900 int len, *newbuf, retval; 901 ip_fw_x_header *x_header; 902 903 if (fw3_socket < 0) 904 err(EX_UNAVAILABLE, "socket not avaialble"); 905 906 len = optlen + sizeof(ip_fw_x_header); 907 newbuf = malloc(len); 908 if (newbuf == NULL) 909 err(EX_OSERR, "malloc newbuf in do_set_x"); 910 911 bzero(newbuf, len); 912 x_header = (ip_fw_x_header *)newbuf; 913 x_header->opcode = optname; 914 /* copy the rule into the newbuf, just after the x_header*/ 915 bcopy(rule, ++x_header, optlen); 916 retval = setsockopt(fw3_socket, IPPROTO_IP, IP_FW_X, newbuf, len); 917 free(newbuf); 918 return retval; 919 } 920 921 /* 922 * same as do_set_x 923 */ 924 int 925 do_get_x(int optname, void *rule, int *optlen) 926 { 927 int len, *newbuf, retval; 928 ip_fw_x_header *x_header; 929 930 if (fw3_socket < 0) 931 err(EX_UNAVAILABLE, "socket not avaialble"); 932 933 len = *optlen + sizeof(ip_fw_x_header); 934 newbuf = malloc(len); 935 if (newbuf == NULL) 936 err(EX_OSERR, "malloc newbuf in do_get_x"); 937 938 bzero(newbuf, len); 939 x_header = (ip_fw_x_header *)newbuf; 940 x_header->opcode = optname; 941 /* copy the rule into the newbuf, just after the x_header*/ 942 bcopy(rule, ++x_header, *optlen); 943 retval = getsockopt(fw3_socket, IPPROTO_IP, IP_FW_X, newbuf, &len); 944 bcopy(newbuf, rule, len); 945 free(newbuf); 946 *optlen = len; 947 return retval; 948 } 949 950 int 951 ipfw3_main(int ac, char **av) 952 { 953 int ch; 954 955 if (ac == 1) 956 help(); 957 958 /* Set the force flag for non-interactive processes */ 959 do_force = !isatty(STDIN_FILENO); 960 961 optind = optreset = 1; 962 while ((ch = getopt(ac, av, "hs:acefStTv")) != -1) 963 switch (ch) { 964 case 'h': /* help */ 965 help(); 966 break; /* NOTREACHED */ 967 968 case 's': /* sort */ 969 do_sort = atoi(optarg); 970 break; 971 case 'a': 972 do_acct = 1; 973 break; 974 case 'c': 975 do_compact = 1; 976 break; 977 case 'e': 978 do_expired = 1; 979 break; 980 case 'f': 981 do_force = 1; 982 break; 983 case 'S': 984 show_sets = 1; 985 break; 986 case 't': 987 do_time = 1; 988 break; 989 case 'T': 990 do_time = 2; 991 break; 992 case 'v': 993 do_quiet = 0; 994 verbose++; 995 break; 996 default: 997 help(); 998 } 999 1000 ac -= optind; 1001 av += optind; 1002 NEED1("bad arguments, for usage summary ``ipfw3''"); 1003 1004 /* 1005 * optional: pipe or queue or nat 1006 */ 1007 do_nat = 0; 1008 do_pipe = 0; 1009 if (!strncmp(*av, "nat", strlen(*av))) 1010 do_nat = 1; 1011 else if (!strncmp(*av, "pipe", strlen(*av))) { 1012 do_pipe = 1; 1013 } else if (!strncmp(*av, "queue", strlen(*av))) { 1014 do_pipe = 2; 1015 } 1016 NEED1("missing command"); 1017 1018 /* 1019 * for pipes and queues and nat we normally say 'pipe NN config' 1020 * but the code is easier to parse as 'pipe config NN' 1021 * so we swap the two arguments. 1022 */ 1023 if ((do_pipe || do_nat) && ac > 2 && isdigit(*(av[1]))) { 1024 char *p = av[1]; 1025 av[1] = av[2]; 1026 av[2] = p; 1027 } 1028 1029 if (!strncmp(*av, "add", strlen(*av))) { 1030 module_load(); 1031 rule_add(ac, av); 1032 } else if (!strncmp(*av, "delete", strlen(*av))) { 1033 rule_delete(ac, av); 1034 } else if (!strncmp(*av, "flush", strlen(*av))) { 1035 rule_flush(); 1036 } else if (!strncmp(*av, "list", strlen(*av))) { 1037 module_load(); 1038 rule_list(ac, av); 1039 } else if (!strncmp(*av, "show", strlen(*av))) { 1040 do_acct++; 1041 module_load(); 1042 rule_list(ac, av); 1043 } else if (!strncmp(*av, "zero", strlen(*av))) { 1044 rule_zero(ac, av); 1045 } else if (!strncmp(*av, "set", strlen(*av))) { 1046 set_main(ac, av); 1047 } else if (!strncmp(*av, "module", strlen(*av))) { 1048 NEXT_ARG; 1049 if (!strncmp(*av, "list", strlen(*av))) { 1050 module_list(ac, av); 1051 } else { 1052 errx(EX_USAGE, "bad ipfw3 module command `%s'", *av); 1053 } 1054 } else if (!strncmp(*av, "log", strlen(*av))) { 1055 NEXT_ARG; 1056 log_main(ac, av); 1057 } else if (!strncmp(*av, "nat", strlen(*av))) { 1058 NEXT_ARG; 1059 nat_main(ac, av); 1060 } else if (!strncmp(*av, "pipe", strlen(*av)) || 1061 !strncmp(*av, "queue", strlen(*av))) { 1062 NEXT_ARG; 1063 dummynet_main(ac, av); 1064 } else if (!strncmp(*av, "state", strlen(*av))) { 1065 NEXT_ARG; 1066 state_main(ac, av); 1067 } else if (!strncmp(*av, "table", strlen(*av))) { 1068 if (ac > 2 && isdigit(*(av[1]))) { 1069 char *p = av[1]; 1070 av[1] = av[2]; 1071 av[2] = p; 1072 } 1073 NEXT_ARG; 1074 table_main(ac, av); 1075 } else if (!strncmp(*av, "sync", strlen(*av))) { 1076 NEXT_ARG; 1077 sync_main(ac, av); 1078 } else { 1079 errx(EX_USAGE, "bad ipfw3 command `%s'", *av); 1080 } 1081 return 0; 1082 } 1083 1084 void 1085 ipfw3_readfile(int ac, char *av[]) 1086 { 1087 char buf[BUFSIZ]; 1088 char *a, *p, *args[MAX_ARGS], *cmd = NULL; 1089 char linename[17]; 1090 int i=0, lineno=0, qflag=0, pflag=0, status; 1091 FILE *f = NULL; 1092 pid_t preproc = 0; 1093 int c; 1094 1095 while ((c = getopt(ac, av, "D:U:p:q")) != -1) { 1096 switch (c) { 1097 case 'D': 1098 if (!pflag) 1099 errx(EX_USAGE, "-D requires -p"); 1100 if (i > MAX_ARGS - 2) 1101 errx(EX_USAGE, "too many -D or -U options"); 1102 args[i++] = "-D"; 1103 args[i++] = optarg; 1104 break; 1105 1106 case 'U': 1107 if (!pflag) 1108 errx(EX_USAGE, "-U requires -p"); 1109 if (i > MAX_ARGS - 2) 1110 errx(EX_USAGE, "too many -D or -U options"); 1111 args[i++] = "-U"; 1112 args[i++] = optarg; 1113 break; 1114 1115 case 'p': 1116 pflag = 1; 1117 cmd = optarg; 1118 args[0] = cmd; 1119 i = 1; 1120 break; 1121 1122 case 'q': 1123 qflag = 1; 1124 break; 1125 1126 default: 1127 errx(EX_USAGE, "bad arguments, for usage" 1128 " summary ``ipfw''"); 1129 } 1130 } 1131 1132 av += optind; 1133 ac -= optind; 1134 if (ac != 1) 1135 errx(EX_USAGE, "extraneous filename arguments"); 1136 1137 if ((f = fopen(av[0], "r")) == NULL) 1138 err(EX_UNAVAILABLE, "fopen: %s", av[0]); 1139 1140 if (pflag) { 1141 /* pipe through preprocessor (cpp or m4) */ 1142 int pipedes[2]; 1143 1144 args[i] = NULL; 1145 1146 if (pipe(pipedes) == -1) 1147 err(EX_OSERR, "cannot create pipe"); 1148 1149 switch ((preproc = fork())) { 1150 case -1: 1151 err(EX_OSERR, "cannot fork"); 1152 1153 case 0: 1154 /* child */ 1155 if (dup2(fileno(f), 0) == -1 || 1156 dup2(pipedes[1], 1) == -1) { 1157 err(EX_OSERR, "dup2()"); 1158 } 1159 fclose(f); 1160 close(pipedes[1]); 1161 close(pipedes[0]); 1162 execvp(cmd, args); 1163 err(EX_OSERR, "execvp(%s) failed", cmd); 1164 1165 default: 1166 /* parent */ 1167 fclose(f); 1168 close(pipedes[1]); 1169 if ((f = fdopen(pipedes[0], "r")) == NULL) { 1170 int savederrno = errno; 1171 1172 kill(preproc, SIGTERM); 1173 errno = savederrno; 1174 err(EX_OSERR, "fdopen()"); 1175 } 1176 } 1177 } 1178 1179 while (fgets(buf, BUFSIZ, f)) { 1180 lineno++; 1181 sprintf(linename, "Line %d", lineno); 1182 args[0] = linename; 1183 1184 if (*buf == '#') 1185 continue; 1186 if ((p = strchr(buf, '#')) != NULL) 1187 *p = '\0'; 1188 i = 1; 1189 if (qflag) 1190 args[i++] = "-q"; 1191 for (a = strtok(buf, WHITESP); a && i < MAX_ARGS; 1192 a = strtok(NULL, WHITESP), i++) { 1193 args[i] = a; 1194 } 1195 1196 if (i == (qflag? 2: 1)) 1197 continue; 1198 if (i == MAX_ARGS) 1199 errx(EX_USAGE, "%s: too many arguments", linename); 1200 1201 args[i] = NULL; 1202 ipfw3_main(i, args); 1203 } 1204 fclose(f); 1205 if (pflag) { 1206 if (waitpid(preproc, &status, 0) == -1) 1207 errx(EX_OSERR, "waitpid()"); 1208 if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK) 1209 errx(EX_UNAVAILABLE, "preprocessor exited with status %d", 1210 WEXITSTATUS(status)); 1211 else if (WIFSIGNALED(status)) 1212 errx(EX_UNAVAILABLE, "preprocessor exited with signal %d", 1213 WTERMSIG(status)); 1214 } 1215 } 1216 1217 int 1218 main(int ac, char *av[]) 1219 { 1220 fw3_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); 1221 if (fw3_socket < 0) 1222 err(EX_UNAVAILABLE, "socket"); 1223 1224 memset(keywords, 0, LEN_FW3_KEYWORD * KEYWORD_SIZE); 1225 memset(mappings, 0, LEN_FW3_MAPPING * MAPPING_SIZE); 1226 1227 prepare_default_funcs(); 1228 1229 if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0) 1230 ipfw3_readfile(ac, av); 1231 else 1232 ipfw3_main(ac, av); 1233 return EX_OK; 1234 } 1235