2 * Copyright (c) 2014 - 2016 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>
28 #include <sys/socket.h>
29 #include <sys/sockio.h>
30 #include <sys/sysctl.h>
34 #include <arpa/inet.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>
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/ip_fw3_table.h>
65 #include <net/ipfw3/ip_fw3_sync.h>
66 #include <net/dummynet3/ip_dummynet3.h>
67 #include <net/ipfw3_basic/ip_fw3_basic.h>
68 #include <net/ipfw3_nat/ip_fw3_nat.h>
71 #include "ipfw3sync.h"
75 #define KEYWORD_SIZE 256
76 #define MAPPING_SIZE 256
78 #define MAX_KEYWORD_LEN 20
80 #define WHITESP " \t\f\v\n\r"
81 #define IPFW_LIB_PATH "/usr/lib/libipfw3%s.so"
82 #define IP_MASK_ALL 0xffffffff
84 * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines
85 * This is only used in this code.
87 #define IPPROTO_ETHERTYPE 0x1000
90 * show_rules() prints the body of an ipfw rule.
91 * Because the standard rule has at least proto src_ip dst_ip, we use
92 * a helper function to produce these entries if not provided explicitly.
93 * The first argument is the list of fields we have, the second is
94 * the list of fields we want to be printed.
96 * Special cases if we have provided a MAC header:
97 * + if the rule does not contain IP addresses/ports, do not print them;
98 * + if the rule does not contain an IP proto, print "all" instead of "ip";
101 #define HAVE_PROTO 0x0001
102 #define HAVE_SRCIP 0x0002
103 #define HAVE_DSTIP 0x0004
104 #define HAVE_MAC 0x0008
105 #define HAVE_MACTYPE 0x0010
106 #define HAVE_OPTIONS 0x8000
108 #define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP)
111 int ipfw_socket = -1; /* main RAW socket */
112 int do_resolv, /* Would try to resolve all */
113 do_acct, /* Show packet/byte count */
114 do_time, /* Show time stamps */
115 do_quiet = 1, /* Be quiet , default is quiet*/
116 do_force, /* Don't ask for confirmation */
117 do_pipe, /* this cmd refers to a pipe */
118 do_nat, /* Nat configuration. */
119 do_sort, /* field to sort results (0 = no) */
120 do_dynamic, /* display dynamic rules */
121 do_expired, /* display expired dynamic rules */
122 do_compact, /* show rules in compact mode */
123 show_sets, /* display rule sets */
126 struct char_int_map dummynet_params[] = {
128 { "noerror", TOK_NOERROR },
129 { "buckets", TOK_BUCKETS },
130 { "dst-ip", TOK_DSTIP },
131 { "src-ip", TOK_SRCIP },
132 { "dst-port", TOK_DSTPORT },
133 { "src-port", TOK_SRCPORT },
134 { "proto", TOK_PROTO },
135 { "weight", TOK_WEIGHT },
137 { "mask", TOK_MASK },
138 { "droptail", TOK_DROPTAIL },
140 { "gred", TOK_GRED },
142 { "bandwidth", TOK_BW },
143 { "delay", TOK_DELAY },
144 { "pipe", TOK_PIPE },
145 { "queue", TOK_QUEUE },
146 { "dummynet-params", TOK_NULL },
150 struct ipfw_keyword {
152 char word[MAX_KEYWORD_LEN];
157 struct ipfw_mapping {
165 struct ipfw_keyword keywords[KEYWORD_SIZE];
166 struct ipfw_mapping mappings[MAPPING_SIZE];
169 match_token(struct char_int_map *table, char *string)
172 if (strcmp(table->key, string) == 0) {
181 get_modules(char *modules_str, int len)
183 if (do_get_x(IP_FW_MODULE, modules_str, &len) < 0)
184 errx(EX_USAGE, "ipfw3 not loaded.");
188 list_modules(int ac, char *av[])
190 void *module_str = NULL;
192 if ((module_str = realloc(module_str, len)) == NULL)
193 err(EX_OSERR, "realloc");
195 get_modules(module_str, len);
196 printf("%s\n", (char *)module_str);
199 parse_accept(ipfw_insn **cmd, int *ac, char **av[])
201 (*cmd)->opcode = O_BASIC_ACCEPT;
202 (*cmd)->module = MODULE_BASIC_ID;
203 (*cmd)->len = (*cmd)->len|LEN_OF_IPFWINSN;
205 if (!strncmp(**av, "log", strlen(**av))) {
208 if (isdigit(***av)) {
209 (*cmd)->arg1 = strtoul(**av, NULL, 10);
216 parse_deny(ipfw_insn **cmd, int *ac, char **av[])
218 (*cmd)->opcode = O_BASIC_DENY;
219 (*cmd)->module = MODULE_BASIC_ID;
220 (*cmd)->len = (*cmd)->len|LEN_OF_IPFWINSN;
222 if (!strncmp(**av, "log", strlen(**av))) {
225 if (isdigit(***av)) {
226 (*cmd)->arg1 = strtoul(**av, NULL, 10);
233 show_accept(ipfw_insn *cmd, int show_or)
237 printf(" log %d", cmd->arg1);
242 show_deny(ipfw_insn *cmd, int show_or)
246 printf(" log %d", cmd->arg1);
254 init_module mod_init_func;
256 char module_lib_file[50];
257 void *module_str = NULL;
260 if ((module_str = realloc(module_str, len)) == NULL)
261 err(EX_OSERR, "realloc");
263 get_modules(module_str, len);
265 const char s[2] = ",";
267 token = strtok(module_str, s);
268 while (token != NULL) {
269 sprintf(module_lib_file, IPFW_LIB_PATH, token);
270 token = strtok(NULL, s);
271 module_lib = dlopen(module_lib_file, RTLD_LAZY);
273 fprintf(stderr, "Couldn't open %s: %s\n",
274 module_lib_file, dlerror());
277 mod_init_func = dlsym(module_lib, "load_module");
278 if ((error = dlerror()))
280 fprintf(stderr, "Couldn't find init function: %s\n", error);
283 (*mod_init_func)((register_func)register_ipfw_func,
284 (register_keyword)register_ipfw_keyword);
289 prepare_default_funcs(void)
292 register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_ACCEPT, "allow", ACTION);
293 register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_ACCEPT, "accept", ACTION);
294 register_ipfw_func(MODULE_BASIC_ID, O_BASIC_ACCEPT,
295 (parser_func)parse_accept, (shower_func)show_accept);
297 register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_DENY, "deny", ACTION);
298 register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_DENY, "reject", ACTION);
299 register_ipfw_func(MODULE_BASIC_ID, O_BASIC_DENY,
300 (parser_func)parse_deny, (shower_func)show_deny);
304 register_ipfw_keyword(int module, int opcode, char *word, int type)
306 struct ipfw_keyword *tmp;
310 if (tmp->type == NONE) {
311 strcpy(tmp->word, word);
312 tmp->module = module;
313 tmp->opcode = opcode;
317 if (strcmp(tmp->word, word) == 0)
318 errx(EX_USAGE, "keyword `%s' exists", word);
326 register_ipfw_func(int module, int opcode, parser_func parser, shower_func shower)
328 struct ipfw_mapping *tmp;
332 if (tmp->type == NONE) {
333 tmp->module = module;
334 tmp->opcode = opcode;
335 tmp->parser = parser;
336 tmp->shower = shower;
340 if (tmp->opcode == opcode && tmp->module == module) {
341 errx(EX_USAGE, "func `%d' of module `%d' exists",
352 * this func need to check whether 'or' need to be printed,
353 * when the filter is the first filter with 'or' when dont print
354 * when not first and same as previous, then print or and no filter name
355 * when not first but different from previous, print name without 'or'
356 * show_or = 1: show or and ignore filter name
357 * show_or = 0: show filter name ignore or
359 void prev_show_chk(ipfw_insn *cmd, uint8_t *prev_module, uint8_t *prev_opcode,
362 if (cmd->len & F_OR) {
363 if (*prev_module == 0 && *prev_opcode == 0) {
364 /* first cmd with 'or' flag */
366 *prev_module = cmd->module;
367 *prev_opcode = cmd->opcode;
368 } else if (cmd->module == *prev_module &&
369 cmd->opcode == *prev_opcode) {
370 /* cmd same as previous, same module and opcode */
373 /* cmd different from prev*/
375 *prev_module = cmd->module;
376 *prev_opcode = cmd->opcode;
387 * word can be: proto from to other
391 * other show all other filters
393 int show_filter(ipfw_insn *cmd, char *word, int type)
395 struct ipfw_keyword *k;
396 struct ipfw_mapping *m;
399 uint8_t prev_module, prev_opcode;
403 for (i = 1; i < KEYWORD_SIZE; i++, k++) {
404 if (k->type == type) {
405 if (k->module == cmd->module &&
406 k->opcode == cmd->opcode) {
407 for (j = 1; j < MAPPING_SIZE; j++, m++) {
408 if (m->type == IN_USE &&
409 k->module == m->module &&
410 k->opcode == m->opcode) {
411 prev_show_chk(cmd, &prev_module,
412 &prev_opcode, &show_or);
413 if (cmd->len & F_NOT)
428 show_rules(struct ipfw_ioc_rule *rule, int pcwidth, int bcwidth)
430 static int twidth = 0;
434 u_int32_t set_disable = rule->set_disable;
436 if (set_disable & (1 << rule->set)) { /* disabled */
440 printf("# DISABLED ");
442 printf("%05u ", rule->rulenum);
445 printf("%*ju %*ju ", pcwidth, (uintmax_t)rule->pcnt, bcwidth,
446 (uintmax_t)rule->bcnt);
452 strcpy(timestr, ctime((time_t *)&twidth));
453 *strchr(timestr, '\n') = '\0';
454 twidth = strlen(timestr);
456 if (rule->timestamp) {
457 time_t t = _long_to_time(rule->timestamp);
459 strcpy(timestr, ctime(&t));
460 *strchr(timestr, '\n') = '\0';
461 printf("%s ", timestr);
463 printf("%*s ", twidth, " ");
465 } else if (do_time == 2) {
466 printf( "%10u ", rule->timestamp);
470 printf("set %d ", rule->set);
473 struct ipfw_keyword *k;
474 struct ipfw_mapping *m;
475 shower_func fn, comment_fn = NULL;
476 ipfw_insn *comment_cmd;
480 * show others and actions
482 for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule);
483 l > 0; l -= F_LEN(cmd),
484 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
487 for (i = 1; i< KEYWORD_SIZE; i++, k++) {
488 if ( k->module == cmd->module && k->opcode == cmd->opcode ) {
489 for (j = 1; j< MAPPING_SIZE; j++, m++) {
490 if (m->type == IN_USE &&
491 m->module == cmd->module &&
492 m->opcode == cmd->opcode) {
493 if (cmd->module == MODULE_BASIC_ID &&
494 cmd->opcode == O_BASIC_COMMENT) {
495 comment_fn = m->shower;
501 if (cmd->module == MODULE_BASIC_ID &&
503 O_BASIC_CHECK_STATE) {
518 for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd),
519 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
520 changed = show_filter(cmd, "proto", PROTO);
522 if (!changed && !do_quiet)
529 for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd),
530 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
531 changed = show_filter(cmd, "from", FROM);
533 if (!changed && !do_quiet)
540 for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd),
541 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
542 changed = show_filter(cmd, "to", TO);
544 if (!changed && !do_quiet)
550 for (l = rule->act_ofs, cmd = rule->cmd, m = mappings;
551 l > 0; l -= F_LEN(cmd),
552 cmd=(ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
553 show_filter(cmd, "other", FILTER);
556 /* show the comment in the end */
557 if (comment_fn != NULL) {
558 (*comment_fn)(comment_cmd, 0);
565 show_states(struct ipfw_ioc_state *d, int pcwidth, int bcwidth)
570 printf("%05u ", d->rulenum);
572 printf("%*ju %*ju ", pcwidth, (uintmax_t)d->pcnt,
573 bcwidth, (uintmax_t)d->bcnt);
577 /* state->timestamp */
579 time_t t = _long_to_time(d->timestamp);
580 strcpy(timestr, ctime(&t));
581 *strchr(timestr, '\n') = '\0';
582 printf(" (%s", timestr);
584 /* state->lifetime */
585 printf(" %ds", d->lifetime);
589 t = _long_to_time(d->expiry);
590 strcpy(timestr, ctime(&t));
591 *strchr(timestr, '\n') = '\0';
592 printf(" %s)", timestr);
597 } else if (do_time == 2) {
598 printf("(%u %ds %u) ", d->timestamp, d->lifetime, d->expiry);
601 if ((pe = getprotobynumber(d->flow_id.proto)) != NULL)
602 printf(" %s", pe->p_name);
604 printf(" proto %u", d->flow_id.proto);
606 a.s_addr = htonl(d->flow_id.src_ip);
607 printf(" %s %d", inet_ntoa(a), d->flow_id.src_port);
609 a.s_addr = htonl(d->flow_id.dst_ip);
610 printf(" <-> %s %d", inet_ntoa(a), d->flow_id.dst_port);
611 printf(" CPU %d", d->cpuid);
616 sort_q(const void *pa, const void *pb)
618 int rev = (do_sort < 0);
619 int field = rev ? -do_sort : do_sort;
621 const struct dn_ioc_flowqueue *a = pa;
622 const struct dn_ioc_flowqueue *b = pb;
626 res = a->len - b->len;
629 res = a->len_bytes - b->len_bytes;
632 case 3: /* tot pkts */
633 res = a->tot_pkts - b->tot_pkts;
636 case 4: /* tot bytes */
637 res = a->tot_bytes - b->tot_bytes;
644 return (int)(rev ? res : -res);
648 show_queues(struct dn_ioc_flowset *fs, struct dn_ioc_flowqueue *q)
652 printf("mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
653 fs->flow_mask.u.ip.proto,
654 fs->flow_mask.u.ip.src_ip, fs->flow_mask.u.ip.src_port,
655 fs->flow_mask.u.ip.dst_ip, fs->flow_mask.u.ip.dst_port);
656 if (fs->rq_elements == 0)
659 printf("BKT Prot ___Source IP/port____ "
660 "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
662 heapsort(q, fs->rq_elements, sizeof(*q), sort_q);
663 for (l = 0; l < fs->rq_elements; l++) {
667 ina.s_addr = htonl(q[l].id.u.ip.src_ip);
668 printf("%3d ", q[l].hash_slot);
669 pe = getprotobynumber(q[l].id.u.ip.proto);
671 printf("%-4s ", pe->p_name);
673 printf("%4u ", q[l].id.u.ip.proto);
675 inet_ntoa(ina), q[l].id.u.ip.src_port);
676 ina.s_addr = htonl(q[l].id.u.ip.dst_ip);
678 inet_ntoa(ina), q[l].id.u.ip.dst_port);
679 printf("%4ju %8ju %2u %4u %3u\n",
680 (uintmax_t)q[l].tot_pkts, (uintmax_t)q[l].tot_bytes,
681 q[l].len, q[l].len_bytes, q[l].drops);
683 printf(" S %20ju F %20ju\n",
684 (uintmax_t)q[l].S, (uintmax_t)q[l].F);
689 show_flowset_parms(struct dn_ioc_flowset *fs, char *prefix)
693 char red[90]; /* Display RED parameters */
697 if (fs->flags_fs & DN_QSIZE_IS_BYTES) {
699 sprintf(qs, "%d KB", l / 1024);
701 sprintf(qs, "%d B", l);
703 sprintf(qs, "%3d sl.", l);
705 sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff));
708 if (fs->flags_fs & DN_IS_RED) /* RED parameters */
710 "\n\t %cRED w_q %f min_th %d max_th %d max_p %f",
711 (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ',
712 1.0 * fs->w_q / (double)(1 << SCALE_RED),
713 SCALE_VAL(fs->min_th),
714 SCALE_VAL(fs->max_th),
715 1.0 * fs->max_p / (double)(1 << SCALE_RED));
717 sprintf(red, "droptail");
719 printf("%s %s%s %d queues (%d buckets) %s\n",
720 prefix, qs, plr, fs->rq_elements, fs->rq_size, red);
724 show_pipes(void *data, int nbytes, int ac, char *av[])
728 struct dn_ioc_pipe *p = (struct dn_ioc_pipe *)data;
729 struct dn_ioc_flowset *fs;
730 struct dn_ioc_flowqueue *q;
734 rulenum = strtoul(*av++, NULL, 10);
737 for (; nbytes >= sizeof(*p); p = (struct dn_ioc_pipe *)next) {
738 double b = p->bandwidth;
742 if (p->fs.fs_type != DN_IS_PIPE)
743 break; /* done with pipes, now queues */
746 * compute length, as pipe have variable size
748 l = sizeof(*p) + p->fs.rq_elements * sizeof(*q);
749 next = (void *)p + l;
752 if (rulenum != 0 && rulenum != p->pipe_nr)
759 sprintf(buf, "unlimited");
760 else if (b >= 1000000)
761 sprintf(buf, "%7.3f Mbit/s", b/1000000);
763 sprintf(buf, "%7.3f Kbit/s", b/1000);
765 sprintf(buf, "%7.3f bit/s ", b);
767 sprintf(prefix, "%05d: %s %4d ms ",
768 p->pipe_nr, buf, p->delay);
769 show_flowset_parms(&p->fs, prefix);
771 printf(" V %20ju\n", (uintmax_t)p->V >> MY_M);
773 q = (struct dn_ioc_flowqueue *)(p+1);
774 show_queues(&p->fs, q);
777 for (fs = next; nbytes >= sizeof(*fs); fs = next) {
780 if (fs->fs_type != DN_IS_QUEUE)
782 l = sizeof(*fs) + fs->rq_elements * sizeof(*q);
783 next = (void *)fs + l;
785 q = (struct dn_ioc_flowqueue *)(fs+1);
786 sprintf(prefix, "q%05d: weight %d pipe %d ",
787 fs->fs_nr, fs->weight, fs->parent_nr);
788 show_flowset_parms(fs, prefix);
794 * This one handles all set-related commands
795 * ipfw set { show | enable | disable }
797 * ipfw set move X to Y
798 * ipfw set move rule X to Y
801 sets_handler(int ac, char *av[])
803 u_int32_t set_disable, masks[2];
805 u_int8_t cmd, new_set;
810 errx(EX_USAGE, "set needs command");
811 if (!strncmp(*av, "show", strlen(*av)) ) {
817 while (nbytes >= nalloc) {
818 nalloc = nalloc * 2+321;
821 if ((data = malloc(nbytes)) == NULL) {
822 err(EX_OSERR, "malloc");
824 } else if ((data = realloc(data, nbytes)) == NULL) {
825 err(EX_OSERR, "realloc");
827 if (do_get_x(IP_FW_GET, data, &nbytes) < 0) {
828 err(EX_OSERR, "getsockopt(IP_FW_GET)");
831 set_disable = ((struct ipfw_ioc_rule *)data)->set_disable;
832 for (i = 0, msg = "disable" ; i < 31; i++)
833 if ( (set_disable & (1<<i))) {
834 printf("%s %d", msg, i);
837 msg = (set_disable) ? " enable" : "enable";
838 for (i = 0; i < 31; i++)
839 if ( !(set_disable & (1<<i))) {
840 printf("%s %d", msg, i);
844 } else if (!strncmp(*av, "swap", strlen(*av))) {
847 errx(EX_USAGE, "set swap needs 2 set numbers\n");
848 rulenum = atoi(av[0]);
849 new_set = atoi(av[1]);
850 if (!isdigit(*(av[0])) || rulenum > 30)
851 errx(EX_DATAERR, "invalid set number %s\n", av[0]);
852 if (!isdigit(*(av[1])) || new_set > 30)
853 errx(EX_DATAERR, "invalid set number %s\n", av[1]);
854 masks[0] = (4 << 24) | (new_set << 16) | (rulenum);
855 i = do_set_x(IP_FW_DEL, masks, sizeof(u_int32_t));
856 } else if (!strncmp(*av, "move", strlen(*av))) {
858 if (ac && !strncmp(*av, "rule", strlen(*av))) {
863 if (ac != 3 || strncmp(av[1], "to", strlen(*av)))
864 errx(EX_USAGE, "syntax: set move [rule] X to Y\n");
865 rulenum = atoi(av[0]);
866 new_set = atoi(av[2]);
867 if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > 30) ||
868 (cmd == 2 && rulenum == 65535) )
869 errx(EX_DATAERR, "invalid source number %s\n", av[0]);
870 if (!isdigit(*(av[2])) || new_set > 30)
871 errx(EX_DATAERR, "invalid dest. set %s\n", av[1]);
872 masks[0] = (cmd << 24) | (new_set << 16) | (rulenum);
873 i = do_set_x(IP_FW_DEL, masks, sizeof(u_int32_t));
874 } else if (!strncmp(*av, "disable", strlen(*av)) ||
875 !strncmp(*av, "enable", strlen(*av)) ) {
876 int which = !strncmp(*av, "enable", strlen(*av)) ? 1 : 0;
879 masks[0] = masks[1] = 0;
885 errx(EX_DATAERR, "invalid set number %d\n", i);
886 masks[which] |= (1<<i);
887 } else if (!strncmp(*av, "disable", strlen(*av)))
889 else if (!strncmp(*av, "enable", strlen(*av)))
892 errx(EX_DATAERR, "invalid set command %s\n", *av);
895 if ( (masks[0] & masks[1]) != 0 )
896 errx(EX_DATAERR, "cannot enable and disable the same set\n");
897 i = do_set_x(IP_FW_DEL, masks, sizeof(masks));
899 warn("set enable/disable: setsockopt(IP_FW_DEL)");
901 errx(EX_USAGE, "invalid set command %s\n", *av);
905 add_state(int ac, char *av[])
907 struct ipfw_ioc_state ioc_state;
908 ioc_state.expiry = 0;
909 ioc_state.lifetime = 0;
911 if (strcmp(*av, "rulenum") == 0) {
913 ioc_state.rulenum = atoi(*av);
915 errx(EX_USAGE, "ipfw state add rule");
919 pe = getprotobyname(*av);
920 ioc_state.flow_id.proto = pe->p_proto;
923 ioc_state.flow_id.src_ip = inet_addr(*av);
926 ioc_state.flow_id.src_port = atoi(*av);
929 ioc_state.flow_id.dst_ip = inet_addr(*av);
932 ioc_state.flow_id.dst_port = atoi(*av);
935 if (strcmp(*av, "live") == 0) {
937 ioc_state.lifetime = atoi(*av);
941 if (strcmp(*av, "expiry") == 0) {
943 ioc_state.expiry = strtoul(*av, NULL, 10);
944 printf("ioc_state.expiry=%d\n", ioc_state.expiry);
947 if (do_set_x(IP_FW_STATE_ADD, &ioc_state, sizeof(struct ipfw_ioc_state)) < 0 ) {
948 err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_ADD)");
951 printf("Flushed all states.\n");
956 delete_state(int ac, char *av[])
960 if (ac == 1 && isdigit(**av))
962 if (do_set_x(IP_FW_STATE_DEL, &rulenum, sizeof(int)) < 0 )
963 err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_DEL)");
965 printf("Flushed all states.\n");
969 flush_state(int ac, char *av[])
974 printf("Are you sure? [yn] ");
977 c = toupper(getc(stdin));
978 while (c != '\n' && getc(stdin) != '\n')
980 return; /* and do not flush */
981 } while (c != 'Y' && c != 'N');
982 if (c == 'N') /* user said no */
985 if (do_set_x(IP_FW_STATE_FLUSH, NULL, 0) < 0 )
986 err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_FLUSH)");
988 printf("Flushed all states.\n");
992 lookup_host (char *host, struct in_addr *ipaddr)
996 if (!inet_aton(host, ipaddr)) {
997 if ((he = gethostbyname(host)) == NULL)
999 *ipaddr = *(struct in_addr *)he->h_addr_list[0];
1005 table_append(int ac, char *av[])
1007 struct ipfw_ioc_table tbl;
1015 errx(EX_USAGE, "table id `%s' invalid", *av);
1017 if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
1018 errx(EX_USAGE, "table id `%d' invalid", tbl.id);
1021 if (strcmp(*av, "ip") == 0)
1023 else if (strcmp(*av, "mac") == 0)
1026 errx(EX_USAGE, "table type `%s' not supported", *av);
1029 if (tbl.type == 1) { /* table type ipv4 */
1030 struct ipfw_ioc_table_ip_entry ip_ent;
1032 errx(EX_USAGE, "IP address required");
1034 p = strchr(*av, '/');
1037 ip_ent.masklen = atoi(p);
1038 if (ip_ent.masklen > 32)
1039 errx(EX_DATAERR, "bad width ``%s''", p);
1041 ip_ent.masklen = 32;
1044 if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
1045 errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
1047 tbl.ip_ent[0] = ip_ent;
1048 size = sizeof(tbl) + sizeof(ip_ent);
1049 } else if (tbl.type == 2) { /* table type mac */
1050 struct ipfw_ioc_table_mac_entry mac_ent;
1052 errx(EX_USAGE, "MAC address required");
1054 mac_ent.addr = *ether_aton(*av);
1055 tbl.mac_ent[0] = mac_ent;
1056 size = sizeof(tbl) + sizeof(mac_ent);
1058 if (do_set_x(IP_FW_TABLE_APPEND, &tbl, size) < 0 )
1059 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_APPEND) "
1060 "table `%d' append `%s' failed", tbl.id, *av);
1064 table_remove(int ac, char *av[])
1066 struct ipfw_ioc_table tbl;
1067 struct ipfw_ioc_table_ip_entry ip_ent;
1075 errx(EX_USAGE, "table id `%s' invalid", *av);
1077 if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
1078 errx(EX_USAGE, "table id `%d' invalid", tbl.id);
1081 if (strcmp(*av, "ip") == 0)
1083 else if (strcmp(*av, "mac") == 0)
1086 errx(EX_USAGE, "table type `%s' not supported", *av);
1090 errx(EX_USAGE, "IP address required");
1091 p = strchr(*av, '/');
1094 ip_ent.masklen = atoi(p);
1095 if (ip_ent.masklen > 32)
1096 errx(EX_DATAERR, "bad width ``%s''", p);
1098 ip_ent.masklen = 32;
1101 if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
1102 errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
1104 tbl.ip_ent[0] = ip_ent;
1105 size = sizeof(tbl) + sizeof(ip_ent);
1106 if (do_set_x(IP_FW_TABLE_REMOVE, &tbl, size) < 0 ) {
1107 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_REMOVE) "
1108 "table `%d' append `%s' failed", tbl.id, *av);
1113 table_flush(int ac, char *av[])
1115 struct ipfw_ioc_table ioc_table;
1116 struct ipfw_ioc_table *t = &ioc_table;
1119 if (isdigit(**av)) {
1121 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1122 errx(EX_USAGE, "table id `%d' invalid", t->id);
1124 errx(EX_USAGE, "table id `%s' invalid", *av);
1126 if (do_set_x(IP_FW_TABLE_FLUSH, t, sizeof(struct ipfw_ioc_table)) < 0 )
1127 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_FLUSH) "
1128 "table `%s' flush failed", *av);
1132 table_list(int ac, char *av[])
1134 struct ipfw_ioc_table *ioc_table;
1135 int i, count, nbytes, nalloc = 1024;
1138 if (strcmp(*av, "list") == 0) {
1140 while (nbytes >= nalloc) {
1141 nalloc = nalloc * 2 ;
1143 if ((data = realloc(data, nbytes)) == NULL)
1144 err(EX_OSERR, "realloc");
1145 if (do_get_x(IP_FW_TABLE_LIST, data, &nbytes) < 0)
1146 err(EX_OSERR, "do_get_x(IP_FW_TABLE_LIST)");
1148 ioc_table = (struct ipfw_ioc_table *)data;
1149 count = nbytes / sizeof(struct ipfw_ioc_table);
1150 for (i = 0; i < count; i++, ioc_table++) {
1151 if (ioc_table->type > 0) {
1152 printf("table %d",ioc_table->id);
1153 if (ioc_table->type == 1)
1155 else if (ioc_table->type == 2)
1156 printf(" type mac");
1157 printf(" count %d",ioc_table->count);
1158 if (strlen(ioc_table->name) > 0)
1159 printf(" name %s",ioc_table->name);
1165 errx(EX_USAGE, "ipfw3 table `%s' delete invalid", *av);
1170 print_table(struct ipfw_ioc_table * tbl)
1174 errx(EX_USAGE, "table %d is not in use", tbl->id);
1176 printf("table %d", tbl->id);
1179 else if (tbl->type == 2)
1180 printf(" type mac");
1182 printf(" count %d", tbl->count);
1183 if (strlen(tbl->name) > 0)
1184 printf(" name %s", tbl->name);
1188 if (tbl->type == 1) {
1189 struct ipfw_ioc_table_ip_entry *ip_ent;
1190 ip_ent = tbl->ip_ent;
1191 for (i = 0; i < tbl->count; i++) {
1192 printf("%s", inet_ntoa(*(struct in_addr *)&ip_ent->addr));
1193 printf("/%d ", ip_ent->masklen);
1197 } else if (tbl->type == 2) {
1198 struct ipfw_ioc_table_mac_entry *mac_ent;
1199 mac_ent = tbl->mac_ent;
1200 for (i = 0; i < tbl->count; i++) {
1201 printf("%s", ether_ntoa(&mac_ent->addr));
1209 table_show(int ac, char *av[])
1211 int nbytes, nalloc = 1024;
1214 if (isdigit(**av)) {
1216 while (nbytes >= nalloc) {
1217 nalloc = nalloc * 2 + 256;
1220 if ((data = malloc(nbytes)) == NULL) {
1221 err(EX_OSERR, "malloc");
1223 } else if ((data = realloc(data, nbytes)) == NULL) {
1224 err(EX_OSERR, "realloc");
1226 /* store table id in the header of data */
1227 int *head = (int *)data;
1229 if (*head < 0 || *head > IPFW_TABLES_MAX - 1)
1230 errx(EX_USAGE, "table id `%d' invalid", *head);
1231 if (do_get_x(IP_FW_TABLE_SHOW, data, &nbytes) < 0)
1232 err(EX_OSERR, "do_get_x(IP_FW_TABLE_LIST)");
1233 struct ipfw_ioc_table *tbl;
1234 tbl = (struct ipfw_ioc_table *)data;
1238 errx(EX_USAGE, "ipfw3 table `%s' show invalid", *av);
1243 table_create(int ac, char *av[])
1245 struct ipfw_ioc_table ioc_table;
1246 struct ipfw_ioc_table *t = &ioc_table;
1250 errx(EX_USAGE, "table parameters invalid");
1251 if (isdigit(**av)) {
1253 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1254 errx(EX_USAGE, "table id `%d' invalid", t->id);
1256 errx(EX_USAGE, "table id `%s' invalid", *av);
1259 if (strcmp(*av, "ip") == 0)
1261 else if (strcmp(*av, "mac") == 0)
1264 errx(EX_USAGE, "table type `%s' not supported", *av);
1267 memset(t->name, 0, IPFW_TABLE_NAME_LEN);
1268 if (ac == 2 && strcmp(*av, "name") == 0) {
1270 if (strlen(*av) < IPFW_TABLE_NAME_LEN) {
1271 strncpy(t->name, *av, strlen(*av));
1273 errx(EX_USAGE, "table name `%s' too long", *av);
1275 } else if (ac == 1) {
1276 errx(EX_USAGE, "table `%s' invalid", *av);
1279 if (do_set_x(IP_FW_TABLE_CREATE, t, sizeof(struct ipfw_ioc_table)) < 0)
1280 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_CREATE) "
1281 "table `%d' in use", t->id);
1285 table_delete(int ac, char *av[])
1287 struct ipfw_ioc_table ioc_table;
1288 struct ipfw_ioc_table *t = &ioc_table;
1291 if (isdigit(**av)) {
1293 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1294 errx(EX_USAGE, "table id `%d' invalid", t->id);
1296 errx(EX_USAGE, "table id `%s' invalid", *av);
1298 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1299 errx(EX_USAGE, "table id `%d' invalid", t->id);
1301 if (do_set_x(IP_FW_TABLE_DELETE, t, sizeof(struct ipfw_ioc_table)) < 0)
1302 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_DELETE) "
1303 "table `%s' delete failed", *av);
1307 table_test(int ac, char *av[])
1309 struct ipfw_ioc_table tbl;
1316 errx(EX_USAGE, "table id `%s' invalid", *av);
1318 if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
1319 errx(EX_USAGE, "table id `%d' invalid", tbl.id);
1322 if (strcmp(*av, "ip") == 0)
1324 else if (strcmp(*av, "mac") == 0)
1327 errx(EX_USAGE, "table type `%s' not supported", *av);
1330 if (tbl.type == 1) { /* table type ipv4 */
1331 struct ipfw_ioc_table_ip_entry ip_ent;
1332 if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
1333 errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
1335 tbl.ip_ent[0] = ip_ent;
1336 size = sizeof(tbl) + sizeof(ip_ent);
1337 } else if (tbl.type == 2) { /* table type mac */
1338 struct ipfw_ioc_table_mac_entry mac_ent;
1340 errx(EX_USAGE, "MAC address required");
1342 mac_ent.addr = *ether_aton(*av);
1343 tbl.mac_ent[0] = mac_ent;
1344 size = sizeof(tbl) + sizeof(mac_ent);
1346 if (do_set_x(IP_FW_TABLE_TEST, &tbl, size) < 0 ) {
1347 printf("NO, %s not exists in table %d\n", *av, tbl.id);
1349 printf("YES, %s exists in table %d\n", *av, tbl.id);
1354 table_rename(int ac, char *av[])
1356 struct ipfw_ioc_table tbl;
1359 bzero(&tbl, sizeof(tbl));
1364 errx(EX_USAGE, "table id `%s' invalid", *av);
1366 if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
1367 errx(EX_USAGE, "table id `%d' invalid", tbl.id);
1370 strlcpy(tbl.name, *av, IPFW_TABLE_NAME_LEN);
1372 if (do_set_x(IP_FW_TABLE_RENAME, &tbl, size) < 0 )
1373 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_RENAME) "
1374 "table `%d' not in use", tbl.id);
1378 list(int ac, char *av[])
1380 struct ipfw_ioc_state *dynrules, *d;
1381 struct ipfw_ioc_rule *r;
1385 int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width;
1386 int exitval = EX_OK, lac;
1387 char **lav, *endptr;
1393 /* get rules or pipes from kernel, resizing array as necessary */
1396 while (nbytes >= nalloc) {
1397 nalloc = nalloc * 2 ;
1399 if ((data = realloc(data, nbytes)) == NULL)
1400 err(EX_OSERR, "realloc");
1401 if (do_get_x(IP_FW_GET, data, &nbytes) < 0)
1402 err(EX_OSERR, "do_get_x(IP_FW_GET)");
1406 * Count static rules.
1409 nstat = r->static_count;
1412 * Count dynamic rules. This is easier as they have
1415 dynrules = (struct ipfw_ioc_state *)((void *)r + r->static_len);
1416 ndyn = (nbytes - r->static_len) / sizeof(*dynrules);
1418 /* if showing stats, figure out column widths ahead of time */
1419 bcwidth = pcwidth = 0;
1421 for (n = 0, r = data; n < nstat;
1422 n++, r = (void *)r + IOC_RULESIZE(r)) {
1423 /* packet counter */
1424 width = snprintf(NULL, 0, "%ju", (uintmax_t)r->pcnt);
1425 if (width > pcwidth)
1429 width = snprintf(NULL, 0, "%ju", (uintmax_t)r->bcnt);
1430 if (width > bcwidth)
1434 if (do_dynamic && ndyn) {
1435 for (n = 0, d = dynrules; n < ndyn; n++, d++) {
1436 width = snprintf(NULL, 0, "%ju", (uintmax_t)d->pcnt);
1437 if (width > pcwidth)
1440 width = snprintf(NULL, 0, "%ju", (uintmax_t)d->bcnt);
1441 if (width > bcwidth)
1446 /* if no rule numbers were specified, list all rules */
1448 if (do_dynamic != 2) {
1449 for (n = 0, r = data; n < nstat; n++,
1450 r = (void *)r + IOC_RULESIZE(r)) {
1451 show_rules(r, pcwidth, bcwidth);
1454 if (do_dynamic && ndyn) {
1455 if (do_dynamic != 2) {
1456 printf("## States (%d):\n", ndyn);
1458 for (n = 0, d = dynrules; n < ndyn; n++, d++)
1459 show_states(d, pcwidth, bcwidth);
1464 /* display specific rules requested on command line */
1466 if (do_dynamic != 2) {
1467 for (lac = ac, lav = av; lac != 0; lac--) {
1468 /* convert command line rule # */
1469 rnum = strtoul(*lav++, &endptr, 10);
1472 warnx("invalid rule number: %s", *(lav - 1));
1475 for (n = seen = 0, r = data; n < nstat;
1476 n++, r = (void *)r + IOC_RULESIZE(r) ) {
1477 if (r->rulenum > rnum)
1479 if (r->rulenum == rnum) {
1480 show_rules(r, pcwidth, bcwidth);
1485 /* give precedence to other error(s) */
1486 if (exitval == EX_OK)
1487 exitval = EX_UNAVAILABLE;
1488 warnx("rule %lu does not exist", rnum);
1493 if (do_dynamic && ndyn) {
1494 if (do_dynamic != 2) {
1495 printf("## States (%d):\n", ndyn);
1497 for (lac = ac, lav = av; lac != 0; lac--) {
1498 rnum = strtoul(*lav++, &endptr, 10);
1500 /* already warned */
1502 for (n = 0, d = dynrules; n < ndyn; n++, d++) {
1503 if (d->rulenum > rnum)
1505 if (d->rulenum == rnum)
1506 show_states(d, pcwidth, bcwidth);
1516 if (exitval != EX_OK)
1521 show_dummynet(int ac, char *av[])
1525 int nalloc = 1024; /* start somewhere... */
1530 while (nbytes >= nalloc) {
1531 nalloc = nalloc * 2 + 200;
1533 if ((data = realloc(data, nbytes)) == NULL)
1534 err(EX_OSERR, "realloc");
1535 if (do_get_x(IP_DUMMYNET_GET, data, &nbytes) < 0) {
1536 err(EX_OSERR, "do_get_x(IP_%s_GET)",
1537 do_pipe ? "DUMMYNET" : "FW");
1541 show_pipes(data, nbytes, ac, av);
1548 fprintf(stderr, "usage: ipfw [options]\n"
1549 " ipfw add [rulenum] [set id] action filters\n"
1550 " ipfw delete [rulenum]\n"
1552 " ipfw list [rulenum]\n"
1553 " ipfw show [rulenum]\n"
1554 " ipfw zero [rulenum]\n"
1555 " ipfw set [show|enable|disable]\n"
1557 " ipfw [enable|disable]\n"
1558 " ipfw log [reset|off|on]\n"
1559 " ipfw nat [config|show|delete]\n"
1560 " ipfw pipe [config|show|delete]\n"
1561 " ipfw state [add|delete|list|show]"
1562 "\nsee ipfw manpage for details\n");
1568 delete_rules(int ac, char *av[])
1570 struct dn_ioc_pipe pipe;
1572 int exitval = EX_OK;
1576 memset(&pipe, 0, sizeof pipe);
1579 if (ac > 0 && !strncmp(*av, "set", strlen(*av))) {
1580 do_set = 1; /* delete set */
1585 while (ac && isdigit(**av)) {
1594 i = do_set_x(IP_DUMMYNET_DEL, &pipe, sizeof pipe);
1597 warn("rule %u: setsockopt(IP_DUMMYNET_DEL)",
1598 do_pipe == 1 ? pipe.pipe_nr :
1602 rulenum = (i & 0xffff) | (do_set << 24);
1603 i = do_set_x(IP_FW_DEL, &rulenum, sizeof rulenum);
1605 exitval = EX_UNAVAILABLE;
1606 warn("rule %u: setsockopt(IP_FW_DEL)",
1611 if (exitval != EX_OK)
1616 static unsigned long
1617 getbw(const char *str, u_short *flags, int kb)
1623 val = strtoul(str, &end, 0);
1624 if (*end == 'k' || *end == 'K') {
1627 } else if (*end == 'm' || *end == 'M') {
1633 * Deal with bits or bytes or b(bits) or B(bytes). If there is no
1634 * trailer assume bits.
1636 if (strncasecmp(end, "bit", 3) == 0) {
1638 } else if (strncasecmp(end, "byte", 4) == 0) {
1640 } else if (*end == 'b') {
1642 } else if (*end == 'B') {
1647 * Return in bits if flags is NULL, else flag bits
1648 * or bytes in flags and return the unconverted value.
1650 if (inbytes && flags)
1651 *flags |= DN_QSIZE_IS_BYTES;
1652 else if (inbytes && flags == NULL)
1659 * config dummynet pipe/queue
1662 config_dummynet(int ac, char **av)
1664 struct dn_ioc_pipe pipe;
1671 memset(&pipe, 0, sizeof pipe);
1673 if (ac && isdigit(**av)) {
1685 int tok = match_token(dummynet_params, *av);
1690 pipe.fs.flags_fs |= DN_NOERROR;
1694 NEED1("plr needs argument 0..1\n");
1695 d = strtod(av[0], NULL);
1700 pipe.fs.plr = (int)(d*0x7fffffff);
1705 NEED1("queue needs queue size\n");
1707 pipe.fs.qsize = getbw(av[0], &pipe.fs.flags_fs, 1024);
1712 NEED1("buckets needs argument\n");
1713 pipe.fs.rq_size = strtoul(av[0], NULL, 0);
1718 NEED1("mask needs mask specifier\n");
1720 * per-flow queue, mask is dst_ip, dst_port,
1721 * src_ip, src_port, proto measured in bits
1725 pipe.fs.flow_mask.type = ETHERTYPE_IP;
1726 pipe.fs.flow_mask.u.ip.dst_ip = 0;
1727 pipe.fs.flow_mask.u.ip.src_ip = 0;
1728 pipe.fs.flow_mask.u.ip.dst_port = 0;
1729 pipe.fs.flow_mask.u.ip.src_port = 0;
1730 pipe.fs.flow_mask.u.ip.proto = 0;
1734 u_int32_t *p32 = NULL;
1735 u_int16_t *p16 = NULL;
1737 tok = match_token(dummynet_params, *av);
1742 * special case, all bits significant
1744 pipe.fs.flow_mask.u.ip.dst_ip = ~0;
1745 pipe.fs.flow_mask.u.ip.src_ip = ~0;
1746 pipe.fs.flow_mask.u.ip.dst_port = ~0;
1747 pipe.fs.flow_mask.u.ip.src_port = ~0;
1748 pipe.fs.flow_mask.u.ip.proto = ~0;
1749 pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
1753 p32 = &pipe.fs.flow_mask.u.ip.dst_ip;
1757 p32 = &pipe.fs.flow_mask.u.ip.src_ip;
1761 p16 = &pipe.fs.flow_mask.u.ip.dst_port;
1765 p16 = &pipe.fs.flow_mask.u.ip.src_port;
1776 errx(EX_USAGE, "mask: value missing");
1777 if (*av[0] == '/') {
1778 a = strtoul(av[0]+1, &end, 0);
1779 a = (a == 32) ? ~0 : (1 << a) - 1;
1781 a = strtoul(av[0], &end, 0);
1784 else if (p16 != NULL) {
1787 "mask: must be 16 bit");
1788 *p16 = (u_int16_t)a;
1792 "mask: must be 8 bit");
1793 pipe.fs.flow_mask.u.ip.proto =
1797 pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
1799 } /* end while, config masks */
1806 NEED1("red/gred needs w_q/min_th/max_th/max_p\n");
1807 pipe.fs.flags_fs |= DN_IS_RED;
1808 if (tok == TOK_GRED)
1809 pipe.fs.flags_fs |= DN_IS_GENTLE_RED;
1811 * the format for parameters is w_q/min_th/max_th/max_p
1813 if ((end = strsep(&av[0], "/"))) {
1814 double w_q = strtod(end, NULL);
1815 if (w_q > 1 || w_q <= 0)
1816 errx(EX_DATAERR, "0 < w_q <= 1");
1817 pipe.fs.w_q = (int) (w_q * (1 << SCALE_RED));
1819 if ((end = strsep(&av[0], "/"))) {
1820 pipe.fs.min_th = strtoul(end, &end, 0);
1821 if (*end == 'K' || *end == 'k')
1822 pipe.fs.min_th *= 1024;
1824 if ((end = strsep(&av[0], "/"))) {
1825 pipe.fs.max_th = strtoul(end, &end, 0);
1826 if (*end == 'K' || *end == 'k')
1827 pipe.fs.max_th *= 1024;
1829 if ((end = strsep(&av[0], "/"))) {
1830 double max_p = strtod(end, NULL);
1831 if (max_p > 1 || max_p <= 0)
1832 errx(EX_DATAERR, "0 < max_p <= 1");
1833 pipe.fs.max_p = (int)(max_p * (1 << SCALE_RED));
1839 pipe.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED);
1843 NEED1("bw needs bandwidth\n");
1846 "bandwidth only valid for pipes");
1848 * set bandwidth value
1850 pipe.bandwidth = getbw(av[0], NULL, 1000);
1851 if (pipe.bandwidth < 0)
1852 errx(EX_DATAERR, "bandwidth too large");
1858 errx(EX_DATAERR, "delay only valid for pipes");
1859 NEED1("delay needs argument 0..10000ms\n");
1860 pipe.delay = strtoul(av[0], NULL, 0);
1867 "weight only valid for queues");
1868 NEED1("weight needs argument 0..100\n");
1869 pipe.fs.weight = strtoul(av[0], &end, 0);
1875 errx(EX_DATAERR, "pipe only valid for queues");
1876 NEED1("pipe needs pipe_number\n");
1877 pipe.fs.parent_nr = strtoul(av[0], &end, 0);
1882 errx(EX_DATAERR, "unrecognised option ``%s''", *av);
1886 if (pipe.pipe_nr == 0)
1887 errx(EX_DATAERR, "pipe_nr must be > 0");
1888 if (pipe.delay > 10000)
1889 errx(EX_DATAERR, "delay must be < 10000");
1890 } else { /* do_pipe == 2, queue */
1891 if (pipe.fs.parent_nr == 0)
1892 errx(EX_DATAERR, "pipe must be > 0");
1893 if (pipe.fs.weight >100)
1894 errx(EX_DATAERR, "weight must be <= 100");
1896 if (pipe.fs.flags_fs & DN_QSIZE_IS_BYTES) {
1897 if (pipe.fs.qsize > 1024*1024)
1898 errx(EX_DATAERR, "queue size must be < 1MB");
1900 if (pipe.fs.qsize > 100)
1901 errx(EX_DATAERR, "2 <= queue size <= 100");
1903 if (pipe.fs.flags_fs & DN_IS_RED) {
1905 int lookup_depth, avg_pkt_size;
1906 double s, idle, weight, w_q;
1910 if (pipe.fs.min_th >= pipe.fs.max_th)
1911 errx(EX_DATAERR, "min_th %d must be < than max_th %d",
1912 pipe.fs.min_th, pipe.fs.max_th);
1913 if (pipe.fs.max_th == 0)
1914 errx(EX_DATAERR, "max_th must be > 0");
1917 if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
1918 &lookup_depth, &len, NULL, 0) == -1)
1920 errx(1, "sysctlbyname(\"%s\")",
1921 "net.inet.ip.dummynet.red_lookup_depth");
1922 if (lookup_depth == 0)
1923 errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth"
1924 " must be greater than zero");
1927 if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
1928 &avg_pkt_size, &len, NULL, 0) == -1)
1930 errx(1, "sysctlbyname(\"%s\")",
1931 "net.inet.ip.dummynet.red_avg_pkt_size");
1932 if (avg_pkt_size == 0)
1934 "net.inet.ip.dummynet.red_avg_pkt_size must"
1935 " be greater than zero");
1937 len = sizeof(clock_hz);
1938 if (sysctlbyname("net.inet.ip.dummynet.hz", &clock_hz, &len,
1940 errx(1, "sysctlbyname(\"%s\")",
1941 "net.inet.ip.dummynet.hz");
1945 * Ticks needed for sending a medium-sized packet.
1946 * Unfortunately, when we are configuring a WF2Q+ queue, we
1947 * do not have bandwidth information, because that is stored
1948 * in the parent pipe, and also we have multiple queues
1949 * competing for it. So we set s=0, which is not very
1950 * correct. But on the other hand, why do we want RED with
1953 if (pipe.bandwidth == 0) /* this is a WF2Q+ queue */
1956 s = clock_hz * avg_pkt_size * 8 / pipe.bandwidth;
1959 * max idle time (in ticks) before avg queue size becomes 0.
1960 * NOTA: (3/w_q) is approx the value x so that
1961 * (1-w_q)^x < 10^-3.
1963 w_q = ((double)pipe.fs.w_q) / (1 << SCALE_RED);
1964 idle = s * 3. / w_q;
1965 pipe.fs.lookup_step = (int)idle / lookup_depth;
1966 if (!pipe.fs.lookup_step)
1967 pipe.fs.lookup_step = 1;
1969 for (t = pipe.fs.lookup_step; t > 0; --t)
1971 pipe.fs.lookup_weight = (int)(weight * (1 << SCALE_RED));
1973 i = do_set_x(IP_DUMMYNET_CONFIGURE, &pipe, sizeof pipe);
1975 err(1, "do_set_x(%s)", "IP_DUMMYNET_CONFIGURE");
1979 * helper function, updates the pointer to cmd with the length
1980 * of the current command, and also cleans up the first word of
1981 * the new command in case it has been clobbered before.
1984 next_cmd(ipfw_insn *cmd)
1987 bzero(cmd, sizeof(*cmd));
1992 * Parse arguments and assemble the microinstructions which make up a rule.
1993 * Rules are added into the 'rulebuf' and then copied in the correct order
1994 * into the actual rule.
1999 add(int ac, char *av[])
2002 * rules are added into the 'rulebuf' and then copied in
2003 * the correct order into the actual rule.
2004 * Some things that need to go out of order (prob, action etc.)
2007 static uint32_t rulebuf[IPFW_RULE_SIZE_MAX];
2008 static uint32_t actbuf[IPFW_RULE_SIZE_MAX];
2009 static uint32_t othbuf[IPFW_RULE_SIZE_MAX];
2010 static uint32_t cmdbuf[IPFW_RULE_SIZE_MAX];
2012 ipfw_insn *src, *dst, *cmd, *action, *other;
2015 ipfw_insn *the_comment = NULL;
2016 struct ipfw_ioc_rule *rule;
2017 struct ipfw_keyword *key;
2018 struct ipfw_mapping *map;
2022 bzero(actbuf, sizeof(actbuf)); /* actions go here */
2023 bzero(othbuf, sizeof(actbuf)); /* others */
2024 bzero(cmdbuf, sizeof(cmdbuf)); /* filters */
2025 bzero(rulebuf, sizeof(rulebuf));
2027 rule = (struct ipfw_ioc_rule *)rulebuf;
2028 cmd = (ipfw_insn *)cmdbuf;
2029 action = (ipfw_insn *)actbuf;
2030 other = (ipfw_insn *)othbuf;
2032 NEED2("need more parameters");
2035 /* [rule N] -- Rule number optional */
2036 if (ac && isdigit(**av)) {
2037 rule->rulenum = atoi(*av);
2041 /* [set N] -- set number (0..30), optional */
2042 if (ac > 1 && !strncmp(*av, "set", strlen(*av))) {
2043 int set = strtoul(av[1], NULL, 10);
2044 if (set < 0 || set > 30)
2045 errx(EX_DATAERR, "illegal set %s", av[1]);
2054 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
2055 if (key->type == BEFORE &&
2056 strcmp(key->word, *av) == 0) {
2057 for (j = 0, map = mappings;
2058 j < MAPPING_SIZE; j++, map++) {
2059 if (map->type == IN_USE &&
2060 map->module == key->module &&
2061 map->opcode == key->opcode ) {
2063 (*fn)(&other, &ac, &av);
2070 if (i >= KEYWORD_SIZE) {
2072 } else if (F_LEN(other) > 0) {
2073 if (other->module == MODULE_BASIC_ID &&
2074 other->opcode == O_BASIC_CHECK_STATE) {
2075 other = next_cmd(other);
2078 other = next_cmd(other);
2085 * only accept 1 action
2087 NEED1("missing action");
2088 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
2089 if (ac > 0 && key->type == ACTION &&
2090 strcmp(key->word, *av) == 0) {
2091 for (j = 0, map = mappings;
2092 j < MAPPING_SIZE; j++, map++) {
2093 if (map->type == IN_USE &&
2094 map->module == key->module &&
2095 map->opcode == key->opcode) {
2097 (*fn)(&action, &ac, &av);
2104 if (F_LEN(action) > 0)
2105 action = next_cmd(action);
2110 if (strcmp(*av, "proto") == 0){
2114 NEED1("missing protocol");
2115 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
2116 if (key->type == PROTO &&
2117 strcmp(key->word, "proto") == 0) {
2118 for (j = 0, map = mappings;
2119 j < MAPPING_SIZE; j++, map++) {
2120 if (map->type == IN_USE &&
2121 map->module == key->module &&
2122 map->opcode == key->opcode ) {
2124 (*fn)(&cmd, &ac, &av);
2132 cmd = next_cmd(cmd);
2138 char *s, *cur; /* current filter */
2139 ipfw_insn_u32 *cmd32; /* alias for cmd */
2142 cmd32 = (ipfw_insn_u32 *)cmd;
2143 if (strcmp(*av, "or") == 0) {
2145 errx(EX_USAGE, "'or' should"
2146 "between two filters\n");
2151 if (strcmp(*av, "not") == 0) {
2152 if (cmd->len & F_NOT)
2153 errx(EX_USAGE, "double \"not\" not allowed\n");
2159 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
2160 if ((key->type == FILTER ||
2161 key->type == AFTER ||
2162 key->type == FROM ||
2164 strcmp(key->word, cur) == 0) {
2165 for (j = 0, map = mappings;
2166 j< MAPPING_SIZE; j++, map++) {
2167 if (map->type == IN_USE &&
2168 map->module == key->module &&
2169 map->opcode == key->opcode ) {
2171 (*fn)(&cmd, &ac, &av);
2176 } else if (i == KEYWORD_SIZE - 1) {
2177 errx(EX_USAGE, "bad command `%s'", cur);
2180 if (i >= KEYWORD_SIZE) {
2182 } else if (F_LEN(cmd) > 0) {
2185 cmd = next_cmd(cmd);
2191 errx(EX_USAGE, "bad command `%s'", *av);
2194 * Now copy stuff into the rule.
2195 * [filters][others][action][comment]
2197 dst = (ipfw_insn *)rule->cmd;
2199 * copy all filters, except comment
2201 src = (ipfw_insn *)cmdbuf;
2202 for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) {
2203 /* pick comment out */
2205 if (src->module == MODULE_BASIC_ID &&
2206 src->opcode == O_BASIC_COMMENT) {
2209 bcopy(src, dst, i * sizeof(u_int32_t));
2210 dst = (ipfw_insn *)((uint32_t *)dst + i);
2215 * start action section, it begin with others
2217 rule->act_ofs = (uint32_t *)dst - (uint32_t *)(rule->cmd);
2220 * copy all other others
2222 for (src = (ipfw_insn *)othbuf; src != other; src += i) {
2224 bcopy(src, dst, i * sizeof(u_int32_t));
2225 dst = (ipfw_insn *)((uint32_t *)dst + i);
2228 /* copy the action to the end of rule */
2229 src = (ipfw_insn *)actbuf;
2231 bcopy(src, dst, i * sizeof(u_int32_t));
2232 dst = (ipfw_insn *)((uint32_t *)dst + i);
2235 * comment place behind the action
2237 if (the_comment != NULL) {
2238 i = F_LEN(the_comment);
2239 bcopy(the_comment, dst, i * sizeof(u_int32_t));
2240 dst = (ipfw_insn *)((uint32_t *)dst + i);
2243 rule->cmd_len = (u_int32_t *)dst - (u_int32_t *)(rule->cmd);
2244 i = (void *)dst - (void *)rule;
2245 if (do_set_x(IP_FW_ADD, (void *)rule, i) == -1) {
2246 err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD");
2249 show_rules(rule, 10, 10);
2253 zero(int ac, char *av[])
2261 /* clear all entries */
2262 if (do_set_x(IP_FW_ZERO, NULL, 0) < 0)
2263 err(EX_UNAVAILABLE, "do_set_x(IP_FW_ZERO)");
2265 printf("Accounting cleared.\n");
2271 if (isdigit(**av)) {
2272 rulenum = atoi(*av);
2274 if (do_set_x(IP_FW_ZERO, &rulenum, sizeof rulenum)) {
2275 warn("rule %u: do_set_x(IP_FW_ZERO)", rulenum);
2276 failed = EX_UNAVAILABLE;
2277 } else if (!do_quiet)
2278 printf("Entry %d cleared\n", rulenum);
2280 errx(EX_USAGE, "invalid rule number ``%s''", *av);
2283 if (failed != EX_OK)
2288 resetlog(int ac, char *av[])
2296 /* clear all entries */
2297 if (setsockopt(ipfw_socket, IPPROTO_IP,
2298 IP_FW_RESETLOG, NULL, 0) < 0)
2299 err(EX_UNAVAILABLE, "setsockopt(IP_FW_RESETLOG)");
2301 printf("Logging counts reset.\n");
2308 if (isdigit(**av)) {
2309 rulenum = atoi(*av);
2311 if (setsockopt(ipfw_socket, IPPROTO_IP,
2312 IP_FW_RESETLOG, &rulenum, sizeof rulenum)) {
2313 warn("rule %u: setsockopt(IP_FW_RESETLOG)",
2315 failed = EX_UNAVAILABLE;
2316 } else if (!do_quiet)
2317 printf("Entry %d logging count reset\n",
2320 errx(EX_DATAERR, "invalid rule number ``%s''", *av);
2323 if (failed != EX_OK)
2330 int cmd = IP_FW_FLUSH;
2332 cmd = IP_DUMMYNET_FLUSH;
2337 printf("Are you sure? [yn] ");
2340 c = toupper(getc(stdin));
2341 while (c != '\n' && getc(stdin) != '\n')
2343 return; /* and do not flush */
2344 } while (c != 'Y' && c != 'N');
2345 if (c == 'N') /* user said no */
2348 if (do_set_x(cmd, NULL, 0) < 0 ) {
2350 errx(EX_USAGE, "pipe/queue in use");
2352 errx(EX_USAGE, "do_set_x(IP_FW_FLUSH) failed");
2355 printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules");
2360 * do_set_x - extended version og do_set
2361 * insert a x_header in the beginning of the rule buf
2362 * and call setsockopt() with IP_FW_X.
2365 do_set_x(int optname, void *rule, int optlen)
2369 ip_fw_x_header *x_header;
2370 if (ipfw_socket < 0)
2371 err(EX_UNAVAILABLE, "socket not avaialble");
2372 len = optlen + sizeof(ip_fw_x_header);
2373 newbuf = malloc(len);
2375 err(EX_OSERR, "malloc newbuf in do_set_x");
2377 x_header = (ip_fw_x_header *)newbuf;
2378 x_header->opcode = optname;
2379 /* copy the rule into the newbuf, just after the x_header*/
2380 bcopy(rule, ++x_header, optlen);
2381 return setsockopt(ipfw_socket, IPPROTO_IP, IP_FW_X, newbuf, len);
2388 do_get_x(int optname, void *rule, int *optlen)
2390 int len, *newbuf, retval;
2392 ip_fw_x_header *x_header;
2393 if (ipfw_socket < 0)
2394 err(EX_UNAVAILABLE, "socket not avaialble");
2395 len = *optlen + sizeof(ip_fw_x_header);
2396 newbuf = malloc(len);
2398 err(EX_OSERR, "malloc newbuf in do_get_x");
2400 x_header = (ip_fw_x_header *)newbuf;
2401 x_header->opcode = optname;
2402 /* copy the rule into the newbuf, just after the x_header*/
2403 bcopy(rule, ++x_header, *optlen);
2404 retval = getsockopt(ipfw_socket, IPPROTO_IP, IP_FW_X, newbuf, &len);
2405 bcopy(newbuf, rule, len);
2411 ipfw_main(int ac, char **av)
2418 /* Set the force flag for non-interactive processes */
2419 do_force = !isatty(STDIN_FILENO);
2421 optind = optreset = 1;
2422 while ((ch = getopt(ac, av, "hs:acdDefNStTv")) != -1)
2424 case 'h': /* help */
2426 break; /* NOTREACHED */
2428 case 's': /* sort */
2429 do_sort = atoi(optarg);
2471 NEED1("bad arguments, for usage summary ``ipfw''");
2474 * optional: pipe or queue or nat
2478 if (!strncmp(*av, "nat", strlen(*av)))
2480 else if (!strncmp(*av, "pipe", strlen(*av))) {
2482 } else if (!strncmp(*av, "queue", strlen(*av))) {
2485 NEED1("missing command");
2488 * for pipes and queues and nat we normally say 'pipe NN config'
2489 * but the code is easier to parse as 'pipe config NN'
2490 * so we swap the two arguments.
2492 if ((do_pipe || do_nat) && ac > 2 && isdigit(*(av[1]))) {
2498 if (!strncmp(*av, "add", strlen(*av))) {
2501 } else if (!strncmp(*av, "delete", strlen(*av))) {
2502 delete_rules(ac, av);
2503 } else if (!strncmp(*av, "flush", strlen(*av))) {
2505 } else if (!strncmp(*av, "list", strlen(*av))) {
2508 } else if (!strncmp(*av, "show", strlen(*av))) {
2512 } else if (!strncmp(*av, "zero", strlen(*av))) {
2514 } else if (!strncmp(*av, "set", strlen(*av))) {
2515 sets_handler(ac, av);
2516 } else if (!strncmp(*av, "module", strlen(*av))) {
2518 if (!strncmp(*av, "list", strlen(*av))) {
2519 list_modules(ac, av);
2521 errx(EX_USAGE, "bad ipfw module command `%s'", *av);
2523 } else if (!strncmp(*av, "resetlog", strlen(*av))) {
2525 } else if (!strncmp(*av, "log", strlen(*av))) {
2527 if (!strncmp(*av, "reset", strlen(*av))) {
2529 } else if (!strncmp(*av, "off", strlen(*av))) {
2531 } else if (!strncmp(*av, "on", strlen(*av))) {
2534 errx(EX_USAGE, "bad command `%s'", *av);
2536 } else if (!strncmp(*av, "nat", strlen(*av))) {
2539 } else if (!strncmp(*av, "pipe", strlen(*av)) ||
2540 !strncmp(*av, "queue", strlen(*av))) {
2542 if (!strncmp(*av, "config", strlen(*av))) {
2543 config_dummynet(ac, av);
2544 } else if (!strncmp(*av, "flush", strlen(*av))) {
2546 } else if (!strncmp(*av, "show", strlen(*av))) {
2547 show_dummynet(ac, av);
2549 errx(EX_USAGE, "bad ipfw pipe command `%s'", *av);
2551 } else if (!strncmp(*av, "state", strlen(*av))) {
2553 if (!strncmp(*av, "add", strlen(*av))) {
2555 } else if (!strncmp(*av, "delete", strlen(*av))) {
2556 delete_state(ac, av);
2557 } else if (!strncmp(*av, "flush", strlen(*av))) {
2558 flush_state(ac, av);
2559 } else if (!strncmp(*av, "list", strlen(*av))) {
2562 } else if (!strncmp(*av, "show", strlen(*av))) {
2567 errx(EX_USAGE, "bad ipfw state command `%s'", *av);
2569 } else if (!strncmp(*av, "table", strlen(*av))) {
2570 if (ac > 2 && isdigit(*(av[1]))) {
2576 if (!strncmp(*av, "append", strlen(*av))) {
2577 table_append(ac, av);
2578 } else if (!strncmp(*av, "remove", strlen(*av))) {
2579 table_remove(ac, av);
2580 } else if (!strncmp(*av, "flush", strlen(*av))) {
2581 table_flush(ac, av);
2582 } else if (!strncmp(*av, "list", strlen(*av))) {
2584 } else if (!strncmp(*av, "show", strlen(*av))) {
2586 } else if (!strncmp(*av, "type", strlen(*av))) {
2587 table_create(ac, av);
2588 } else if (!strncmp(*av, "delete", strlen(*av))) {
2589 table_delete(ac, av);
2590 } else if (!strncmp(*av, "test", strlen(*av))) {
2592 } else if (!strncmp(*av, "name", strlen(*av))) {
2593 table_rename(ac, av);
2595 errx(EX_USAGE, "bad ipfw table command `%s'", *av);
2597 } else if (!strncmp(*av, "sync", strlen(*av))) {
2599 if (!strncmp(*av, "edge", strlen(*av))) {
2600 sync_config_edge(ac, av);
2601 } else if (!strncmp(*av, "centre", strlen(*av))) {
2602 sync_config_centre(ac, av);
2603 } else if (!strncmp(*av, "show", strlen(*av))) {
2605 if (!strncmp(*av, "config", strlen(*av))) {
2606 sync_show_config(ac, av);
2607 } else if (!strncmp(*av, "status", strlen(*av))) {
2608 sync_show_status(ac, av);
2610 errx(EX_USAGE, "bad show command `%s'", *av);
2612 } else if (!strncmp(*av, "start", strlen(*av))) {
2614 if (!strncmp(*av, "edge", strlen(*av))) {
2615 sync_edge_start(ac, av);
2616 } else if (!strncmp(*av, "centre", strlen(*av))) {
2617 sync_centre_start(ac, av);
2619 } else if (!strncmp(*av, "stop", strlen(*av))) {
2621 if (!strncmp(*av, "edge", strlen(*av))) {
2622 sync_edge_stop(ac, av);
2623 } else if (!strncmp(*av, "centre", strlen(*av))) {
2624 sync_centre_stop(ac, av);
2626 } else if (!strncmp(*av, "clear", strlen(*av))) {
2628 if (!strncmp(*av, "edge", strlen(*av))) {
2629 sync_edge_clear(ac, av);
2630 } else if (!strncmp(*av, "centre", strlen(*av))) {
2631 sync_centre_clear(ac, av);
2633 } else if (!strncmp(*av, "test", strlen(*av))) {
2635 if (!strncmp(*av, "edge", strlen(*av))) {
2636 sync_edge_test(ac, av);
2637 } else if (!strncmp(*av, "centre", strlen(*av))) {
2638 sync_centre_test(ac, av);
2641 errx(EX_USAGE, "bad ipfw sync command `%s'", *av);
2644 errx(EX_USAGE, "bad ipfw command `%s'", *av);
2650 ipfw_readfile(int ac, char *av[])
2653 char *a, *p, *args[MAX_ARGS], *cmd = NULL;
2655 int i=0, lineno=0, qflag=0, pflag=0, status;
2660 while ((c = getopt(ac, av, "D:U:p:q")) != -1) {
2664 errx(EX_USAGE, "-D requires -p");
2665 if (i > MAX_ARGS - 2)
2666 errx(EX_USAGE, "too many -D or -U options");
2673 errx(EX_USAGE, "-U requires -p");
2674 if (i > MAX_ARGS - 2)
2675 errx(EX_USAGE, "too many -D or -U options");
2692 errx(EX_USAGE, "bad arguments, for usage"
2693 " summary ``ipfw''");
2700 errx(EX_USAGE, "extraneous filename arguments");
2702 if ((f = fopen(av[0], "r")) == NULL)
2703 err(EX_UNAVAILABLE, "fopen: %s", av[0]);
2706 /* pipe through preprocessor (cpp or m4) */
2711 if (pipe(pipedes) == -1)
2712 err(EX_OSERR, "cannot create pipe");
2714 switch ((preproc = fork())) {
2716 err(EX_OSERR, "cannot fork");
2720 if (dup2(fileno(f), 0) == -1 ||
2721 dup2(pipedes[1], 1) == -1) {
2722 err(EX_OSERR, "dup2()");
2728 err(EX_OSERR, "execvp(%s) failed", cmd);
2734 if ((f = fdopen(pipedes[0], "r")) == NULL) {
2735 int savederrno = errno;
2737 kill(preproc, SIGTERM);
2739 err(EX_OSERR, "fdopen()");
2744 while (fgets(buf, BUFSIZ, f)) {
2746 sprintf(linename, "Line %d", lineno);
2751 if ((p = strchr(buf, '#')) != NULL)
2756 for (a = strtok(buf, WHITESP); a && i < MAX_ARGS;
2757 a = strtok(NULL, WHITESP), i++) {
2761 if (i == (qflag? 2: 1))
2764 errx(EX_USAGE, "%s: too many arguments", linename);
2771 if (waitpid(preproc, &status, 0) == -1)
2772 errx(EX_OSERR, "waitpid()");
2773 if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK)
2774 errx(EX_UNAVAILABLE, "preprocessor exited with status %d",
2775 WEXITSTATUS(status));
2776 else if (WIFSIGNALED(status))
2777 errx(EX_UNAVAILABLE, "preprocessor exited with signal %d",
2783 main(int ac, char *av[])
2785 ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2786 if (ipfw_socket < 0)
2787 err(EX_UNAVAILABLE, "socket");
2789 memset(keywords, 0, sizeof(struct ipfw_keyword) * KEYWORD_SIZE);
2790 memset(mappings, 0, sizeof(struct ipfw_mapping) * MAPPING_SIZE);
2792 prepare_default_funcs();
2794 if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0)
2795 ipfw_readfile(ac, av);