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