drm/linux/timer.h: No need to protect a callout struct from MP accesses
[dragonfly.git] / sbin / ipfw3 / ipfw3.c
blobd1e10e17da0f1be342228d80232600442ad8ee2d
1 /*
2 * Copyright (c) 2014 - 2018 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Bill Yuan <bycn82@dragonflybsd.org>
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
11 * Idea and grammar partially left from:
12 * Copyright (c) 1993 Daniel Boulet
15 * Redistribution and use in source forms, with and without modification,
16 * are permitted provided that this entire comment appears intact.
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.
22 * This software is provided ``AS IS'' without any warranties of any kind.
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>
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>
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>
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>
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"
81 #define MAX_ARGS 32
82 #define WHITESP " \t\f\v\n\r"
83 #define IPFW3_LIB_PATH "/usr/lib/libipfw3%s.so"
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;
98 struct ipfw3_keyword keywords[KEYWORD_SIZE];
99 struct ipfw3_mapping mappings[MAPPING_SIZE];
102 match_token(struct char_int_map *table, char *string)
104 while (table->key) {
105 if (strcmp(table->key, string) == 0) {
106 return table->val;
108 table++;
110 return 0;
113 void
114 module_get(char *modules_str, int len)
116 if (do_get_x(IP_FW_MODULE, modules_str, &len) < 0)
117 errx(EX_USAGE, "ipfw3 not loaded.");
120 void
121 module_list(int ac, char *av[])
123 void *module_str = NULL;
124 int len = 1024;
125 if ((module_str = realloc(module_str, len)) == NULL)
126 err(EX_OSERR, "realloc");
128 module_get(module_str, len);
129 printf("%s\n", (char *)module_str);
132 void
133 module_load(void)
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;
142 if ((module_str = realloc(module_str, len)) == NULL)
143 err(EX_OSERR, "realloc");
145 module_get(module_str, len);
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);
159 mod_init_func = dlsym(module_lib, "load_module");
160 if ((error = dlerror()))
162 fprintf(stderr, "Couldn't find init function: %s\n", error);
163 exit(EX_SOFTWARE);
165 (*mod_init_func)((register_func)register_ipfw_func,
166 (register_keyword)register_ipfw_keyword);
170 void
171 register_ipfw_keyword(int module, int opcode, char *word, int type)
173 struct ipfw3_keyword *tmp;
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++;
192 void
193 register_ipfw_func(int module, int opcode, parser_func parser, shower_func shower)
195 struct ipfw3_mapping *tmp;
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++;
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
226 void prev_show_chk(ipfw_insn *cmd, uint8_t *prev_module, uint8_t *prev_opcode,
227 int *show_or)
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;
246 } else {
247 *show_or = 0;
248 *prev_module = 0;
249 *prev_opcode = 0;
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
260 int show_filter(ipfw_insn *cmd, char *word, int type)
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;
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");
283 fn = m->shower;
284 (*fn)(cmd, show_or);
285 return 1;
291 return 0;
294 void
295 help(void)
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);
316 void
317 rule_delete(int ac, char *av[])
319 int error, rulenum;
321 NEXT_ARG;
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)");
329 NEXT_ARG;
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.
338 ipfw_insn*
339 next_cmd(ipfw_insn *cmd)
341 cmd += F_LEN(cmd);
342 bzero(cmd, sizeof(*cmd));
343 return cmd;
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.
353 void
354 rule_add(int ac, char *av[])
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[].
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];
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;
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));
382 rule = (struct ipfw_ioc_rule *)rulebuf;
383 cmd = (ipfw_insn *)cmdbuf;
384 action = (ipfw_insn *)actbuf;
385 other = (ipfw_insn *)othbuf;
387 NEED2("need more parameters");
388 NEXT_ARG;
390 /* [rule N] -- Rule number optional */
391 if (ac && isdigit(**av)) {
392 rule->rulenum = atoi(*av);
393 NEXT_ARG;
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;
406 * parse before
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;
422 break;
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;
433 other = next_cmd(other);
438 * parse actions
440 * only accept 1 action
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;
456 break;
459 if (F_LEN(action) > 0)
460 action = next_cmd(action);
463 * parse protocol
465 if (strcmp(*av, "proto") == 0){
466 NEXT_ARG;
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;
483 break;
486 if (F_LEN(cmd) > 0)
487 cmd = next_cmd(cmd);
490 * other filters
492 while (ac > 0) {
493 char *s, *cur; /* current filter */
494 ipfw_insn_u32 *cmd32; /* alias for cmd */
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;
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;
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;
530 break;
531 } else if (i == KEYWORD_SIZE - 1) {
532 errx(EX_USAGE, "bad command `%s'", cur);
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);
544 done:
545 if (ac>0)
546 errx(EX_USAGE, "bad command `%s'", *av);
549 * Now copy stuff into the rule.
550 * [filters][others][action][comment]
552 dst = (ipfw_insn *)rule->cmd;
554 * copy all filters, except comment
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);
570 * start action section, it begin with others
572 rule->act_ofs = (uint32_t *)dst - (uint32_t *)(rule->cmd);
575 * copy all other others
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);
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);
590 * comment place behind the action
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);
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");
603 if (!do_quiet)
604 rule_show(rule, 10, 10);
607 void
608 rule_zero(int ac, char *av[])
610 int rulenum;
611 int failed = EX_OK;
613 NEXT_ARG;
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;
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);
638 if (failed != EX_OK)
639 exit(failed);
642 void
643 rule_flush(void)
645 int cmd = IP_FW_FLUSH;
646 if (do_pipe) {
647 cmd = IP_DUMMYNET_FLUSH;
649 if (!do_force) {
650 int c;
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;
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");
669 if (!do_quiet) {
670 printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules");
674 void
675 rule_list(int ac, char *av[])
677 struct ipfw_ioc_rule *rule;
679 void *data = NULL;
680 int bcwidth, nbytes, pcwidth, width;
681 int nalloc = 1024;
682 int the_rule_num = 0;
683 int total_len;
685 NEXT_ARG;
687 /* get rules or pipes from kernel, resizing array as necessary */
688 nbytes = nalloc;
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)");
700 * Count static rules.
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;
712 /* byte counter */
713 width = snprintf(NULL, 0, "%ju", (uintmax_t)rule->bcnt);
714 if (width > bcwidth)
715 bcwidth = width;
717 total_len += IOC_RULESIZE(rule);
718 if (total_len == nbytes) {
719 break;
725 if (ac == 1) {
726 the_rule_num = atoi(*av);
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);
734 total_len += IOC_RULESIZE(rule);
735 if (total_len == nbytes) {
736 break;
742 void
743 rule_show(struct ipfw_ioc_rule *rule, int pcwidth, int bcwidth)
745 static int twidth = 0;
746 ipfw_insn *cmd;
747 int l;
749 u_int32_t set_disable = rule->sets;
751 if (set_disable & (1 << rule->set)) { /* disabled */
752 if (!show_sets)
753 return;
754 else
755 printf("# DISABLED ");
757 if (do_compact) {
758 printf("%u", rule->rulenum);
759 } else {
760 printf("%05u", rule->rulenum);
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);
773 if (do_time == 1) {
774 char timestr[30];
776 if (twidth == 0) {
777 strcpy(timestr, ctime((time_t *)&twidth));
778 *strchr(timestr, '\n') = '\0';
779 twidth = strlen(timestr);
781 if (rule->timestamp) {
782 time_t t = _long_to_time(rule->timestamp);
784 strcpy(timestr, ctime(&t));
785 *strchr(timestr, '\n') = '\0';
786 printf(" %s", timestr);
787 } else {
788 printf(" %*s", twidth, " ");
790 } else if (do_time == 2) {
791 printf( " %10u", rule->timestamp);
794 if (show_sets)
795 printf(" set %d", rule->set);
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;
805 * show others and actions
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);
826 if (cmd->module == MODULE_BASIC_ID &&
827 cmd->opcode ==
828 O_BASIC_CHECK_STATE) {
829 goto done;
831 break;
834 break;
840 * show proto
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);
847 if (!changed && !do_quiet)
848 printf(" ip");
851 * show from
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);
858 if (!changed && !do_quiet)
859 printf(" from any");
862 * show to
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);
869 if (!changed && !do_quiet)
870 printf(" to any");
873 * show other filters
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));
884 /* show the comment in the end */
885 if (comment_fn != NULL) {
886 (*comment_fn)(comment_cmd, 0);
888 done:
889 printf("\n");
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.
898 do_set_x(int optname, void *rule, int optlen)
900 int len, *newbuf, retval;
901 ip_fw_x_header *x_header;
903 if (fw3_socket < 0)
904 err(EX_UNAVAILABLE, "socket not avaialble");
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");
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;
922 * same as do_set_x
925 do_get_x(int optname, void *rule, int *optlen)
927 int len, *newbuf, retval;
928 ip_fw_x_header *x_header;
930 if (fw3_socket < 0)
931 err(EX_UNAVAILABLE, "socket not avaialble");
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");
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;
951 ipfw3_main(int ac, char **av)
953 int ch;
955 if (ac == 1)
956 help();
958 /* Set the force flag for non-interactive processes */
959 do_force = !isatty(STDIN_FILENO);
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 */
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();
1000 ac -= optind;
1001 av += optind;
1002 NEED1("bad arguments, for usage summary ``ipfw3''");
1005 * optional: pipe or queue or nat
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;
1016 NEED1("missing command");
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.
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;
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);
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;
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);
1081 return 0;
1084 void
1085 ipfw3_readfile(int ac, char *av[])
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;
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;
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;
1115 case 'p':
1116 pflag = 1;
1117 cmd = optarg;
1118 args[0] = cmd;
1119 i = 1;
1120 break;
1122 case 'q':
1123 qflag = 1;
1124 break;
1126 default:
1127 errx(EX_USAGE, "bad arguments, for usage"
1128 " summary ``ipfw''");
1132 av += optind;
1133 ac -= optind;
1134 if (ac != 1)
1135 errx(EX_USAGE, "extraneous filename arguments");
1137 if ((f = fopen(av[0], "r")) == NULL)
1138 err(EX_UNAVAILABLE, "fopen: %s", av[0]);
1140 if (pflag) {
1141 /* pipe through preprocessor (cpp or m4) */
1142 int pipedes[2];
1144 args[i] = NULL;
1146 if (pipe(pipedes) == -1)
1147 err(EX_OSERR, "cannot create pipe");
1149 switch ((preproc = fork())) {
1150 case -1:
1151 err(EX_OSERR, "cannot fork");
1153 case 0:
1154 /* child */
1155 if (dup2(fileno(f), 0) == -1 ||
1156 dup2(pipedes[1], 1) == -1) {
1157 err(EX_OSERR, "dup2()");
1159 fclose(f);
1160 close(pipedes[1]);
1161 close(pipedes[0]);
1162 execvp(cmd, args);
1163 err(EX_OSERR, "execvp(%s) failed", cmd);
1165 default:
1166 /* parent */
1167 fclose(f);
1168 close(pipedes[1]);
1169 if ((f = fdopen(pipedes[0], "r")) == NULL) {
1170 int savederrno = errno;
1172 kill(preproc, SIGTERM);
1173 errno = savederrno;
1174 err(EX_OSERR, "fdopen()");
1179 while (fgets(buf, BUFSIZ, f)) {
1180 lineno++;
1181 sprintf(linename, "Line %d", lineno);
1182 args[0] = linename;
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;
1196 if (i == (qflag? 2: 1))
1197 continue;
1198 if (i == MAX_ARGS)
1199 errx(EX_USAGE, "%s: too many arguments", linename);
1201 args[i] = NULL;
1202 ipfw3_main(i, args);
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));
1218 main(int ac, char *av[])
1220 fw3_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
1221 if (fw3_socket < 0)
1222 err(EX_UNAVAILABLE, "socket");
1224 memset(keywords, 0, LEN_FW3_KEYWORD * KEYWORD_SIZE);
1225 memset(mappings, 0, LEN_FW3_MAPPING * MAPPING_SIZE);
1227 prepare_default_funcs();
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;