Merge branch 'vendor/BINUTILS225'
[dragonfly.git] / sbin / ipfw3 / ipfw3.c
1 /*
2  * Copyright (c) 2002 Luigi Rizzo
3  * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
4  * Copyright (c) 1994 Ugen J.S.Antsilevich
5  *
6  * Idea and grammar partially left from:
7  * Copyright (c) 1993 Daniel Boulet
8  *
9  * Redistribution and use in source forms, with and without modification,
10  * are permitted provided that this entire comment appears intact.
11  *
12  * Redistribution in binary form may occur without any restrictions.
13  * Obviously, it would be nice if you gave credit where credit is due
14  * but requiring it would be too onerous.
15  *
16  * This software is provided ``AS IS'' without any warranties of any kind.
17  *
18  * NEW command line interface for IP firewall facility
19  *
20  * $FreeBSD: src/sbin/ipfw/ipfw2.c,v 1.4.2.13 2003/05/27 22:21:11 gshapiro Exp $
21  */
22
23 #include <sys/param.h>
24 #include <sys/mbuf.h>
25 #include <sys/socket.h>
26 #include <sys/sockio.h>
27 #include <sys/sysctl.h>
28 #include <sys/time.h>
29 #include <sys/wait.h>
30
31 #include <arpa/inet.h>
32 #include <ctype.h>
33 #include <dlfcn.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <grp.h>
37 #include <limits.h>
38 #include <netdb.h>
39 #include <pwd.h>
40 #include <sysexits.h>
41 #include <signal.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <stdarg.h>
45 #include <string.h>
46 #include <timeconv.h>
47 #include <unistd.h>
48
49 #include <netinet/in.h>
50 #include <netinet/in_systm.h>
51 #include <netinet/ip.h>
52 #include <netinet/ip_icmp.h>
53 #include <netinet/tcp.h>
54 #include <net/if.h>
55 #include <net/if_dl.h>
56 #include <net/route.h>
57 #include <net/ethernet.h>
58
59
60 #include "../../sys/net/ipfw3/ip_fw3.h"
61 #include "../../sys/net/ipfw3/ip_fw3_table.h"
62 #include "../../sys/net/dummynet3/ip_dummynet3.h"
63 #include "../../sys/net/libalias/alias.h"
64 #include "../../sys/net/ipfw3_basic/ip_fw3_basic.h"
65 #include "../../sys/net/ipfw3_nat/ip_fw3_nat.h"
66 #include "ipfw.h"
67
68
69 #define KEYWORD_SIZE    256
70 #define MAPPING_SIZE    256
71
72 #define MAX_KEYWORD_LEN 20
73 #define MAX_ARGS        32
74 #define WHITESP         " \t\f\v\n\r"
75 #define IPFW_LIB_PATH   "/usr/lib/libipfw3%s.so"
76 #define IP_MASK_ALL     0xffffffff
77 #define NAT_BUF_LEN     1024
78 /*
79  * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines
80  * This is only used in this code.
81  */
82 #define IPPROTO_ETHERTYPE       0x1000
83
84 /*
85  * This macro returns the size of a struct sockaddr when passed
86  * through a routing socket. Basically we round up sa_len to
87  * a multiple of sizeof(long), with a minimum of sizeof(long).
88  * The check for a NULL pointer is just a convenience, probably never used.
89  * The case sa_len == 0 should only apply to empty structures.
90  */
91 #define SA_SIZE(sa)                                             \
92         ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ?   \
93         sizeof(long)            :                               \
94         1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
95
96 /*
97  * show_rules() prints the body of an ipfw rule.
98  * Because the standard rule has at least proto src_ip dst_ip, we use
99  * a helper function to produce these entries if not provided explicitly.
100  * The first argument is the list of fields we have, the second is
101  * the list of fields we want to be printed.
102  *
103  * Special cases if we have provided a MAC header:
104  * + if the rule does not contain IP addresses/ports, do not print them;
105  * + if the rule does not contain an IP proto, print "all" instead of "ip";
106  *
107  */
108 #define HAVE_PROTO      0x0001
109 #define HAVE_SRCIP      0x0002
110 #define HAVE_DSTIP      0x0004
111 #define HAVE_MAC        0x0008
112 #define HAVE_MACTYPE    0x0010
113 #define HAVE_OPTIONS    0x8000
114
115 #define HAVE_IP         (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP)
116
117 /*
118  * Definition of a port range, and macros to deal with values.
119  * FORMAT: HI 16-bits == first port in range, 0 == all ports.
120  *               LO 16-bits == number of ports in range
121  * NOTES: - Port values are not stored in network byte order.
122  */
123
124 #define port_range u_long
125
126 #define GETLOPORT(x)    ((x) >> 0x10)
127 #define GETNUMPORTS(x)  ((x) & 0x0000ffff)
128 #define GETHIPORT(x)    (GETLOPORT((x)) + GETNUMPORTS((x)))
129
130 /* Set y to be the low-port value in port_range variable x. */
131 #define SETLOPORT(x, y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
132
133 /* Set y to be the number of ports in port_range variable x. */
134 #define SETNUMPORTS(x, y) ((x) = ((x) & 0xffff0000) | (y))
135
136 #define INC_ARGCV() do {                        \
137         (*_av)++;                               \
138         (*_ac)--;                               \
139         av = *_av;                              \
140         ac = *_ac;                              \
141 } while (0)
142
143
144 int             ipfw_socket = -1;       /* main RAW socket */
145 int             do_resolv,              /* Would try to resolve all */
146                 do_acct,                /* Show packet/byte count */
147                 do_time,                /* Show time stamps */
148                 do_quiet = 1,           /* Be quiet , default is quiet*/
149                 do_force,               /* Don't ask for confirmation */
150                 do_pipe,                /* this cmd refers to a pipe */
151                 do_nat,                 /* Nat configuration. */
152                 do_sort,                /* field to sort results (0 = no) */
153                 do_dynamic,             /* display dynamic rules */
154                 do_expired,             /* display expired dynamic rules */
155                 do_compact,             /* show rules in compact mode */
156                 show_sets,              /* display rule sets */
157                 verbose;
158
159 enum tokens {
160         TOK_NULL=0,
161
162         TOK_IP,
163         TOK_IF,
164         TOK_ALOG,
165         TOK_DENY_INC,
166         TOK_SAME_PORTS,
167         TOK_UNREG_ONLY,
168         TOK_RESET_ADDR,
169         TOK_ALIAS_REV,
170         TOK_PROXY_ONLY,
171         TOK_REDIR_ADDR,
172         TOK_REDIR_PORT,
173         TOK_REDIR_PROTO,
174
175         TOK_PIPE,
176         TOK_QUEUE,
177         TOK_PLR,
178         TOK_NOERROR,
179         TOK_BUCKETS,
180         TOK_DSTIP,
181         TOK_SRCIP,
182         TOK_DSTPORT,
183         TOK_SRCPORT,
184         TOK_ALL,
185         TOK_MASK,
186         TOK_BW,
187         TOK_DELAY,
188         TOK_RED,
189         TOK_GRED,
190         TOK_DROPTAIL,
191         TOK_PROTO,
192         TOK_WEIGHT,
193 };
194
195 struct char_int_map dummynet_params[] = {
196         { "plr",                TOK_PLR },
197         { "noerror",            TOK_NOERROR },
198         { "buckets",            TOK_BUCKETS },
199         { "dst-ip",             TOK_DSTIP },
200         { "src-ip",             TOK_SRCIP },
201         { "dst-port",           TOK_DSTPORT },
202         { "src-port",           TOK_SRCPORT },
203         { "proto",              TOK_PROTO },
204         { "weight",             TOK_WEIGHT },
205         { "all",                TOK_ALL },
206         { "mask",               TOK_MASK },
207         { "droptail",           TOK_DROPTAIL },
208         { "red",                TOK_RED },
209         { "gred",               TOK_GRED },
210         { "bw",                 TOK_BW },
211         { "bandwidth",          TOK_BW },
212         { "delay",              TOK_DELAY },
213         { "pipe",               TOK_PIPE },
214         { "queue",              TOK_QUEUE },
215         { "dummynet-params",    TOK_NULL },
216         { NULL, 0 }
217 };
218
219 struct char_int_map nat_params[] = {
220         { "ip",                 TOK_IP },
221         { "if",                 TOK_IF },
222         { "log",                TOK_ALOG },
223         { "deny_in",            TOK_DENY_INC },
224         { "same_ports",         TOK_SAME_PORTS },
225         { "unreg_only",         TOK_UNREG_ONLY },
226         { "reset",              TOK_RESET_ADDR },
227         { "reverse",            TOK_ALIAS_REV },
228         { "proxy_only",         TOK_PROXY_ONLY },
229         { "redirect_addr",      TOK_REDIR_ADDR },
230         { "redirect_port",      TOK_REDIR_PORT },
231         { "redirect_proto",     TOK_REDIR_PROTO },
232         { NULL, 0 },
233 };
234
235 struct ipfw_keyword {
236         int type;
237         char word[MAX_KEYWORD_LEN];
238         int module;
239         int opcode;
240 };
241
242 struct ipfw_mapping {
243         int type;
244         int module;
245         int opcode;
246         parser_func parser;
247         shower_func shower;
248 };
249
250 struct ipfw_keyword keywords[KEYWORD_SIZE];
251 struct ipfw_mapping mappings[MAPPING_SIZE];
252
253 static int
254 match_token(struct char_int_map *table, char *string)
255 {
256         while (table->key) {
257                 if (strcmp(table->key, string) == 0) {
258                         return table->val;
259                 }
260                 table++;
261         }
262         return 0;
263 }
264
265 static void
266 get_modules(char *modules_str, int len)
267 {
268         if (do_get_x(IP_FW_MODULE, modules_str, &len) < 0)
269                 errx(EX_USAGE, "ipfw3 not loaded.");
270 }
271
272 static void
273 list_modules(int ac, char *av[])
274 {
275         void *module_str = NULL;
276         int len = 1024;
277         if ((module_str = realloc(module_str, len)) == NULL)
278                 err(EX_OSERR, "realloc");
279
280         get_modules(module_str, len);
281         printf("%s", (char *)module_str);
282 }
283 void
284 parse_accept(ipfw_insn **cmd, int *ac, char **av[])
285 {
286         (*cmd)->opcode = O_BASIC_ACCEPT;
287         (*cmd)->module = MODULE_BASIC_ID;
288         (*cmd)->len = (*cmd)->len|LEN_OF_IPFWINSN;
289         NEXT_ARG1;
290         if (!strncmp(**av, "log", strlen(**av))) {
291                 (*cmd)->arg3 = 1;
292                 NEXT_ARG1;
293                 if (isdigit(***av)) {
294                         (*cmd)->arg1 = strtoul(**av, NULL, 10);
295                         NEXT_ARG1;
296                 }
297         }
298 }
299
300 void
301 parse_deny(ipfw_insn **cmd, int *ac, char **av[])
302 {
303         (*cmd)->opcode = O_BASIC_DENY;
304         (*cmd)->module = MODULE_BASIC_ID;
305         (*cmd)->len = (*cmd)->len|LEN_OF_IPFWINSN;
306         NEXT_ARG1;
307         if (!strncmp(**av, "log", strlen(**av))) {
308                 (*cmd)->arg3 = 1;
309                 NEXT_ARG1;
310                 if (isdigit(***av)) {
311                         (*cmd)->arg1 = strtoul(**av, NULL, 10);
312                         NEXT_ARG1;
313                 }
314         }
315 }
316
317 void
318 show_accept(ipfw_insn *cmd, int show_or)
319 {
320         printf(" allow");
321         if (cmd->arg3) {
322                 printf(" log %d", cmd->arg1);
323         }
324 }
325
326 void
327 show_deny(ipfw_insn *cmd, int show_or)
328 {
329         printf(" deny");
330         if (cmd->arg3) {
331                 printf(" log %d", cmd->arg1);
332         }
333 }
334
335 static void
336 load_modules(void)
337 {
338         const char *error;
339         init_module mod_init_func;
340         void *module_lib;
341         char module_lib_file[50];
342         void *module_str = NULL;
343         int len = 1024;
344
345         if ((module_str = realloc(module_str, len)) == NULL)
346                 err(EX_OSERR, "realloc");
347
348         get_modules(module_str, len);
349
350         const char s[2] = ",";
351         char *token;
352         token = strtok(module_str, s);
353         while (token != NULL) {
354                 sprintf(module_lib_file, IPFW_LIB_PATH, token);
355                 token = strtok(NULL, s);
356                 module_lib = dlopen(module_lib_file, RTLD_LAZY);
357                 if (!module_lib) {
358                         fprintf(stderr, "Couldn't open %s: %s\n",
359                                 module_lib_file, dlerror());
360                         exit(EX_SOFTWARE);
361                 }
362                 mod_init_func = dlsym(module_lib, "load_module");
363                 if ((error = dlerror()))
364                 {
365                         fprintf(stderr, "Couldn't find init function: %s\n", error);
366                         exit(EX_SOFTWARE);
367                 }
368                 (*mod_init_func)((register_func)register_ipfw_func,
369                                 (register_keyword)register_ipfw_keyword);
370         }
371 }
372
373 void
374 prepare_default_funcs(void)
375 {
376         /* register allow*/
377         register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_ACCEPT, "allow", ACTION);
378         register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_ACCEPT, "accept", ACTION);
379         register_ipfw_func(MODULE_BASIC_ID, O_BASIC_ACCEPT,
380                         (parser_func)parse_accept, (shower_func)show_accept);
381         /* register deny*/
382         register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_DENY, "deny", ACTION);
383         register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_DENY, "reject", ACTION);
384         register_ipfw_func(MODULE_BASIC_ID, O_BASIC_DENY,
385                         (parser_func)parse_deny, (shower_func)show_deny);
386 }
387
388 void
389 register_ipfw_keyword(int module, int opcode, char *word, int type)
390 {
391         struct ipfw_keyword *tmp;
392
393         tmp=keywords;
394         for(;;) {
395                 if (tmp->type == NONE) {
396                         strcpy(tmp->word, word);
397                         tmp->module = module;
398                         tmp->opcode = opcode;
399                         tmp->type = type;
400                         break;
401                 } else {
402                         if (strcmp(tmp->word, word) == 0)
403                                 errx(EX_USAGE, "keyword `%s' exists", word);
404                         else
405                                 tmp++;
406                 }
407         }
408 }
409
410 void
411 register_ipfw_func(int module, int opcode, parser_func parser, shower_func shower)
412 {
413         struct ipfw_mapping *tmp;
414
415         tmp = mappings;
416         while (1) {
417                 if (tmp->type == NONE) {
418                         tmp->module = module;
419                         tmp->opcode = opcode;
420                         tmp->parser = parser;
421                         tmp->shower = shower;
422                         tmp->type = IN_USE;
423                         break;
424                 } else {
425                         if (tmp->opcode == opcode && tmp->module == module) {
426                                 errx(EX_USAGE, "func `%d' of module `%d' exists",
427                                         opcode, module);
428                                 break;
429                         } else {
430                                 tmp++;
431                         }
432                 }
433         }
434 }
435
436 /*
437  * this func need to check whether 'or' need to be printed,
438  * when the filter is the first filter with 'or' when dont print
439  * when not first and same as previous, then print or and no filter name
440  * when not first but different from previous, print name without 'or'
441  * show_or = 1: show or and ignore filter name
442  * show_or = 0: show filter name ignore or
443  */
444 void prev_show_chk(ipfw_insn *cmd, uint8_t *prev_module, uint8_t *prev_opcode,
445                 int *show_or)
446 {
447         if (cmd->len & F_OR) {
448                 if (*prev_module == 0 && *prev_opcode == 0) {
449                         /* first cmd with 'or' flag */
450                         *show_or = 0;
451                         *prev_module = cmd->module;
452                         *prev_opcode = cmd->opcode;
453                 } else if (cmd->module == *prev_module &&
454                                 cmd->opcode == *prev_opcode) {
455                         /* cmd same as previous, same module and opcode */
456                         *show_or = 1;
457                 } else {
458                         /* cmd different from prev*/
459                         *show_or = 0;
460                         *prev_module = cmd->module;
461                         *prev_opcode = cmd->opcode;
462
463                 }
464         } else {
465                 *show_or = 0;
466                 *prev_module = 0;
467                 *prev_opcode = 0;
468         }
469 }
470
471 /*
472  * word can be: proto from to other
473  * proto show proto
474  * from show from
475  * to show to
476  * other show all other filters
477  */
478 int show_filter(ipfw_insn *cmd, char *word, int type)
479 {
480         struct ipfw_keyword *k;
481         struct ipfw_mapping *m;
482         shower_func fn;
483         int i, j, show_or;
484         uint8_t prev_module, prev_opcode;
485
486         k = keywords;
487         m = mappings;
488         for (i = 1; i < KEYWORD_SIZE; i++, k++) {
489                 if (k->type == type) {
490                         if (k->module == cmd->module &&
491                                         k->opcode == cmd->opcode) {
492                                 for (j = 1; j < MAPPING_SIZE; j++, m++) {
493                                         if (m->type == IN_USE &&
494                                                 k->module == m->module &&
495                                                 k->opcode == m->opcode) {
496                                                 prev_show_chk(cmd, &prev_module,
497                                                         &prev_opcode, &show_or);
498                                                 if (cmd->len & F_NOT)
499                                                         printf(" not");
500
501                                                 fn = m->shower;
502                                                 (*fn)(cmd, show_or);
503                                                 return 1;
504                                         }
505                                 }
506                         }
507                 }
508         }
509         return 0;
510 }
511
512 static void
513 show_rules(struct ipfw_ioc_rule *rule, int pcwidth, int bcwidth)
514 {
515         static int twidth = 0;
516         ipfw_insn *cmd;
517         int l;
518
519         u_int32_t set_disable = rule->set_disable;
520
521         if (set_disable & (1 << rule->set)) { /* disabled */
522                 if (!show_sets)
523                         return;
524                 else
525                         printf("# DISABLED ");
526         }
527         printf("%05u ", rule->rulenum);
528
529         if (do_acct)
530                 printf("%*ju %*ju ", pcwidth, (uintmax_t)rule->pcnt, bcwidth,
531                         (uintmax_t)rule->bcnt);
532
533         if (do_time == 1) {
534                 char timestr[30];
535
536                 if (twidth == 0) {
537                         strcpy(timestr, ctime((time_t *)&twidth));
538                         *strchr(timestr, '\n') = '\0';
539                         twidth = strlen(timestr);
540                 }
541                 if (rule->timestamp) {
542                         time_t t = _long_to_time(rule->timestamp);
543
544                         strcpy(timestr, ctime(&t));
545                         *strchr(timestr, '\n') = '\0';
546                         printf("%s ", timestr);
547                 } else {
548                         printf("%*s ", twidth, " ");
549                 }
550         } else if (do_time == 2) {
551                 printf( "%10u ", rule->timestamp);
552         }
553
554         if (show_sets)
555                 printf("set %d ", rule->set);
556
557
558         struct ipfw_keyword *k;
559         struct ipfw_mapping *m;
560         shower_func fn, comment_fn = NULL;
561         ipfw_insn *comment_cmd;
562         int i, j, changed;
563
564         /*
565          * show others and actions
566          */
567         for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule);
568                 l > 0; l -= F_LEN(cmd),
569                 cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
570                 k = keywords;
571                 m = mappings;
572                 for (i = 1; i< KEYWORD_SIZE; i++, k++) {
573                         if ( k->module == cmd->module && k->opcode == cmd->opcode ) {
574                                 for (j = 1; j< MAPPING_SIZE; j++, m++) {
575                                         if (m->type == IN_USE &&
576                                                 m->module == cmd->module &&
577                                                 m->opcode == cmd->opcode) {
578                                                 if (cmd->module == MODULE_BASIC_ID &&
579                                                         cmd->opcode == O_BASIC_COMMENT) {
580                                                         comment_fn = m->shower;
581                                                         comment_cmd = cmd;
582                                                 } else {
583                                                         fn = m->shower;
584                                                         (*fn)(cmd, 0);
585                                                 }
586                                                 if (cmd->module == MODULE_BASIC_ID &&
587                                                         cmd->opcode ==
588                                                                 O_BASIC_CHECK_STATE) {
589                                                         goto done;
590                                                 }
591                                                 break;
592                                         }
593                                 }
594                                 break;
595                         }
596                 }
597         }
598
599         /*
600          * show proto
601          */
602         changed=0;
603         for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd),
604                         cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
605                 changed = show_filter(cmd, "proto", PROTO);
606         }
607         if (!changed && !do_quiet)
608                 printf(" ip");
609
610         /*
611          * show from
612          */
613         changed = 0;
614         for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd),
615                         cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
616                 changed = show_filter(cmd, "from", FROM);
617         }
618         if (!changed && !do_quiet)
619                 printf(" from any");
620
621         /*
622          * show to
623          */
624         changed = 0;
625         for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd),
626                         cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
627                 changed = show_filter(cmd, "to", TO);
628         }
629         if (!changed && !do_quiet)
630                 printf(" to any");
631
632         /*
633          * show other filters
634          */
635         for (l = rule->act_ofs, cmd = rule->cmd, m = mappings;
636                         l > 0; l -= F_LEN(cmd),
637                         cmd=(ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
638                 show_filter(cmd, "other", FILTER);
639         }
640
641         /* show the comment in the end */
642         if (comment_fn != NULL) {
643                 (*comment_fn)(comment_cmd, 0);
644         }
645 done:
646         printf("\n");
647 }
648
649 static void
650 show_states(struct ipfw_ioc_state *d, int pcwidth, int bcwidth)
651 {
652         struct protoent *pe;
653         struct in_addr a;
654
655         printf("%05u ", d->rulenum);
656         if (do_acct) {
657                 printf("%*ju %*ju ", pcwidth, (uintmax_t)d->pcnt,
658                                 bcwidth, (uintmax_t)d->bcnt);
659         }
660
661         if (do_time == 1) {
662                 /* state->timestamp */
663                 char timestr[30];
664                 time_t t = _long_to_time(d->timestamp);
665                 strcpy(timestr, ctime(&t));
666                 *strchr(timestr, '\n') = '\0';
667                 printf(" (%s", timestr);
668
669                 /* state->lifetime */
670                 printf(" %ds", d->lifetime);
671
672                 /* state->expiry */
673                 if (d->expiry !=0) {
674                         t = _long_to_time(d->expiry);
675                         strcpy(timestr, ctime(&t));
676                         *strchr(timestr, '\n') = '\0';
677                         printf(" %s)", timestr);
678                 } else {
679                         printf(" 0)");
680                 }
681
682         } else if (do_time == 2) {
683                 printf("(%u %ds %u) ", d->timestamp, d->lifetime, d->expiry);
684         }
685
686         if ((pe = getprotobynumber(d->flow_id.proto)) != NULL)
687                 printf(" %s", pe->p_name);
688         else
689                 printf(" proto %u", d->flow_id.proto);
690
691         a.s_addr = htonl(d->flow_id.src_ip);
692         printf(" %s %d", inet_ntoa(a), d->flow_id.src_port);
693
694         a.s_addr = htonl(d->flow_id.dst_ip);
695         printf(" <-> %s %d", inet_ntoa(a), d->flow_id.dst_port);
696         printf(" CPU %d", d->cpuid);
697         printf("\n");
698 }
699
700 int
701 sort_q(const void *pa, const void *pb)
702 {
703         int rev = (do_sort < 0);
704         int field = rev ? -do_sort : do_sort;
705         long long res = 0;
706         const struct dn_ioc_flowqueue *a = pa;
707         const struct dn_ioc_flowqueue *b = pb;
708
709         switch(field) {
710         case 1: /* pkts */
711                 res = a->len - b->len;
712                 break;
713         case 2: /* bytes */
714                 res = a->len_bytes - b->len_bytes;
715                 break;
716
717         case 3: /* tot pkts */
718                 res = a->tot_pkts - b->tot_pkts;
719                 break;
720
721         case 4: /* tot bytes */
722                 res = a->tot_bytes - b->tot_bytes;
723                 break;
724         }
725         if (res < 0)
726                 res = -1;
727         if (res > 0)
728                 res = 1;
729         return (int)(rev ? res : -res);
730 }
731
732 static void
733 show_queues(struct dn_ioc_flowset *fs, struct dn_ioc_flowqueue *q)
734 {
735         int l;
736
737         printf("mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
738                 fs->flow_mask.u.ip.proto,
739                 fs->flow_mask.u.ip.src_ip, fs->flow_mask.u.ip.src_port,
740                 fs->flow_mask.u.ip.dst_ip, fs->flow_mask.u.ip.dst_port);
741         if (fs->rq_elements == 0)
742                 return;
743
744         printf("BKT Prot ___Source IP/port____ "
745                 "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
746         if (do_sort != 0)
747                 heapsort(q, fs->rq_elements, sizeof(*q), sort_q);
748         for (l = 0; l < fs->rq_elements; l++) {
749                 struct in_addr ina;
750                 struct protoent *pe;
751
752                 ina.s_addr = htonl(q[l].id.u.ip.src_ip);
753                 printf("%3d ", q[l].hash_slot);
754                 pe = getprotobynumber(q[l].id.u.ip.proto);
755                 if (pe)
756                         printf("%-4s ", pe->p_name);
757                 else
758                         printf("%4u ", q[l].id.u.ip.proto);
759                 printf("%15s/%-5d ",
760                         inet_ntoa(ina), q[l].id.u.ip.src_port);
761                 ina.s_addr = htonl(q[l].id.u.ip.dst_ip);
762                 printf("%15s/%-5d ",
763                         inet_ntoa(ina), q[l].id.u.ip.dst_port);
764                 printf("%4ju %8ju %2u %4u %3u\n",
765                         (uintmax_t)q[l].tot_pkts, (uintmax_t)q[l].tot_bytes,
766                         q[l].len, q[l].len_bytes, q[l].drops);
767                 if (verbose)
768                         printf(" S %20ju F %20ju\n",
769                                 (uintmax_t)q[l].S, (uintmax_t)q[l].F);
770         }
771 }
772
773 static void
774 show_flowset_parms(struct dn_ioc_flowset *fs, char *prefix)
775 {
776         char qs[30];
777         char plr[30];
778         char red[90];   /* Display RED parameters */
779         int l;
780
781         l = fs->qsize;
782         if (fs->flags_fs & DN_QSIZE_IS_BYTES) {
783                 if (l >= 8192)
784                         sprintf(qs, "%d KB", l / 1024);
785                 else
786                         sprintf(qs, "%d B", l);
787         } else
788                 sprintf(qs, "%3d sl.", l);
789         if (fs->plr)
790                 sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff));
791         else
792                 plr[0] = '\0';
793         if (fs->flags_fs & DN_IS_RED)   /* RED parameters */
794                 sprintf(red,
795                         "\n\t %cRED w_q %f min_th %d max_th %d max_p %f",
796                         (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ',
797                         1.0 * fs->w_q / (double)(1 << SCALE_RED),
798                         SCALE_VAL(fs->min_th),
799                         SCALE_VAL(fs->max_th),
800                         1.0 * fs->max_p / (double)(1 << SCALE_RED));
801         else
802                 sprintf(red, "droptail");
803
804         printf("%s %s%s %d queues (%d buckets) %s\n",
805                 prefix, qs, plr, fs->rq_elements, fs->rq_size, red);
806 }
807
808 static void
809 show_pipes(void *data, int nbytes, int ac, char *av[])
810 {
811         u_long rulenum;
812         void *next = data;
813         struct dn_ioc_pipe *p = (struct dn_ioc_pipe *)data;
814         struct dn_ioc_flowset *fs;
815         struct dn_ioc_flowqueue *q;
816         int l;
817
818         if (ac > 0)
819                 rulenum = strtoul(*av++, NULL, 10);
820         else
821                 rulenum = 0;
822         for (; nbytes >= sizeof(*p); p = (struct dn_ioc_pipe *)next) {
823                 double b = p->bandwidth;
824                 char buf[30];
825                 char prefix[80];
826
827                 if (p->fs.fs_type != DN_IS_PIPE)
828                         break;  /* done with pipes, now queues */
829
830                 /*
831                  * compute length, as pipe have variable size
832                  */
833                 l = sizeof(*p) + p->fs.rq_elements * sizeof(*q);
834                 next = (void *)p + l;
835                 nbytes -= l;
836
837                 if (rulenum != 0 && rulenum != p->pipe_nr)
838                         continue;
839
840                 /*
841                  * Print rate
842                  */
843                 if (b == 0)
844                         sprintf(buf, "unlimited");
845                 else if (b >= 1000000)
846                         sprintf(buf, "%7.3f Mbit/s", b/1000000);
847                 else if (b >= 1000)
848                         sprintf(buf, "%7.3f Kbit/s", b/1000);
849                 else
850                         sprintf(buf, "%7.3f bit/s ", b);
851
852                 sprintf(prefix, "%05d: %s %4d ms ",
853                         p->pipe_nr, buf, p->delay);
854                 show_flowset_parms(&p->fs, prefix);
855                 if (verbose)
856                         printf(" V %20ju\n", (uintmax_t)p->V >> MY_M);
857
858                 q = (struct dn_ioc_flowqueue *)(p+1);
859                 show_queues(&p->fs, q);
860         }
861
862         for (fs = next; nbytes >= sizeof(*fs); fs = next) {
863                 char prefix[80];
864
865                 if (fs->fs_type != DN_IS_QUEUE)
866                         break;
867                 l = sizeof(*fs) + fs->rq_elements * sizeof(*q);
868                 next = (void *)fs + l;
869                 nbytes -= l;
870                 q = (struct dn_ioc_flowqueue *)(fs+1);
871                 sprintf(prefix, "q%05d: weight %d pipe %d ",
872                         fs->fs_nr, fs->weight, fs->parent_nr);
873                 show_flowset_parms(fs, prefix);
874                 show_queues(fs, q);
875         }
876 }
877
878 /*
879  * This one handles all set-related commands
880  *      ipfw set { show | enable | disable }
881  *      ipfw set swap X Y
882  *      ipfw set move X to Y
883  *      ipfw set move rule X to Y
884  */
885 static void
886 sets_handler(int ac, char *av[])
887 {
888         u_int32_t set_disable, masks[2];
889         u_int16_t rulenum;
890         u_int8_t cmd, new_set;
891         int i, nbytes;
892
893         NEXT_ARG;
894         if (!ac)
895                 errx(EX_USAGE, "set needs command");
896         if (!strncmp(*av, "show", strlen(*av)) ) {
897                 void *data = NULL;
898                 char *msg;
899                 int nalloc=1000;
900                 nbytes = nalloc;
901
902                 while (nbytes >= nalloc) {
903                         nalloc = nalloc * 2+321;
904                         nbytes = nalloc;
905                         if (data == NULL) {
906                                 if ((data = malloc(nbytes)) == NULL) {
907                                         err(EX_OSERR, "malloc");
908                                 }
909                         } else if ((data = realloc(data, nbytes)) == NULL) {
910                                 err(EX_OSERR, "realloc");
911                         }
912                         if (do_get_x(IP_FW_GET, data, &nbytes) < 0) {
913                                 err(EX_OSERR, "getsockopt(IP_FW_GET)");
914                         }
915                 }
916                 set_disable = ((struct ipfw_ioc_rule *)data)->set_disable;
917                 for (i = 0, msg = "disable" ; i < 31; i++)
918                         if ( (set_disable & (1<<i))) {
919                                 printf("%s %d", msg, i);
920                                 msg = "";
921                         }
922                 msg = (set_disable) ? " enable" : "enable";
923                 for (i = 0; i < 31; i++)
924                         if ( !(set_disable & (1<<i))) {
925                                 printf("%s %d", msg, i);
926                                 msg = "";
927                         }
928                 printf("\n");
929         } else if (!strncmp(*av, "swap", strlen(*av))) {
930                 NEXT_ARG;
931                 if (ac != 2)
932                         errx(EX_USAGE, "set swap needs 2 set numbers\n");
933                 rulenum = atoi(av[0]);
934                 new_set = atoi(av[1]);
935                 if (!isdigit(*(av[0])) || rulenum > 30)
936                         errx(EX_DATAERR, "invalid set number %s\n", av[0]);
937                 if (!isdigit(*(av[1])) || new_set > 30)
938                         errx(EX_DATAERR, "invalid set number %s\n", av[1]);
939                 masks[0] = (4 << 24) | (new_set << 16) | (rulenum);
940                 i = do_set_x(IP_FW_DEL, masks, sizeof(u_int32_t));
941         } else if (!strncmp(*av, "move", strlen(*av))) {
942                 NEXT_ARG;
943                 if (ac && !strncmp(*av, "rule", strlen(*av))) {
944                         cmd = 2;
945                         NEXT_ARG;
946                 } else
947                         cmd = 3;
948                 if (ac != 3 || strncmp(av[1], "to", strlen(*av)))
949                         errx(EX_USAGE, "syntax: set move [rule] X to Y\n");
950                 rulenum = atoi(av[0]);
951                 new_set = atoi(av[2]);
952                 if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > 30) ||
953                                 (cmd == 2 && rulenum == 65535) )
954                         errx(EX_DATAERR, "invalid source number %s\n", av[0]);
955                 if (!isdigit(*(av[2])) || new_set > 30)
956                         errx(EX_DATAERR, "invalid dest. set %s\n", av[1]);
957                 masks[0] = (cmd << 24) | (new_set << 16) | (rulenum);
958                 i = do_set_x(IP_FW_DEL, masks, sizeof(u_int32_t));
959         } else if (!strncmp(*av, "disable", strlen(*av)) ||
960                         !strncmp(*av, "enable", strlen(*av)) ) {
961                 int which = !strncmp(*av, "enable", strlen(*av)) ? 1 : 0;
962
963                 NEXT_ARG;
964                 masks[0] = masks[1] = 0;
965
966                 while (ac) {
967                         if (isdigit(**av)) {
968                                 i = atoi(*av);
969                                 if (i < 0 || i > 30)
970                                         errx(EX_DATAERR, "invalid set number %d\n", i);
971                                 masks[which] |= (1<<i);
972                         } else if (!strncmp(*av, "disable", strlen(*av)))
973                                 which = 0;
974                         else if (!strncmp(*av, "enable", strlen(*av)))
975                                 which = 1;
976                         else
977                                 errx(EX_DATAERR, "invalid set command %s\n", *av);
978                         NEXT_ARG;
979                 }
980                 if ( (masks[0] & masks[1]) != 0 )
981                         errx(EX_DATAERR, "cannot enable and disable the same set\n");
982                 i = do_set_x(IP_FW_DEL, masks, sizeof(masks));
983                 if (i)
984                         warn("set enable/disable: setsockopt(IP_FW_DEL)");
985         } else
986                 errx(EX_USAGE, "invalid set command %s\n", *av);
987 }
988
989 static void
990 add_state(int ac, char *av[])
991 {
992         struct ipfw_ioc_state ioc_state;
993         ioc_state.expiry = 0;
994         ioc_state.lifetime = 0;
995         NEXT_ARG;
996         if (strcmp(*av, "rulenum") == 0) {
997                 NEXT_ARG;
998                 ioc_state.rulenum = atoi(*av);
999         } else {
1000                 errx(EX_USAGE, "ipfw state add rule");
1001         }
1002         NEXT_ARG;
1003         struct protoent *pe;
1004         pe = getprotobyname(*av);
1005         ioc_state.flow_id.proto = pe->p_proto;
1006
1007         NEXT_ARG;
1008         ioc_state.flow_id.src_ip = inet_addr(*av);
1009
1010         NEXT_ARG;
1011         ioc_state.flow_id.src_port = atoi(*av);
1012
1013         NEXT_ARG;
1014         ioc_state.flow_id.dst_ip = inet_addr(*av);
1015
1016         NEXT_ARG;
1017         ioc_state.flow_id.dst_port = atoi(*av);
1018
1019         NEXT_ARG;
1020         if (strcmp(*av, "live") == 0) {
1021                 NEXT_ARG;
1022                 ioc_state.lifetime = atoi(*av);
1023                 NEXT_ARG;
1024         }
1025
1026         if (strcmp(*av, "expiry") == 0) {
1027                 NEXT_ARG;
1028                 ioc_state.expiry = strtoul(*av, NULL, 10);
1029                 printf("ioc_state.expiry=%d\n", ioc_state.expiry);
1030         }
1031
1032         if (do_set_x(IP_FW_STATE_ADD, &ioc_state, sizeof(struct ipfw_ioc_state)) < 0 ) {
1033                 err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_ADD)");
1034         }
1035         if (!do_quiet) {
1036                 printf("Flushed all states.\n");
1037         }
1038 }
1039
1040 static void
1041 delete_state(int ac, char *av[])
1042 {
1043         int rulenum;
1044         NEXT_ARG;
1045         if (ac == 1 && isdigit(**av))
1046                 rulenum = atoi(*av);
1047         if (do_set_x(IP_FW_STATE_DEL, &rulenum, sizeof(int)) < 0 )
1048                 err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_DEL)");
1049         if (!do_quiet)
1050                 printf("Flushed all states.\n");
1051 }
1052
1053 static void
1054 flush_state(int ac, char *av[])
1055 {
1056         if (!do_force) {
1057                 int c;
1058
1059                 printf("Are you sure? [yn] ");
1060                 fflush(stdout);
1061                 do {
1062                         c = toupper(getc(stdin));
1063                         while (c != '\n' && getc(stdin) != '\n')
1064                                 if (feof(stdin))
1065                                         return; /* and do not flush */
1066                 } while (c != 'Y' && c != 'N');
1067                 if (c == 'N')   /* user said no */
1068                         return;
1069         }
1070         if (do_set_x(IP_FW_STATE_FLUSH, NULL, 0) < 0 )
1071                 err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_FLUSH)");
1072         if (!do_quiet)
1073                 printf("Flushed all states.\n");
1074 }
1075
1076 static int
1077 lookup_host (char *host, struct in_addr *ipaddr)
1078 {
1079         struct hostent *he;
1080
1081         if (!inet_aton(host, ipaddr)) {
1082                 if ((he = gethostbyname(host)) == NULL)
1083                         return(-1);
1084                 *ipaddr = *(struct in_addr *)he->h_addr_list[0];
1085         }
1086         return(0);
1087 }
1088
1089 static void
1090 table_append(int ac, char *av[])
1091 {
1092         struct ipfw_ioc_table tbl;
1093         char *p;
1094         int size;
1095
1096         NEXT_ARG;
1097         if (isdigit(**av))
1098                 tbl.id = atoi(*av);
1099         else
1100                 errx(EX_USAGE, "table id `%s' invalid", *av);
1101
1102         if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
1103                 errx(EX_USAGE, "table id `%d' invalid", tbl.id);
1104
1105         NEXT_ARG;
1106         if (strcmp(*av, "ip") == 0)
1107                 tbl.type = 1;
1108         else if (strcmp(*av, "mac") == 0)
1109                 tbl.type = 2;
1110         else
1111                 errx(EX_USAGE, "table type `%s' not supported", *av);
1112
1113         NEXT_ARG;
1114         if (tbl.type == 1) { /* table type ipv4 */
1115                 struct ipfw_ioc_table_ip_entry ip_ent;
1116                 if (!ac)
1117                         errx(EX_USAGE, "IP address required");
1118
1119                 p = strchr(*av, '/');
1120                 if (p) {
1121                         *p++ = '\0';
1122                         ip_ent.masklen = atoi(p);
1123                         if (ip_ent.masklen > 32)
1124                                 errx(EX_DATAERR, "bad width ``%s''", p);
1125                 } else {
1126                         ip_ent.masklen = 32;
1127                 }
1128
1129                 if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
1130                         errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
1131
1132                 tbl.ip_ent[0] = ip_ent;
1133                 size = sizeof(tbl) + sizeof(ip_ent);
1134         } else if (tbl.type == 2) { /* table type mac */
1135                 struct ipfw_ioc_table_mac_entry mac_ent;
1136                 if (!ac)
1137                         errx(EX_USAGE, "MAC address required");
1138
1139                 mac_ent.addr = *ether_aton(*av);
1140                 tbl.mac_ent[0] = mac_ent;
1141                 size = sizeof(tbl) + sizeof(mac_ent);
1142         }
1143         if (do_set_x(IP_FW_TABLE_APPEND, &tbl, size) < 0 )
1144                 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_APPEND) "
1145                         "table `%d' append `%s' failed", tbl.id, *av);
1146 }
1147
1148 static void
1149 table_remove(int ac, char *av[])
1150 {
1151         struct ipfw_ioc_table tbl;
1152         struct ipfw_ioc_table_ip_entry ip_ent;
1153         char *p;
1154         int size;
1155
1156         NEXT_ARG;
1157         if (isdigit(**av))
1158                 tbl.id = atoi(*av);
1159         else
1160                 errx(EX_USAGE, "table id `%s' invalid", *av);
1161
1162         if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
1163                 errx(EX_USAGE, "table id `%d' invalid", tbl.id);
1164
1165         NEXT_ARG;
1166         if (strcmp(*av, "ip") == 0)
1167                 tbl.type = 1;
1168         else if (strcmp(*av, "mac") == 0)
1169                 tbl.type = 2;
1170         else
1171                 errx(EX_USAGE, "table type `%s' not supported", *av);
1172
1173         NEXT_ARG;
1174         if (!ac)
1175                 errx(EX_USAGE, "IP address required");
1176         p = strchr(*av, '/');
1177         if (p) {
1178                 *p++ = '\0';
1179                 ip_ent.masklen = atoi(p);
1180                 if (ip_ent.masklen > 32)
1181                         errx(EX_DATAERR, "bad width ``%s''", p);
1182         } else {
1183                 ip_ent.masklen = 32;
1184         }
1185
1186         if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
1187                 errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
1188
1189         tbl.ip_ent[0] = ip_ent;
1190         size = sizeof(tbl) + sizeof(ip_ent);
1191         if (do_set_x(IP_FW_TABLE_REMOVE, &tbl, size) < 0 ) {
1192                 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_REMOVE) "
1193                         "table `%d' append `%s' failed", tbl.id, *av);
1194         }
1195 }
1196
1197 static void
1198 table_flush(int ac, char *av[])
1199 {
1200         struct ipfw_ioc_table ioc_table;
1201         struct ipfw_ioc_table *t = &ioc_table;
1202
1203         NEXT_ARG;
1204         if (isdigit(**av)) {
1205                 t->id = atoi(*av);
1206                 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1207                         errx(EX_USAGE, "table id `%d' invalid", t->id);
1208         } else {
1209                 errx(EX_USAGE, "table id `%s' invalid", *av);
1210         }
1211         if (do_set_x(IP_FW_TABLE_FLUSH, t, sizeof(struct ipfw_ioc_table)) < 0 )
1212                 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_FLUSH) "
1213                                         "table `%s' flush failed", *av);
1214 }
1215
1216 static void
1217 table_list(int ac, char *av[])
1218 {
1219         struct ipfw_ioc_table *ioc_table;
1220         int i, count, nbytes, nalloc = 1024;
1221         void *data = NULL;
1222         NEXT_ARG;
1223         if (strcmp(*av, "list") == 0) {
1224                 nbytes = nalloc;
1225                 while (nbytes >= nalloc) {
1226                         nalloc = nalloc * 2 ;
1227                         nbytes = nalloc;
1228                         if ((data = realloc(data, nbytes)) == NULL)
1229                                 err(EX_OSERR, "realloc");
1230                         if (do_get_x(IP_FW_TABLE_LIST, data, &nbytes) < 0)
1231                                 err(EX_OSERR, "do_get_x(IP_FW_TABLE_LIST)");
1232                 }
1233                 ioc_table = (struct ipfw_ioc_table *)data;
1234                 count = nbytes / sizeof(struct ipfw_ioc_table);
1235                 for (i = 0; i < count; i++, ioc_table++) {
1236                         if (ioc_table->type > 0) {
1237                                 printf("table %d",ioc_table->id);
1238                                 if (ioc_table->type == 1)
1239                                         printf(" type ip");
1240                                 else if (ioc_table->type == 2)
1241                                         printf(" type mac");
1242                                 printf(" count %d",ioc_table->count);
1243                                 if (strlen(ioc_table->name) > 0)
1244                                         printf(" name %s",ioc_table->name);
1245                                 printf("\n");
1246
1247                         }
1248                 }
1249         } else {
1250                 errx(EX_USAGE, "ipfw3 table `%s' delete invalid", *av);
1251         }
1252 }
1253
1254 void
1255 print_table(struct ipfw_ioc_table * tbl)
1256 {
1257         int i;
1258         if (tbl->type == 0)
1259                 errx(EX_USAGE, "table %d is not in use", tbl->id);
1260
1261         printf("table %d", tbl->id);
1262         if (tbl->type == 1)
1263                 printf(" type ip");
1264         else if (tbl->type == 2)
1265                 printf(" type mac");
1266
1267         printf(" count %d", tbl->count);
1268         if (strlen(tbl->name) > 0)
1269                 printf(" name %s", tbl->name);
1270
1271         printf("\n");
1272
1273         if (tbl->type == 1) {
1274                 struct ipfw_ioc_table_ip_entry *ip_ent;
1275                 ip_ent = tbl->ip_ent;
1276                 for (i = 0; i < tbl->count; i++) {
1277                         printf("%s", inet_ntoa(*(struct in_addr *)&ip_ent->addr));
1278                         printf("/%d ", ip_ent->masklen);
1279                         printf("\n");
1280                         ip_ent++;
1281                 }
1282         } else if (tbl->type == 2) {
1283                 struct ipfw_ioc_table_mac_entry *mac_ent;
1284                 mac_ent = tbl->mac_ent;
1285                 for (i = 0; i < tbl->count; i++) {
1286                         printf("%s", ether_ntoa(&mac_ent->addr));
1287                         printf("\n");
1288                         mac_ent++;
1289                 }
1290         }
1291 }
1292
1293 static void
1294 table_show(int ac, char *av[])
1295 {
1296         int nbytes, nalloc = 1024;
1297         void *data = NULL;
1298         NEXT_ARG;
1299         if (isdigit(**av)) {
1300                 nbytes = nalloc;
1301                 while (nbytes >= nalloc) {
1302                         nalloc = nalloc * 2 + 256;
1303                         nbytes = nalloc;
1304                         if (data == NULL) {
1305                                 if ((data = malloc(nbytes)) == NULL) {
1306                                         err(EX_OSERR, "malloc");
1307                                 }
1308                         } else if ((data = realloc(data, nbytes)) == NULL) {
1309                                 err(EX_OSERR, "realloc");
1310                         }
1311                         /* store table id in the header of data */
1312                         int *head = (int *)data;
1313                         *head = atoi(*av);
1314                         if (*head < 0 || *head > IPFW_TABLES_MAX - 1)
1315                                 errx(EX_USAGE, "table id `%d' invalid", *head);
1316                         if (do_get_x(IP_FW_TABLE_SHOW, data, &nbytes) < 0)
1317                                 err(EX_OSERR, "do_get_x(IP_FW_TABLE_LIST)");
1318                         struct ipfw_ioc_table *tbl;
1319                         tbl = (struct ipfw_ioc_table *)data;
1320                         print_table(tbl);
1321                 }
1322         } else {
1323                 errx(EX_USAGE, "ipfw3 table `%s' show invalid", *av);
1324         }
1325 }
1326
1327 static void
1328 table_create(int ac, char *av[])
1329 {
1330         struct ipfw_ioc_table ioc_table;
1331         struct ipfw_ioc_table *t = &ioc_table;
1332
1333         NEXT_ARG;
1334         if (ac < 2)
1335                 errx(EX_USAGE, "table parameters invalid");
1336         if (isdigit(**av)) {
1337                 t->id = atoi(*av);
1338                 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1339                         errx(EX_USAGE, "table id `%d' invalid", t->id);
1340         } else {
1341                 errx(EX_USAGE, "table id `%s' invalid", *av);
1342         }
1343         NEXT_ARG;
1344         if (strcmp(*av, "ip") == 0)
1345                 t->type = 1;
1346         else if (strcmp(*av, "mac") == 0)
1347                 t->type = 2;
1348         else
1349                 errx(EX_USAGE, "table type `%s' not supported", *av);
1350
1351         NEXT_ARG;
1352         memset(t->name, 0, IPFW_TABLE_NAME_LEN);
1353         if (ac == 2 && strcmp(*av, "name") == 0) {
1354                 NEXT_ARG;
1355                 if (strlen(*av) < IPFW_TABLE_NAME_LEN) {
1356                         strncpy(t->name, *av, strlen(*av));
1357                 } else {
1358                         errx(EX_USAGE, "table name `%s' too long", *av);
1359                 }
1360         } else if (ac == 1) {
1361                 errx(EX_USAGE, "table `%s' invalid", *av);
1362         }
1363
1364         if (do_set_x(IP_FW_TABLE_CREATE, t, sizeof(struct ipfw_ioc_table)) < 0)
1365                 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_CREATE) "
1366                                         "table `%d' in use", t->id);
1367 }
1368
1369 static void
1370 table_delete(int ac, char *av[])
1371 {
1372         struct ipfw_ioc_table ioc_table;
1373         struct ipfw_ioc_table *t = &ioc_table;
1374
1375         NEXT_ARG;
1376         if (isdigit(**av)) {
1377                 t->id = atoi(*av);
1378                 if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1379                         errx(EX_USAGE, "table id `%d' invalid", t->id);
1380         } else {
1381                 errx(EX_USAGE, "table id `%s' invalid", *av);
1382         }
1383         if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1384                 errx(EX_USAGE, "table id `%d' invalid", t->id);
1385
1386         if (do_set_x(IP_FW_TABLE_DELETE, t, sizeof(struct ipfw_ioc_table)) < 0)
1387                 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_DELETE) "
1388                                         "table `%s' delete failed", *av);
1389 }
1390
1391 static void
1392 table_test(int ac, char *av[])
1393 {
1394         struct ipfw_ioc_table tbl;
1395         int size;
1396
1397         NEXT_ARG;
1398         if (isdigit(**av))
1399                 tbl.id = atoi(*av);
1400         else
1401                 errx(EX_USAGE, "table id `%s' invalid", *av);
1402
1403         if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
1404                 errx(EX_USAGE, "table id `%d' invalid", tbl.id);
1405
1406         NEXT_ARG;
1407         if (strcmp(*av, "ip") == 0)
1408                 tbl.type = 1;
1409         else if (strcmp(*av, "mac") == 0)
1410                 tbl.type = 2;
1411         else
1412                 errx(EX_USAGE, "table type `%s' not supported", *av);
1413
1414         NEXT_ARG;
1415         if (tbl.type == 1) { /* table type ipv4 */
1416                 struct ipfw_ioc_table_ip_entry ip_ent;
1417                 if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
1418                         errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
1419
1420                 tbl.ip_ent[0] = ip_ent;
1421                 size = sizeof(tbl) + sizeof(ip_ent);
1422         } else if (tbl.type == 2) { /* table type mac */
1423                 struct ipfw_ioc_table_mac_entry mac_ent;
1424                 if (!ac)
1425                         errx(EX_USAGE, "MAC address required");
1426
1427                 mac_ent.addr = *ether_aton(*av);
1428                 tbl.mac_ent[0] = mac_ent;
1429                 size = sizeof(tbl) + sizeof(mac_ent);
1430         }
1431         if (do_set_x(IP_FW_TABLE_TEST, &tbl, size) < 0 ) {
1432                 printf("NO, %s not exists in table %d\n", *av, tbl.id);
1433         } else {
1434                 printf("YES, %s exists in table %d\n", *av, tbl.id);
1435         }
1436 }
1437
1438 static void
1439 table_rename(int ac, char *av[])
1440 {
1441         struct ipfw_ioc_table tbl;
1442         int size;
1443
1444         bzero(&tbl, sizeof(tbl));
1445         NEXT_ARG;
1446         if (isdigit(**av))
1447                 tbl.id = atoi(*av);
1448         else
1449                 errx(EX_USAGE, "table id `%s' invalid", *av);
1450
1451         if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
1452                 errx(EX_USAGE, "table id `%d' invalid", tbl.id);
1453
1454         NEXT_ARG;
1455         strlcpy(tbl.name, *av, IPFW_TABLE_NAME_LEN);
1456         size = sizeof(tbl);
1457         if (do_set_x(IP_FW_TABLE_RENAME, &tbl, size) < 0 )
1458                 errx(EX_USAGE, "do_set_x(IP_FW_TABLE_RENAME) "
1459                                         "table `%d' not in use", tbl.id);
1460 }
1461
1462 static void
1463 list(int ac, char *av[])
1464 {
1465         struct ipfw_ioc_state *dynrules, *d;
1466         struct ipfw_ioc_rule *r;
1467
1468         u_long rnum;
1469         void *data = NULL;
1470         int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width;
1471         int exitval = EX_OK, lac;
1472         char **lav, *endptr;
1473         int seen = 0;
1474         int nalloc = 1024;
1475
1476         NEXT_ARG;
1477
1478         /* get rules or pipes from kernel, resizing array as necessary */
1479         nbytes = nalloc;
1480
1481         while (nbytes >= nalloc) {
1482                 nalloc = nalloc * 2 ;
1483                 nbytes = nalloc;
1484                 if ((data = realloc(data, nbytes)) == NULL)
1485                         err(EX_OSERR, "realloc");
1486                 if (do_get_x(IP_FW_GET, data, &nbytes) < 0)
1487                         err(EX_OSERR, "do_get_x(IP_FW_GET)");
1488         }
1489
1490         /*
1491          * Count static rules.
1492          */
1493         r = data;
1494         nstat = r->static_count;
1495
1496         /*
1497          * Count dynamic rules. This is easier as they have
1498          * fixed size.
1499          */
1500         dynrules = (struct ipfw_ioc_state *)((void *)r + r->static_len);
1501         ndyn = (nbytes - r->static_len) / sizeof(*dynrules);
1502
1503         /* if showing stats, figure out column widths ahead of time */
1504         bcwidth = pcwidth = 0;
1505         if (do_acct) {
1506                 for (n = 0, r = data; n < nstat;
1507                         n++, r = (void *)r + IOC_RULESIZE(r)) {
1508                         /* packet counter */
1509                         width = snprintf(NULL, 0, "%ju", (uintmax_t)r->pcnt);
1510                         if (width > pcwidth)
1511                                 pcwidth = width;
1512
1513                         /* byte counter */
1514                         width = snprintf(NULL, 0, "%ju", (uintmax_t)r->bcnt);
1515                         if (width > bcwidth)
1516                                 bcwidth = width;
1517                 }
1518         }
1519         if (do_dynamic && ndyn) {
1520                 for (n = 0, d = dynrules; n < ndyn; n++, d++) {
1521                         width = snprintf(NULL, 0, "%ju", (uintmax_t)d->pcnt);
1522                         if (width > pcwidth)
1523                                 pcwidth = width;
1524
1525                         width = snprintf(NULL, 0, "%ju", (uintmax_t)d->bcnt);
1526                         if (width > bcwidth)
1527                                 bcwidth = width;
1528                 }
1529         }
1530
1531         /* if no rule numbers were specified, list all rules */
1532         if (ac == 0) {
1533                 if (do_dynamic != 2) {
1534                         for (n = 0, r = data; n < nstat; n++,
1535                                 r = (void *)r + IOC_RULESIZE(r)) {
1536                                 show_rules(r, pcwidth, bcwidth);
1537                         }
1538                 }
1539                 if (do_dynamic && ndyn) {
1540                         if (do_dynamic != 2) {
1541                                 printf("## States (%d):\n", ndyn);
1542                         }
1543                         for (n = 0, d = dynrules; n < ndyn; n++, d++)
1544                                 show_states(d, pcwidth, bcwidth);
1545                 }
1546                 goto done;
1547         }
1548
1549         /* display specific rules requested on command line */
1550
1551         if (do_dynamic != 2) {
1552                 for (lac = ac, lav = av; lac != 0; lac--) {
1553                         /* convert command line rule # */
1554                         rnum = strtoul(*lav++, &endptr, 10);
1555                         if (*endptr) {
1556                                 exitval = EX_USAGE;
1557                                 warnx("invalid rule number: %s", *(lav - 1));
1558                                 continue;
1559                         }
1560                         for (n = seen = 0, r = data; n < nstat;
1561                                 n++, r = (void *)r + IOC_RULESIZE(r) ) {
1562                                 if (r->rulenum > rnum)
1563                                         break;
1564                                 if (r->rulenum == rnum) {
1565                                         show_rules(r, pcwidth, bcwidth);
1566                                         seen = 1;
1567                                 }
1568                         }
1569                         if (!seen) {
1570                                 /* give precedence to other error(s) */
1571                                 if (exitval == EX_OK)
1572                                         exitval = EX_UNAVAILABLE;
1573                                 warnx("rule %lu does not exist", rnum);
1574                         }
1575                 }
1576         }
1577
1578         if (do_dynamic && ndyn) {
1579                 if (do_dynamic != 2) {
1580                         printf("## States (%d):\n", ndyn);
1581                 }
1582                 for (lac = ac, lav = av; lac != 0; lac--) {
1583                         rnum = strtoul(*lav++, &endptr, 10);
1584                         if (*endptr)
1585                                 /* already warned */
1586                                 continue;
1587                         for (n = 0, d = dynrules; n < ndyn; n++, d++) {
1588                                 if (d->rulenum > rnum)
1589                                         break;
1590                                 if (d->rulenum == rnum)
1591                                         show_states(d, pcwidth, bcwidth);
1592                         }
1593                 }
1594         }
1595
1596         ac = 0;
1597
1598 done:
1599         free(data);
1600
1601         if (exitval != EX_OK)
1602                 exit(exitval);
1603 }
1604
1605 static void
1606 show_dummynet(int ac, char *av[])
1607 {
1608         void *data = NULL;
1609         int nbytes;
1610         int nalloc = 1024;      /* start somewhere... */
1611
1612         NEXT_ARG;
1613
1614         nbytes = nalloc;
1615         while (nbytes >= nalloc) {
1616                 nalloc = nalloc * 2 + 200;
1617                 nbytes = nalloc;
1618                 if ((data = realloc(data, nbytes)) == NULL)
1619                         err(EX_OSERR, "realloc");
1620                 if (do_get_x(IP_DUMMYNET_GET, data, &nbytes) < 0) {
1621                         err(EX_OSERR, "do_get_x(IP_%s_GET)",
1622                                 do_pipe ? "DUMMYNET" : "FW");
1623                 }
1624         }
1625
1626         show_pipes(data, nbytes, ac, av);
1627         free(data);
1628 }
1629
1630 static void
1631 help(void)
1632 {
1633         fprintf(stderr, "usage: ipfw [options]\n"
1634                         "       ipfw add [rulenum] [set id] action filters\n"
1635                         "       ipfw delete [rulenum]\n"
1636                         "       ipfw flush\n"
1637                         "       ipfw list [rulenum]\n"
1638                         "       ipfw show [rulenum]\n"
1639                         "       ipfw zero [rulenum]\n"
1640                         "       ipfw set [show|enable|disable]\n"
1641                         "       ipfw module\n"
1642                         "       ipfw [enable|disable]\n"
1643                         "       ipfw log [reset|off|on]\n"
1644                         "       ipfw nat [config|show|delete]\n"
1645                         "       ipfw pipe [config|show|delete]\n"
1646                         "       ipfw state [add|delete|list|show]"
1647                         "\nsee ipfw manpage for details\n");
1648         exit(EX_USAGE);
1649 }
1650
1651 static void
1652 delete_nat_config(int ac, char *av[])
1653 {
1654         NEXT_ARG;
1655         int i = 0;
1656         if (ac > 0) {
1657                 i = atoi(*av);
1658         }
1659         if (do_set_x(IP_FW_NAT_DEL, &i, sizeof(i)) == -1)
1660                 errx(EX_USAGE, "NAT %d in use or not exists", i);
1661 }
1662
1663 static void
1664 delete_rules(int ac, char *av[])
1665 {
1666         struct dn_ioc_pipe pipe;
1667         u_int32_t rulenum;
1668         int exitval = EX_OK;
1669         int do_set = 0;
1670         int i;
1671
1672         memset(&pipe, 0, sizeof pipe);
1673
1674         NEXT_ARG;
1675         if (ac > 0 && !strncmp(*av, "set", strlen(*av))) {
1676                 do_set = 1;     /* delete set */
1677                 NEXT_ARG;
1678         }
1679
1680         /* Rule number */
1681         while (ac && isdigit(**av)) {
1682                 i = atoi(*av);
1683                 NEXT_ARG;
1684                 if (do_pipe) {
1685                         if (do_pipe == 1)
1686                                 pipe.pipe_nr = i;
1687                         else
1688                                 pipe.fs.fs_nr = i;
1689
1690                         i = do_set_x(IP_DUMMYNET_DEL, &pipe, sizeof pipe);
1691                         if (i) {
1692                                 exitval = 1;
1693                                 warn("rule %u: setsockopt(IP_DUMMYNET_DEL)",
1694                                         do_pipe == 1 ? pipe.pipe_nr : pipe.fs.fs_nr);
1695                         }
1696                 } else {
1697                         rulenum = (i & 0xffff) | (do_set << 24);
1698                         i = do_set_x(IP_FW_DEL, &rulenum, sizeof rulenum);
1699                         if (i) {
1700                                 exitval = EX_UNAVAILABLE;
1701                                 warn("rule %u: setsockopt(IP_FW_DEL)",
1702                                         rulenum);
1703                         }
1704                 }
1705         }
1706         if (exitval != EX_OK)
1707                 exit(exitval);
1708 }
1709
1710
1711 static unsigned long
1712 getbw(const char *str, u_short *flags, int kb)
1713 {
1714         unsigned long val;
1715         int inbytes = 0;
1716         char *end;
1717
1718         val = strtoul(str, &end, 0);
1719         if (*end == 'k' || *end == 'K') {
1720                 ++end;
1721                 val *= kb;
1722         } else if (*end == 'm' || *end == 'M') {
1723                 ++end;
1724                 val *= kb * kb;
1725         }
1726
1727         /*
1728          * Deal with bits or bytes or b(bits) or B(bytes). If there is no
1729          * trailer assume bits.
1730          */
1731         if (strncasecmp(end, "bit", 3) == 0) {
1732                 ;
1733         } else if (strncasecmp(end, "byte", 4) == 0) {
1734                 inbytes = 1;
1735         } else if (*end == 'b') {
1736                 ;
1737         } else if (*end == 'B') {
1738                 inbytes = 1;
1739         }
1740
1741         /*
1742          * Return in bits if flags is NULL, else flag bits
1743          * or bytes in flags and return the unconverted value.
1744          */
1745         if (inbytes && flags)
1746                 *flags |= DN_QSIZE_IS_BYTES;
1747         else if (inbytes && flags == NULL)
1748                 val *= 8;
1749
1750         return(val);
1751 }
1752
1753 /*
1754  * config dummynet pipe/queue
1755  */
1756 static void
1757 config_dummynet(int ac, char **av)
1758 {
1759         struct dn_ioc_pipe pipe;
1760         u_int32_t a;
1761         void *par = NULL;
1762         int i;
1763         char *end;
1764
1765         NEXT_ARG;
1766         memset(&pipe, 0, sizeof pipe);
1767         /* Pipe number */
1768         if (ac && isdigit(**av)) {
1769                 i = atoi(*av);
1770                 NEXT_ARG;
1771                 if (do_pipe == 1)
1772                         pipe.pipe_nr = i;
1773                 else
1774                         pipe.fs.fs_nr = i;
1775         }
1776
1777         while (ac > 0) {
1778                 double d;
1779
1780                 int tok = match_token(dummynet_params, *av);
1781                 NEXT_ARG;
1782
1783                 switch(tok) {
1784                 case TOK_NOERROR:
1785                         pipe.fs.flags_fs |= DN_NOERROR;
1786                         break;
1787
1788                 case TOK_PLR:
1789                         NEED1("plr needs argument 0..1\n");
1790                         d = strtod(av[0], NULL);
1791                         if (d > 1)
1792                                 d = 1;
1793                         else if (d < 0)
1794                                 d = 0;
1795                         pipe.fs.plr = (int)(d*0x7fffffff);
1796                         NEXT_ARG;
1797                         break;
1798
1799                 case TOK_QUEUE:
1800                         NEED1("queue needs queue size\n");
1801                         end = NULL;
1802                         pipe.fs.qsize = getbw(av[0], &pipe.fs.flags_fs, 1024);
1803                         NEXT_ARG;
1804                         break;
1805
1806                 case TOK_BUCKETS:
1807                         NEED1("buckets needs argument\n");
1808                         pipe.fs.rq_size = strtoul(av[0], NULL, 0);
1809                         NEXT_ARG;
1810                         break;
1811
1812                 case TOK_MASK:
1813                         NEED1("mask needs mask specifier\n");
1814                         /*
1815                          * per-flow queue, mask is dst_ip, dst_port,
1816                          * src_ip, src_port, proto measured in bits
1817                          */
1818                         par = NULL;
1819
1820                         pipe.fs.flow_mask.type = ETHERTYPE_IP;
1821                         pipe.fs.flow_mask.u.ip.dst_ip = 0;
1822                         pipe.fs.flow_mask.u.ip.src_ip = 0;
1823                         pipe.fs.flow_mask.u.ip.dst_port = 0;
1824                         pipe.fs.flow_mask.u.ip.src_port = 0;
1825                         pipe.fs.flow_mask.u.ip.proto = 0;
1826                         end = NULL;
1827
1828                         while (ac >= 1) {
1829                                 u_int32_t *p32 = NULL;
1830                                 u_int16_t *p16 = NULL;
1831
1832                                 tok = match_token(dummynet_params, *av);
1833                                 NEXT_ARG;
1834                                 switch(tok) {
1835                                 case TOK_ALL:
1836                                         /*
1837                                          * special case, all bits significant
1838                                          */
1839                                         pipe.fs.flow_mask.u.ip.dst_ip = ~0;
1840                                         pipe.fs.flow_mask.u.ip.src_ip = ~0;
1841                                         pipe.fs.flow_mask.u.ip.dst_port = ~0;
1842                                         pipe.fs.flow_mask.u.ip.src_port = ~0;
1843                                         pipe.fs.flow_mask.u.ip.proto = ~0;
1844                                         pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
1845                                         goto end_mask;
1846
1847                                 case TOK_DSTIP:
1848                                         p32 = &pipe.fs.flow_mask.u.ip.dst_ip;
1849                                         break;
1850
1851                                 case TOK_SRCIP:
1852                                         p32 = &pipe.fs.flow_mask.u.ip.src_ip;
1853                                         break;
1854
1855                                 case TOK_DSTPORT:
1856                                         p16 = &pipe.fs.flow_mask.u.ip.dst_port;
1857                                         break;
1858
1859                                 case TOK_SRCPORT:
1860                                         p16 = &pipe.fs.flow_mask.u.ip.src_port;
1861                                         break;
1862
1863                                 case TOK_PROTO:
1864                                         break;
1865
1866                                 default:
1867                                         NEXT_ARG;
1868                                         goto end_mask;
1869                                 }
1870                                 if (ac < 1)
1871                                         errx(EX_USAGE, "mask: value missing");
1872                                 if (*av[0] == '/') {
1873                                         a = strtoul(av[0]+1, &end, 0);
1874                                         a = (a == 32) ? ~0 : (1 << a) - 1;
1875                                 } else
1876                                         a = strtoul(av[0], &end, 0);
1877                                 if (p32 != NULL)
1878                                         *p32 = a;
1879                                 else if (p16 != NULL) {
1880                                         if (a > 65535)
1881                                                 errx(EX_DATAERR,
1882                                                 "mask: must be 16 bit");
1883                                         *p16 = (u_int16_t)a;
1884                                 } else {
1885                                         if (a > 255)
1886                                                 errx(EX_DATAERR,
1887                                                 "mask: must be 8 bit");
1888                                         pipe.fs.flow_mask.u.ip.proto = (uint8_t)a;
1889                                 }
1890                                 if (a != 0)
1891                                         pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
1892                                 NEXT_ARG;
1893                         } /* end while, config masks */
1894
1895 end_mask:
1896                         break;
1897
1898                 case TOK_RED:
1899                 case TOK_GRED:
1900                         NEED1("red/gred needs w_q/min_th/max_th/max_p\n");
1901                         pipe.fs.flags_fs |= DN_IS_RED;
1902                         if (tok == TOK_GRED)
1903                                 pipe.fs.flags_fs |= DN_IS_GENTLE_RED;
1904                         /*
1905                          * the format for parameters is w_q/min_th/max_th/max_p
1906                          */
1907                         if ((end = strsep(&av[0], "/"))) {
1908                                 double w_q = strtod(end, NULL);
1909                                 if (w_q > 1 || w_q <= 0)
1910                                         errx(EX_DATAERR, "0 < w_q <= 1");
1911                                 pipe.fs.w_q = (int) (w_q * (1 << SCALE_RED));
1912                         }
1913                         if ((end = strsep(&av[0], "/"))) {
1914                                 pipe.fs.min_th = strtoul(end, &end, 0);
1915                                 if (*end == 'K' || *end == 'k')
1916                                         pipe.fs.min_th *= 1024;
1917                         }
1918                         if ((end = strsep(&av[0], "/"))) {
1919                                 pipe.fs.max_th = strtoul(end, &end, 0);
1920                                 if (*end == 'K' || *end == 'k')
1921                                         pipe.fs.max_th *= 1024;
1922                         }
1923                         if ((end = strsep(&av[0], "/"))) {
1924                                 double max_p = strtod(end, NULL);
1925                                 if (max_p > 1 || max_p <= 0)
1926                                         errx(EX_DATAERR, "0 < max_p <= 1");
1927                                 pipe.fs.max_p = (int)(max_p * (1 << SCALE_RED));
1928                         }
1929                         NEXT_ARG;
1930                         break;
1931
1932                 case TOK_DROPTAIL:
1933                         pipe.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED);
1934                         break;
1935
1936                 case TOK_BW:
1937                         NEED1("bw needs bandwidth\n");
1938                         if (do_pipe != 1)
1939                                 errx(EX_DATAERR, "bandwidth only valid for pipes");
1940                         /*
1941                          * set bandwidth value
1942                          */
1943                         pipe.bandwidth = getbw(av[0], NULL, 1000);
1944                         if (pipe.bandwidth < 0)
1945                                 errx(EX_DATAERR, "bandwidth too large");
1946                         NEXT_ARG;
1947                         break;
1948
1949                 case TOK_DELAY:
1950                         if (do_pipe != 1)
1951                                 errx(EX_DATAERR, "delay only valid for pipes");
1952                         NEED1("delay needs argument 0..10000ms\n");
1953                         pipe.delay = strtoul(av[0], NULL, 0);
1954                         NEXT_ARG;
1955                         break;
1956
1957                 case TOK_WEIGHT:
1958                         if (do_pipe == 1)
1959                                 errx(EX_DATAERR, "weight only valid for queues");
1960                         NEED1("weight needs argument 0..100\n");
1961                         pipe.fs.weight = strtoul(av[0], &end, 0);
1962                         NEXT_ARG;
1963                         break;
1964
1965                 case TOK_PIPE:
1966                         if (do_pipe == 1)
1967                                 errx(EX_DATAERR, "pipe only valid for queues");
1968                         NEED1("pipe needs pipe_number\n");
1969                         pipe.fs.parent_nr = strtoul(av[0], &end, 0);
1970                         NEXT_ARG;
1971                         break;
1972
1973                 default:
1974                         errx(EX_DATAERR, "unrecognised option ``%s''", *av);
1975                 }
1976         }
1977         if (do_pipe == 1) {
1978                 if (pipe.pipe_nr == 0)
1979                         errx(EX_DATAERR, "pipe_nr must be > 0");
1980                 if (pipe.delay > 10000)
1981                         errx(EX_DATAERR, "delay must be < 10000");
1982         } else { /* do_pipe == 2, queue */
1983                 if (pipe.fs.parent_nr == 0)
1984                         errx(EX_DATAERR, "pipe must be > 0");
1985                 if (pipe.fs.weight >100)
1986                         errx(EX_DATAERR, "weight must be <= 100");
1987         }
1988         if (pipe.fs.flags_fs & DN_QSIZE_IS_BYTES) {
1989                 if (pipe.fs.qsize > 1024*1024)
1990                         errx(EX_DATAERR, "queue size must be < 1MB");
1991         } else {
1992                 if (pipe.fs.qsize > 100)
1993                         errx(EX_DATAERR, "2 <= queue size <= 100");
1994         }
1995         if (pipe.fs.flags_fs & DN_IS_RED) {
1996                 size_t len;
1997                 int lookup_depth, avg_pkt_size;
1998                 double s, idle, weight, w_q;
1999                 int clock_hz;
2000                 int t;
2001
2002                 if (pipe.fs.min_th >= pipe.fs.max_th)
2003                         errx(EX_DATAERR, "min_th %d must be < than max_th %d",
2004                         pipe.fs.min_th, pipe.fs.max_th);
2005                 if (pipe.fs.max_th == 0)
2006                         errx(EX_DATAERR, "max_th must be > 0");
2007
2008                 len = sizeof(int);
2009                 if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
2010                         &lookup_depth, &len, NULL, 0) == -1)
2011
2012                         errx(1, "sysctlbyname(\"%s\")",
2013                                 "net.inet.ip.dummynet.red_lookup_depth");
2014                 if (lookup_depth == 0)
2015                         errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth"
2016                                 " must be greater than zero");
2017
2018                 len = sizeof(int);
2019                 if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
2020                         &avg_pkt_size, &len, NULL, 0) == -1)
2021
2022                         errx(1, "sysctlbyname(\"%s\")",
2023                                 "net.inet.ip.dummynet.red_avg_pkt_size");
2024                 if (avg_pkt_size == 0)
2025                         errx(EX_DATAERR,
2026                                 "net.inet.ip.dummynet.red_avg_pkt_size must"
2027                                 " be greater than zero");
2028
2029                 len = sizeof(clock_hz);
2030                 if (sysctlbyname("net.inet.ip.dummynet.hz", &clock_hz, &len,
2031                                  NULL, 0) == -1) {
2032                         errx(1, "sysctlbyname(\"%s\")",
2033                                  "net.inet.ip.dummynet.hz");
2034                 }
2035
2036                 /*
2037                  * Ticks needed for sending a medium-sized packet.
2038                  * Unfortunately, when we are configuring a WF2Q+ queue, we
2039                  * do not have bandwidth information, because that is stored
2040                  * in the parent pipe, and also we have multiple queues
2041                  * competing for it. So we set s=0, which is not very
2042                  * correct. But on the other hand, why do we want RED with
2043                  * WF2Q+ ?
2044                  */
2045                 if (pipe.bandwidth == 0) /* this is a WF2Q+ queue */
2046                         s = 0;
2047                 else
2048                         s = clock_hz * avg_pkt_size * 8 / pipe.bandwidth;
2049
2050                 /*
2051                  * max idle time (in ticks) before avg queue size becomes 0.
2052                  * NOTA: (3/w_q) is approx the value x so that
2053                  * (1-w_q)^x < 10^-3.
2054                  */
2055                 w_q = ((double)pipe.fs.w_q) / (1 << SCALE_RED);
2056                 idle = s * 3. / w_q;
2057                 pipe.fs.lookup_step = (int)idle / lookup_depth;
2058                 if (!pipe.fs.lookup_step)
2059                         pipe.fs.lookup_step = 1;
2060                 weight = 1 - w_q;
2061                 for (t = pipe.fs.lookup_step; t > 0; --t)
2062                         weight *= weight;
2063                 pipe.fs.lookup_weight = (int)(weight * (1 << SCALE_RED));
2064         }
2065         i = do_set_x(IP_DUMMYNET_CONFIGURE, &pipe, sizeof pipe);
2066         if (i)
2067                 err(1, "do_set_x(%s)", "IP_DUMMYNET_CONFIGURE");
2068 }
2069
2070 /*
2071  * helper function, updates the pointer to cmd with the length
2072  * of the current command, and also cleans up the first word of
2073  * the new command in case it has been clobbered before.
2074  */
2075 static ipfw_insn*
2076 next_cmd(ipfw_insn *cmd)
2077 {
2078         cmd += F_LEN(cmd);
2079         bzero(cmd, sizeof(*cmd));
2080         return cmd;
2081 }
2082
2083 /*
2084  * Parse arguments and assemble the microinstructions which make up a rule.
2085  * Rules are added into the 'rulebuf' and then copied in the correct order
2086  * into the actual rule.
2087  *
2088  *
2089  */
2090 static void
2091 add(int ac, char *av[])
2092 {
2093         /*
2094          * rules are added into the 'rulebuf' and then copied in
2095          * the correct order into the actual rule.
2096          * Some things that need to go out of order (prob, action etc.)
2097          * go into actbuf[].
2098          */
2099         static uint32_t rulebuf[IPFW_RULE_SIZE_MAX];
2100         static uint32_t actbuf[IPFW_RULE_SIZE_MAX];
2101         static uint32_t othbuf[IPFW_RULE_SIZE_MAX];
2102         static uint32_t cmdbuf[IPFW_RULE_SIZE_MAX];
2103
2104         ipfw_insn *src, *dst, *cmd, *action, *other;
2105         ipfw_insn *prev;
2106         char *prev_av;
2107         ipfw_insn *the_comment = NULL;
2108         struct ipfw_ioc_rule *rule;
2109         struct ipfw_keyword *key;
2110         struct ipfw_mapping *map;
2111         parser_func fn;
2112         int i, j;
2113
2114         bzero(actbuf, sizeof(actbuf));          /* actions go here */
2115         bzero(othbuf, sizeof(actbuf));          /* others */
2116         bzero(cmdbuf, sizeof(cmdbuf));          /* filters */
2117         bzero(rulebuf, sizeof(rulebuf));
2118
2119         rule = (struct ipfw_ioc_rule *)rulebuf;
2120         cmd = (ipfw_insn *)cmdbuf;
2121         action = (ipfw_insn *)actbuf;
2122         other = (ipfw_insn *)othbuf;
2123
2124         NEED2("need more parameters");
2125         NEXT_ARG;
2126
2127         /* [rule N]     -- Rule number optional */
2128         if (ac && isdigit(**av)) {
2129                 rule->rulenum = atoi(*av);
2130                 NEXT_ARG;
2131         }
2132
2133         /* [set N]      -- set number (0..30), optional */
2134         if (ac > 1 && !strncmp(*av, "set", strlen(*av))) {
2135                 int set = strtoul(av[1], NULL, 10);
2136                 if (set < 0 || set > 30)
2137                         errx(EX_DATAERR, "illegal set %s", av[1]);
2138                 rule->set = set;
2139                 av += 2; ac -= 2;
2140         }
2141
2142         /*
2143          * parse before
2144          */
2145         for (;;) {
2146                 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
2147                         if (key->type == BEFORE &&
2148                                 strcmp(key->word, *av) == 0) {
2149                                 for (j = 0, map = mappings;
2150                                         j < MAPPING_SIZE; j++, map++) {
2151                                         if (map->type == IN_USE &&
2152                                                 map->module == key->module &&
2153                                                 map->opcode == key->opcode ) {
2154                                                 fn = map->parser;
2155                                                 (*fn)(&other, &ac, &av);
2156                                                 break;
2157                                         }
2158                                 }
2159                                 break;
2160                         }
2161                 }
2162                 if (i >= KEYWORD_SIZE) {
2163                         break;
2164                 } else if (F_LEN(other) > 0) {
2165                         if (other->module == MODULE_BASIC_ID &&
2166                                 other->opcode == O_BASIC_CHECK_STATE) {
2167                                 other = next_cmd(other);
2168                                 goto done;
2169                         }
2170                         other = next_cmd(other);
2171                 }
2172         }
2173
2174         /*
2175          * parse actions
2176          *
2177          * only accept 1 action
2178          */
2179         NEED1("missing action");
2180         for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
2181                 if (ac > 0 && key->type == ACTION &&
2182                         strcmp(key->word, *av) == 0) {
2183                         for (j = 0, map = mappings; j<MAPPING_SIZE; j++, map++) {
2184                                 if (map->type == IN_USE &&
2185                                         map->module == key->module &&
2186                                         map->opcode == key->opcode) {
2187                                         fn = map->parser;
2188                                         (*fn)(&action, &ac, &av);
2189                                         break;
2190                                 }
2191                         }
2192                         break;
2193                 }
2194         }
2195         if (F_LEN(action) > 0)
2196                 action = next_cmd(action);
2197
2198         /*
2199          * parse protocol
2200          */
2201         if (strcmp(*av, "proto") == 0){
2202                 NEXT_ARG;
2203         }
2204
2205         NEED1("missing protocol");
2206         for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
2207                 if (key->type == PROTO &&
2208                         strcmp(key->word, "proto") == 0) {
2209                         for (j = 0, map = mappings; j<MAPPING_SIZE; j++, map++) {
2210                                 if (map->type == IN_USE &&
2211                                         map->module == key->module &&
2212                                         map->opcode == key->opcode ) {
2213                                         fn = map->parser;
2214                                         (*fn)(&cmd, &ac, &av);
2215                                         break;
2216                                 }
2217                         }
2218                         break;
2219                 }
2220         }
2221         if (F_LEN(cmd) > 0)
2222                 cmd = next_cmd(cmd);
2223
2224         /*
2225          * other filters
2226          */
2227         while (ac > 0) {
2228                 char *s, *cur;          /* current filter */
2229                 ipfw_insn_u32 *cmd32;   /* alias for cmd */
2230
2231                 s = *av;
2232                 cmd32 = (ipfw_insn_u32 *)cmd;
2233                 if (strcmp(*av, "or") == 0) {
2234                         if (prev == NULL)
2235                                 errx(EX_USAGE, "'or' should"
2236                                                 "between two filters\n");
2237                         prev->len |= F_OR;
2238                         cmd->len = F_OR;
2239                         *av = prev_av;
2240                 }
2241                 if (strcmp(*av, "not") == 0) {
2242                         if (cmd->len & F_NOT)
2243                                 errx(EX_USAGE, "double \"not\" not allowed\n");
2244                         cmd->len = F_NOT;
2245                         NEXT_ARG;
2246                         continue;
2247                 }
2248                 cur = *av;
2249                 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
2250                         if ((key->type == FILTER ||
2251                                 key->type == AFTER ||
2252                                 key->type == FROM ||
2253                                 key->type == TO) &&
2254                                 strcmp(key->word, cur) == 0) {
2255                                 for (j = 0, map = mappings;
2256                                         j< MAPPING_SIZE; j++, map++) {
2257                                         if (map->type == IN_USE &&
2258                                                 map->module == key->module &&
2259                                                 map->opcode == key->opcode ) {
2260                                                 fn = map->parser;
2261                                                 (*fn)(&cmd, &ac, &av);
2262                                                 break;
2263                                         }
2264                                 }
2265                                 break;
2266                         } else if (i == KEYWORD_SIZE - 1) {
2267                                 errx(EX_USAGE, "bad command `%s'", cur);
2268                         }
2269                 }
2270                 if (i >= KEYWORD_SIZE) {
2271                         break;
2272                 } else if (F_LEN(cmd) > 0) {
2273                         prev = cmd;
2274                         prev_av = cur;
2275                         cmd = next_cmd(cmd);
2276                 }
2277         }
2278
2279 done:
2280         if (ac>0)
2281                 errx(EX_USAGE, "bad command `%s'", *av);
2282
2283         /*
2284          * Now copy stuff into the rule.
2285          * [filters][others][action][comment]
2286          */
2287         dst = (ipfw_insn *)rule->cmd;
2288         /*
2289          * copy all filters, except comment
2290          */
2291         src = (ipfw_insn *)cmdbuf;
2292         for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) {
2293                 /* pick comment out */
2294                 i = F_LEN(src);
2295                 if (src->module == MODULE_BASIC_ID && src->opcode == O_BASIC_COMMENT) {
2296                         the_comment=src;
2297                 } else {
2298                         bcopy(src, dst, i * sizeof(u_int32_t));
2299                         dst = (ipfw_insn *)((uint32_t *)dst + i);
2300                 }
2301         }
2302
2303         /*
2304          * start action section, it begin with others
2305          */
2306         rule->act_ofs = (uint32_t *)dst - (uint32_t *)(rule->cmd);
2307
2308         /*
2309          * copy all other others
2310          */
2311         for (src = (ipfw_insn *)othbuf; src != other; src += i) {
2312                 i = F_LEN(src);
2313                 bcopy(src, dst, i * sizeof(u_int32_t));
2314                 dst = (ipfw_insn *)((uint32_t *)dst + i);
2315         }
2316
2317         /* copy the action to the end of rule */
2318         src = (ipfw_insn *)actbuf;
2319         i = F_LEN(src);
2320         bcopy(src, dst, i * sizeof(u_int32_t));
2321         dst = (ipfw_insn *)((uint32_t *)dst + i);
2322
2323         /*
2324          * comment place behind the action
2325          */
2326         if (the_comment != NULL) {
2327                 i = F_LEN(the_comment);
2328                 bcopy(the_comment, dst, i * sizeof(u_int32_t));
2329                 dst = (ipfw_insn *)((uint32_t *)dst + i);
2330         }
2331
2332         rule->cmd_len = (u_int32_t *)dst - (u_int32_t *)(rule->cmd);
2333         i = (void *)dst - (void *)rule;
2334         if (do_set_x(IP_FW_ADD, (void *)rule, i) == -1) {
2335                 err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD");
2336         }
2337         if (!do_quiet)
2338                 show_rules(rule, 10, 10);
2339 }
2340
2341 static void
2342 zero(int ac, char *av[])
2343 {
2344         int rulenum;
2345         int failed = EX_OK;
2346
2347         NEXT_ARG;
2348
2349         if (!ac) {
2350                 /* clear all entries */
2351                 if (do_set_x(IP_FW_ZERO, NULL, 0) < 0)
2352                         err(EX_UNAVAILABLE, "do_set_x(IP_FW_ZERO)");
2353                 if (!do_quiet)
2354                         printf("Accounting cleared.\n");
2355                 return;
2356         }
2357
2358         while (ac) {
2359                 /* Rule number */
2360                 if (isdigit(**av)) {
2361                         rulenum = atoi(*av);
2362                         NEXT_ARG;
2363                         if (do_set_x(IP_FW_ZERO, &rulenum, sizeof rulenum)) {
2364                                 warn("rule %u: do_set_x(IP_FW_ZERO)", rulenum);
2365                                 failed = EX_UNAVAILABLE;
2366                         } else if (!do_quiet)
2367                                 printf("Entry %d cleared\n", rulenum);
2368                 } else {
2369                         errx(EX_USAGE, "invalid rule number ``%s''", *av);
2370                 }
2371         }
2372         if (failed != EX_OK)
2373                 exit(failed);
2374 }
2375
2376 static void
2377 resetlog(int ac, char *av[])
2378 {
2379         int rulenum;
2380         int failed = EX_OK;
2381
2382         NEXT_ARG;
2383
2384         if (!ac) {
2385                 /* clear all entries */
2386                 if (setsockopt(ipfw_socket, IPPROTO_IP, IP_FW_RESETLOG, NULL, 0) < 0)
2387                         err(EX_UNAVAILABLE, "setsockopt(IP_FW_RESETLOG)");
2388                 if (!do_quiet)
2389                         printf("Logging counts reset.\n");
2390
2391                 return;
2392         }
2393
2394         while (ac) {
2395                 /* Rule number */
2396                 if (isdigit(**av)) {
2397                         rulenum = atoi(*av);
2398                         NEXT_ARG;
2399                         if (setsockopt(ipfw_socket, IPPROTO_IP,
2400                                 IP_FW_RESETLOG, &rulenum, sizeof rulenum)) {
2401                                 warn("rule %u: setsockopt(IP_FW_RESETLOG)", rulenum);
2402                                 failed = EX_UNAVAILABLE;
2403                         } else if (!do_quiet)
2404                                 printf("Entry %d logging count reset\n", rulenum);
2405                 } else {
2406                         errx(EX_DATAERR, "invalid rule number ``%s''", *av);
2407                 }
2408         }
2409         if (failed != EX_OK)
2410                 exit(failed);
2411 }
2412
2413 static void
2414 flush(void)
2415 {
2416         int cmd = IP_FW_FLUSH;
2417         if (do_pipe) {
2418                 cmd = IP_DUMMYNET_FLUSH;
2419         } else if (do_nat) {
2420                 cmd = IP_FW_NAT_FLUSH;
2421         }
2422         if (!do_force) {
2423                 int c;
2424
2425                 printf("Are you sure? [yn] ");
2426                 fflush(stdout);
2427                 do {
2428                         c = toupper(getc(stdin));
2429                         while (c != '\n' && getc(stdin) != '\n')
2430                                 if (feof(stdin))
2431                                         return; /* and do not flush */
2432                 } while (c != 'Y' && c != 'N');
2433                 if (c == 'N')   /* user said no */
2434                         return;
2435         }
2436         if (do_set_x(cmd, NULL, 0) < 0 ) {
2437                 if (do_pipe)
2438                         errx(EX_USAGE, "pipe/queue in use");
2439                 else if (do_nat)
2440                         errx(EX_USAGE, "NAT configuration in use");
2441                 else
2442                         errx(EX_USAGE, "do_set_x(IP_FWFLUSH) failed");
2443         }
2444         if (!do_quiet) {
2445                 printf("Flushed all %s.\n", do_pipe ? "pipes":
2446                                 (do_nat?"nat configurations":"rules"));
2447         }
2448 }
2449
2450 static void
2451 str2addr(const char* str, struct in_addr* addr)
2452 {
2453         struct hostent* hp;
2454
2455         if (inet_aton (str, addr))
2456                 return;
2457
2458         hp = gethostbyname (str);
2459         if (!hp)
2460                 errx (1, "unknown host %s", str);
2461
2462         memcpy (addr, hp->h_addr, sizeof (struct in_addr));
2463 }
2464
2465 static int
2466 str2portrange(const char* str, const char* proto, port_range *portRange)
2467 {
2468         struct servent* sp;
2469         char*   sep;
2470         char*   end;
2471         u_short loPort, hiPort;
2472
2473         /* First see if this is a service, return corresponding port if so. */
2474         sp = getservbyname (str, proto);
2475         if (sp) {
2476                 SETLOPORT(*portRange, ntohs(sp->s_port));
2477                 SETNUMPORTS(*portRange, 1);
2478                 return 0;
2479         }
2480
2481         /* Not a service, see if it's a single port or port range. */
2482         sep = strchr (str, '-');
2483         if (sep == NULL) {
2484                 SETLOPORT(*portRange, strtol(str, &end, 10));
2485                 if (end != str) {
2486                         /* Single port. */
2487                         SETNUMPORTS(*portRange, 1);
2488                         return 0;
2489                 }
2490
2491                 /* Error in port range field. */
2492                 errx (EX_DATAERR, "%s/%s: unknown service", str, proto);
2493         }
2494
2495         /* Port range, get the values and sanity check. */
2496         sscanf (str, "%hu-%hu", &loPort, &hiPort);
2497         SETLOPORT(*portRange, loPort);
2498         SETNUMPORTS(*portRange, 0);     /* Error by default */
2499         if (loPort <= hiPort)
2500                 SETNUMPORTS(*portRange, hiPort - loPort + 1);
2501
2502         if (GETNUMPORTS(*portRange) == 0)
2503                 errx (EX_DATAERR, "invalid port range %s", str);
2504
2505         return 0;
2506 }
2507
2508 static int
2509 str2proto(const char* str)
2510 {
2511         if (!strcmp (str, "tcp"))
2512                 return IPPROTO_TCP;
2513         if (!strcmp (str, "udp"))
2514                 return IPPROTO_UDP;
2515         errx (EX_DATAERR, "unknown protocol %s. Expected tcp or udp", str);
2516 }
2517
2518 static int
2519 str2addr_portrange (const char* str, struct in_addr* addr,
2520         char* proto, port_range *portRange)
2521 {
2522         char*   ptr;
2523
2524         ptr = strchr (str, ':');
2525         if (!ptr)
2526                 errx (EX_DATAERR, "%s is missing port number", str);
2527
2528         *ptr = '\0';
2529         ++ptr;
2530
2531         str2addr (str, addr);
2532         return str2portrange (ptr, proto, portRange);
2533 }
2534
2535 /*
2536  * Search for interface with name "ifn", and fill n accordingly:
2537  *
2538  * n->ip                ip address of interface "ifn"
2539  * n->if_name copy of interface name "ifn"
2540  */
2541 static void
2542 set_addr_dynamic(const char *ifn, struct cfg_nat *n)
2543 {
2544         struct if_msghdr *ifm;
2545         struct ifa_msghdr *ifam;
2546         struct sockaddr_dl *sdl;
2547         struct sockaddr_in *sin;
2548         char *buf, *lim, *next;
2549         size_t needed;
2550         int mib[6];
2551         int ifIndex, ifMTU;
2552
2553         mib[0] = CTL_NET;
2554         mib[1] = PF_ROUTE;
2555         mib[2] = 0;
2556         mib[3] = AF_INET;
2557         mib[4] = NET_RT_IFLIST;
2558         mib[5] = 0;
2559
2560         /*
2561          * Get interface data.
2562          */
2563         if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
2564                 err(1, "iflist-sysctl-estimate");
2565         if ((buf = malloc(needed)) == NULL)
2566                 errx(1, "malloc failed");
2567         if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
2568                 err(1, "iflist-sysctl-get");
2569         lim = buf + needed;
2570         /*
2571          * Loop through interfaces until one with
2572          * given name is found. This is done to
2573          * find correct interface index for routing
2574          * message processing.
2575          */
2576         ifIndex = 0;
2577         next = buf;
2578         while (next < lim) {
2579                 ifm = (struct if_msghdr *)next;
2580                 next += ifm->ifm_msglen;
2581                 if (ifm->ifm_version != RTM_VERSION) {
2582                         if (verbose)
2583                                 warnx("routing message version %d "
2584                                         "not understood", ifm->ifm_version);
2585                         continue;
2586                 }
2587                 if (ifm->ifm_type == RTM_IFINFO) {
2588                         sdl = (struct sockaddr_dl *)(ifm + 1);
2589                         if (strlen(ifn) == sdl->sdl_nlen &&
2590                                 strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
2591                                 ifIndex = ifm->ifm_index;
2592                                 ifMTU = ifm->ifm_data.ifi_mtu;
2593                                 break;
2594                         }
2595                 }
2596         }
2597         if (!ifIndex)
2598                 errx(1, "unknown interface name %s", ifn);
2599         /*
2600          * Get interface address.
2601          */
2602         sin = NULL;
2603         while (next < lim) {
2604                 ifam = (struct ifa_msghdr *)next;
2605                 next += ifam->ifam_msglen;
2606                 if (ifam->ifam_version != RTM_VERSION) {
2607                         if (verbose)
2608                                 warnx("routing message version %d "
2609                                         "not understood", ifam->ifam_version);
2610                         continue;
2611                 }
2612                 if (ifam->ifam_type != RTM_NEWADDR)
2613                         break;
2614                 if (ifam->ifam_addrs & RTA_IFA) {
2615                         int i;
2616                         char *cp = (char *)(ifam + 1);
2617
2618                         for (i = 1; i < RTA_IFA; i <<= 1) {
2619                                 if (ifam->ifam_addrs & i)
2620                                         cp += SA_SIZE((struct sockaddr *)cp);
2621                         }
2622                         if (((struct sockaddr *)cp)->sa_family == AF_INET) {
2623                                 sin = (struct sockaddr_in *)cp;
2624                                 break;
2625                         }
2626                 }
2627         }
2628         if (sin == NULL)
2629                 errx(1, "%s: cannot get interface address", ifn);
2630
2631         n->ip = sin->sin_addr;
2632         strncpy(n->if_name, ifn, IF_NAMESIZE);
2633
2634         free(buf);
2635 }
2636
2637 static int
2638 setup_redir_addr(char *spool_buf, int len, int *_ac, char ***_av)
2639 {
2640         struct cfg_redir *r;
2641         struct cfg_spool *tmp;
2642         char **av, *sep;
2643         char tmp_spool_buf[NAT_BUF_LEN];
2644         int ac, i, space, lsnat;
2645
2646         i=0;
2647         av = *_av;
2648         ac = *_ac;
2649         space = 0;
2650         lsnat = 0;
2651         if (len >= SOF_REDIR) {
2652                 r = (struct cfg_redir *)spool_buf;
2653                 /* Skip cfg_redir at beginning of buf. */
2654                 spool_buf = &spool_buf[SOF_REDIR];
2655                 space = SOF_REDIR;
2656                 len -= SOF_REDIR;
2657         } else {
2658                 goto nospace;
2659         }
2660
2661         r->mode = REDIR_ADDR;
2662         /* Extract local address. */
2663         if (ac == 0)
2664                 errx(EX_DATAERR, "redirect_addr: missing local address");
2665
2666         sep = strchr(*av, ',');
2667         if (sep) {              /* LSNAT redirection syntax. */
2668                 r->laddr.s_addr = INADDR_NONE;
2669                 /* Preserve av, copy spool servers to tmp_spool_buf. */
2670                 strncpy(tmp_spool_buf, *av, strlen(*av)+1);
2671                 lsnat = 1;
2672         } else {
2673                 str2addr(*av, &r->laddr);
2674         }
2675         INC_ARGCV();
2676
2677         /* Extract public address. */
2678         if (ac == 0)
2679                 errx(EX_DATAERR, "redirect_addr: missing public address");
2680
2681         str2addr(*av, &r->paddr);
2682         INC_ARGCV();
2683
2684         /* Setup LSNAT server pool. */
2685         if (sep) {
2686                 sep = strtok(tmp_spool_buf, ", ");
2687                 while (sep != NULL) {
2688                         tmp = (struct cfg_spool *)spool_buf;
2689                         if (len < SOF_SPOOL)
2690                                 goto nospace;
2691
2692                         len -= SOF_SPOOL;
2693                         space += SOF_SPOOL;
2694                         str2addr(sep, &tmp->addr);
2695                         tmp->port = ~0;
2696                         r->spool_cnt++;
2697                         /* Point to the next possible cfg_spool. */
2698                         spool_buf = &spool_buf[SOF_SPOOL];
2699                         sep = strtok(NULL, ", ");
2700                 }
2701         }
2702         return(space);
2703
2704 nospace:
2705         errx(EX_DATAERR, "redirect_addr: buf is too small\n");
2706 }
2707
2708 static int
2709 setup_redir_port(char *spool_buf, int len, int *_ac, char ***_av)
2710 {
2711         char **av, *sep, *protoName;
2712         char tmp_spool_buf[NAT_BUF_LEN];
2713         int ac, space, lsnat;
2714         struct cfg_redir *r;
2715         struct cfg_spool *tmp;
2716         u_short numLocalPorts;
2717         port_range portRange;
2718
2719         av = *_av;
2720         ac = *_ac;
2721         space = 0;
2722         lsnat = 0;
2723         numLocalPorts = 0;
2724
2725         if (len >= SOF_REDIR) {
2726                 r = (struct cfg_redir *)spool_buf;
2727                 /* Skip cfg_redir at beginning of buf. */
2728                 spool_buf = &spool_buf[SOF_REDIR];
2729                 space = SOF_REDIR;
2730                 len -= SOF_REDIR;
2731         } else {
2732                 goto nospace;
2733         }
2734
2735         r->mode = REDIR_PORT;
2736         /*
2737          * Extract protocol.
2738          */
2739         if (ac == 0)
2740                 errx (EX_DATAERR, "redirect_port: missing protocol");
2741
2742         r->proto = str2proto(*av);
2743         protoName = *av;
2744         INC_ARGCV();
2745
2746         /*
2747          * Extract local address.
2748          */
2749         if (ac == 0)
2750                 errx (EX_DATAERR, "redirect_port: missing local address");
2751
2752         sep = strchr(*av, ',');
2753         /* LSNAT redirection syntax. */
2754         if (sep) {
2755                 r->laddr.s_addr = INADDR_NONE;
2756                 r->lport = ~0;
2757                 numLocalPorts = 1;
2758                 /* Preserve av, copy spool servers to tmp_spool_buf. */
2759                 strncpy(tmp_spool_buf, *av, strlen(*av)+1);
2760                 lsnat = 1;
2761         } else {
2762                 if (str2addr_portrange (*av, &r->laddr, protoName, &portRange) != 0)
2763                         errx(EX_DATAERR, "redirect_port:"
2764                                 "invalid local port range");
2765
2766                 r->lport = GETLOPORT(portRange);
2767                 numLocalPorts = GETNUMPORTS(portRange);
2768         }
2769         INC_ARGCV();
2770
2771         /*
2772          * Extract public port and optionally address.
2773          */
2774         if (ac == 0)
2775                 errx (EX_DATAERR, "redirect_port: missing public port");
2776
2777         sep = strchr (*av, ':');
2778         if (sep) {
2779                 if (str2addr_portrange (*av, &r->paddr, protoName, &portRange) != 0)
2780                         errx(EX_DATAERR, "redirect_port:"
2781                                 "invalid public port range");
2782         } else {
2783                 r->paddr.s_addr = INADDR_ANY;
2784                 if (str2portrange(*av, protoName, &portRange) != 0)
2785                         errx(EX_DATAERR, "redirect_port:"
2786                                 "invalid public port range");
2787         }
2788
2789         r->pport = GETLOPORT(portRange);
2790         r->pport_cnt = GETNUMPORTS(portRange);
2791         INC_ARGCV();
2792
2793         /*
2794          * Extract remote address and optionally port.
2795          */
2796         /*
2797          * NB: isalpha(**av) => we've to check that next parameter is really an
2798          * option for this redirect entry, else stop here processing arg[cv].
2799          */
2800         if (ac != 0 && !isalpha(**av)) {
2801                 sep = strchr (*av, ':');
2802                 if (sep) {
2803                         if (str2addr_portrange (*av, &r->raddr,
2804                                 protoName, &portRange) != 0)
2805                                 errx(EX_DATAERR, "redirect_port:"
2806                                         "invalid remote port range");
2807                 } else {
2808                         SETLOPORT(portRange, 0);
2809                         SETNUMPORTS(portRange, 1);
2810                         str2addr (*av, &r->raddr);
2811                 }
2812                 INC_ARGCV();
2813         } else {
2814                 SETLOPORT(portRange, 0);
2815                 SETNUMPORTS(portRange, 1);
2816                 r->raddr.s_addr = INADDR_ANY;
2817         }
2818         r->rport = GETLOPORT(portRange);
2819         r->rport_cnt = GETNUMPORTS(portRange);
2820
2821         /*
2822          * Make sure port ranges match up, then add the redirect ports.
2823          */
2824         if (numLocalPorts != r->pport_cnt)
2825                 errx(EX_DATAERR, "redirect_port:"
2826                         "port ranges must be equal in size");
2827
2828         /* Remote port range is allowed to be '0' which means all ports. */
2829         if (r->rport_cnt != numLocalPorts &&
2830                 (r->rport_cnt != 1 || r->rport != 0))
2831                         errx(EX_DATAERR, "redirect_port: remote port must"
2832                                 "be 0 or equal to local port range in size");
2833
2834         /*
2835          * Setup LSNAT server pool.
2836          */
2837         if (lsnat) {
2838                 sep = strtok(tmp_spool_buf, ", ");
2839                 while (sep != NULL) {
2840                         tmp = (struct cfg_spool *)spool_buf;
2841                         if (len < SOF_SPOOL)
2842                                 goto nospace;
2843
2844                         len -= SOF_SPOOL;
2845                         space += SOF_SPOOL;
2846                         if (str2addr_portrange(sep,
2847                                 &tmp->addr, protoName, &portRange) != 0)
2848                                 errx(EX_DATAERR, "redirect_port:"
2849                                         "invalid local port range");
2850                         if (GETNUMPORTS(portRange) != 1)
2851                                 errx(EX_DATAERR, "redirect_port: local port"
2852                                         "must be single in this context");
2853                         tmp->port = GETLOPORT(portRange);
2854                         r->spool_cnt++;
2855                         /* Point to the next possible cfg_spool. */
2856                         spool_buf = &spool_buf[SOF_SPOOL];
2857                         sep = strtok(NULL, ", ");
2858                 }
2859         }
2860         return (space);
2861
2862 nospace:
2863         errx(EX_DATAERR, "redirect_port: buf is too small\n");
2864 }
2865
2866 static int
2867 setup_redir_proto(char *spool_buf, int len, int *_ac, char ***_av)
2868 {
2869         struct protoent *protoent;
2870         struct cfg_redir *r;
2871         int ac, i, space;
2872         char **av;
2873
2874         i=0;
2875         av = *_av;
2876         ac = *_ac;
2877         if (len >= SOF_REDIR) {
2878                 r = (struct cfg_redir *)spool_buf;
2879                 /* Skip cfg_redir at beginning of buf. */
2880                 spool_buf = &spool_buf[SOF_REDIR];
2881                 space = SOF_REDIR;
2882                 len -= SOF_REDIR;
2883         } else {
2884                 goto nospace;
2885         }
2886         r->mode = REDIR_PROTO;
2887         /*
2888          * Extract protocol.
2889          */
2890         if (ac == 0)
2891                 errx(EX_DATAERR, "redirect_proto: missing protocol");
2892
2893         protoent = getprotobyname(*av);
2894         if (protoent == NULL)
2895                 errx(EX_DATAERR, "redirect_proto: unknown protocol %s", *av);
2896         else
2897                 r->proto = protoent->p_proto;
2898
2899         INC_ARGCV();
2900
2901         /*
2902          * Extract local address.
2903          */
2904         if (ac == 0)
2905                 errx(EX_DATAERR, "redirect_proto: missing local address");
2906         else
2907                 str2addr(*av, &r->laddr);
2908         INC_ARGCV();
2909
2910         /*
2911          * Extract optional public address.
2912          */
2913         if (ac == 0) {
2914                 r->paddr.s_addr = INADDR_ANY;
2915                 r->raddr.s_addr = INADDR_ANY;
2916         } else {
2917                 /* see above in setup_redir_port() */
2918                 if (!isalpha(**av)) {
2919                         str2addr(*av, &r->paddr);
2920                         INC_ARGCV();
2921
2922                         /*
2923                          * Extract optional remote address.
2924                          */
2925                         /* see above in setup_redir_port() */
2926                         if (ac != 0 && !isalpha(**av)) {
2927                                 str2addr(*av, &r->raddr);
2928                                 INC_ARGCV();
2929                         }
2930                 }
2931         }
2932         return (space);
2933
2934 nospace:
2935         errx(EX_DATAERR, "redirect_proto: buf is too small\n");
2936 }
2937
2938 static void
2939 show_nat_config(char *buf) {
2940         struct cfg_nat *n;
2941         struct cfg_redir *t;
2942         struct cfg_spool *s;
2943         struct protoent *p;
2944         int i, cnt, flag, off;
2945
2946         n = (struct cfg_nat *)buf;
2947         flag = 1;
2948         off = sizeof(*n);
2949         printf("ipfw nat %u config", n->id);
2950         if (strlen(n->if_name) != 0)
2951                 printf(" if %s", n->if_name);
2952         else if (n->ip.s_addr != 0)
2953                 printf(" ip %s", inet_ntoa(n->ip));
2954         while (n->mode != 0) {
2955                 if (n->mode & PKT_ALIAS_LOG) {
2956                         printf(" log");
2957                         n->mode &= ~PKT_ALIAS_LOG;
2958                 } else if (n->mode & PKT_ALIAS_DENY_INCOMING) {
2959                         printf(" deny_in");
2960                         n->mode &= ~PKT_ALIAS_DENY_INCOMING;
2961                 } else if (n->mode & PKT_ALIAS_SAME_PORTS) {
2962                         printf(" same_ports");
2963                         n->mode &= ~PKT_ALIAS_SAME_PORTS;
2964                 } else if (n->mode & PKT_ALIAS_UNREGISTERED_ONLY) {
2965                         printf(" unreg_only");
2966                         n->mode &= ~PKT_ALIAS_UNREGISTERED_ONLY;
2967                 } else if (n->mode & PKT_ALIAS_RESET_ON_ADDR_CHANGE) {
2968                         printf(" reset");
2969                         n->mode &= ~PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2970                 } else if (n->mode & PKT_ALIAS_REVERSE) {
2971                         printf(" reverse");
2972                         n->mode &= ~PKT_ALIAS_REVERSE;
2973                 } else if (n->mode & PKT_ALIAS_PROXY_ONLY) {
2974                         printf(" proxy_only");
2975                         n->mode &= ~PKT_ALIAS_PROXY_ONLY;
2976                 }
2977         }
2978         /* Print all the redirect's data configuration. */
2979         for (cnt = 0; cnt < n->redir_cnt; cnt++) {
2980                 t = (struct cfg_redir *)&buf[off];
2981                 off += SOF_REDIR;
2982                 switch (t->mode) {
2983                 case REDIR_ADDR:
2984                         printf(" redirect_addr");
2985                         if (t->spool_cnt == 0)
2986                                 printf(" %s", inet_ntoa(t->laddr));
2987                         else
2988                                 for (i = 0; i < t->spool_cnt; i++) {
2989                                         s = (struct cfg_spool *)&buf[off];
2990                                         if (i)
2991                                                 printf(", ");
2992                                         else
2993                                                 printf(" ");
2994                                         printf("%s", inet_ntoa(s->addr));
2995                                         off += SOF_SPOOL;
2996                                 }
2997                         printf(" %s", inet_ntoa(t->paddr));
2998                         break;
2999                 case REDIR_PORT:
3000                         p = getprotobynumber(t->proto);
3001                         printf(" redirect_port %s ", p->p_name);
3002                         if (!t->spool_cnt) {
3003                                 printf("%s:%u", inet_ntoa(t->laddr), t->lport);
3004                                 if (t->pport_cnt > 1)
3005                                         printf("-%u", t->lport + t->pport_cnt - 1);
3006                         } else
3007                                 for (i=0; i < t->spool_cnt; i++) {
3008                                         s = (struct cfg_spool *)&buf[off];
3009                                         if (i)
3010                                                 printf(", ");
3011                                         printf("%s:%u", inet_ntoa(s->addr), s->port);
3012                                         off += SOF_SPOOL;
3013                                 }
3014
3015                         printf(" ");
3016                         if (t->paddr.s_addr)
3017                                 printf("%s:", inet_ntoa(t->paddr));
3018                         printf("%u", t->pport);
3019                         if (!t->spool_cnt && t->pport_cnt > 1)
3020                                 printf("-%u", t->pport + t->pport_cnt - 1);
3021
3022                         if (t->raddr.s_addr) {
3023                                 printf(" %s", inet_ntoa(t->raddr));
3024                                 if (t->rport) {
3025                                         printf(":%u", t->rport);
3026                                         if (!t->spool_cnt && t->rport_cnt > 1)
3027                                                 printf("-%u", t->rport +
3028                                                         t->rport_cnt - 1);
3029                                 }
3030                         }
3031                         break;
3032                 case REDIR_PROTO:
3033                         p = getprotobynumber(t->proto);
3034                         printf(" redirect_proto %s %s", p->p_name,
3035                                 inet_ntoa(t->laddr));
3036                         if (t->paddr.s_addr != 0) {
3037                                 printf(" %s", inet_ntoa(t->paddr));
3038                                 if (t->raddr.s_addr)
3039                                         printf(" %s", inet_ntoa(t->raddr));
3040                         }
3041                         break;
3042                 default:
3043                         errx(EX_DATAERR, "unknown redir mode");
3044                         break;
3045                 }
3046         }
3047         printf("\n");
3048 }
3049
3050
3051 static void
3052 show_nat(int ac, char **av) {
3053         struct cfg_nat *n;
3054         struct cfg_redir *e;
3055         int i, nbytes, nalloc, size;
3056         int nat_cnt, redir_cnt, nat_id;
3057         uint8_t *data;
3058
3059         nalloc = 1024;
3060         size = 0;
3061         data = NULL;
3062
3063         NEXT_ARG;
3064
3065         if (ac == 0)
3066                 nat_id = 0;
3067         else
3068                 nat_id = strtoul(*av, NULL, 10);
3069
3070         nbytes = nalloc;
3071         while (nbytes >= nalloc) {
3072                 nalloc = nalloc * 2;
3073                 nbytes = nalloc;
3074                 if ((data = realloc(data, nbytes)) == NULL) {
3075                         err(EX_OSERR, "realloc");
3076                 }
3077                 if (do_get_x(IP_FW_NAT_GET, data, &nbytes) < 0) {
3078                         err(EX_OSERR, "do_get_x(IP_FW_NAT_GET)");
3079                 }
3080         }
3081
3082         if (nbytes == 0) {
3083                 exit(EX_OK);
3084         }
3085
3086         nat_cnt = *((int *)data);
3087         for (i = sizeof(nat_cnt); nat_cnt; nat_cnt--) {
3088                 n = (struct cfg_nat *)&data[i];
3089                 if (n->id >= 0 && n->id <= IPFW_DEFAULT_RULE) {
3090                         if (nat_id == 0 || n->id == nat_id)
3091                                 show_nat_config(&data[i]);
3092                 }
3093                 i += sizeof(struct cfg_nat);
3094                 for (redir_cnt = 0; redir_cnt < n->redir_cnt; redir_cnt++) {
3095                         e = (struct cfg_redir *)&data[i];
3096                         i += sizeof(struct cfg_redir) +
3097                                 e->spool_cnt * sizeof(struct cfg_spool);
3098                 }
3099         }
3100 }
3101
3102 int
3103 get_kern_boottime(void)
3104 {
3105         struct timeval boottime;
3106         size_t size;
3107         int mib[2];
3108         mib[0] = CTL_KERN;
3109         mib[1] = KERN_BOOTTIME;
3110         size = sizeof(boottime);
3111         if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 &&
3112                         boottime.tv_sec != 0) {
3113                 return boottime.tv_sec;
3114         }
3115         return -1;
3116 }
3117
3118 void
3119 show_nat_state(int ac, char **av)
3120 {
3121         int nbytes, nalloc;
3122         int nat_id;
3123         uint8_t *data;
3124
3125         nalloc = 1024;
3126         data = NULL;
3127
3128         NEXT_ARG;
3129         if (ac == 0)
3130                 nat_id = 0;
3131         else
3132                 nat_id = strtoul(*av, NULL, 10);
3133
3134         nbytes = nalloc;
3135         while (nbytes >= nalloc) {
3136                 nalloc = nalloc * 2;
3137                 nbytes = nalloc;
3138                 if ((data = realloc(data, nbytes)) == NULL) {
3139                         err(EX_OSERR, "realloc");
3140                 }
3141                 memcpy(data, &nat_id, sizeof(int));
3142                 if (do_get_x(IP_FW_NAT_LOG, data, &nbytes) < 0) {
3143                         err(EX_OSERR, "do_get_x(IP_FW_NAT_GET_STATE)");
3144                 }
3145         }
3146         if (nbytes == 0)
3147                 exit(EX_OK);
3148         struct ipfw_ioc_nat_state *nat_state;
3149         nat_state =(struct ipfw_ioc_nat_state *)data;
3150         int count = nbytes / sizeof( struct ipfw_ioc_nat_state);
3151         int i, uptime_sec;
3152         uptime_sec = get_kern_boottime();
3153         for (i = 0; i < count; i ++) {
3154                 struct protoent *pe = getprotobynumber(nat_state->link_type);
3155                 printf("%s ", pe->p_name);
3156                 printf("%s:%hu => ",inet_ntoa(nat_state->src_addr),
3157                                 htons(nat_state->src_port));
3158                 printf("%s:%hu",inet_ntoa(nat_state->alias_addr),
3159                                 htons(nat_state->alias_port));
3160                 printf(" -> %s:%hu ",inet_ntoa(nat_state->dst_addr),
3161                                 htons(nat_state->dst_port));
3162                 if (do_time == 1) {
3163                         char timestr[30];
3164                         time_t t = _long_to_time(uptime_sec + nat_state->timestamp);
3165                         strcpy(timestr, ctime(&t));
3166                         *strchr(timestr, '\n') = '\0';
3167                         printf("%s ", timestr);
3168                 } else if (do_time == 2) {
3169                         printf( "%10u ", uptime_sec + nat_state->timestamp);
3170                 }
3171                 printf("\n");
3172                 nat_state++;
3173         }
3174 }
3175
3176 /*
3177  * do_set_x - extended version og do_set
3178  * insert a x_header in the beginning of the rule buf
3179  * and call setsockopt() with IP_FW_X.
3180  */
3181 int
3182 do_set_x(int optname, void *rule, int optlen)
3183 {
3184         int len, *newbuf;
3185
3186         ip_fw_x_header *x_header;
3187         if (ipfw_socket < 0)
3188                 err(EX_UNAVAILABLE, "socket not avaialble");
3189         len = optlen + sizeof(ip_fw_x_header);
3190         newbuf = malloc(len);
3191         if (newbuf == NULL)
3192                 err(EX_OSERR, "malloc newbuf in do_set_x");
3193         bzero(newbuf, len);
3194         x_header = (ip_fw_x_header *)newbuf;
3195         x_header->opcode = optname;
3196         /* copy the rule into the newbuf, just after the x_header*/
3197         bcopy(rule, ++x_header, optlen);
3198         return setsockopt(ipfw_socket, IPPROTO_IP, IP_FW_X, newbuf, len);
3199 }
3200
3201 /*
3202  * same as do_set_x
3203  */
3204 int
3205 do_get_x(int optname, void *rule, int *optlen)
3206 {
3207         int len, *newbuf, retval;
3208
3209         ip_fw_x_header *x_header;
3210         if (ipfw_socket < 0)
3211                 err(EX_UNAVAILABLE, "socket not avaialble");
3212         len = *optlen + sizeof(ip_fw_x_header);
3213         newbuf = malloc(len);
3214         if (newbuf == NULL)
3215                 err(EX_OSERR, "malloc newbuf in do_get_x");
3216         bzero(newbuf, len);
3217         x_header = (ip_fw_x_header *)newbuf;
3218         x_header->opcode = optname;
3219         /* copy the rule into the newbuf, just after the x_header*/
3220         bcopy(rule, ++x_header, *optlen);
3221         retval = getsockopt(ipfw_socket, IPPROTO_IP, IP_FW_X, newbuf, &len);
3222         bcopy(newbuf, rule, len);
3223         *optlen=len;
3224         return retval;
3225 }
3226
3227 static void
3228 config_nat(int ac, char **av)
3229 {
3230         struct cfg_nat *n;                       /* Nat instance configuration. */
3231         int i, len, off, tok;
3232         char *id, buf[NAT_BUF_LEN];     /* Buffer for serialized data. */
3233
3234         len = NAT_BUF_LEN;
3235         /* Offset in buf: save space for n at the beginning. */
3236         off = sizeof(struct cfg_nat);
3237         memset(buf, 0, sizeof(buf));
3238         n = (struct cfg_nat *)buf;
3239
3240         NEXT_ARG;
3241         /* Nat id. */
3242         if (ac && isdigit(**av)) {
3243                 id = *av;
3244                 i = atoi(*av);
3245                 NEXT_ARG;
3246                 n->id = i;
3247         } else
3248                 errx(EX_DATAERR, "missing nat id");
3249         if (ac == 0)
3250                 errx(EX_DATAERR, "missing option");
3251
3252         while (ac > 0) {
3253                 tok = match_token(nat_params, *av);
3254                 NEXT_ARG;
3255                 switch (tok) {
3256                 case TOK_IP:
3257                         if (ac == 0)
3258                                 errx(EX_DATAERR, "missing option");
3259                         if (!inet_aton(av[0], &(n->ip)))
3260                                 errx(EX_DATAERR, "bad ip address ``%s''",
3261                                         av[0]);
3262                         NEXT_ARG;
3263                         break;
3264                 case TOK_IF:
3265                         if (ac == 0)
3266                                 errx(EX_DATAERR, "missing option");
3267                         set_addr_dynamic(av[0], n);
3268                         NEXT_ARG;
3269                         break;
3270                 case TOK_ALOG:
3271                         n->mode |= PKT_ALIAS_LOG;
3272                         break;
3273                 case TOK_DENY_INC:
3274                         n->mode |= PKT_ALIAS_DENY_INCOMING;
3275                         break;
3276                 case TOK_SAME_PORTS:
3277                         n->mode |= PKT_ALIAS_SAME_PORTS;
3278                         break;
3279                 case TOK_UNREG_ONLY:
3280                         n->mode |= PKT_ALIAS_UNREGISTERED_ONLY;
3281                         break;
3282                 case TOK_RESET_ADDR:
3283                         n->mode |= PKT_ALIAS_RESET_ON_ADDR_CHANGE;
3284                         break;
3285                 case TOK_ALIAS_REV:
3286                         n->mode |= PKT_ALIAS_REVERSE;
3287                         break;
3288                 case TOK_PROXY_ONLY:
3289                         n->mode |= PKT_ALIAS_PROXY_ONLY;
3290                         break;
3291                         /*
3292                          * All the setup_redir_* functions work directly in the final
3293                          * buffer, see above for details.
3294                          */
3295                 case TOK_REDIR_ADDR:
3296                 case TOK_REDIR_PORT:
3297                 case TOK_REDIR_PROTO:
3298                         switch (tok) {
3299                         case TOK_REDIR_ADDR:
3300                                 i = setup_redir_addr(&buf[off], len, &ac, &av);
3301                                 break;
3302                         case TOK_REDIR_PORT:
3303                                 i = setup_redir_port(&buf[off], len, &ac, &av);
3304                                 break;
3305                         case TOK_REDIR_PROTO:
3306                                 i = setup_redir_proto(&buf[off], len, &ac, &av);
3307                                 break;
3308                         }
3309                         n->redir_cnt++;
3310                         off += i;
3311                         len -= i;
3312                         break;
3313                 default:
3314                         errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]);
3315                 }
3316         }
3317         i = do_set_x(IP_FW_NAT_CFG, buf, off);
3318         if (i)
3319                 err(1, "do_set_x(%s)", "IP_FW_NAT_CFG");
3320
3321         /* After every modification, we show the resultant rule. */
3322         int _ac = 2;
3323         char *_av[] = {"config", id};
3324         show_nat(_ac, _av);
3325 }
3326
3327
3328 static int
3329 ipfw_main(int ac, char **av)
3330 {
3331         int ch;
3332
3333         if (ac == 1)
3334                 help();
3335
3336         /* Set the force flag for non-interactive processes */
3337         do_force = !isatty(STDIN_FILENO);
3338
3339         optind = optreset = 1;
3340         while ((ch = getopt(ac, av, "hs:acdDefNStTv")) != -1)
3341                 switch (ch) {
3342                 case 'h': /* help */
3343                         help();
3344                         break;  /* NOTREACHED */
3345
3346                 case 's': /* sort */
3347                         do_sort = atoi(optarg);
3348                         break;
3349                 case 'a':
3350                         do_acct = 1;
3351                         break;
3352                 case 'c':
3353                         do_compact = 1;
3354                         break;
3355                 case 'd':
3356                         do_dynamic = 1;
3357                         break;
3358                 case 'D':
3359                         do_dynamic = 2;
3360                         break;
3361                 case 'e':
3362                         do_expired = 1;
3363                         break;
3364                 case 'f':
3365                         do_force = 1;
3366                         break;
3367                 case 'N':
3368                         do_resolv = 1;
3369                         break;
3370                 case 'S':
3371                         show_sets = 1;
3372                         break;
3373                 case 't':
3374                         do_time = 1;
3375                         break;
3376                 case 'T':
3377                         do_time = 2;
3378                         break;
3379                 case 'v':
3380                         do_quiet = 0;
3381                         verbose++;
3382                         break;
3383                 default:
3384                         help();
3385                 }
3386
3387         ac -= optind;
3388         av += optind;
3389         NEED1("bad arguments, for usage summary ``ipfw''");
3390
3391         /*
3392          * optional: pipe or queue or nat
3393          */
3394         do_nat = 0;
3395         do_pipe = 0;
3396         if (!strncmp(*av, "nat", strlen(*av)))
3397                 do_nat = 1;
3398         else if (!strncmp(*av, "pipe", strlen(*av))) {
3399                 do_pipe = 1;
3400         } else if (!strncmp(*av, "queue", strlen(*av))) {
3401                 do_pipe = 2;
3402         }
3403         NEED1("missing command");
3404
3405         /*
3406          * for pipes and queues and nat we normally say 'pipe NN config'
3407          * but the code is easier to parse as 'pipe config NN'
3408          * so we swap the two arguments.
3409          */
3410         if ((do_pipe || do_nat) && ac > 2 && isdigit(*(av[1]))) {
3411                 char *p = av[1];
3412                 av[1] = av[2];
3413                 av[2] = p;
3414         }
3415
3416         if (!strncmp(*av, "add", strlen(*av))) {
3417                 load_modules();
3418                 add(ac, av);
3419         } else if (!strncmp(*av, "delete", strlen(*av))) {
3420                 delete_rules(ac, av);
3421         } else if (!strncmp(*av, "flush", strlen(*av))) {
3422                 flush();
3423         } else if (!strncmp(*av, "list", strlen(*av))) {
3424                 load_modules();
3425                 list(ac, av);
3426         } else if (!strncmp(*av, "show", strlen(*av))) {
3427                 do_acct++;
3428                 load_modules();
3429                 list(ac, av);
3430         } else if (!strncmp(*av, "zero", strlen(*av))) {
3431                 zero(ac, av);
3432         } else if (!strncmp(*av, "set", strlen(*av))) {
3433                 sets_handler(ac, av);
3434         } else if (!strncmp(*av, "module", strlen(*av))) {
3435                 NEXT_ARG;
3436                 if (!strncmp(*av, "show", strlen(*av)) ||
3437                         !strncmp(*av, "show", strlen(*av))) {
3438                         list_modules(ac, av);
3439                 } else {
3440                         errx(EX_USAGE, "bad ipfw module command `%s'", *av);
3441                 }
3442         } else if (!strncmp(*av, "resetlog", strlen(*av))) {
3443                 resetlog(ac, av);
3444         } else if (!strncmp(*av, "log", strlen(*av))) {
3445                 NEXT_ARG;
3446                 if (!strncmp(*av, "reset", strlen(*av))) {
3447                         resetlog(ac, av);
3448                 } else if (!strncmp(*av, "off", strlen(*av))) {
3449
3450                 } else if (!strncmp(*av, "on", strlen(*av))) {
3451
3452                 } else {
3453                         errx(EX_USAGE, "bad command `%s'", *av);
3454                 }
3455         } else if (!strncmp(*av, "nat", strlen(*av))) {
3456                 NEXT_ARG;
3457                 if (!strncmp(*av, "config", strlen(*av))) {
3458                         config_nat(ac, av);
3459                 } else if (!strncmp(*av, "flush", strlen(*av))) {
3460                         flush();
3461                 } else if (!strncmp(*av, "show", strlen(*av)) ||
3462                                 !strncmp(*av, "list", strlen(*av))) {
3463                         if (ac > 2 && isdigit(*(av[1]))) {
3464                                 char *p = av[1];
3465                                 av[1] = av[2];
3466                                 av[2] = p;
3467                         }
3468                         NEXT_ARG;
3469                         if (!strncmp(*av, "config", strlen(*av))) {
3470                                 show_nat(ac, av);
3471                         } else if (!strncmp(*av, "state", strlen(*av))) {
3472                                 show_nat_state(ac,av);
3473                         } else {
3474                                  errx(EX_USAGE,
3475                                         "bad nat show command `%s'", *av);
3476                         }
3477                 } else if (!strncmp(*av, "delete", strlen(*av))) {
3478                         delete_nat_config(ac, av);
3479                 } else {
3480                         errx(EX_USAGE, "bad ipfw nat command `%s'", *av);
3481                 }
3482         } else if (!strncmp(*av, "pipe", strlen(*av)) ||
3483                 !strncmp(*av, "queue", strlen(*av))) {
3484                 NEXT_ARG;
3485                 if (!strncmp(*av, "config", strlen(*av))) {
3486                         config_dummynet(ac, av);
3487                 } else if (!strncmp(*av, "flush", strlen(*av))) {
3488                         flush();
3489                 } else if (!strncmp(*av, "show", strlen(*av))) {
3490                         show_dummynet(ac, av);
3491                 } else {
3492                         errx(EX_USAGE, "bad ipfw pipe command `%s'", *av);
3493                 }
3494         } else if (!strncmp(*av, "state", strlen(*av))) {
3495                 NEXT_ARG;
3496                 if (!strncmp(*av, "add", strlen(*av))) {
3497                         add_state(ac, av);
3498                 } else if (!strncmp(*av, "delete", strlen(*av))) {
3499                         delete_state(ac, av);
3500                 } else if (!strncmp(*av, "flush", strlen(*av))) {
3501                         flush_state(ac, av);
3502                 } else if (!strncmp(*av, "list", strlen(*av))) {
3503                         do_dynamic = 2;
3504                         list(ac, av);
3505                 } else if (!strncmp(*av, "show", strlen(*av))) {
3506                         do_acct = 1;
3507                         do_dynamic =2;
3508                         list(ac, av);
3509                 } else {
3510                         errx(EX_USAGE, "bad ipfw state command `%s'", *av);
3511                 }
3512         } else if (!strncmp(*av, "table", strlen(*av))) {
3513                 if (ac > 2 && isdigit(*(av[1]))) {
3514                         char *p = av[1];
3515                         av[1] = av[2];
3516                         av[2] = p;
3517                 }
3518                 NEXT_ARG;
3519                 if (!strncmp(*av, "append", strlen(*av))) {
3520                         table_append(ac, av);
3521                 } else if (!strncmp(*av, "remove", strlen(*av))) {
3522                         table_remove(ac, av);
3523                 } else if (!strncmp(*av, "flush", strlen(*av))) {
3524                         table_flush(ac, av);
3525                 } else if (!strncmp(*av, "list", strlen(*av))) {
3526                         table_list(ac, av);
3527                 } else if (!strncmp(*av, "show", strlen(*av))) {
3528                         table_show(ac, av);
3529                 } else if (!strncmp(*av, "type", strlen(*av))) {
3530                         table_create(ac, av);
3531                 } else if (!strncmp(*av, "delete", strlen(*av))) {
3532                         table_delete(ac, av);
3533                 } else if (!strncmp(*av, "test", strlen(*av))) {
3534                         table_test(ac,av);
3535                 } else if (!strncmp(*av, "name", strlen(*av))) {
3536                         table_rename(ac, av);
3537                 } else {
3538                         errx(EX_USAGE, "bad ipfw table command `%s'", *av);
3539                 }
3540
3541         } else {
3542                 errx(EX_USAGE, "bad ipfw command `%s'", *av);
3543         }
3544         return 0;
3545 }
3546
3547 static void
3548 ipfw_readfile(int ac, char *av[])
3549 {
3550         char    buf[BUFSIZ];
3551         char    *a, *p, *args[MAX_ARGS], *cmd = NULL;
3552         char    linename[10];
3553         int     i=0, lineno=0, qflag=0, pflag=0, status;
3554         FILE    *f = NULL;
3555         pid_t   preproc = 0;
3556         int     c;
3557
3558         while ((c = getopt(ac, av, "D:U:p:q")) != -1) {
3559                 switch (c) {
3560                 case 'D':
3561                         if (!pflag)
3562                                 errx(EX_USAGE, "-D requires -p");
3563                         if (i > MAX_ARGS - 2)
3564                                 errx(EX_USAGE, "too many -D or -U options");
3565                         args[i++] = "-D";
3566                         args[i++] = optarg;
3567                         break;
3568
3569                 case 'U':
3570                         if (!pflag)
3571                                 errx(EX_USAGE, "-U requires -p");
3572                         if (i > MAX_ARGS - 2)
3573                                 errx(EX_USAGE, "too many -D or -U options");
3574                         args[i++] = "-U";
3575                         args[i++] = optarg;
3576                         break;
3577
3578                 case 'p':
3579                         pflag = 1;
3580                         cmd = optarg;
3581                         args[0] = cmd;
3582                         i = 1;
3583                         break;
3584
3585                 case 'q':
3586                         qflag = 1;
3587                         break;
3588
3589                 default:
3590                         errx(EX_USAGE, "bad arguments, for usage"
3591                             " summary ``ipfw''");
3592                 }
3593         }
3594
3595         av += optind;
3596         ac -= optind;
3597         if (ac != 1)
3598                 errx(EX_USAGE, "extraneous filename arguments");
3599
3600         if ((f = fopen(av[0], "r")) == NULL)
3601                 err(EX_UNAVAILABLE, "fopen: %s", av[0]);
3602
3603         if (pflag) {
3604                 /* pipe through preprocessor (cpp or m4) */
3605                 int pipedes[2];
3606
3607                 args[i] = NULL;
3608
3609                 if (pipe(pipedes) == -1)
3610                         err(EX_OSERR, "cannot create pipe");
3611
3612                 switch ((preproc = fork())) {
3613                 case -1:
3614                         err(EX_OSERR, "cannot fork");
3615
3616                 case 0:
3617                         /* child */
3618                         if (dup2(fileno(f), 0) == -1 ||
3619                             dup2(pipedes[1], 1) == -1) {
3620                                 err(EX_OSERR, "dup2()");
3621                         }
3622                         fclose(f);
3623                         close(pipedes[1]);
3624                         close(pipedes[0]);
3625                         execvp(cmd, args);
3626                         err(EX_OSERR, "execvp(%s) failed", cmd);
3627
3628                 default:
3629                         /* parent */
3630                         fclose(f);
3631                         close(pipedes[1]);
3632                         if ((f = fdopen(pipedes[0], "r")) == NULL) {
3633                                 int savederrno = errno;
3634
3635                                 kill(preproc, SIGTERM);
3636                                 errno = savederrno;
3637                                 err(EX_OSERR, "fdopen()");
3638                         }
3639                 }
3640         }
3641
3642         while (fgets(buf, BUFSIZ, f)) {
3643                 lineno++;
3644                 sprintf(linename, "Line %d", lineno);
3645                 args[0] = linename;
3646
3647                 if (*buf == '#')
3648                         continue;
3649                 if ((p = strchr(buf, '#')) != NULL)
3650                         *p = '\0';
3651                 i = 1;
3652                 if (qflag)
3653                         args[i++] = "-q";
3654                 for (a = strtok(buf, WHITESP); a && i < MAX_ARGS;
3655                         a = strtok(NULL, WHITESP), i++) {
3656                         args[i] = a;
3657                 }
3658
3659                 if (i == (qflag? 2: 1))
3660                         continue;
3661                 if (i == MAX_ARGS)
3662                         errx(EX_USAGE, "%s: too many arguments", linename);
3663
3664                 args[i] = NULL;
3665                 ipfw_main(i, args);
3666         }
3667         fclose(f);
3668         if (pflag) {
3669                 if (waitpid(preproc, &status, 0) == -1)
3670                         errx(EX_OSERR, "waitpid()");
3671                 if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK)
3672                         errx(EX_UNAVAILABLE, "preprocessor exited with status %d",
3673                                 WEXITSTATUS(status));
3674                 else if (WIFSIGNALED(status))
3675                         errx(EX_UNAVAILABLE, "preprocessor exited with signal %d",
3676                                 WTERMSIG(status));
3677         }
3678 }
3679
3680 int
3681 main(int ac, char *av[])
3682 {
3683         ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
3684         if (ipfw_socket < 0)
3685                 err(EX_UNAVAILABLE, "socket");
3686
3687         memset(keywords, 0, sizeof(struct ipfw_keyword) * KEYWORD_SIZE);
3688         memset(mappings, 0, sizeof(struct ipfw_mapping) * MAPPING_SIZE);
3689
3690         prepare_default_funcs();
3691
3692         if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0)
3693                 ipfw_readfile(ac, av);
3694         else
3695                 ipfw_main(ac, av);
3696         return EX_OK;
3697 }