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