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 "../../sys/net/ipfw3/ip_fw3.h"
64 #include "../../sys/net/ipfw3/ip_fw3_table.h"
65 #include "../../sys/net/ipfw3/ip_fw3_sync.h"
66 #include "../../sys/net/dummynet3/ip_dummynet3.h"
67 #include "../../sys/net/libalias/alias.h"
68 #include "../../sys/net/ipfw3_basic/ip_fw3_basic.h"
69 #include "../../sys/net/ipfw3_nat/ip_fw3_nat.h"
72 #include "ipfw3sync.h"
76 #define KEYWORD_SIZE 256
77 #define MAPPING_SIZE 256
79 #define MAX_KEYWORD_LEN 20
81 #define WHITESP " \t\f\v\n\r"
82 #define IPFW_LIB_PATH "/usr/lib/libipfw3%s.so"
83 #define IP_MASK_ALL 0xffffffff
85 * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines
86 * This is only used in this code.
88 #define IPPROTO_ETHERTYPE 0x1000
91 * show_rules() prints the body of an ipfw rule.
92 * Because the standard rule has at least proto src_ip dst_ip, we use
93 * a helper function to produce these entries if not provided explicitly.
94 * The first argument is the list of fields we have, the second is
95 * the list of fields we want to be printed.
97 * Special cases if we have provided a MAC header:
98 * + if the rule does not contain IP addresses/ports, do not print them;
99 * + if the rule does not contain an IP proto, print "all" instead of "ip";
102 #define HAVE_PROTO 0x0001
103 #define HAVE_SRCIP 0x0002
104 #define HAVE_DSTIP 0x0004
105 #define HAVE_MAC 0x0008
106 #define HAVE_MACTYPE 0x0010
107 #define HAVE_OPTIONS 0x8000
109 #define HAVE_IP (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP)
112 int ipfw_socket = -1; /* main RAW socket */
113 int do_resolv, /* Would try to resolve all */
114 do_acct, /* Show packet/byte count */
115 do_time, /* Show time stamps */
116 do_quiet = 1, /* Be quiet , default is quiet*/
117 do_force, /* Don't ask for confirmation */
118 do_pipe, /* this cmd refers to a pipe */
119 do_nat, /* Nat configuration. */
120 do_sort, /* field to sort results (0 = no) */
121 do_dynamic, /* display dynamic rules */
122 do_expired, /* display expired dynamic rules */
123 do_compact, /* show rules in compact mode */
124 show_sets, /* display rule sets */
127 struct char_int_map dummynet_params[] = {
129 { "noerror", TOK_NOERROR },
130 { "buckets", TOK_BUCKETS },
131 { "dst-ip", TOK_DSTIP },
132 { "src-ip", TOK_SRCIP },
133 { "dst-port", TOK_DSTPORT },
134 { "src-port", TOK_SRCPORT },
135 { "proto", TOK_PROTO },
136 { "weight", TOK_WEIGHT },
138 { "mask", TOK_MASK },
139 { "droptail", TOK_DROPTAIL },
141 { "gred", TOK_GRED },
143 { "bandwidth", TOK_BW },
144 { "delay", TOK_DELAY },
145 { "pipe", TOK_PIPE },
146 { "queue", TOK_QUEUE },
147 { "dummynet-params", TOK_NULL },
151 struct ipfw_keyword {
153 char word[MAX_KEYWORD_LEN];
158 struct ipfw_mapping {
166 struct ipfw_keyword keywords[KEYWORD_SIZE];
167 struct ipfw_mapping mappings[MAPPING_SIZE];
170 match_token(struct char_int_map *table, char *string)
173 if (strcmp(table->key, string) == 0) {
182 get_modules(char *modules_str, int len)
184 if (do_get_x(IP_FW_MODULE, modules_str, &len) < 0)
185 errx(EX_USAGE, "ipfw3 not loaded.");
189 list_modules(int ac, char *av[])
191 void *module_str = NULL;
193 if ((module_str = realloc(module_str, len)) == NULL)
194 err(EX_OSERR, "realloc");
196 get_modules(module_str, len);
197 printf("%s", (char *)module_str);
200 parse_accept(ipfw_insn **cmd, int *ac, char **av[])
202 (*cmd)->opcode = O_BASIC_ACCEPT;
203 (*cmd)->module = MODULE_BASIC_ID;
204 (*cmd)->len = (*cmd)->len|LEN_OF_IPFWINSN;
206 if (!strncmp(**av, "log", strlen(**av))) {
209 if (isdigit(***av)) {
210 (*cmd)->arg1 = strtoul(**av, NULL, 10);
217 parse_deny(ipfw_insn **cmd, int *ac, char **av[])
219 (*cmd)->opcode = O_BASIC_DENY;
220 (*cmd)->module = MODULE_BASIC_ID;
221 (*cmd)->len = (*cmd)->len|LEN_OF_IPFWINSN;
223 if (!strncmp(**av, "log", strlen(**av))) {
226 if (isdigit(***av)) {
227 (*cmd)->arg1 = strtoul(**av, NULL, 10);
234 show_accept(ipfw_insn *cmd, int show_or)
238 printf(" log %d", cmd->arg1);
243 show_deny(ipfw_insn *cmd, int show_or)
247 printf(" log %d", cmd->arg1);
255 init_module mod_init_func;
257 char module_lib_file[50];
258 void *module_str = NULL;
261 if ((module_str = realloc(module_str, len)) == NULL)
262 err(EX_OSERR, "realloc");
264 get_modules(module_str, len);
266 const char s[2] = ",";
268 token = strtok(module_str, s);
269 while (token != NULL) {
270 sprintf(module_lib_file, IPFW_LIB_PATH, token);
271 token = strtok(NULL, s);
272 module_lib = dlopen(module_lib_file, RTLD_LAZY);
274 fprintf(stderr, "Couldn't open %s: %s\n",
275 module_lib_file, dlerror());
278 mod_init_func = dlsym(module_lib, "load_module");
279 if ((error = dlerror()))
281 fprintf(stderr, "Couldn't find init function: %s\n", error);
284 (*mod_init_func)((register_func)register_ipfw_func,
285 (register_keyword)register_ipfw_keyword);
290 prepare_default_funcs(void)
293 register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_ACCEPT, "allow", ACTION);
294 register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_ACCEPT, "accept", ACTION);
295 register_ipfw_func(MODULE_BASIC_ID, O_BASIC_ACCEPT,
296 (parser_func)parse_accept, (shower_func)show_accept);
298 register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_DENY, "deny", ACTION);
299 register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_DENY, "reject", ACTION);
300 register_ipfw_func(MODULE_BASIC_ID, O_BASIC_DENY,
301 (parser_func)parse_deny, (shower_func)show_deny);
305 register_ipfw_keyword(int module, int opcode, char *word, int type)
307 struct ipfw_keyword *tmp;
311 if (tmp->type == NONE) {
312 strcpy(tmp->word, word);
313 tmp->module = module;
314 tmp->opcode = opcode;
318 if (strcmp(tmp->word, word) == 0)
319 errx(EX_USAGE, "keyword `%s' exists", word);
327 register_ipfw_func(int module, int opcode, parser_func parser, shower_func shower)
329 struct ipfw_mapping *tmp;
333 if (tmp->type == NONE) {
334 tmp->module = module;
335 tmp->opcode = opcode;
336 tmp->parser = parser;
337 tmp->shower = shower;
341 if (tmp->opcode == opcode && tmp->module == module) {
342 errx(EX_USAGE, "func `%d' of module `%d' exists",
353 * this func need to check whether 'or' need to be printed,
354 * when the filter is the first filter with 'or' when dont print
355 * when not first and same as previous, then print or and no filter name
356 * when not first but different from previous, print name without 'or'
357 * show_or = 1: show or and ignore filter name
358 * show_or = 0: show filter name ignore or
360 void prev_show_chk(ipfw_insn *cmd, uint8_t *prev_module, uint8_t *prev_opcode,
363 if (cmd->len & F_OR) {
364 if (*prev_module == 0 && *prev_opcode == 0) {
365 /* first cmd with 'or' flag */
367 *prev_module = cmd->module;
368 *prev_opcode = cmd->opcode;
369 } else if (cmd->module == *prev_module &&
370 cmd->opcode == *prev_opcode) {
371 /* cmd same as previous, same module and opcode */
374 /* cmd different from prev*/
376 *prev_module = cmd->module;
377 *prev_opcode = cmd->opcode;
388 * word can be: proto from to other
392 * other show all other filters
394 int show_filter(ipfw_insn *cmd, char *word, int type)
396 struct ipfw_keyword *k;
397 struct ipfw_mapping *m;
400 uint8_t prev_module, prev_opcode;
404 for (i = 1; i < KEYWORD_SIZE; i++, k++) {
405 if (k->type == type) {
406 if (k->module == cmd->module &&
407 k->opcode == cmd->opcode) {
408 for (j = 1; j < MAPPING_SIZE; j++, m++) {
409 if (m->type == IN_USE &&
410 k->module == m->module &&
411 k->opcode == m->opcode) {
412 prev_show_chk(cmd, &prev_module,
413 &prev_opcode, &show_or);
414 if (cmd->len & F_NOT)
429 show_rules(struct ipfw_ioc_rule *rule, int pcwidth, int bcwidth)
431 static int twidth = 0;
435 u_int32_t set_disable = rule->set_disable;
437 if (set_disable & (1 << rule->set)) { /* disabled */
441 printf("# DISABLED ");
443 printf("%05u ", rule->rulenum);
446 printf("%*ju %*ju ", pcwidth, (uintmax_t)rule->pcnt, bcwidth,
447 (uintmax_t)rule->bcnt);
453 strcpy(timestr, ctime((time_t *)&twidth));
454 *strchr(timestr, '\n') = '\0';
455 twidth = strlen(timestr);
457 if (rule->timestamp) {
458 time_t t = _long_to_time(rule->timestamp);
460 strcpy(timestr, ctime(&t));
461 *strchr(timestr, '\n') = '\0';
462 printf("%s ", timestr);
464 printf("%*s ", twidth, " ");
466 } else if (do_time == 2) {
467 printf( "%10u ", rule->timestamp);
471 printf("set %d ", rule->set);
474 struct ipfw_keyword *k;
475 struct ipfw_mapping *m;
476 shower_func fn, comment_fn = NULL;
477 ipfw_insn *comment_cmd;
481 * show others and actions
483 for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule);
484 l > 0; l -= F_LEN(cmd),
485 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
488 for (i = 1; i< KEYWORD_SIZE; i++, k++) {
489 if ( k->module == cmd->module && k->opcode == cmd->opcode ) {
490 for (j = 1; j< MAPPING_SIZE; j++, m++) {
491 if (m->type == IN_USE &&
492 m->module == cmd->module &&
493 m->opcode == cmd->opcode) {
494 if (cmd->module == MODULE_BASIC_ID &&
495 cmd->opcode == O_BASIC_COMMENT) {
496 comment_fn = m->shower;
502 if (cmd->module == MODULE_BASIC_ID &&
504 O_BASIC_CHECK_STATE) {
519 for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd),
520 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
521 changed = show_filter(cmd, "proto", PROTO);
523 if (!changed && !do_quiet)
530 for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd),
531 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
532 changed = show_filter(cmd, "from", FROM);
534 if (!changed && !do_quiet)
541 for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd),
542 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
543 changed = show_filter(cmd, "to", TO);
545 if (!changed && !do_quiet)
551 for (l = rule->act_ofs, cmd = rule->cmd, m = mappings;
552 l > 0; l -= F_LEN(cmd),
553 cmd=(ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
554 show_filter(cmd, "other", FILTER);
557 /* show the comment in the end */
558 if (comment_fn != NULL) {
559 (*comment_fn)(comment_cmd, 0);
566 show_states(struct ipfw_ioc_state *d, int pcwidth, int bcwidth)
571 printf("%05u ", d->rulenum);
573 printf("%*ju %*ju ", pcwidth, (uintmax_t)d->pcnt,
574 bcwidth, (uintmax_t)d->bcnt);
578 /* state->timestamp */
580 time_t t = _long_to_time(d->timestamp);
581 strcpy(timestr, ctime(&t));
582 *strchr(timestr, '\n') = '\0';
583 printf(" (%s", timestr);
585 /* state->lifetime */
586 printf(" %ds", d->lifetime);
590 t = _long_to_time(d->expiry);
591 strcpy(timestr, ctime(&t));
592 *strchr(timestr, '\n') = '\0';
593 printf(" %s)", timestr);
598 } else if (do_time == 2) {
599 printf("(%u %ds %u) ", d->timestamp, d->lifetime, d->expiry);
602 if ((pe = getprotobynumber(d->flow_id.proto)) != NULL)
603 printf(" %s", pe->p_name);
605 printf(" proto %u", d->flow_id.proto);
607 a.s_addr = htonl(d->flow_id.src_ip);
608 printf(" %s %d", inet_ntoa(a), d->flow_id.src_port);
610 a.s_addr = htonl(d->flow_id.dst_ip);
611 printf(" <-> %s %d", inet_ntoa(a), d->flow_id.dst_port);
612 printf(" CPU %d", d->cpuid);
617 sort_q(const void *pa, const void *pb)
619 int rev = (do_sort < 0);
620 int field = rev ? -do_sort : do_sort;
622 const struct dn_ioc_flowqueue *a = pa;
623 const struct dn_ioc_flowqueue *b = pb;
627 res = a->len - b->len;
630 res = a->len_bytes - b->len_bytes;
633 case 3: /* tot pkts */
634 res = a->tot_pkts - b->tot_pkts;
637 case 4: /* tot bytes */
638 res = a->tot_bytes - b->tot_bytes;
645 return (int)(rev ? res : -res);
649 show_queues(struct dn_ioc_flowset *fs, struct dn_ioc_flowqueue *q)
653 printf("mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
654 fs->flow_mask.u.ip.proto,
655 fs->flow_mask.u.ip.src_ip, fs->flow_mask.u.ip.src_port,
656 fs->flow_mask.u.ip.dst_ip, fs->flow_mask.u.ip.dst_port);
657 if (fs->rq_elements == 0)
660 printf("BKT Prot ___Source IP/port____ "
661 "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
663 heapsort(q, fs->rq_elements, sizeof(*q), sort_q);
664 for (l = 0; l < fs->rq_elements; l++) {
668 ina.s_addr = htonl(q[l].id.u.ip.src_ip);
669 printf("%3d ", q[l].hash_slot);
670 pe = getprotobynumber(q[l].id.u.ip.proto);
672 printf("%-4s ", pe->p_name);
674 printf("%4u ", q[l].id.u.ip.proto);
676 inet_ntoa(ina), q[l].id.u.ip.src_port);
677 ina.s_addr = htonl(q[l].id.u.ip.dst_ip);
679 inet_ntoa(ina), q[l].id.u.ip.dst_port);
680 printf("%4ju %8ju %2u %4u %3u\n",
681 (uintmax_t)q[l].tot_pkts, (uintmax_t)q[l].tot_bytes,
682 q[l].len, q[l].len_bytes, q[l].drops);
684 printf(" S %20ju F %20ju\n",
685 (uintmax_t)q[l].S, (uintmax_t)q[l].F);
690 show_flowset_parms(struct dn_ioc_flowset *fs, char *prefix)
694 char red[90]; /* Display RED parameters */
698 if (fs->flags_fs & DN_QSIZE_IS_BYTES) {
700 sprintf(qs, "%d KB", l / 1024);
702 sprintf(qs, "%d B", l);
704 sprintf(qs, "%3d sl.", l);
706 sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff));
709 if (fs->flags_fs & DN_IS_RED) /* RED parameters */
711 "\n\t %cRED w_q %f min_th %d max_th %d max_p %f",
712 (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ',
713 1.0 * fs->w_q / (double)(1 << SCALE_RED),
714 SCALE_VAL(fs->min_th),
715 SCALE_VAL(fs->max_th),
716 1.0 * fs->max_p / (double)(1 << SCALE_RED));
718 sprintf(red, "droptail");
720 printf("%s %s%s %d queues (%d buckets) %s\n",
721 prefix, qs, plr, fs->rq_elements, fs->rq_size, red);
725 show_pipes(void *data, int nbytes, int ac, char *av[])
729 struct dn_ioc_pipe *p = (struct dn_ioc_pipe *)data;
730 struct dn_ioc_flowset *fs;
731 struct dn_ioc_flowqueue *q;
735 rulenum = strtoul(*av++, NULL, 10);
738 for (; nbytes >= sizeof(*p); p = (struct dn_ioc_pipe *)next) {
739 double b = p->bandwidth;
743 if (p->fs.fs_type != DN_IS_PIPE)
744 break; /* done with pipes, now queues */
747 * compute length, as pipe have variable size
749 l = sizeof(*p) + p->fs.rq_elements * sizeof(*q);
750 next = (void *)p + l;
753 if (rulenum != 0 && rulenum != p->pipe_nr)
760 sprintf(buf, "unlimited");
761 else if (b >= 1000000)
762 sprintf(buf, "%7.3f Mbit/s", b/1000000);
764 sprintf(buf, "%7.3f Kbit/s", b/1000);
766 sprintf(buf, "%7.3f bit/s ", b);
768 sprintf(prefix, "%05d: %s %4d ms ",
769 p->pipe_nr, buf, p->delay);
770 show_flowset_parms(&p->fs, prefix);
772 printf(" V %20ju\n", (uintmax_t)p->V >> MY_M);
774 q = (struct dn_ioc_flowqueue *)(p+1);
775 show_queues(&p->fs, q);
778 for (fs = next; nbytes >= sizeof(*fs); fs = next) {
781 if (fs->fs_type != DN_IS_QUEUE)
783 l = sizeof(*fs) + fs->rq_elements * sizeof(*q);
784 next = (void *)fs + l;
786 q = (struct dn_ioc_flowqueue *)(fs+1);
787 sprintf(prefix, "q%05d: weight %d pipe %d ",
788 fs->fs_nr, fs->weight, fs->parent_nr);
789 show_flowset_parms(fs, prefix);
795 * This one handles all set-related commands
796 * ipfw set { show | enable | disable }
798 * ipfw set move X to Y
799 * ipfw set move rule X to Y
802 sets_handler(int ac, char *av[])
804 u_int32_t set_disable, masks[2];
806 u_int8_t cmd, new_set;
811 errx(EX_USAGE, "set needs command");
812 if (!strncmp(*av, "show", strlen(*av)) ) {
818 while (nbytes >= nalloc) {
819 nalloc = nalloc * 2+321;
822 if ((data = malloc(nbytes)) == NULL) {
823 err(EX_OSERR, "malloc");
825 } else if ((data = realloc(data, nbytes)) == NULL) {
826 err(EX_OSERR, "realloc");
828 if (do_get_x(IP_FW_GET, data, &nbytes) < 0) {
829 err(EX_OSERR, "getsockopt(IP_FW_GET)");
832 set_disable = ((struct ipfw_ioc_rule *)data)->set_disable;
833 for (i = 0, msg = "disable" ; i < 31; i++)
834 if ( (set_disable & (1<<i))) {
835 printf("%s %d", msg, i);
838 msg = (set_disable) ? " enable" : "enable";
839 for (i = 0; i < 31; i++)
840 if ( !(set_disable & (1<<i))) {
841 printf("%s %d", msg, i);
845 } else if (!strncmp(*av, "swap", strlen(*av))) {
848 errx(EX_USAGE, "set swap needs 2 set numbers\n");
849 rulenum = atoi(av[0]);
850 new_set = atoi(av[1]);
851 if (!isdigit(*(av[0])) || rulenum > 30)
852 errx(EX_DATAERR, "invalid set number %s\n", av[0]);
853 if (!isdigit(*(av[1])) || new_set > 30)
854 errx(EX_DATAERR, "invalid set number %s\n", av[1]);
855 masks[0] = (4 << 24) | (new_set << 16) | (rulenum);
856 i = do_set_x(IP_FW_DEL, masks, sizeof(u_int32_t));
857 } else if (!strncmp(*av, "move", strlen(*av))) {
859 if (ac && !strncmp(*av, "rule", strlen(*av))) {
864 if (ac != 3 || strncmp(av[1], "to", strlen(*av)))
865 errx(EX_USAGE, "syntax: set move [rule] X to Y\n");
866 rulenum = atoi(av[0]);
867 new_set = atoi(av[2]);
868 if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > 30) ||
869 (cmd == 2 && rulenum == 65535) )
870 errx(EX_DATAERR, "invalid source number %s\n", av[0]);
871 if (!isdigit(*(av[2])) || new_set > 30)
872 errx(EX_DATAERR, "invalid dest. set %s\n", av[1]);
873 masks[0] = (cmd << 24) | (new_set << 16) | (rulenum);
874 i = do_set_x(IP_FW_DEL, masks, sizeof(u_int32_t));
875 } else if (!strncmp(*av, "disable", strlen(*av)) ||
876 !strncmp(*av, "enable", strlen(*av)) ) {
877 int which = !strncmp(*av, "enable", strlen(*av)) ? 1 : 0;
880 masks[0] = masks[1] = 0;
886 errx(EX_DATAERR, "invalid set number %d\n", i);
887 masks[which] |= (1<<i);
888 } else if (!strncmp(*av, "disable", strlen(*av)))
890 else if (!strncmp(*av, "enable", strlen(*av)))
893 errx(EX_DATAERR, "invalid set command %s\n", *av);
896 if ( (masks[0] & masks[1]) != 0 )
897 errx(EX_DATAERR, "cannot enable and disable the same set\n");
898 i = do_set_x(IP_FW_DEL, masks, sizeof(masks));
900 warn("set enable/disable: setsockopt(IP_FW_DEL)");
902 errx(EX_USAGE, "invalid set command %s\n", *av);
906 add_state(int ac, char *av[])
908 struct ipfw_ioc_state ioc_state;
909 ioc_state.expiry = 0;
910 ioc_state.lifetime = 0;
912 if (strcmp(*av, "rulenum") == 0) {
914 ioc_state.rulenum = atoi(*av);
916 errx(EX_USAGE, "ipfw state add rule");
920 pe = getprotobyname(*av);
921 ioc_state.flow_id.proto = pe->p_proto;
924 ioc_state.flow_id.src_ip = inet_addr(*av);
927 ioc_state.flow_id.src_port = atoi(*av);
930 ioc_state.flow_id.dst_ip = inet_addr(*av);
933 ioc_state.flow_id.dst_port = atoi(*av);
936 if (strcmp(*av, "live") == 0) {
938 ioc_state.lifetime = atoi(*av);
942 if (strcmp(*av, "expiry") == 0) {
944 ioc_state.expiry = strtoul(*av, NULL, 10);
945 printf("ioc_state.expiry=%d\n", ioc_state.expiry);
948 if (do_set_x(IP_FW_STATE_ADD, &ioc_state, sizeof(struct ipfw_ioc_state)) < 0 ) {
949 err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_ADD)");
952 printf("Flushed all states.\n");
957 delete_state(int ac, char *av[])
961 if (ac == 1 && isdigit(**av))
963 if (do_set_x(IP_FW_STATE_DEL, &rulenum, sizeof(int)) < 0 )
964 err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_DEL)");
966 printf("Flushed all states.\n");
970 flush_state(int ac, char *av[])
975 printf("Are you sure? [yn] ");
978 c = toupper(getc(stdin));
979 while (c != '\n' && getc(stdin) != '\n')
981 return; /* and do not flush */
982 } while (c != 'Y' && c != 'N');
983 if (c == 'N') /* user said no */
986 if (do_set_x(IP_FW_STATE_FLUSH, NULL, 0) < 0 )
987 err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_FLUSH)");
989 printf("Flushed all states.\n");
993 lookup_host (char *host, struct in_addr *ipaddr)
997 if (!inet_aton(host, ipaddr)) {
998 if ((he = gethostbyname(host)) == NULL)
1000 *ipaddr = *(struct in_addr *)he->h_addr_list[0];
1006 table_append(int ac, char *av[])
1008 struct ipfw_ioc_table tbl;
1016 errx(EX_USAGE, "table id `%s' invalid", *av);
1018 if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
1019 errx(EX_USAGE, "table id `%d' invalid", tbl.id);
1022 if (strcmp(*av, "ip") == 0)
1024 else if (strcmp(*av, "mac") == 0)
1027 errx(EX_USAGE, "table type `%s' not supported", *av);
1030 if (tbl.type == 1) { /* table type ipv4 */
1031 struct ipfw_ioc_table_ip_entry ip_ent;
1033 errx(EX_USAGE, "IP address required");
1035 p = strchr(*av, '/');
1038 ip_ent.masklen = atoi(p);
1039 if (ip_ent.masklen > 32)
1040 errx(EX_DATAERR, "bad width ``%s''", p);
1042 ip_ent.masklen = 32;
1045 if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
1046 errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
1048 tbl.ip_ent[0] = ip_ent;
1049 size = sizeof(tbl) + sizeof(ip_ent);
1050 } else if (tbl.type == 2) { /* table type mac */
1051 struct ipfw_ioc_table_mac_entry mac_ent;
1053 errx(EX_USAGE, "MAC address required");
1055 mac_ent.addr = *ether_aton(*av);
1056 tbl.mac_ent[0] = mac_ent;
1057 size = sizeof(tbl) + sizeof(mac_ent);
1059 if (do_set_x(IP_FW_TABLE_APPEND, &tbl, size) < 0 )
1060 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_APPEND) "
1061 "table `%d' append `%s' failed", tbl.id, *av);
1065 table_remove(int ac, char *av[])
1067 struct ipfw_ioc_table tbl;
1068 struct ipfw_ioc_table_ip_entry ip_ent;
1076 errx(EX_USAGE, "table id `%s' invalid", *av);
1078 if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
1079 errx(EX_USAGE, "table id `%d' invalid", tbl.id);
1082 if (strcmp(*av, "ip") == 0)
1084 else if (strcmp(*av, "mac") == 0)
1087 errx(EX_USAGE, "table type `%s' not supported", *av);
1091 errx(EX_USAGE, "IP address required");
1092 p = strchr(*av, '/');
1095 ip_ent.masklen = atoi(p);
1096 if (ip_ent.masklen > 32)
1097 errx(EX_DATAERR, "bad width ``%s''", p);
1099 ip_ent.masklen = 32;
1102 if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
1103 errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
1105 tbl.ip_ent[0] = ip_ent;
1106 size = sizeof(tbl) + sizeof(ip_ent);
1107 if (do_set_x(IP_FW_TABLE_REMOVE, &tbl, size) < 0 ) {
1108 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_REMOVE) "
1109 "table `%d' append `%s' failed", tbl.id, *av);
1114 table_flush(int ac, char *av[])
1116 struct ipfw_ioc_table ioc_table;
1117 struct ipfw_ioc_table *t = &ioc_table;
1120 if (isdigit(**av)) {
1122 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1123 errx(EX_USAGE, "table id `%d' invalid", t->id);
1125 errx(EX_USAGE, "table id `%s' invalid", *av);
1127 if (do_set_x(IP_FW_TABLE_FLUSH, t, sizeof(struct ipfw_ioc_table)) < 0 )
1128 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_FLUSH) "
1129 "table `%s' flush failed", *av);
1133 table_list(int ac, char *av[])
1135 struct ipfw_ioc_table *ioc_table;
1136 int i, count, nbytes, nalloc = 1024;
1139 if (strcmp(*av, "list") == 0) {
1141 while (nbytes >= nalloc) {
1142 nalloc = nalloc * 2 ;
1144 if ((data = realloc(data, nbytes)) == NULL)
1145 err(EX_OSERR, "realloc");
1146 if (do_get_x(IP_FW_TABLE_LIST, data, &nbytes) < 0)
1147 err(EX_OSERR, "do_get_x(IP_FW_TABLE_LIST)");
1149 ioc_table = (struct ipfw_ioc_table *)data;
1150 count = nbytes / sizeof(struct ipfw_ioc_table);
1151 for (i = 0; i < count; i++, ioc_table++) {
1152 if (ioc_table->type > 0) {
1153 printf("table %d",ioc_table->id);
1154 if (ioc_table->type == 1)
1156 else if (ioc_table->type == 2)
1157 printf(" type mac");
1158 printf(" count %d",ioc_table->count);
1159 if (strlen(ioc_table->name) > 0)
1160 printf(" name %s",ioc_table->name);
1166 errx(EX_USAGE, "ipfw3 table `%s' delete invalid", *av);
1171 print_table(struct ipfw_ioc_table * tbl)
1175 errx(EX_USAGE, "table %d is not in use", tbl->id);
1177 printf("table %d", tbl->id);
1180 else if (tbl->type == 2)
1181 printf(" type mac");
1183 printf(" count %d", tbl->count);
1184 if (strlen(tbl->name) > 0)
1185 printf(" name %s", tbl->name);
1189 if (tbl->type == 1) {
1190 struct ipfw_ioc_table_ip_entry *ip_ent;
1191 ip_ent = tbl->ip_ent;
1192 for (i = 0; i < tbl->count; i++) {
1193 printf("%s", inet_ntoa(*(struct in_addr *)&ip_ent->addr));
1194 printf("/%d ", ip_ent->masklen);
1198 } else if (tbl->type == 2) {
1199 struct ipfw_ioc_table_mac_entry *mac_ent;
1200 mac_ent = tbl->mac_ent;
1201 for (i = 0; i < tbl->count; i++) {
1202 printf("%s", ether_ntoa(&mac_ent->addr));
1210 table_show(int ac, char *av[])
1212 int nbytes, nalloc = 1024;
1215 if (isdigit(**av)) {
1217 while (nbytes >= nalloc) {
1218 nalloc = nalloc * 2 + 256;
1221 if ((data = malloc(nbytes)) == NULL) {
1222 err(EX_OSERR, "malloc");
1224 } else if ((data = realloc(data, nbytes)) == NULL) {
1225 err(EX_OSERR, "realloc");
1227 /* store table id in the header of data */
1228 int *head = (int *)data;
1230 if (*head < 0 || *head > IPFW_TABLES_MAX - 1)
1231 errx(EX_USAGE, "table id `%d' invalid", *head);
1232 if (do_get_x(IP_FW_TABLE_SHOW, data, &nbytes) < 0)
1233 err(EX_OSERR, "do_get_x(IP_FW_TABLE_LIST)");
1234 struct ipfw_ioc_table *tbl;
1235 tbl = (struct ipfw_ioc_table *)data;
1239 errx(EX_USAGE, "ipfw3 table `%s' show invalid", *av);
1244 table_create(int ac, char *av[])
1246 struct ipfw_ioc_table ioc_table;
1247 struct ipfw_ioc_table *t = &ioc_table;
1251 errx(EX_USAGE, "table parameters invalid");
1252 if (isdigit(**av)) {
1254 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1255 errx(EX_USAGE, "table id `%d' invalid", t->id);
1257 errx(EX_USAGE, "table id `%s' invalid", *av);
1260 if (strcmp(*av, "ip") == 0)
1262 else if (strcmp(*av, "mac") == 0)
1265 errx(EX_USAGE, "table type `%s' not supported", *av);
1268 memset(t->name, 0, IPFW_TABLE_NAME_LEN);
1269 if (ac == 2 && strcmp(*av, "name") == 0) {
1271 if (strlen(*av) < IPFW_TABLE_NAME_LEN) {
1272 strncpy(t->name, *av, strlen(*av));
1274 errx(EX_USAGE, "table name `%s' too long", *av);
1276 } else if (ac == 1) {
1277 errx(EX_USAGE, "table `%s' invalid", *av);
1280 if (do_set_x(IP_FW_TABLE_CREATE, t, sizeof(struct ipfw_ioc_table)) < 0)
1281 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_CREATE) "
1282 "table `%d' in use", t->id);
1286 table_delete(int ac, char *av[])
1288 struct ipfw_ioc_table ioc_table;
1289 struct ipfw_ioc_table *t = &ioc_table;
1292 if (isdigit(**av)) {
1294 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1295 errx(EX_USAGE, "table id `%d' invalid", t->id);
1297 errx(EX_USAGE, "table id `%s' invalid", *av);
1299 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1300 errx(EX_USAGE, "table id `%d' invalid", t->id);
1302 if (do_set_x(IP_FW_TABLE_DELETE, t, sizeof(struct ipfw_ioc_table)) < 0)
1303 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_DELETE) "
1304 "table `%s' delete failed", *av);
1308 table_test(int ac, char *av[])
1310 struct ipfw_ioc_table tbl;
1317 errx(EX_USAGE, "table id `%s' invalid", *av);
1319 if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
1320 errx(EX_USAGE, "table id `%d' invalid", tbl.id);
1323 if (strcmp(*av, "ip") == 0)
1325 else if (strcmp(*av, "mac") == 0)
1328 errx(EX_USAGE, "table type `%s' not supported", *av);
1331 if (tbl.type == 1) { /* table type ipv4 */
1332 struct ipfw_ioc_table_ip_entry ip_ent;
1333 if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
1334 errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
1336 tbl.ip_ent[0] = ip_ent;
1337 size = sizeof(tbl) + sizeof(ip_ent);
1338 } else if (tbl.type == 2) { /* table type mac */
1339 struct ipfw_ioc_table_mac_entry mac_ent;
1341 errx(EX_USAGE, "MAC address required");
1343 mac_ent.addr = *ether_aton(*av);
1344 tbl.mac_ent[0] = mac_ent;
1345 size = sizeof(tbl) + sizeof(mac_ent);
1347 if (do_set_x(IP_FW_TABLE_TEST, &tbl, size) < 0 ) {
1348 printf("NO, %s not exists in table %d\n", *av, tbl.id);
1350 printf("YES, %s exists in table %d\n", *av, tbl.id);
1355 table_rename(int ac, char *av[])
1357 struct ipfw_ioc_table tbl;
1360 bzero(&tbl, sizeof(tbl));
1365 errx(EX_USAGE, "table id `%s' invalid", *av);
1367 if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
1368 errx(EX_USAGE, "table id `%d' invalid", tbl.id);
1371 strlcpy(tbl.name, *av, IPFW_TABLE_NAME_LEN);
1373 if (do_set_x(IP_FW_TABLE_RENAME, &tbl, size) < 0 )
1374 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_RENAME) "
1375 "table `%d' not in use", tbl.id);
1379 list(int ac, char *av[])
1381 struct ipfw_ioc_state *dynrules, *d;
1382 struct ipfw_ioc_rule *r;
1386 int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width;
1387 int exitval = EX_OK, lac;
1388 char **lav, *endptr;
1394 /* get rules or pipes from kernel, resizing array as necessary */
1397 while (nbytes >= nalloc) {
1398 nalloc = nalloc * 2 ;
1400 if ((data = realloc(data, nbytes)) == NULL)
1401 err(EX_OSERR, "realloc");
1402 if (do_get_x(IP_FW_GET, data, &nbytes) < 0)
1403 err(EX_OSERR, "do_get_x(IP_FW_GET)");
1407 * Count static rules.
1410 nstat = r->static_count;
1413 * Count dynamic rules. This is easier as they have
1416 dynrules = (struct ipfw_ioc_state *)((void *)r + r->static_len);
1417 ndyn = (nbytes - r->static_len) / sizeof(*dynrules);
1419 /* if showing stats, figure out column widths ahead of time */
1420 bcwidth = pcwidth = 0;
1422 for (n = 0, r = data; n < nstat;
1423 n++, r = (void *)r + IOC_RULESIZE(r)) {
1424 /* packet counter */
1425 width = snprintf(NULL, 0, "%ju", (uintmax_t)r->pcnt);
1426 if (width > pcwidth)
1430 width = snprintf(NULL, 0, "%ju", (uintmax_t)r->bcnt);
1431 if (width > bcwidth)
1435 if (do_dynamic && ndyn) {
1436 for (n = 0, d = dynrules; n < ndyn; n++, d++) {
1437 width = snprintf(NULL, 0, "%ju", (uintmax_t)d->pcnt);
1438 if (width > pcwidth)
1441 width = snprintf(NULL, 0, "%ju", (uintmax_t)d->bcnt);
1442 if (width > bcwidth)
1447 /* if no rule numbers were specified, list all rules */
1449 if (do_dynamic != 2) {
1450 for (n = 0, r = data; n < nstat; n++,
1451 r = (void *)r + IOC_RULESIZE(r)) {
1452 show_rules(r, pcwidth, bcwidth);
1455 if (do_dynamic && ndyn) {
1456 if (do_dynamic != 2) {
1457 printf("## States (%d):\n", ndyn);
1459 for (n = 0, d = dynrules; n < ndyn; n++, d++)
1460 show_states(d, pcwidth, bcwidth);
1465 /* display specific rules requested on command line */
1467 if (do_dynamic != 2) {
1468 for (lac = ac, lav = av; lac != 0; lac--) {
1469 /* convert command line rule # */
1470 rnum = strtoul(*lav++, &endptr, 10);
1473 warnx("invalid rule number: %s", *(lav - 1));
1476 for (n = seen = 0, r = data; n < nstat;
1477 n++, r = (void *)r + IOC_RULESIZE(r) ) {
1478 if (r->rulenum > rnum)
1480 if (r->rulenum == rnum) {
1481 show_rules(r, pcwidth, bcwidth);
1486 /* give precedence to other error(s) */
1487 if (exitval == EX_OK)
1488 exitval = EX_UNAVAILABLE;
1489 warnx("rule %lu does not exist", rnum);
1494 if (do_dynamic && ndyn) {
1495 if (do_dynamic != 2) {
1496 printf("## States (%d):\n", ndyn);
1498 for (lac = ac, lav = av; lac != 0; lac--) {
1499 rnum = strtoul(*lav++, &endptr, 10);
1501 /* already warned */
1503 for (n = 0, d = dynrules; n < ndyn; n++, d++) {
1504 if (d->rulenum > rnum)
1506 if (d->rulenum == rnum)
1507 show_states(d, pcwidth, bcwidth);
1517 if (exitval != EX_OK)
1522 show_dummynet(int ac, char *av[])
1526 int nalloc = 1024; /* start somewhere... */
1531 while (nbytes >= nalloc) {
1532 nalloc = nalloc * 2 + 200;
1534 if ((data = realloc(data, nbytes)) == NULL)
1535 err(EX_OSERR, "realloc");
1536 if (do_get_x(IP_DUMMYNET_GET, data, &nbytes) < 0) {
1537 err(EX_OSERR, "do_get_x(IP_%s_GET)",
1538 do_pipe ? "DUMMYNET" : "FW");
1542 show_pipes(data, nbytes, ac, av);
1549 fprintf(stderr, "usage: ipfw [options]\n"
1550 " ipfw add [rulenum] [set id] action filters\n"
1551 " ipfw delete [rulenum]\n"
1553 " ipfw list [rulenum]\n"
1554 " ipfw show [rulenum]\n"
1555 " ipfw zero [rulenum]\n"
1556 " ipfw set [show|enable|disable]\n"
1558 " ipfw [enable|disable]\n"
1559 " ipfw log [reset|off|on]\n"
1560 " ipfw nat [config|show|delete]\n"
1561 " ipfw pipe [config|show|delete]\n"
1562 " ipfw state [add|delete|list|show]"
1563 "\nsee ipfw manpage for details\n");
1569 delete_rules(int ac, char *av[])
1571 struct dn_ioc_pipe pipe;
1573 int exitval = EX_OK;
1577 memset(&pipe, 0, sizeof pipe);
1580 if (ac > 0 && !strncmp(*av, "set", strlen(*av))) {
1581 do_set = 1; /* delete set */
1586 while (ac && isdigit(**av)) {
1595 i = do_set_x(IP_DUMMYNET_DEL, &pipe, sizeof pipe);
1598 warn("rule %u: setsockopt(IP_DUMMYNET_DEL)",
1599 do_pipe == 1 ? pipe.pipe_nr :
1603 rulenum = (i & 0xffff) | (do_set << 24);
1604 i = do_set_x(IP_FW_DEL, &rulenum, sizeof rulenum);
1606 exitval = EX_UNAVAILABLE;
1607 warn("rule %u: setsockopt(IP_FW_DEL)",
1612 if (exitval != EX_OK)
1617 static unsigned long
1618 getbw(const char *str, u_short *flags, int kb)
1624 val = strtoul(str, &end, 0);
1625 if (*end == 'k' || *end == 'K') {
1628 } else if (*end == 'm' || *end == 'M') {
1634 * Deal with bits or bytes or b(bits) or B(bytes). If there is no
1635 * trailer assume bits.
1637 if (strncasecmp(end, "bit", 3) == 0) {
1639 } else if (strncasecmp(end, "byte", 4) == 0) {
1641 } else if (*end == 'b') {
1643 } else if (*end == 'B') {
1648 * Return in bits if flags is NULL, else flag bits
1649 * or bytes in flags and return the unconverted value.
1651 if (inbytes && flags)
1652 *flags |= DN_QSIZE_IS_BYTES;
1653 else if (inbytes && flags == NULL)
1660 * config dummynet pipe/queue
1663 config_dummynet(int ac, char **av)
1665 struct dn_ioc_pipe pipe;
1672 memset(&pipe, 0, sizeof pipe);
1674 if (ac && isdigit(**av)) {
1686 int tok = match_token(dummynet_params, *av);
1691 pipe.fs.flags_fs |= DN_NOERROR;
1695 NEED1("plr needs argument 0..1\n");
1696 d = strtod(av[0], NULL);
1701 pipe.fs.plr = (int)(d*0x7fffffff);
1706 NEED1("queue needs queue size\n");
1708 pipe.fs.qsize = getbw(av[0], &pipe.fs.flags_fs, 1024);
1713 NEED1("buckets needs argument\n");
1714 pipe.fs.rq_size = strtoul(av[0], NULL, 0);
1719 NEED1("mask needs mask specifier\n");
1721 * per-flow queue, mask is dst_ip, dst_port,
1722 * src_ip, src_port, proto measured in bits
1726 pipe.fs.flow_mask.type = ETHERTYPE_IP;
1727 pipe.fs.flow_mask.u.ip.dst_ip = 0;
1728 pipe.fs.flow_mask.u.ip.src_ip = 0;
1729 pipe.fs.flow_mask.u.ip.dst_port = 0;
1730 pipe.fs.flow_mask.u.ip.src_port = 0;
1731 pipe.fs.flow_mask.u.ip.proto = 0;
1735 u_int32_t *p32 = NULL;
1736 u_int16_t *p16 = NULL;
1738 tok = match_token(dummynet_params, *av);
1743 * special case, all bits significant
1745 pipe.fs.flow_mask.u.ip.dst_ip = ~0;
1746 pipe.fs.flow_mask.u.ip.src_ip = ~0;
1747 pipe.fs.flow_mask.u.ip.dst_port = ~0;
1748 pipe.fs.flow_mask.u.ip.src_port = ~0;
1749 pipe.fs.flow_mask.u.ip.proto = ~0;
1750 pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
1754 p32 = &pipe.fs.flow_mask.u.ip.dst_ip;
1758 p32 = &pipe.fs.flow_mask.u.ip.src_ip;
1762 p16 = &pipe.fs.flow_mask.u.ip.dst_port;
1766 p16 = &pipe.fs.flow_mask.u.ip.src_port;
1777 errx(EX_USAGE, "mask: value missing");
1778 if (*av[0] == '/') {
1779 a = strtoul(av[0]+1, &end, 0);
1780 a = (a == 32) ? ~0 : (1 << a) - 1;
1782 a = strtoul(av[0], &end, 0);
1785 else if (p16 != NULL) {
1788 "mask: must be 16 bit");
1789 *p16 = (u_int16_t)a;
1793 "mask: must be 8 bit");
1794 pipe.fs.flow_mask.u.ip.proto =
1798 pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
1800 } /* end while, config masks */
1807 NEED1("red/gred needs w_q/min_th/max_th/max_p\n");
1808 pipe.fs.flags_fs |= DN_IS_RED;
1809 if (tok == TOK_GRED)
1810 pipe.fs.flags_fs |= DN_IS_GENTLE_RED;
1812 * the format for parameters is w_q/min_th/max_th/max_p
1814 if ((end = strsep(&av[0], "/"))) {
1815 double w_q = strtod(end, NULL);
1816 if (w_q > 1 || w_q <= 0)
1817 errx(EX_DATAERR, "0 < w_q <= 1");
1818 pipe.fs.w_q = (int) (w_q * (1 << SCALE_RED));
1820 if ((end = strsep(&av[0], "/"))) {
1821 pipe.fs.min_th = strtoul(end, &end, 0);
1822 if (*end == 'K' || *end == 'k')
1823 pipe.fs.min_th *= 1024;
1825 if ((end = strsep(&av[0], "/"))) {
1826 pipe.fs.max_th = strtoul(end, &end, 0);
1827 if (*end == 'K' || *end == 'k')
1828 pipe.fs.max_th *= 1024;
1830 if ((end = strsep(&av[0], "/"))) {
1831 double max_p = strtod(end, NULL);
1832 if (max_p > 1 || max_p <= 0)
1833 errx(EX_DATAERR, "0 < max_p <= 1");
1834 pipe.fs.max_p = (int)(max_p * (1 << SCALE_RED));
1840 pipe.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED);
1844 NEED1("bw needs bandwidth\n");
1847 "bandwidth only valid for pipes");
1849 * set bandwidth value
1851 pipe.bandwidth = getbw(av[0], NULL, 1000);
1852 if (pipe.bandwidth < 0)
1853 errx(EX_DATAERR, "bandwidth too large");
1859 errx(EX_DATAERR, "delay only valid for pipes");
1860 NEED1("delay needs argument 0..10000ms\n");
1861 pipe.delay = strtoul(av[0], NULL, 0);
1868 "weight only valid for queues");
1869 NEED1("weight needs argument 0..100\n");
1870 pipe.fs.weight = strtoul(av[0], &end, 0);
1876 errx(EX_DATAERR, "pipe only valid for queues");
1877 NEED1("pipe needs pipe_number\n");
1878 pipe.fs.parent_nr = strtoul(av[0], &end, 0);
1883 errx(EX_DATAERR, "unrecognised option ``%s''", *av);
1887 if (pipe.pipe_nr == 0)
1888 errx(EX_DATAERR, "pipe_nr must be > 0");
1889 if (pipe.delay > 10000)
1890 errx(EX_DATAERR, "delay must be < 10000");
1891 } else { /* do_pipe == 2, queue */
1892 if (pipe.fs.parent_nr == 0)
1893 errx(EX_DATAERR, "pipe must be > 0");
1894 if (pipe.fs.weight >100)
1895 errx(EX_DATAERR, "weight must be <= 100");
1897 if (pipe.fs.flags_fs & DN_QSIZE_IS_BYTES) {
1898 if (pipe.fs.qsize > 1024*1024)
1899 errx(EX_DATAERR, "queue size must be < 1MB");
1901 if (pipe.fs.qsize > 100)
1902 errx(EX_DATAERR, "2 <= queue size <= 100");
1904 if (pipe.fs.flags_fs & DN_IS_RED) {
1906 int lookup_depth, avg_pkt_size;
1907 double s, idle, weight, w_q;
1911 if (pipe.fs.min_th >= pipe.fs.max_th)
1912 errx(EX_DATAERR, "min_th %d must be < than max_th %d",
1913 pipe.fs.min_th, pipe.fs.max_th);
1914 if (pipe.fs.max_th == 0)
1915 errx(EX_DATAERR, "max_th must be > 0");
1918 if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
1919 &lookup_depth, &len, NULL, 0) == -1)
1921 errx(1, "sysctlbyname(\"%s\")",
1922 "net.inet.ip.dummynet.red_lookup_depth");
1923 if (lookup_depth == 0)
1924 errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth"
1925 " must be greater than zero");
1928 if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
1929 &avg_pkt_size, &len, NULL, 0) == -1)
1931 errx(1, "sysctlbyname(\"%s\")",
1932 "net.inet.ip.dummynet.red_avg_pkt_size");
1933 if (avg_pkt_size == 0)
1935 "net.inet.ip.dummynet.red_avg_pkt_size must"
1936 " be greater than zero");
1938 len = sizeof(clock_hz);
1939 if (sysctlbyname("net.inet.ip.dummynet.hz", &clock_hz, &len,
1941 errx(1, "sysctlbyname(\"%s\")",
1942 "net.inet.ip.dummynet.hz");
1946 * Ticks needed for sending a medium-sized packet.
1947 * Unfortunately, when we are configuring a WF2Q+ queue, we
1948 * do not have bandwidth information, because that is stored
1949 * in the parent pipe, and also we have multiple queues
1950 * competing for it. So we set s=0, which is not very
1951 * correct. But on the other hand, why do we want RED with
1954 if (pipe.bandwidth == 0) /* this is a WF2Q+ queue */
1957 s = clock_hz * avg_pkt_size * 8 / pipe.bandwidth;
1960 * max idle time (in ticks) before avg queue size becomes 0.
1961 * NOTA: (3/w_q) is approx the value x so that
1962 * (1-w_q)^x < 10^-3.
1964 w_q = ((double)pipe.fs.w_q) / (1 << SCALE_RED);
1965 idle = s * 3. / w_q;
1966 pipe.fs.lookup_step = (int)idle / lookup_depth;
1967 if (!pipe.fs.lookup_step)
1968 pipe.fs.lookup_step = 1;
1970 for (t = pipe.fs.lookup_step; t > 0; --t)
1972 pipe.fs.lookup_weight = (int)(weight * (1 << SCALE_RED));
1974 i = do_set_x(IP_DUMMYNET_CONFIGURE, &pipe, sizeof pipe);
1976 err(1, "do_set_x(%s)", "IP_DUMMYNET_CONFIGURE");
1980 * helper function, updates the pointer to cmd with the length
1981 * of the current command, and also cleans up the first word of
1982 * the new command in case it has been clobbered before.
1985 next_cmd(ipfw_insn *cmd)
1988 bzero(cmd, sizeof(*cmd));
1993 * Parse arguments and assemble the microinstructions which make up a rule.
1994 * Rules are added into the 'rulebuf' and then copied in the correct order
1995 * into the actual rule.
2000 add(int ac, char *av[])
2003 * rules are added into the 'rulebuf' and then copied in
2004 * the correct order into the actual rule.
2005 * Some things that need to go out of order (prob, action etc.)
2008 static uint32_t rulebuf[IPFW_RULE_SIZE_MAX];
2009 static uint32_t actbuf[IPFW_RULE_SIZE_MAX];
2010 static uint32_t othbuf[IPFW_RULE_SIZE_MAX];
2011 static uint32_t cmdbuf[IPFW_RULE_SIZE_MAX];
2013 ipfw_insn *src, *dst, *cmd, *action, *other;
2016 ipfw_insn *the_comment = NULL;
2017 struct ipfw_ioc_rule *rule;
2018 struct ipfw_keyword *key;
2019 struct ipfw_mapping *map;
2023 bzero(actbuf, sizeof(actbuf)); /* actions go here */
2024 bzero(othbuf, sizeof(actbuf)); /* others */
2025 bzero(cmdbuf, sizeof(cmdbuf)); /* filters */
2026 bzero(rulebuf, sizeof(rulebuf));
2028 rule = (struct ipfw_ioc_rule *)rulebuf;
2029 cmd = (ipfw_insn *)cmdbuf;
2030 action = (ipfw_insn *)actbuf;
2031 other = (ipfw_insn *)othbuf;
2033 NEED2("need more parameters");
2036 /* [rule N] -- Rule number optional */
2037 if (ac && isdigit(**av)) {
2038 rule->rulenum = atoi(*av);
2042 /* [set N] -- set number (0..30), optional */
2043 if (ac > 1 && !strncmp(*av, "set", strlen(*av))) {
2044 int set = strtoul(av[1], NULL, 10);
2045 if (set < 0 || set > 30)
2046 errx(EX_DATAERR, "illegal set %s", av[1]);
2055 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
2056 if (key->type == BEFORE &&
2057 strcmp(key->word, *av) == 0) {
2058 for (j = 0, map = mappings;
2059 j < MAPPING_SIZE; j++, map++) {
2060 if (map->type == IN_USE &&
2061 map->module == key->module &&
2062 map->opcode == key->opcode ) {
2064 (*fn)(&other, &ac, &av);
2071 if (i >= KEYWORD_SIZE) {
2073 } else if (F_LEN(other) > 0) {
2074 if (other->module == MODULE_BASIC_ID &&
2075 other->opcode == O_BASIC_CHECK_STATE) {
2076 other = next_cmd(other);
2079 other = next_cmd(other);
2086 * only accept 1 action
2088 NEED1("missing action");
2089 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
2090 if (ac > 0 && key->type == ACTION &&
2091 strcmp(key->word, *av) == 0) {
2092 for (j = 0, map = mappings;
2093 j < MAPPING_SIZE; j++, map++) {
2094 if (map->type == IN_USE &&
2095 map->module == key->module &&
2096 map->opcode == key->opcode) {
2098 (*fn)(&action, &ac, &av);
2105 if (F_LEN(action) > 0)
2106 action = next_cmd(action);
2111 if (strcmp(*av, "proto") == 0){
2115 NEED1("missing protocol");
2116 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
2117 if (key->type == PROTO &&
2118 strcmp(key->word, "proto") == 0) {
2119 for (j = 0, map = mappings;
2120 j < MAPPING_SIZE; j++, map++) {
2121 if (map->type == IN_USE &&
2122 map->module == key->module &&
2123 map->opcode == key->opcode ) {
2125 (*fn)(&cmd, &ac, &av);
2133 cmd = next_cmd(cmd);
2139 char *s, *cur; /* current filter */
2140 ipfw_insn_u32 *cmd32; /* alias for cmd */
2143 cmd32 = (ipfw_insn_u32 *)cmd;
2144 if (strcmp(*av, "or") == 0) {
2146 errx(EX_USAGE, "'or' should"
2147 "between two filters\n");
2152 if (strcmp(*av, "not") == 0) {
2153 if (cmd->len & F_NOT)
2154 errx(EX_USAGE, "double \"not\" not allowed\n");
2160 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
2161 if ((key->type == FILTER ||
2162 key->type == AFTER ||
2163 key->type == FROM ||
2165 strcmp(key->word, cur) == 0) {
2166 for (j = 0, map = mappings;
2167 j< MAPPING_SIZE; j++, map++) {
2168 if (map->type == IN_USE &&
2169 map->module == key->module &&
2170 map->opcode == key->opcode ) {
2172 (*fn)(&cmd, &ac, &av);
2177 } else if (i == KEYWORD_SIZE - 1) {
2178 errx(EX_USAGE, "bad command `%s'", cur);
2181 if (i >= KEYWORD_SIZE) {
2183 } else if (F_LEN(cmd) > 0) {
2186 cmd = next_cmd(cmd);
2192 errx(EX_USAGE, "bad command `%s'", *av);
2195 * Now copy stuff into the rule.
2196 * [filters][others][action][comment]
2198 dst = (ipfw_insn *)rule->cmd;
2200 * copy all filters, except comment
2202 src = (ipfw_insn *)cmdbuf;
2203 for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) {
2204 /* pick comment out */
2206 if (src->module == MODULE_BASIC_ID &&
2207 src->opcode == O_BASIC_COMMENT) {
2210 bcopy(src, dst, i * sizeof(u_int32_t));
2211 dst = (ipfw_insn *)((uint32_t *)dst + i);
2216 * start action section, it begin with others
2218 rule->act_ofs = (uint32_t *)dst - (uint32_t *)(rule->cmd);
2221 * copy all other others
2223 for (src = (ipfw_insn *)othbuf; src != other; src += i) {
2225 bcopy(src, dst, i * sizeof(u_int32_t));
2226 dst = (ipfw_insn *)((uint32_t *)dst + i);
2229 /* copy the action to the end of rule */
2230 src = (ipfw_insn *)actbuf;
2232 bcopy(src, dst, i * sizeof(u_int32_t));
2233 dst = (ipfw_insn *)((uint32_t *)dst + i);
2236 * comment place behind the action
2238 if (the_comment != NULL) {
2239 i = F_LEN(the_comment);
2240 bcopy(the_comment, dst, i * sizeof(u_int32_t));
2241 dst = (ipfw_insn *)((uint32_t *)dst + i);
2244 rule->cmd_len = (u_int32_t *)dst - (u_int32_t *)(rule->cmd);
2245 i = (void *)dst - (void *)rule;
2246 if (do_set_x(IP_FW_ADD, (void *)rule, i) == -1) {
2247 err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD");
2250 show_rules(rule, 10, 10);
2254 zero(int ac, char *av[])
2262 /* clear all entries */
2263 if (do_set_x(IP_FW_ZERO, NULL, 0) < 0)
2264 err(EX_UNAVAILABLE, "do_set_x(IP_FW_ZERO)");
2266 printf("Accounting cleared.\n");
2272 if (isdigit(**av)) {
2273 rulenum = atoi(*av);
2275 if (do_set_x(IP_FW_ZERO, &rulenum, sizeof rulenum)) {
2276 warn("rule %u: do_set_x(IP_FW_ZERO)", rulenum);
2277 failed = EX_UNAVAILABLE;
2278 } else if (!do_quiet)
2279 printf("Entry %d cleared\n", rulenum);
2281 errx(EX_USAGE, "invalid rule number ``%s''", *av);
2284 if (failed != EX_OK)
2289 resetlog(int ac, char *av[])
2297 /* clear all entries */
2298 if (setsockopt(ipfw_socket, IPPROTO_IP,
2299 IP_FW_RESETLOG, NULL, 0) < 0)
2300 err(EX_UNAVAILABLE, "setsockopt(IP_FW_RESETLOG)");
2302 printf("Logging counts reset.\n");
2309 if (isdigit(**av)) {
2310 rulenum = atoi(*av);
2312 if (setsockopt(ipfw_socket, IPPROTO_IP,
2313 IP_FW_RESETLOG, &rulenum, sizeof rulenum)) {
2314 warn("rule %u: setsockopt(IP_FW_RESETLOG)",
2316 failed = EX_UNAVAILABLE;
2317 } else if (!do_quiet)
2318 printf("Entry %d logging count reset\n",
2321 errx(EX_DATAERR, "invalid rule number ``%s''", *av);
2324 if (failed != EX_OK)
2331 int cmd = IP_FW_FLUSH;
2333 cmd = IP_DUMMYNET_FLUSH;
2338 printf("Are you sure? [yn] ");
2341 c = toupper(getc(stdin));
2342 while (c != '\n' && getc(stdin) != '\n')
2344 return; /* and do not flush */
2345 } while (c != 'Y' && c != 'N');
2346 if (c == 'N') /* user said no */
2349 if (do_set_x(cmd, NULL, 0) < 0 ) {
2351 errx(EX_USAGE, "pipe/queue in use");
2353 errx(EX_USAGE, "do_set_x(IP_FW_FLUSH) failed");
2356 printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules");
2361 * do_set_x - extended version og do_set
2362 * insert a x_header in the beginning of the rule buf
2363 * and call setsockopt() with IP_FW_X.
2366 do_set_x(int optname, void *rule, int optlen)
2370 ip_fw_x_header *x_header;
2371 if (ipfw_socket < 0)
2372 err(EX_UNAVAILABLE, "socket not avaialble");
2373 len = optlen + sizeof(ip_fw_x_header);
2374 newbuf = malloc(len);
2376 err(EX_OSERR, "malloc newbuf in do_set_x");
2378 x_header = (ip_fw_x_header *)newbuf;
2379 x_header->opcode = optname;
2380 /* copy the rule into the newbuf, just after the x_header*/
2381 bcopy(rule, ++x_header, optlen);
2382 return setsockopt(ipfw_socket, IPPROTO_IP, IP_FW_X, newbuf, len);
2389 do_get_x(int optname, void *rule, int *optlen)
2391 int len, *newbuf, retval;
2393 ip_fw_x_header *x_header;
2394 if (ipfw_socket < 0)
2395 err(EX_UNAVAILABLE, "socket not avaialble");
2396 len = *optlen + sizeof(ip_fw_x_header);
2397 newbuf = malloc(len);
2399 err(EX_OSERR, "malloc newbuf in do_get_x");
2401 x_header = (ip_fw_x_header *)newbuf;
2402 x_header->opcode = optname;
2403 /* copy the rule into the newbuf, just after the x_header*/
2404 bcopy(rule, ++x_header, *optlen);
2405 retval = getsockopt(ipfw_socket, IPPROTO_IP, IP_FW_X, newbuf, &len);
2406 bcopy(newbuf, rule, len);
2412 ipfw_main(int ac, char **av)
2419 /* Set the force flag for non-interactive processes */
2420 do_force = !isatty(STDIN_FILENO);
2422 optind = optreset = 1;
2423 while ((ch = getopt(ac, av, "hs:acdDefNStTv")) != -1)
2425 case 'h': /* help */
2427 break; /* NOTREACHED */
2429 case 's': /* sort */
2430 do_sort = atoi(optarg);
2472 NEED1("bad arguments, for usage summary ``ipfw''");
2475 * optional: pipe or queue or nat
2479 if (!strncmp(*av, "nat", strlen(*av)))
2481 else if (!strncmp(*av, "pipe", strlen(*av))) {
2483 } else if (!strncmp(*av, "queue", strlen(*av))) {
2486 NEED1("missing command");
2489 * for pipes and queues and nat we normally say 'pipe NN config'
2490 * but the code is easier to parse as 'pipe config NN'
2491 * so we swap the two arguments.
2493 if ((do_pipe || do_nat) && ac > 2 && isdigit(*(av[1]))) {
2499 if (!strncmp(*av, "add", strlen(*av))) {
2502 } else if (!strncmp(*av, "delete", strlen(*av))) {
2503 delete_rules(ac, av);
2504 } else if (!strncmp(*av, "flush", strlen(*av))) {
2506 } else if (!strncmp(*av, "list", strlen(*av))) {
2509 } else if (!strncmp(*av, "show", strlen(*av))) {
2513 } else if (!strncmp(*av, "zero", strlen(*av))) {
2515 } else if (!strncmp(*av, "set", strlen(*av))) {
2516 sets_handler(ac, av);
2517 } else if (!strncmp(*av, "module", strlen(*av))) {
2519 if (!strncmp(*av, "show", strlen(*av)) ||
2520 !strncmp(*av, "show", strlen(*av))) {
2521 list_modules(ac, av);
2523 errx(EX_USAGE, "bad ipfw module command `%s'", *av);
2525 } else if (!strncmp(*av, "resetlog", strlen(*av))) {
2527 } else if (!strncmp(*av, "log", strlen(*av))) {
2529 if (!strncmp(*av, "reset", strlen(*av))) {
2531 } else if (!strncmp(*av, "off", strlen(*av))) {
2533 } else if (!strncmp(*av, "on", strlen(*av))) {
2536 errx(EX_USAGE, "bad command `%s'", *av);
2538 } else if (!strncmp(*av, "nat", strlen(*av))) {
2541 } else if (!strncmp(*av, "pipe", strlen(*av)) ||
2542 !strncmp(*av, "queue", strlen(*av))) {
2544 if (!strncmp(*av, "config", strlen(*av))) {
2545 config_dummynet(ac, av);
2546 } else if (!strncmp(*av, "flush", strlen(*av))) {
2548 } else if (!strncmp(*av, "show", strlen(*av))) {
2549 show_dummynet(ac, av);
2551 errx(EX_USAGE, "bad ipfw pipe command `%s'", *av);
2553 } else if (!strncmp(*av, "state", strlen(*av))) {
2555 if (!strncmp(*av, "add", strlen(*av))) {
2557 } else if (!strncmp(*av, "delete", strlen(*av))) {
2558 delete_state(ac, av);
2559 } else if (!strncmp(*av, "flush", strlen(*av))) {
2560 flush_state(ac, av);
2561 } else if (!strncmp(*av, "list", strlen(*av))) {
2564 } else if (!strncmp(*av, "show", strlen(*av))) {
2569 errx(EX_USAGE, "bad ipfw state command `%s'", *av);
2571 } else if (!strncmp(*av, "table", strlen(*av))) {
2572 if (ac > 2 && isdigit(*(av[1]))) {
2578 if (!strncmp(*av, "append", strlen(*av))) {
2579 table_append(ac, av);
2580 } else if (!strncmp(*av, "remove", strlen(*av))) {
2581 table_remove(ac, av);
2582 } else if (!strncmp(*av, "flush", strlen(*av))) {
2583 table_flush(ac, av);
2584 } else if (!strncmp(*av, "list", strlen(*av))) {
2586 } else if (!strncmp(*av, "show", strlen(*av))) {
2588 } else if (!strncmp(*av, "type", strlen(*av))) {
2589 table_create(ac, av);
2590 } else if (!strncmp(*av, "delete", strlen(*av))) {
2591 table_delete(ac, av);
2592 } else if (!strncmp(*av, "test", strlen(*av))) {
2594 } else if (!strncmp(*av, "name", strlen(*av))) {
2595 table_rename(ac, av);
2597 errx(EX_USAGE, "bad ipfw table command `%s'", *av);
2599 } else if (!strncmp(*av, "sync", strlen(*av))) {
2601 if (!strncmp(*av, "edge", strlen(*av))) {
2602 sync_config_edge(ac, av);
2603 } else if (!strncmp(*av, "centre", strlen(*av))) {
2604 sync_config_centre(ac, av);
2605 } else if (!strncmp(*av, "show", strlen(*av))) {
2607 if (!strncmp(*av, "config", strlen(*av))) {
2608 sync_show_config(ac, av);
2609 } else if (!strncmp(*av, "status", strlen(*av))) {
2610 sync_show_status(ac, av);
2612 errx(EX_USAGE, "bad show command `%s'", *av);
2614 } else if (!strncmp(*av, "start", strlen(*av))) {
2616 if (!strncmp(*av, "edge", strlen(*av))) {
2617 sync_edge_start(ac, av);
2618 } else if (!strncmp(*av, "centre", strlen(*av))) {
2619 sync_centre_start(ac, av);
2621 } else if (!strncmp(*av, "stop", strlen(*av))) {
2623 if (!strncmp(*av, "edge", strlen(*av))) {
2624 sync_edge_stop(ac, av);
2625 } else if (!strncmp(*av, "centre", strlen(*av))) {
2626 sync_centre_stop(ac, av);
2628 } else if (!strncmp(*av, "clear", strlen(*av))) {
2630 if (!strncmp(*av, "edge", strlen(*av))) {
2631 sync_edge_clear(ac, av);
2632 } else if (!strncmp(*av, "centre", strlen(*av))) {
2633 sync_centre_clear(ac, av);
2635 } else if (!strncmp(*av, "test", strlen(*av))) {
2637 if (!strncmp(*av, "edge", strlen(*av))) {
2638 sync_edge_test(ac, av);
2639 } else if (!strncmp(*av, "centre", strlen(*av))) {
2640 sync_centre_test(ac, av);
2643 errx(EX_USAGE, "bad ipfw sync command `%s'", *av);
2646 errx(EX_USAGE, "bad ipfw command `%s'", *av);
2652 ipfw_readfile(int ac, char *av[])
2655 char *a, *p, *args[MAX_ARGS], *cmd = NULL;
2657 int i=0, lineno=0, qflag=0, pflag=0, status;
2662 while ((c = getopt(ac, av, "D:U:p:q")) != -1) {
2666 errx(EX_USAGE, "-D requires -p");
2667 if (i > MAX_ARGS - 2)
2668 errx(EX_USAGE, "too many -D or -U options");
2675 errx(EX_USAGE, "-U requires -p");
2676 if (i > MAX_ARGS - 2)
2677 errx(EX_USAGE, "too many -D or -U options");
2694 errx(EX_USAGE, "bad arguments, for usage"
2695 " summary ``ipfw''");
2702 errx(EX_USAGE, "extraneous filename arguments");
2704 if ((f = fopen(av[0], "r")) == NULL)
2705 err(EX_UNAVAILABLE, "fopen: %s", av[0]);
2708 /* pipe through preprocessor (cpp or m4) */
2713 if (pipe(pipedes) == -1)
2714 err(EX_OSERR, "cannot create pipe");
2716 switch ((preproc = fork())) {
2718 err(EX_OSERR, "cannot fork");
2722 if (dup2(fileno(f), 0) == -1 ||
2723 dup2(pipedes[1], 1) == -1) {
2724 err(EX_OSERR, "dup2()");
2730 err(EX_OSERR, "execvp(%s) failed", cmd);
2736 if ((f = fdopen(pipedes[0], "r")) == NULL) {
2737 int savederrno = errno;
2739 kill(preproc, SIGTERM);
2741 err(EX_OSERR, "fdopen()");
2746 while (fgets(buf, BUFSIZ, f)) {
2748 sprintf(linename, "Line %d", lineno);
2753 if ((p = strchr(buf, '#')) != NULL)
2758 for (a = strtok(buf, WHITESP); a && i < MAX_ARGS;
2759 a = strtok(NULL, WHITESP), i++) {
2763 if (i == (qflag? 2: 1))
2766 errx(EX_USAGE, "%s: too many arguments", linename);
2773 if (waitpid(preproc, &status, 0) == -1)
2774 errx(EX_OSERR, "waitpid()");
2775 if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK)
2776 errx(EX_UNAVAILABLE, "preprocessor exited with status %d",
2777 WEXITSTATUS(status));
2778 else if (WIFSIGNALED(status))
2779 errx(EX_UNAVAILABLE, "preprocessor exited with signal %d",
2785 main(int ac, char *av[])
2787 ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
2788 if (ipfw_socket < 0)
2789 err(EX_UNAVAILABLE, "socket");
2791 memset(keywords, 0, sizeof(struct ipfw_keyword) * KEYWORD_SIZE);
2792 memset(mappings, 0, sizeof(struct ipfw_mapping) * MAPPING_SIZE);
2794 prepare_default_funcs();
2796 if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0)
2797 ipfw_readfile(ac, av);