Some mdoc cleanup in tuning.7 and swapcache.8
[dragonfly.git] / sbin / ipfw3 / ipfw3.c
blob6c8d6487891c4191774fa2adb79b412bd7737722
1 /*
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>
27 #include <sys/mbuf.h>
28 #include <sys/socket.h>
29 #include <sys/sockio.h>
30 #include <sys/sysctl.h>
31 #include <sys/time.h>
32 #include <sys/wait.h>
34 #include <arpa/inet.h>
35 #include <ctype.h>
36 #include <dlfcn.h>
37 #include <err.h>
38 #include <errno.h>
39 #include <grp.h>
40 #include <limits.h>
41 #include <netdb.h>
42 #include <pwd.h>
43 #include <sysexits.h>
44 #include <signal.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <stdarg.h>
48 #include <string.h>
49 #include <timeconv.h>
50 #include <unistd.h>
52 #include <netinet/in.h>
53 #include <netinet/in_systm.h>
54 #include <netinet/ip.h>
55 #include <netinet/ip_icmp.h>
56 #include <netinet/tcp.h>
57 #include <net/if.h>
58 #include <net/if_dl.h>
59 #include <net/route.h>
60 #include <net/ethernet.h>
63 #include "../../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"
71 #include "ipfw3.h"
72 #include "ipfw3sync.h"
73 #include "ipfw3nat.h"
76 #define KEYWORD_SIZE 256
77 #define MAPPING_SIZE 256
79 #define MAX_KEYWORD_LEN 20
80 #define MAX_ARGS 32
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 */
125 verbose;
127 struct char_int_map dummynet_params[] = {
128 { "plr", TOK_PLR },
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 },
137 { "all", TOK_ALL },
138 { "mask", TOK_MASK },
139 { "droptail", TOK_DROPTAIL },
140 { "red", TOK_RED },
141 { "gred", TOK_GRED },
142 { "bw", TOK_BW },
143 { "bandwidth", TOK_BW },
144 { "delay", TOK_DELAY },
145 { "pipe", TOK_PIPE },
146 { "queue", TOK_QUEUE },
147 { "dummynet-params", TOK_NULL },
148 { NULL, 0 }
151 struct ipfw_keyword {
152 int type;
153 char word[MAX_KEYWORD_LEN];
154 int module;
155 int opcode;
158 struct ipfw_mapping {
159 int type;
160 int module;
161 int opcode;
162 parser_func parser;
163 shower_func shower;
166 struct ipfw_keyword keywords[KEYWORD_SIZE];
167 struct ipfw_mapping mappings[MAPPING_SIZE];
170 match_token(struct char_int_map *table, char *string)
172 while (table->key) {
173 if (strcmp(table->key, string) == 0) {
174 return table->val;
176 table++;
178 return 0;
181 static void
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.");
188 static void
189 list_modules(int ac, char *av[])
191 void *module_str = NULL;
192 int len = 1024;
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);
199 void
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;
205 NEXT_ARG1;
206 if (!strncmp(**av, "log", strlen(**av))) {
207 (*cmd)->arg3 = 1;
208 NEXT_ARG1;
209 if (isdigit(***av)) {
210 (*cmd)->arg1 = strtoul(**av, NULL, 10);
211 NEXT_ARG1;
216 void
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;
222 NEXT_ARG1;
223 if (!strncmp(**av, "log", strlen(**av))) {
224 (*cmd)->arg3 = 1;
225 NEXT_ARG1;
226 if (isdigit(***av)) {
227 (*cmd)->arg1 = strtoul(**av, NULL, 10);
228 NEXT_ARG1;
233 void
234 show_accept(ipfw_insn *cmd, int show_or)
236 printf(" allow");
237 if (cmd->arg3) {
238 printf(" log %d", cmd->arg1);
242 void
243 show_deny(ipfw_insn *cmd, int show_or)
245 printf(" deny");
246 if (cmd->arg3) {
247 printf(" log %d", cmd->arg1);
251 static void
252 load_modules(void)
254 const char *error;
255 init_module mod_init_func;
256 void *module_lib;
257 char module_lib_file[50];
258 void *module_str = NULL;
259 int len = 1024;
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] = ",";
267 char *token;
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);
273 if (!module_lib) {
274 fprintf(stderr, "Couldn't open %s: %s\n",
275 module_lib_file, dlerror());
276 exit(EX_SOFTWARE);
278 mod_init_func = dlsym(module_lib, "load_module");
279 if ((error = dlerror()))
281 fprintf(stderr, "Couldn't find init function: %s\n", error);
282 exit(EX_SOFTWARE);
284 (*mod_init_func)((register_func)register_ipfw_func,
285 (register_keyword)register_ipfw_keyword);
289 void
290 prepare_default_funcs(void)
292 /* register allow*/
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);
297 /* register deny*/
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);
304 void
305 register_ipfw_keyword(int module, int opcode, char *word, int type)
307 struct ipfw_keyword *tmp;
309 tmp=keywords;
310 for(;;) {
311 if (tmp->type == NONE) {
312 strcpy(tmp->word, word);
313 tmp->module = module;
314 tmp->opcode = opcode;
315 tmp->type = type;
316 break;
317 } else {
318 if (strcmp(tmp->word, word) == 0)
319 errx(EX_USAGE, "keyword `%s' exists", word);
320 else
321 tmp++;
326 void
327 register_ipfw_func(int module, int opcode, parser_func parser, shower_func shower)
329 struct ipfw_mapping *tmp;
331 tmp = mappings;
332 while (1) {
333 if (tmp->type == NONE) {
334 tmp->module = module;
335 tmp->opcode = opcode;
336 tmp->parser = parser;
337 tmp->shower = shower;
338 tmp->type = IN_USE;
339 break;
340 } else {
341 if (tmp->opcode == opcode && tmp->module == module) {
342 errx(EX_USAGE, "func `%d' of module `%d' exists",
343 opcode, module);
344 break;
345 } else {
346 tmp++;
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,
361 int *show_or)
363 if (cmd->len & F_OR) {
364 if (*prev_module == 0 && *prev_opcode == 0) {
365 /* first cmd with 'or' flag */
366 *show_or = 0;
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 */
372 *show_or = 1;
373 } else {
374 /* cmd different from prev*/
375 *show_or = 0;
376 *prev_module = cmd->module;
377 *prev_opcode = cmd->opcode;
380 } else {
381 *show_or = 0;
382 *prev_module = 0;
383 *prev_opcode = 0;
388 * word can be: proto from to other
389 * proto show proto
390 * from show from
391 * to show to
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;
398 shower_func fn;
399 int i, j, show_or;
400 uint8_t prev_module, prev_opcode;
402 k = keywords;
403 m = mappings;
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)
415 printf(" not");
417 fn = m->shower;
418 (*fn)(cmd, show_or);
419 return 1;
425 return 0;
428 static void
429 show_rules(struct ipfw_ioc_rule *rule, int pcwidth, int bcwidth)
431 static int twidth = 0;
432 ipfw_insn *cmd;
433 int l;
435 u_int32_t set_disable = rule->set_disable;
437 if (set_disable & (1 << rule->set)) { /* disabled */
438 if (!show_sets)
439 return;
440 else
441 printf("# DISABLED ");
443 printf("%05u ", rule->rulenum);
445 if (do_acct)
446 printf("%*ju %*ju ", pcwidth, (uintmax_t)rule->pcnt, bcwidth,
447 (uintmax_t)rule->bcnt);
449 if (do_time == 1) {
450 char timestr[30];
452 if (twidth == 0) {
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);
463 } else {
464 printf("%*s ", twidth, " ");
466 } else if (do_time == 2) {
467 printf( "%10u ", rule->timestamp);
470 if (show_sets)
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;
478 int i, j, changed;
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))) {
486 k = keywords;
487 m = mappings;
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;
497 comment_cmd = cmd;
498 } else {
499 fn = m->shower;
500 (*fn)(cmd, 0);
502 if (cmd->module == MODULE_BASIC_ID &&
503 cmd->opcode ==
504 O_BASIC_CHECK_STATE) {
505 goto done;
507 break;
510 break;
516 * show proto
518 changed=0;
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)
524 printf(" ip");
527 * show from
529 changed = 0;
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)
535 printf(" from any");
538 * show to
540 changed = 0;
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)
546 printf(" to any");
549 * show other filters
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);
561 done:
562 printf("\n");
565 static void
566 show_states(struct ipfw_ioc_state *d, int pcwidth, int bcwidth)
568 struct protoent *pe;
569 struct in_addr a;
571 printf("%05u ", d->rulenum);
572 if (do_acct) {
573 printf("%*ju %*ju ", pcwidth, (uintmax_t)d->pcnt,
574 bcwidth, (uintmax_t)d->bcnt);
577 if (do_time == 1) {
578 /* state->timestamp */
579 char timestr[30];
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);
588 /* state->expiry */
589 if (d->expiry !=0) {
590 t = _long_to_time(d->expiry);
591 strcpy(timestr, ctime(&t));
592 *strchr(timestr, '\n') = '\0';
593 printf(" %s)", timestr);
594 } else {
595 printf(" 0)");
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);
604 else
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);
613 printf("\n");
617 sort_q(const void *pa, const void *pb)
619 int rev = (do_sort < 0);
620 int field = rev ? -do_sort : do_sort;
621 long long res = 0;
622 const struct dn_ioc_flowqueue *a = pa;
623 const struct dn_ioc_flowqueue *b = pb;
625 switch(field) {
626 case 1: /* pkts */
627 res = a->len - b->len;
628 break;
629 case 2: /* bytes */
630 res = a->len_bytes - b->len_bytes;
631 break;
633 case 3: /* tot pkts */
634 res = a->tot_pkts - b->tot_pkts;
635 break;
637 case 4: /* tot bytes */
638 res = a->tot_bytes - b->tot_bytes;
639 break;
641 if (res < 0)
642 res = -1;
643 if (res > 0)
644 res = 1;
645 return (int)(rev ? res : -res);
648 static void
649 show_queues(struct dn_ioc_flowset *fs, struct dn_ioc_flowqueue *q)
651 int l;
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)
658 return;
660 printf("BKT Prot ___Source IP/port____ "
661 "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
662 if (do_sort != 0)
663 heapsort(q, fs->rq_elements, sizeof(*q), sort_q);
664 for (l = 0; l < fs->rq_elements; l++) {
665 struct in_addr ina;
666 struct protoent *pe;
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);
671 if (pe)
672 printf("%-4s ", pe->p_name);
673 else
674 printf("%4u ", q[l].id.u.ip.proto);
675 printf("%15s/%-5d ",
676 inet_ntoa(ina), q[l].id.u.ip.src_port);
677 ina.s_addr = htonl(q[l].id.u.ip.dst_ip);
678 printf("%15s/%-5d ",
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);
683 if (verbose)
684 printf(" S %20ju F %20ju\n",
685 (uintmax_t)q[l].S, (uintmax_t)q[l].F);
689 static void
690 show_flowset_parms(struct dn_ioc_flowset *fs, char *prefix)
692 char qs[30];
693 char plr[30];
694 char red[90]; /* Display RED parameters */
695 int l;
697 l = fs->qsize;
698 if (fs->flags_fs & DN_QSIZE_IS_BYTES) {
699 if (l >= 8192)
700 sprintf(qs, "%d KB", l / 1024);
701 else
702 sprintf(qs, "%d B", l);
703 } else
704 sprintf(qs, "%3d sl.", l);
705 if (fs->plr)
706 sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff));
707 else
708 plr[0] = '\0';
709 if (fs->flags_fs & DN_IS_RED) /* RED parameters */
710 sprintf(red,
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));
717 else
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);
724 static void
725 show_pipes(void *data, int nbytes, int ac, char *av[])
727 u_long rulenum;
728 void *next = data;
729 struct dn_ioc_pipe *p = (struct dn_ioc_pipe *)data;
730 struct dn_ioc_flowset *fs;
731 struct dn_ioc_flowqueue *q;
732 int l;
734 if (ac > 0)
735 rulenum = strtoul(*av++, NULL, 10);
736 else
737 rulenum = 0;
738 for (; nbytes >= sizeof(*p); p = (struct dn_ioc_pipe *)next) {
739 double b = p->bandwidth;
740 char buf[30];
741 char prefix[80];
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;
751 nbytes -= l;
753 if (rulenum != 0 && rulenum != p->pipe_nr)
754 continue;
757 * Print rate
759 if (b == 0)
760 sprintf(buf, "unlimited");
761 else if (b >= 1000000)
762 sprintf(buf, "%7.3f Mbit/s", b/1000000);
763 else if (b >= 1000)
764 sprintf(buf, "%7.3f Kbit/s", b/1000);
765 else
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);
771 if (verbose)
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) {
779 char prefix[80];
781 if (fs->fs_type != DN_IS_QUEUE)
782 break;
783 l = sizeof(*fs) + fs->rq_elements * sizeof(*q);
784 next = (void *)fs + l;
785 nbytes -= 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);
790 show_queues(fs, q);
795 * This one handles all set-related commands
796 * ipfw set { show | enable | disable }
797 * ipfw set swap X Y
798 * ipfw set move X to Y
799 * ipfw set move rule X to Y
801 static void
802 sets_handler(int ac, char *av[])
804 u_int32_t set_disable, masks[2];
805 u_int16_t rulenum;
806 u_int8_t cmd, new_set;
807 int i, nbytes;
809 NEXT_ARG;
810 if (!ac)
811 errx(EX_USAGE, "set needs command");
812 if (!strncmp(*av, "show", strlen(*av)) ) {
813 void *data = NULL;
814 char *msg;
815 int nalloc=1000;
816 nbytes = nalloc;
818 while (nbytes >= nalloc) {
819 nalloc = nalloc * 2+321;
820 nbytes = nalloc;
821 if (data == NULL) {
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);
836 msg = "";
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);
842 msg = "";
844 printf("\n");
845 } else if (!strncmp(*av, "swap", strlen(*av))) {
846 NEXT_ARG;
847 if (ac != 2)
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))) {
858 NEXT_ARG;
859 if (ac && !strncmp(*av, "rule", strlen(*av))) {
860 cmd = 2;
861 NEXT_ARG;
862 } else
863 cmd = 3;
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;
879 NEXT_ARG;
880 masks[0] = masks[1] = 0;
882 while (ac) {
883 if (isdigit(**av)) {
884 i = atoi(*av);
885 if (i < 0 || i > 30)
886 errx(EX_DATAERR, "invalid set number %d\n", i);
887 masks[which] |= (1<<i);
888 } else if (!strncmp(*av, "disable", strlen(*av)))
889 which = 0;
890 else if (!strncmp(*av, "enable", strlen(*av)))
891 which = 1;
892 else
893 errx(EX_DATAERR, "invalid set command %s\n", *av);
894 NEXT_ARG;
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));
899 if (i)
900 warn("set enable/disable: setsockopt(IP_FW_DEL)");
901 } else
902 errx(EX_USAGE, "invalid set command %s\n", *av);
905 static void
906 add_state(int ac, char *av[])
908 struct ipfw_ioc_state ioc_state;
909 ioc_state.expiry = 0;
910 ioc_state.lifetime = 0;
911 NEXT_ARG;
912 if (strcmp(*av, "rulenum") == 0) {
913 NEXT_ARG;
914 ioc_state.rulenum = atoi(*av);
915 } else {
916 errx(EX_USAGE, "ipfw state add rule");
918 NEXT_ARG;
919 struct protoent *pe;
920 pe = getprotobyname(*av);
921 ioc_state.flow_id.proto = pe->p_proto;
923 NEXT_ARG;
924 ioc_state.flow_id.src_ip = inet_addr(*av);
926 NEXT_ARG;
927 ioc_state.flow_id.src_port = atoi(*av);
929 NEXT_ARG;
930 ioc_state.flow_id.dst_ip = inet_addr(*av);
932 NEXT_ARG;
933 ioc_state.flow_id.dst_port = atoi(*av);
935 NEXT_ARG;
936 if (strcmp(*av, "live") == 0) {
937 NEXT_ARG;
938 ioc_state.lifetime = atoi(*av);
939 NEXT_ARG;
942 if (strcmp(*av, "expiry") == 0) {
943 NEXT_ARG;
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)");
951 if (!do_quiet) {
952 printf("Flushed all states.\n");
956 static void
957 delete_state(int ac, char *av[])
959 int rulenum;
960 NEXT_ARG;
961 if (ac == 1 && isdigit(**av))
962 rulenum = atoi(*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)");
965 if (!do_quiet)
966 printf("Flushed all states.\n");
969 static void
970 flush_state(int ac, char *av[])
972 if (!do_force) {
973 int c;
975 printf("Are you sure? [yn] ");
976 fflush(stdout);
977 do {
978 c = toupper(getc(stdin));
979 while (c != '\n' && getc(stdin) != '\n')
980 if (feof(stdin))
981 return; /* and do not flush */
982 } while (c != 'Y' && c != 'N');
983 if (c == 'N') /* user said no */
984 return;
986 if (do_set_x(IP_FW_STATE_FLUSH, NULL, 0) < 0 )
987 err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_FLUSH)");
988 if (!do_quiet)
989 printf("Flushed all states.\n");
992 static int
993 lookup_host (char *host, struct in_addr *ipaddr)
995 struct hostent *he;
997 if (!inet_aton(host, ipaddr)) {
998 if ((he = gethostbyname(host)) == NULL)
999 return(-1);
1000 *ipaddr = *(struct in_addr *)he->h_addr_list[0];
1002 return(0);
1005 static void
1006 table_append(int ac, char *av[])
1008 struct ipfw_ioc_table tbl;
1009 char *p;
1010 int size;
1012 NEXT_ARG;
1013 if (isdigit(**av))
1014 tbl.id = atoi(*av);
1015 else
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);
1021 NEXT_ARG;
1022 if (strcmp(*av, "ip") == 0)
1023 tbl.type = 1;
1024 else if (strcmp(*av, "mac") == 0)
1025 tbl.type = 2;
1026 else
1027 errx(EX_USAGE, "table type `%s' not supported", *av);
1029 NEXT_ARG;
1030 if (tbl.type == 1) { /* table type ipv4 */
1031 struct ipfw_ioc_table_ip_entry ip_ent;
1032 if (!ac)
1033 errx(EX_USAGE, "IP address required");
1035 p = strchr(*av, '/');
1036 if (p) {
1037 *p++ = '\0';
1038 ip_ent.masklen = atoi(p);
1039 if (ip_ent.masklen > 32)
1040 errx(EX_DATAERR, "bad width ``%s''", p);
1041 } else {
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;
1052 if (!ac)
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);
1064 static void
1065 table_remove(int ac, char *av[])
1067 struct ipfw_ioc_table tbl;
1068 struct ipfw_ioc_table_ip_entry ip_ent;
1069 char *p;
1070 int size;
1072 NEXT_ARG;
1073 if (isdigit(**av))
1074 tbl.id = atoi(*av);
1075 else
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);
1081 NEXT_ARG;
1082 if (strcmp(*av, "ip") == 0)
1083 tbl.type = 1;
1084 else if (strcmp(*av, "mac") == 0)
1085 tbl.type = 2;
1086 else
1087 errx(EX_USAGE, "table type `%s' not supported", *av);
1089 NEXT_ARG;
1090 if (!ac)
1091 errx(EX_USAGE, "IP address required");
1092 p = strchr(*av, '/');
1093 if (p) {
1094 *p++ = '\0';
1095 ip_ent.masklen = atoi(p);
1096 if (ip_ent.masklen > 32)
1097 errx(EX_DATAERR, "bad width ``%s''", p);
1098 } else {
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);
1113 static void
1114 table_flush(int ac, char *av[])
1116 struct ipfw_ioc_table ioc_table;
1117 struct ipfw_ioc_table *t = &ioc_table;
1119 NEXT_ARG;
1120 if (isdigit(**av)) {
1121 t->id = atoi(*av);
1122 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1123 errx(EX_USAGE, "table id `%d' invalid", t->id);
1124 } else {
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);
1132 static void
1133 table_list(int ac, char *av[])
1135 struct ipfw_ioc_table *ioc_table;
1136 int i, count, nbytes, nalloc = 1024;
1137 void *data = NULL;
1138 NEXT_ARG;
1139 if (strcmp(*av, "list") == 0) {
1140 nbytes = nalloc;
1141 while (nbytes >= nalloc) {
1142 nalloc = nalloc * 2 ;
1143 nbytes = nalloc;
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)
1155 printf(" type ip");
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);
1161 printf("\n");
1165 } else {
1166 errx(EX_USAGE, "ipfw3 table `%s' delete invalid", *av);
1170 void
1171 print_table(struct ipfw_ioc_table * tbl)
1173 int i;
1174 if (tbl->type == 0)
1175 errx(EX_USAGE, "table %d is not in use", tbl->id);
1177 printf("table %d", tbl->id);
1178 if (tbl->type == 1)
1179 printf(" type ip");
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);
1187 printf("\n");
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);
1195 printf("\n");
1196 ip_ent++;
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));
1203 printf("\n");
1204 mac_ent++;
1209 static void
1210 table_show(int ac, char *av[])
1212 int nbytes, nalloc = 1024;
1213 void *data = NULL;
1214 NEXT_ARG;
1215 if (isdigit(**av)) {
1216 nbytes = nalloc;
1217 while (nbytes >= nalloc) {
1218 nalloc = nalloc * 2 + 256;
1219 nbytes = nalloc;
1220 if (data == NULL) {
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;
1229 *head = atoi(*av);
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;
1236 print_table(tbl);
1238 } else {
1239 errx(EX_USAGE, "ipfw3 table `%s' show invalid", *av);
1243 static void
1244 table_create(int ac, char *av[])
1246 struct ipfw_ioc_table ioc_table;
1247 struct ipfw_ioc_table *t = &ioc_table;
1249 NEXT_ARG;
1250 if (ac < 2)
1251 errx(EX_USAGE, "table parameters invalid");
1252 if (isdigit(**av)) {
1253 t->id = atoi(*av);
1254 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1255 errx(EX_USAGE, "table id `%d' invalid", t->id);
1256 } else {
1257 errx(EX_USAGE, "table id `%s' invalid", *av);
1259 NEXT_ARG;
1260 if (strcmp(*av, "ip") == 0)
1261 t->type = 1;
1262 else if (strcmp(*av, "mac") == 0)
1263 t->type = 2;
1264 else
1265 errx(EX_USAGE, "table type `%s' not supported", *av);
1267 NEXT_ARG;
1268 memset(t->name, 0, IPFW_TABLE_NAME_LEN);
1269 if (ac == 2 && strcmp(*av, "name") == 0) {
1270 NEXT_ARG;
1271 if (strlen(*av) < IPFW_TABLE_NAME_LEN) {
1272 strncpy(t->name, *av, strlen(*av));
1273 } else {
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);
1285 static void
1286 table_delete(int ac, char *av[])
1288 struct ipfw_ioc_table ioc_table;
1289 struct ipfw_ioc_table *t = &ioc_table;
1291 NEXT_ARG;
1292 if (isdigit(**av)) {
1293 t->id = atoi(*av);
1294 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1295 errx(EX_USAGE, "table id `%d' invalid", t->id);
1296 } else {
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);
1307 static void
1308 table_test(int ac, char *av[])
1310 struct ipfw_ioc_table tbl;
1311 int size;
1313 NEXT_ARG;
1314 if (isdigit(**av))
1315 tbl.id = atoi(*av);
1316 else
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);
1322 NEXT_ARG;
1323 if (strcmp(*av, "ip") == 0)
1324 tbl.type = 1;
1325 else if (strcmp(*av, "mac") == 0)
1326 tbl.type = 2;
1327 else
1328 errx(EX_USAGE, "table type `%s' not supported", *av);
1330 NEXT_ARG;
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;
1340 if (!ac)
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);
1349 } else {
1350 printf("YES, %s exists in table %d\n", *av, tbl.id);
1354 static void
1355 table_rename(int ac, char *av[])
1357 struct ipfw_ioc_table tbl;
1358 int size;
1360 bzero(&tbl, sizeof(tbl));
1361 NEXT_ARG;
1362 if (isdigit(**av))
1363 tbl.id = atoi(*av);
1364 else
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);
1370 NEXT_ARG;
1371 strlcpy(tbl.name, *av, IPFW_TABLE_NAME_LEN);
1372 size = sizeof(tbl);
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);
1378 static void
1379 list(int ac, char *av[])
1381 struct ipfw_ioc_state *dynrules, *d;
1382 struct ipfw_ioc_rule *r;
1384 u_long rnum;
1385 void *data = NULL;
1386 int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width;
1387 int exitval = EX_OK, lac;
1388 char **lav, *endptr;
1389 int seen = 0;
1390 int nalloc = 1024;
1392 NEXT_ARG;
1394 /* get rules or pipes from kernel, resizing array as necessary */
1395 nbytes = nalloc;
1397 while (nbytes >= nalloc) {
1398 nalloc = nalloc * 2 ;
1399 nbytes = nalloc;
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.
1409 r = data;
1410 nstat = r->static_count;
1413 * Count dynamic rules. This is easier as they have
1414 * fixed size.
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;
1421 if (do_acct) {
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)
1427 pcwidth = width;
1429 /* byte counter */
1430 width = snprintf(NULL, 0, "%ju", (uintmax_t)r->bcnt);
1431 if (width > bcwidth)
1432 bcwidth = width;
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)
1439 pcwidth = width;
1441 width = snprintf(NULL, 0, "%ju", (uintmax_t)d->bcnt);
1442 if (width > bcwidth)
1443 bcwidth = width;
1447 /* if no rule numbers were specified, list all rules */
1448 if (ac == 0) {
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);
1462 goto done;
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);
1471 if (*endptr) {
1472 exitval = EX_USAGE;
1473 warnx("invalid rule number: %s", *(lav - 1));
1474 continue;
1476 for (n = seen = 0, r = data; n < nstat;
1477 n++, r = (void *)r + IOC_RULESIZE(r) ) {
1478 if (r->rulenum > rnum)
1479 break;
1480 if (r->rulenum == rnum) {
1481 show_rules(r, pcwidth, bcwidth);
1482 seen = 1;
1485 if (!seen) {
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);
1500 if (*endptr)
1501 /* already warned */
1502 continue;
1503 for (n = 0, d = dynrules; n < ndyn; n++, d++) {
1504 if (d->rulenum > rnum)
1505 break;
1506 if (d->rulenum == rnum)
1507 show_states(d, pcwidth, bcwidth);
1512 ac = 0;
1514 done:
1515 free(data);
1517 if (exitval != EX_OK)
1518 exit(exitval);
1521 static void
1522 show_dummynet(int ac, char *av[])
1524 void *data = NULL;
1525 int nbytes;
1526 int nalloc = 1024; /* start somewhere... */
1528 NEXT_ARG;
1530 nbytes = nalloc;
1531 while (nbytes >= nalloc) {
1532 nalloc = nalloc * 2 + 200;
1533 nbytes = nalloc;
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);
1543 free(data);
1546 static void
1547 help(void)
1549 fprintf(stderr, "usage: ipfw [options]\n"
1550 " ipfw add [rulenum] [set id] action filters\n"
1551 " ipfw delete [rulenum]\n"
1552 " ipfw flush\n"
1553 " ipfw list [rulenum]\n"
1554 " ipfw show [rulenum]\n"
1555 " ipfw zero [rulenum]\n"
1556 " ipfw set [show|enable|disable]\n"
1557 " ipfw module\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");
1564 exit(EX_USAGE);
1568 static void
1569 delete_rules(int ac, char *av[])
1571 struct dn_ioc_pipe pipe;
1572 u_int32_t rulenum;
1573 int exitval = EX_OK;
1574 int do_set = 0;
1575 int i;
1577 memset(&pipe, 0, sizeof pipe);
1579 NEXT_ARG;
1580 if (ac > 0 && !strncmp(*av, "set", strlen(*av))) {
1581 do_set = 1; /* delete set */
1582 NEXT_ARG;
1585 /* Rule number */
1586 while (ac && isdigit(**av)) {
1587 i = atoi(*av);
1588 NEXT_ARG;
1589 if (do_pipe) {
1590 if (do_pipe == 1)
1591 pipe.pipe_nr = i;
1592 else
1593 pipe.fs.fs_nr = i;
1595 i = do_set_x(IP_DUMMYNET_DEL, &pipe, sizeof pipe);
1596 if (i) {
1597 exitval = 1;
1598 warn("rule %u: setsockopt(IP_DUMMYNET_DEL)",
1599 do_pipe == 1 ? pipe.pipe_nr :
1600 pipe.fs.fs_nr);
1602 } else {
1603 rulenum = (i & 0xffff) | (do_set << 24);
1604 i = do_set_x(IP_FW_DEL, &rulenum, sizeof rulenum);
1605 if (i) {
1606 exitval = EX_UNAVAILABLE;
1607 warn("rule %u: setsockopt(IP_FW_DEL)",
1608 rulenum);
1612 if (exitval != EX_OK)
1613 exit(exitval);
1617 static unsigned long
1618 getbw(const char *str, u_short *flags, int kb)
1620 unsigned long val;
1621 int inbytes = 0;
1622 char *end;
1624 val = strtoul(str, &end, 0);
1625 if (*end == 'k' || *end == 'K') {
1626 ++end;
1627 val *= kb;
1628 } else if (*end == 'm' || *end == 'M') {
1629 ++end;
1630 val *= kb * kb;
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) {
1640 inbytes = 1;
1641 } else if (*end == 'b') {
1643 } else if (*end == 'B') {
1644 inbytes = 1;
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)
1654 val *= 8;
1656 return(val);
1660 * config dummynet pipe/queue
1662 static void
1663 config_dummynet(int ac, char **av)
1665 struct dn_ioc_pipe pipe;
1666 u_int32_t a;
1667 void *par = NULL;
1668 int i;
1669 char *end;
1671 NEXT_ARG;
1672 memset(&pipe, 0, sizeof pipe);
1673 /* Pipe number */
1674 if (ac && isdigit(**av)) {
1675 i = atoi(*av);
1676 NEXT_ARG;
1677 if (do_pipe == 1)
1678 pipe.pipe_nr = i;
1679 else
1680 pipe.fs.fs_nr = i;
1683 while (ac > 0) {
1684 double d;
1686 int tok = match_token(dummynet_params, *av);
1687 NEXT_ARG;
1689 switch(tok) {
1690 case TOK_NOERROR:
1691 pipe.fs.flags_fs |= DN_NOERROR;
1692 break;
1694 case TOK_PLR:
1695 NEED1("plr needs argument 0..1\n");
1696 d = strtod(av[0], NULL);
1697 if (d > 1)
1698 d = 1;
1699 else if (d < 0)
1700 d = 0;
1701 pipe.fs.plr = (int)(d*0x7fffffff);
1702 NEXT_ARG;
1703 break;
1705 case TOK_QUEUE:
1706 NEED1("queue needs queue size\n");
1707 end = NULL;
1708 pipe.fs.qsize = getbw(av[0], &pipe.fs.flags_fs, 1024);
1709 NEXT_ARG;
1710 break;
1712 case TOK_BUCKETS:
1713 NEED1("buckets needs argument\n");
1714 pipe.fs.rq_size = strtoul(av[0], NULL, 0);
1715 NEXT_ARG;
1716 break;
1718 case TOK_MASK:
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
1724 par = NULL;
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;
1732 end = NULL;
1734 while (ac >= 1) {
1735 u_int32_t *p32 = NULL;
1736 u_int16_t *p16 = NULL;
1738 tok = match_token(dummynet_params, *av);
1739 NEXT_ARG;
1740 switch(tok) {
1741 case TOK_ALL:
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;
1751 goto end_mask;
1753 case TOK_DSTIP:
1754 p32 = &pipe.fs.flow_mask.u.ip.dst_ip;
1755 break;
1757 case TOK_SRCIP:
1758 p32 = &pipe.fs.flow_mask.u.ip.src_ip;
1759 break;
1761 case TOK_DSTPORT:
1762 p16 = &pipe.fs.flow_mask.u.ip.dst_port;
1763 break;
1765 case TOK_SRCPORT:
1766 p16 = &pipe.fs.flow_mask.u.ip.src_port;
1767 break;
1769 case TOK_PROTO:
1770 break;
1772 default:
1773 NEXT_ARG;
1774 goto end_mask;
1776 if (ac < 1)
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;
1781 } else
1782 a = strtoul(av[0], &end, 0);
1783 if (p32 != NULL)
1784 *p32 = a;
1785 else if (p16 != NULL) {
1786 if (a > 65535)
1787 errx(EX_DATAERR,
1788 "mask: must be 16 bit");
1789 *p16 = (u_int16_t)a;
1790 } else {
1791 if (a > 255)
1792 errx(EX_DATAERR,
1793 "mask: must be 8 bit");
1794 pipe.fs.flow_mask.u.ip.proto =
1795 (uint8_t)a;
1797 if (a != 0)
1798 pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
1799 NEXT_ARG;
1800 } /* end while, config masks */
1802 end_mask:
1803 break;
1805 case TOK_RED:
1806 case TOK_GRED:
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));
1836 NEXT_ARG;
1837 break;
1839 case TOK_DROPTAIL:
1840 pipe.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED);
1841 break;
1843 case TOK_BW:
1844 NEED1("bw needs bandwidth\n");
1845 if (do_pipe != 1)
1846 errx(EX_DATAERR,
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");
1854 NEXT_ARG;
1855 break;
1857 case TOK_DELAY:
1858 if (do_pipe != 1)
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);
1862 NEXT_ARG;
1863 break;
1865 case TOK_WEIGHT:
1866 if (do_pipe == 1)
1867 errx(EX_DATAERR,
1868 "weight only valid for queues");
1869 NEED1("weight needs argument 0..100\n");
1870 pipe.fs.weight = strtoul(av[0], &end, 0);
1871 NEXT_ARG;
1872 break;
1874 case TOK_PIPE:
1875 if (do_pipe == 1)
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);
1879 NEXT_ARG;
1880 break;
1882 default:
1883 errx(EX_DATAERR, "unrecognised option ``%s''", *av);
1886 if (do_pipe == 1) {
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");
1900 } else {
1901 if (pipe.fs.qsize > 100)
1902 errx(EX_DATAERR, "2 <= queue size <= 100");
1904 if (pipe.fs.flags_fs & DN_IS_RED) {
1905 size_t len;
1906 int lookup_depth, avg_pkt_size;
1907 double s, idle, weight, w_q;
1908 int clock_hz;
1909 int t;
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");
1917 len = sizeof(int);
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");
1927 len = sizeof(int);
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)
1934 errx(EX_DATAERR,
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,
1940 NULL, 0) == -1) {
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
1952 * WF2Q+ ?
1954 if (pipe.bandwidth == 0) /* this is a WF2Q+ queue */
1955 s = 0;
1956 else
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;
1969 weight = 1 - w_q;
1970 for (t = pipe.fs.lookup_step; t > 0; --t)
1971 weight *= weight;
1972 pipe.fs.lookup_weight = (int)(weight * (1 << SCALE_RED));
1974 i = do_set_x(IP_DUMMYNET_CONFIGURE, &pipe, sizeof pipe);
1975 if (i)
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.
1984 static ipfw_insn*
1985 next_cmd(ipfw_insn *cmd)
1987 cmd += F_LEN(cmd);
1988 bzero(cmd, sizeof(*cmd));
1989 return 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.
1999 static void
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.)
2006 * go into actbuf[].
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;
2014 ipfw_insn *prev;
2015 char *prev_av;
2016 ipfw_insn *the_comment = NULL;
2017 struct ipfw_ioc_rule *rule;
2018 struct ipfw_keyword *key;
2019 struct ipfw_mapping *map;
2020 parser_func fn;
2021 int i, j;
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");
2034 NEXT_ARG;
2036 /* [rule N] -- Rule number optional */
2037 if (ac && isdigit(**av)) {
2038 rule->rulenum = atoi(*av);
2039 NEXT_ARG;
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]);
2047 rule->set = set;
2048 av += 2; ac -= 2;
2052 * parse before
2054 for (;;) {
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 ) {
2063 fn = map->parser;
2064 (*fn)(&other, &ac, &av);
2065 break;
2068 break;
2071 if (i >= KEYWORD_SIZE) {
2072 break;
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);
2077 goto done;
2079 other = next_cmd(other);
2084 * parse actions
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) {
2097 fn = map->parser;
2098 (*fn)(&action, &ac, &av);
2099 break;
2102 break;
2105 if (F_LEN(action) > 0)
2106 action = next_cmd(action);
2109 * parse protocol
2111 if (strcmp(*av, "proto") == 0){
2112 NEXT_ARG;
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 ) {
2124 fn = map->parser;
2125 (*fn)(&cmd, &ac, &av);
2126 break;
2129 break;
2132 if (F_LEN(cmd) > 0)
2133 cmd = next_cmd(cmd);
2136 * other filters
2138 while (ac > 0) {
2139 char *s, *cur; /* current filter */
2140 ipfw_insn_u32 *cmd32; /* alias for cmd */
2142 s = *av;
2143 cmd32 = (ipfw_insn_u32 *)cmd;
2144 if (strcmp(*av, "or") == 0) {
2145 if (prev == NULL)
2146 errx(EX_USAGE, "'or' should"
2147 "between two filters\n");
2148 prev->len |= F_OR;
2149 cmd->len = F_OR;
2150 *av = prev_av;
2152 if (strcmp(*av, "not") == 0) {
2153 if (cmd->len & F_NOT)
2154 errx(EX_USAGE, "double \"not\" not allowed\n");
2155 cmd->len = F_NOT;
2156 NEXT_ARG;
2157 continue;
2159 cur = *av;
2160 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
2161 if ((key->type == FILTER ||
2162 key->type == AFTER ||
2163 key->type == FROM ||
2164 key->type == TO) &&
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 ) {
2171 fn = map->parser;
2172 (*fn)(&cmd, &ac, &av);
2173 break;
2176 break;
2177 } else if (i == KEYWORD_SIZE - 1) {
2178 errx(EX_USAGE, "bad command `%s'", cur);
2181 if (i >= KEYWORD_SIZE) {
2182 break;
2183 } else if (F_LEN(cmd) > 0) {
2184 prev = cmd;
2185 prev_av = cur;
2186 cmd = next_cmd(cmd);
2190 done:
2191 if (ac>0)
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 */
2205 i = F_LEN(src);
2206 if (src->module == MODULE_BASIC_ID &&
2207 src->opcode == O_BASIC_COMMENT) {
2208 the_comment=src;
2209 } else {
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) {
2224 i = F_LEN(src);
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;
2231 i = F_LEN(src);
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");
2249 if (!do_quiet)
2250 show_rules(rule, 10, 10);
2253 static void
2254 zero(int ac, char *av[])
2256 int rulenum;
2257 int failed = EX_OK;
2259 NEXT_ARG;
2261 if (!ac) {
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)");
2265 if (!do_quiet)
2266 printf("Accounting cleared.\n");
2267 return;
2270 while (ac) {
2271 /* Rule number */
2272 if (isdigit(**av)) {
2273 rulenum = atoi(*av);
2274 NEXT_ARG;
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);
2280 } else {
2281 errx(EX_USAGE, "invalid rule number ``%s''", *av);
2284 if (failed != EX_OK)
2285 exit(failed);
2288 static void
2289 resetlog(int ac, char *av[])
2291 int rulenum;
2292 int failed = EX_OK;
2294 NEXT_ARG;
2296 if (!ac) {
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)");
2301 if (!do_quiet)
2302 printf("Logging counts reset.\n");
2304 return;
2307 while (ac) {
2308 /* Rule number */
2309 if (isdigit(**av)) {
2310 rulenum = atoi(*av);
2311 NEXT_ARG;
2312 if (setsockopt(ipfw_socket, IPPROTO_IP,
2313 IP_FW_RESETLOG, &rulenum, sizeof rulenum)) {
2314 warn("rule %u: setsockopt(IP_FW_RESETLOG)",
2315 rulenum);
2316 failed = EX_UNAVAILABLE;
2317 } else if (!do_quiet)
2318 printf("Entry %d logging count reset\n",
2319 rulenum);
2320 } else {
2321 errx(EX_DATAERR, "invalid rule number ``%s''", *av);
2324 if (failed != EX_OK)
2325 exit(failed);
2328 static void
2329 flush(void)
2331 int cmd = IP_FW_FLUSH;
2332 if (do_pipe) {
2333 cmd = IP_DUMMYNET_FLUSH;
2335 if (!do_force) {
2336 int c;
2338 printf("Are you sure? [yn] ");
2339 fflush(stdout);
2340 do {
2341 c = toupper(getc(stdin));
2342 while (c != '\n' && getc(stdin) != '\n')
2343 if (feof(stdin))
2344 return; /* and do not flush */
2345 } while (c != 'Y' && c != 'N');
2346 if (c == 'N') /* user said no */
2347 return;
2349 if (do_set_x(cmd, NULL, 0) < 0 ) {
2350 if (do_pipe)
2351 errx(EX_USAGE, "pipe/queue in use");
2352 else
2353 errx(EX_USAGE, "do_set_x(IP_FW_FLUSH) failed");
2355 if (!do_quiet) {
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)
2368 int len, *newbuf;
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);
2375 if (newbuf == NULL)
2376 err(EX_OSERR, "malloc newbuf in do_set_x");
2377 bzero(newbuf, len);
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);
2386 * same as do_set_x
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);
2398 if (newbuf == NULL)
2399 err(EX_OSERR, "malloc newbuf in do_get_x");
2400 bzero(newbuf, len);
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);
2407 *optlen=len;
2408 return retval;
2411 static int
2412 ipfw_main(int ac, char **av)
2414 int ch;
2416 if (ac == 1)
2417 help();
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)
2424 switch (ch) {
2425 case 'h': /* help */
2426 help();
2427 break; /* NOTREACHED */
2429 case 's': /* sort */
2430 do_sort = atoi(optarg);
2431 break;
2432 case 'a':
2433 do_acct = 1;
2434 break;
2435 case 'c':
2436 do_compact = 1;
2437 break;
2438 case 'd':
2439 do_dynamic = 1;
2440 break;
2441 case 'D':
2442 do_dynamic = 2;
2443 break;
2444 case 'e':
2445 do_expired = 1;
2446 break;
2447 case 'f':
2448 do_force = 1;
2449 break;
2450 case 'N':
2451 do_resolv = 1;
2452 break;
2453 case 'S':
2454 show_sets = 1;
2455 break;
2456 case 't':
2457 do_time = 1;
2458 break;
2459 case 'T':
2460 do_time = 2;
2461 break;
2462 case 'v':
2463 do_quiet = 0;
2464 verbose++;
2465 break;
2466 default:
2467 help();
2470 ac -= optind;
2471 av += optind;
2472 NEED1("bad arguments, for usage summary ``ipfw''");
2475 * optional: pipe or queue or nat
2477 do_nat = 0;
2478 do_pipe = 0;
2479 if (!strncmp(*av, "nat", strlen(*av)))
2480 do_nat = 1;
2481 else if (!strncmp(*av, "pipe", strlen(*av))) {
2482 do_pipe = 1;
2483 } else if (!strncmp(*av, "queue", strlen(*av))) {
2484 do_pipe = 2;
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]))) {
2494 char *p = av[1];
2495 av[1] = av[2];
2496 av[2] = p;
2499 if (!strncmp(*av, "add", strlen(*av))) {
2500 load_modules();
2501 add(ac, av);
2502 } else if (!strncmp(*av, "delete", strlen(*av))) {
2503 delete_rules(ac, av);
2504 } else if (!strncmp(*av, "flush", strlen(*av))) {
2505 flush();
2506 } else if (!strncmp(*av, "list", strlen(*av))) {
2507 load_modules();
2508 list(ac, av);
2509 } else if (!strncmp(*av, "show", strlen(*av))) {
2510 do_acct++;
2511 load_modules();
2512 list(ac, av);
2513 } else if (!strncmp(*av, "zero", strlen(*av))) {
2514 zero(ac, av);
2515 } else if (!strncmp(*av, "set", strlen(*av))) {
2516 sets_handler(ac, av);
2517 } else if (!strncmp(*av, "module", strlen(*av))) {
2518 NEXT_ARG;
2519 if (!strncmp(*av, "show", strlen(*av)) ||
2520 !strncmp(*av, "show", strlen(*av))) {
2521 list_modules(ac, av);
2522 } else {
2523 errx(EX_USAGE, "bad ipfw module command `%s'", *av);
2525 } else if (!strncmp(*av, "resetlog", strlen(*av))) {
2526 resetlog(ac, av);
2527 } else if (!strncmp(*av, "log", strlen(*av))) {
2528 NEXT_ARG;
2529 if (!strncmp(*av, "reset", strlen(*av))) {
2530 resetlog(ac, av);
2531 } else if (!strncmp(*av, "off", strlen(*av))) {
2533 } else if (!strncmp(*av, "on", strlen(*av))) {
2535 } else {
2536 errx(EX_USAGE, "bad command `%s'", *av);
2538 } else if (!strncmp(*av, "nat", strlen(*av))) {
2539 NEXT_ARG;
2540 nat_main(ac, av);
2541 } else if (!strncmp(*av, "pipe", strlen(*av)) ||
2542 !strncmp(*av, "queue", strlen(*av))) {
2543 NEXT_ARG;
2544 if (!strncmp(*av, "config", strlen(*av))) {
2545 config_dummynet(ac, av);
2546 } else if (!strncmp(*av, "flush", strlen(*av))) {
2547 flush();
2548 } else if (!strncmp(*av, "show", strlen(*av))) {
2549 show_dummynet(ac, av);
2550 } else {
2551 errx(EX_USAGE, "bad ipfw pipe command `%s'", *av);
2553 } else if (!strncmp(*av, "state", strlen(*av))) {
2554 NEXT_ARG;
2555 if (!strncmp(*av, "add", strlen(*av))) {
2556 add_state(ac, 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))) {
2562 do_dynamic = 2;
2563 list(ac, av);
2564 } else if (!strncmp(*av, "show", strlen(*av))) {
2565 do_acct = 1;
2566 do_dynamic =2;
2567 list(ac, av);
2568 } else {
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]))) {
2573 char *p = av[1];
2574 av[1] = av[2];
2575 av[2] = p;
2577 NEXT_ARG;
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))) {
2585 table_list(ac, av);
2586 } else if (!strncmp(*av, "show", strlen(*av))) {
2587 table_show(ac, 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))) {
2593 table_test(ac,av);
2594 } else if (!strncmp(*av, "name", strlen(*av))) {
2595 table_rename(ac, av);
2596 } else {
2597 errx(EX_USAGE, "bad ipfw table command `%s'", *av);
2599 } else if (!strncmp(*av, "sync", strlen(*av))) {
2600 NEXT_ARG;
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))) {
2606 NEXT_ARG;
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);
2611 } else {
2612 errx(EX_USAGE, "bad show command `%s'", *av);
2614 } else if (!strncmp(*av, "start", strlen(*av))) {
2615 NEXT_ARG;
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))) {
2622 NEXT_ARG;
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))) {
2629 NEXT_ARG;
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))) {
2636 NEXT_ARG;
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);
2642 } else {
2643 errx(EX_USAGE, "bad ipfw sync command `%s'", *av);
2645 } else {
2646 errx(EX_USAGE, "bad ipfw command `%s'", *av);
2648 return 0;
2651 static void
2652 ipfw_readfile(int ac, char *av[])
2654 char buf[BUFSIZ];
2655 char *a, *p, *args[MAX_ARGS], *cmd = NULL;
2656 char linename[10];
2657 int i=0, lineno=0, qflag=0, pflag=0, status;
2658 FILE *f = NULL;
2659 pid_t preproc = 0;
2660 int c;
2662 while ((c = getopt(ac, av, "D:U:p:q")) != -1) {
2663 switch (c) {
2664 case 'D':
2665 if (!pflag)
2666 errx(EX_USAGE, "-D requires -p");
2667 if (i > MAX_ARGS - 2)
2668 errx(EX_USAGE, "too many -D or -U options");
2669 args[i++] = "-D";
2670 args[i++] = optarg;
2671 break;
2673 case 'U':
2674 if (!pflag)
2675 errx(EX_USAGE, "-U requires -p");
2676 if (i > MAX_ARGS - 2)
2677 errx(EX_USAGE, "too many -D or -U options");
2678 args[i++] = "-U";
2679 args[i++] = optarg;
2680 break;
2682 case 'p':
2683 pflag = 1;
2684 cmd = optarg;
2685 args[0] = cmd;
2686 i = 1;
2687 break;
2689 case 'q':
2690 qflag = 1;
2691 break;
2693 default:
2694 errx(EX_USAGE, "bad arguments, for usage"
2695 " summary ``ipfw''");
2699 av += optind;
2700 ac -= optind;
2701 if (ac != 1)
2702 errx(EX_USAGE, "extraneous filename arguments");
2704 if ((f = fopen(av[0], "r")) == NULL)
2705 err(EX_UNAVAILABLE, "fopen: %s", av[0]);
2707 if (pflag) {
2708 /* pipe through preprocessor (cpp or m4) */
2709 int pipedes[2];
2711 args[i] = NULL;
2713 if (pipe(pipedes) == -1)
2714 err(EX_OSERR, "cannot create pipe");
2716 switch ((preproc = fork())) {
2717 case -1:
2718 err(EX_OSERR, "cannot fork");
2720 case 0:
2721 /* child */
2722 if (dup2(fileno(f), 0) == -1 ||
2723 dup2(pipedes[1], 1) == -1) {
2724 err(EX_OSERR, "dup2()");
2726 fclose(f);
2727 close(pipedes[1]);
2728 close(pipedes[0]);
2729 execvp(cmd, args);
2730 err(EX_OSERR, "execvp(%s) failed", cmd);
2732 default:
2733 /* parent */
2734 fclose(f);
2735 close(pipedes[1]);
2736 if ((f = fdopen(pipedes[0], "r")) == NULL) {
2737 int savederrno = errno;
2739 kill(preproc, SIGTERM);
2740 errno = savederrno;
2741 err(EX_OSERR, "fdopen()");
2746 while (fgets(buf, BUFSIZ, f)) {
2747 lineno++;
2748 sprintf(linename, "Line %d", lineno);
2749 args[0] = linename;
2751 if (*buf == '#')
2752 continue;
2753 if ((p = strchr(buf, '#')) != NULL)
2754 *p = '\0';
2755 i = 1;
2756 if (qflag)
2757 args[i++] = "-q";
2758 for (a = strtok(buf, WHITESP); a && i < MAX_ARGS;
2759 a = strtok(NULL, WHITESP), i++) {
2760 args[i] = a;
2763 if (i == (qflag? 2: 1))
2764 continue;
2765 if (i == MAX_ARGS)
2766 errx(EX_USAGE, "%s: too many arguments", linename);
2768 args[i] = NULL;
2769 ipfw_main(i, args);
2771 fclose(f);
2772 if (pflag) {
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",
2780 WTERMSIG(status));
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);
2798 else
2799 ipfw_main(ac, av);
2800 return EX_OK;