ipfw2 - Rename FreeBSD ipfw port to ipfw3
[dragonfly.git] / sbin / ipfw3 / ipfw3.c
1 /*
2  * Copyright (c) 2002 Luigi Rizzo
3  * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
4  * Copyright (c) 1994 Ugen J.S.Antsilevich
5  *
6  * Idea and grammar partially left from:
7  * Copyright (c) 1993 Daniel Boulet
8  *
9  * Redistribution and use in source forms, with and without modification,
10  * are permitted provided that this entire comment appears intact.
11  *
12  * Redistribution in binary form may occur without any restrictions.
13  * Obviously, it would be nice if you gave credit where credit is due
14  * but requiring it would be too onerous.
15  *
16  * This software is provided ``AS IS'' without any warranties of any kind.
17  *
18  * NEW command line interface for IP firewall facility
19  *
20  * $FreeBSD: src/sbin/ipfw/ipfw2.c,v 1.4.2.13 2003/05/27 22:21:11 gshapiro Exp $
21  */
22
23 #include <sys/param.h>
24 #include <sys/mbuf.h>
25 #include <sys/socket.h>
26 #include <sys/sockio.h>
27 #include <sys/sysctl.h>
28 #include <sys/time.h>
29 #include <sys/wait.h>
30
31 #include <arpa/inet.h>
32 #include <ctype.h>
33 #include <dlfcn.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <grp.h>
37 #include <limits.h>
38 #include <netdb.h>
39 #include <pwd.h>
40 #include <sysexits.h>
41 #include <signal.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <stdarg.h>
45 #include <string.h>
46 #include <timeconv.h>
47 #include <unistd.h>
48
49 #include <netinet/in.h>
50 #include <netinet/in_systm.h>
51 #include <netinet/ip.h>
52 #include <netinet/ip_icmp.h>
53 #include <netinet/tcp.h>
54 #include <net/if.h>
55 #include <net/if_dl.h>
56 #include <net/route.h>
57 #include <net/ethernet.h>
58
59
60 #include "../../sys/net/ipfw3/ip_fw3.h"
61 #include "../../sys/net/dummynet3/ip_dummynet3.h"
62 #include "../../sys/net/libalias/alias.h"
63 #include "../../sys/net/ipfw3_basic/ip_fw3_basic.h"
64 #include "../../sys/net/ipfw3_nat/ip_fw3_nat.h"
65 #include "ipfw.h"
66
67
68 #define KEYWORD_SIZE    256
69 #define MAPPING_SIZE    256
70
71 #define MAX_KEYWORD_LEN 20
72 #define MAX_ARGS        32
73 #define WHITESP         " \t\f\v\n\r"
74 #define IPFW_LIB_PATH   "/usr/lib/libipfw3%s.so"
75 #define IP_MASK_ALL     0xffffffff
76 #define NAT_BUF_LEN     1024
77 /*
78  * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines
79  * This is only used in this code.
80  */
81 #define IPPROTO_ETHERTYPE       0x1000
82
83 /*
84  * This macro returns the size of a struct sockaddr when passed
85  * through a routing socket. Basically we round up sa_len to
86  * a multiple of sizeof(long), with a minimum of sizeof(long).
87  * The check for a NULL pointer is just a convenience, probably never used.
88  * The case sa_len == 0 should only apply to empty structures.
89  */
90 #define SA_SIZE(sa)                                             \
91         ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ?   \
92         sizeof(long)            :                               \
93         1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
94
95 /*
96  * show_rules() prints the body of an ipfw rule.
97  * Because the standard rule has at least proto src_ip dst_ip, we use
98  * a helper function to produce these entries if not provided explicitly.
99  * The first argument is the list of fields we have, the second is
100  * the list of fields we want to be printed.
101  *
102  * Special cases if we have provided a MAC header:
103  * + if the rule does not contain IP addresses/ports, do not print them;
104  * + if the rule does not contain an IP proto, print "all" instead of "ip";
105  *
106  */
107 #define HAVE_PROTO      0x0001
108 #define HAVE_SRCIP      0x0002
109 #define HAVE_DSTIP      0x0004
110 #define HAVE_MAC        0x0008
111 #define HAVE_MACTYPE    0x0010
112 #define HAVE_OPTIONS    0x8000
113
114 #define HAVE_IP         (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP)
115
116 /*
117  * Definition of a port range, and macros to deal with values.
118  * FORMAT: HI 16-bits == first port in range, 0 == all ports.
119  *               LO 16-bits == number of ports in range
120  * NOTES: - Port values are not stored in network byte order.
121  */
122
123 #define port_range u_long
124
125 #define GETLOPORT(x)    ((x) >> 0x10)
126 #define GETNUMPORTS(x)  ((x) & 0x0000ffff)
127 #define GETHIPORT(x)    (GETLOPORT((x)) + GETNUMPORTS((x)))
128
129 /* Set y to be the low-port value in port_range variable x. */
130 #define SETLOPORT(x, y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
131
132 /* Set y to be the number of ports in port_range variable x. */
133 #define SETNUMPORTS(x, y) ((x) = ((x) & 0xffff0000) | (y))
134
135 #define INC_ARGCV() do {                        \
136         (*_av)++;                               \
137         (*_ac)--;                               \
138         av = *_av;                              \
139         ac = *_ac;                              \
140 } while (0)
141
142
143 int             ipfw_socket = -1;       /* main RAW socket */
144 int             do_resolv,              /* Would try to resolve all */
145                 do_acct,                /* Show packet/byte count */
146                 do_time,                /* Show time stamps */
147                 do_quiet = 1,           /* Be quiet , default is quiet*/
148                 do_force,               /* Don't ask for confirmation */
149                 do_pipe,                /* this cmd refers to a pipe */
150                 do_nat,                 /* Nat configuration. */
151                 do_sort,                /* field to sort results (0 = no) */
152                 do_dynamic,             /* display dynamic rules */
153                 do_expired,             /* display expired dynamic rules */
154                 do_compact,             /* show rules in compact mode */
155                 show_sets,              /* display rule sets */
156                 verbose;
157
158 enum tokens {
159         TOK_NULL=0,
160
161         TOK_IP,
162         TOK_IF,
163         TOK_ALOG,
164         TOK_DENY_INC,
165         TOK_SAME_PORTS,
166         TOK_UNREG_ONLY,
167         TOK_RESET_ADDR,
168         TOK_ALIAS_REV,
169         TOK_PROXY_ONLY,
170         TOK_REDIR_ADDR,
171         TOK_REDIR_PORT,
172         TOK_REDIR_PROTO,
173
174         TOK_PIPE,
175         TOK_QUEUE,
176         TOK_PLR,
177         TOK_NOERROR,
178         TOK_BUCKETS,
179         TOK_DSTIP,
180         TOK_SRCIP,
181         TOK_DSTPORT,
182         TOK_SRCPORT,
183         TOK_ALL,
184         TOK_MASK,
185         TOK_BW,
186         TOK_DELAY,
187         TOK_RED,
188         TOK_GRED,
189         TOK_DROPTAIL,
190         TOK_PROTO,
191         TOK_WEIGHT,
192 };
193
194 struct char_int_map dummynet_params[] = {
195         { "plr",                TOK_PLR },
196         { "noerror",            TOK_NOERROR },
197         { "buckets",            TOK_BUCKETS },
198         { "dst-ip",             TOK_DSTIP },
199         { "src-ip",             TOK_SRCIP },
200         { "dst-port",           TOK_DSTPORT },
201         { "src-port",           TOK_SRCPORT },
202         { "proto",              TOK_PROTO },
203         { "weight",             TOK_WEIGHT },
204         { "all",                TOK_ALL },
205         { "mask",               TOK_MASK },
206         { "droptail",           TOK_DROPTAIL },
207         { "red",                TOK_RED },
208         { "gred",               TOK_GRED },
209         { "bw",                 TOK_BW },
210         { "bandwidth",          TOK_BW },
211         { "delay",              TOK_DELAY },
212         { "pipe",               TOK_PIPE },
213         { "queue",              TOK_QUEUE },
214         { "dummynet-params",    TOK_NULL },
215         { NULL, 0 }
216 };
217
218 struct char_int_map nat_params[] = {
219         { "ip",                 TOK_IP },
220         { "if",                 TOK_IF },
221         { "log",                TOK_ALOG },
222         { "deny_in",            TOK_DENY_INC },
223         { "same_ports",         TOK_SAME_PORTS },
224         { "unreg_only",         TOK_UNREG_ONLY },
225         { "reset",              TOK_RESET_ADDR },
226         { "reverse",            TOK_ALIAS_REV },
227         { "proxy_only",         TOK_PROXY_ONLY },
228         { "redirect_addr",      TOK_REDIR_ADDR },
229         { "redirect_port",      TOK_REDIR_PORT },
230         { "redirect_proto",     TOK_REDIR_PROTO },
231         { NULL, 0 },
232 };
233
234 struct ipfw_keyword {
235         int type;
236         char word[MAX_KEYWORD_LEN];
237         int module;
238         int opcode;
239 };
240
241 struct ipfw_mapping {
242         int type;
243         int module;
244         int opcode;
245         parser_func parser;
246         shower_func shower;
247 };
248
249 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, "ipfw3 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 add_state(int ac, char *av[])
998 {
999         struct ipfw_ioc_state ioc_state;
1000         ioc_state.expiry = 0;
1001         ioc_state.lifetime = 0;
1002         NEXT_ARG;
1003         if (strcmp(*av, "rulenum") == 0) {
1004                 NEXT_ARG;
1005                 ioc_state.rulenum = atoi(*av);
1006         } else {
1007                 errx(EX_USAGE, "ipfw state add rule");
1008         }
1009         NEXT_ARG;
1010         struct protoent *pe;
1011         pe = getprotobyname(*av);
1012         ioc_state.flow_id.proto = pe->p_proto;
1013
1014         NEXT_ARG;
1015         ioc_state.flow_id.src_ip = inet_addr(*av);
1016
1017         NEXT_ARG;
1018         ioc_state.flow_id.src_port = atoi(*av);
1019
1020         NEXT_ARG;
1021         ioc_state.flow_id.dst_ip = inet_addr(*av);
1022
1023         NEXT_ARG;
1024         ioc_state.flow_id.dst_port = atoi(*av);
1025
1026         NEXT_ARG;
1027         if (strcmp(*av, "live") == 0) {
1028                 NEXT_ARG;
1029                 ioc_state.lifetime = atoi(*av);
1030                 NEXT_ARG;
1031         }
1032
1033         if (strcmp(*av, "expiry") == 0) {
1034                 NEXT_ARG;
1035                 ioc_state.expiry = strtoul(*av, NULL, 10);
1036                 printf("ioc_state.expiry=%d\n", ioc_state.expiry);
1037         }
1038
1039         if (do_set_x(IP_FW_STATE_ADD, &ioc_state, sizeof(struct ipfw_ioc_state)) < 0 ) {
1040                 err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_ADD)");
1041         }
1042         if (!do_quiet) {
1043                 printf("Flushed all states.\n");
1044         }
1045 }
1046
1047 static void
1048 delete_state(int ac, char *av[])
1049 {
1050         int rulenum;
1051         NEXT_ARG;
1052         if (ac == 1 && isdigit(**av))
1053                 rulenum = atoi(*av);
1054         if (do_set_x(IP_FW_STATE_DEL, &rulenum, sizeof(int)) < 0 )
1055                 err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_DEL)");
1056         if (!do_quiet)
1057                 printf("Flushed all states.\n");
1058 }
1059
1060 static void
1061 flush_state(int ac, char *av[])
1062 {
1063         if (!do_force) {
1064                 int c;
1065
1066                 printf("Are you sure? [yn] ");
1067                 fflush(stdout);
1068                 do {
1069                         c = toupper(getc(stdin));
1070                         while (c != '\n' && getc(stdin) != '\n')
1071                                 if (feof(stdin))
1072                                         return; /* and do not flush */
1073                 } while (c != 'Y' && c != 'N');
1074                 if (c == 'N')   /* user said no */
1075                         return;
1076         }
1077         if (do_set_x(IP_FW_STATE_FLUSH, NULL, 0) < 0 )
1078                 err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_FLUSH)");
1079         if (!do_quiet)
1080                 printf("Flushed all states.\n");
1081 }
1082
1083 static void
1084 list(int ac, char *av[])
1085 {
1086         struct ipfw_ioc_state *dynrules, *d;
1087         struct ipfw_ioc_rule *r;
1088
1089         u_long rnum;
1090         void *data = NULL;
1091         int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width;
1092         int exitval = EX_OK, lac;
1093         char **lav, *endptr;
1094         int seen = 0;
1095         int nalloc = 1024;
1096
1097         NEXT_ARG;
1098
1099         /* get rules or pipes from kernel, resizing array as necessary */
1100         nbytes = nalloc;
1101
1102         while (nbytes >= nalloc) {
1103                 nalloc = nalloc * 2 ;
1104                 nbytes = nalloc;
1105                 if ((data = realloc(data, nbytes)) == NULL)
1106                         err(EX_OSERR, "realloc");
1107                 if (do_get_x(IP_FW_GET, data, &nbytes) < 0)
1108                         err(EX_OSERR, "do_get_x(IP_FW_GET)");
1109         }
1110
1111         /*
1112          * Count static rules.
1113          */
1114         r = data;
1115         nstat = r->static_count;
1116
1117         /*
1118          * Count dynamic rules. This is easier as they have
1119          * fixed size.
1120          */
1121         dynrules = (struct ipfw_ioc_state *)((void *)r + r->static_len);
1122         ndyn = (nbytes - r->static_len) / sizeof(*dynrules);
1123
1124         /* if showing stats, figure out column widths ahead of time */
1125         bcwidth = pcwidth = 0;
1126         if (do_acct) {
1127                 for (n = 0, r = data; n < nstat;
1128                         n++, r = (void *)r + IOC_RULESIZE(r)) {
1129                         /* packet counter */
1130                         width = snprintf(NULL, 0, "%ju", (uintmax_t)r->pcnt);
1131                         if (width > pcwidth)
1132                                 pcwidth = width;
1133
1134                         /* byte counter */
1135                         width = snprintf(NULL, 0, "%ju", (uintmax_t)r->bcnt);
1136                         if (width > bcwidth)
1137                                 bcwidth = width;
1138                 }
1139         }
1140         if (do_dynamic && ndyn) {
1141                 for (n = 0, d = dynrules; n < ndyn; n++, d++) {
1142                         width = snprintf(NULL, 0, "%ju", (uintmax_t)d->pcnt);
1143                         if (width > pcwidth)
1144                                 pcwidth = width;
1145
1146                         width = snprintf(NULL, 0, "%ju", (uintmax_t)d->bcnt);
1147                         if (width > bcwidth)
1148                                 bcwidth = width;
1149                 }
1150         }
1151
1152         /* if no rule numbers were specified, list all rules */
1153         if (ac == 0) {
1154                 if (do_dynamic != 2) {
1155                         for (n = 0, r = data; n < nstat; n++,
1156                                 r = (void *)r + IOC_RULESIZE(r)) {
1157                                 show_rules(r, pcwidth, bcwidth);
1158                         }
1159                 }
1160                 if (do_dynamic && ndyn) {
1161                         if (do_dynamic != 2) {
1162                                 printf("## States (%d):\n", ndyn);
1163                         }
1164                         for (n = 0, d = dynrules; n < ndyn; n++, d++)
1165                                 show_states(d, pcwidth, bcwidth);
1166                 }
1167                 goto done;
1168         }
1169
1170         /* display specific rules requested on command line */
1171
1172         if (do_dynamic != 2) {
1173                 for (lac = ac, lav = av; lac != 0; lac--) {
1174                         /* convert command line rule # */
1175                         rnum = strtoul(*lav++, &endptr, 10);
1176                         if (*endptr) {
1177                                 exitval = EX_USAGE;
1178                                 warnx("invalid rule number: %s", *(lav - 1));
1179                                 continue;
1180                         }
1181                         for (n = seen = 0, r = data; n < nstat;
1182                                 n++, r = (void *)r + IOC_RULESIZE(r) ) {
1183                                 if (r->rulenum > rnum)
1184                                         break;
1185                                 if (r->rulenum == rnum) {
1186                                         show_rules(r, pcwidth, bcwidth);
1187                                         seen = 1;
1188                                 }
1189                         }
1190                         if (!seen) {
1191                                 /* give precedence to other error(s) */
1192                                 if (exitval == EX_OK)
1193                                         exitval = EX_UNAVAILABLE;
1194                                 warnx("rule %lu does not exist", rnum);
1195                         }
1196                 }
1197         }
1198
1199         if (do_dynamic && ndyn) {
1200                 if (do_dynamic != 2) {
1201                         printf("## States (%d):\n", ndyn);
1202                 }
1203                 for (lac = ac, lav = av; lac != 0; lac--) {
1204                         rnum = strtoul(*lav++, &endptr, 10);
1205                         if (*endptr)
1206                                 /* already warned */
1207                                 continue;
1208                         for (n = 0, d = dynrules; n < ndyn; n++, d++) {
1209                                 if (d->rulenum > rnum)
1210                                         break;
1211                                 if (d->rulenum == rnum)
1212                                         show_states(d, pcwidth, bcwidth);
1213                         }
1214                 }
1215         }
1216
1217         ac = 0;
1218
1219 done:
1220         free(data);
1221
1222         if (exitval != EX_OK)
1223                 exit(exitval);
1224 }
1225
1226 static void
1227 show_dummynet(int ac, char *av[])
1228 {
1229         void *data = NULL;
1230         int nbytes;
1231         int nalloc = 1024;      /* start somewhere... */
1232
1233         NEXT_ARG;
1234
1235         nbytes = nalloc;
1236         while (nbytes >= nalloc) {
1237                 nalloc = nalloc * 2 + 200;
1238                 nbytes = nalloc;
1239                 if ((data = realloc(data, nbytes)) == NULL)
1240                         err(EX_OSERR, "realloc");
1241                 if (do_get_x(IP_DUMMYNET_GET, data, &nbytes) < 0) {
1242                         err(EX_OSERR, "do_get_x(IP_%s_GET)",
1243                                 do_pipe ? "DUMMYNET" : "FW");
1244                 }
1245         }
1246
1247         show_pipes(data, nbytes, ac, av);
1248         free(data);
1249 }
1250
1251 static void
1252 help(void)
1253 {
1254         fprintf(stderr, "usage: ipfw [options]\n"
1255                         "       ipfw add [rulenum] [set id] action filters\n"
1256                         "       ipfw delete [rulenum]\n"
1257                         "       ipfw flush\n"
1258                         "       ipfw list [rulenum]\n"
1259                         "       ipfw show [rulenum]\n"
1260                         "       ipfw zero [rulenum]\n"
1261                         "       ipfw set [show|enable|disable]\n"
1262                         "       ipfw module\n"
1263                         "       ipfw [enable|disable]\n"
1264                         "       ipfw log [reset|off|on]\n"
1265                         "       ipfw nat [config|show|delete]\n"
1266                         "       ipfw pipe [config|show|delete]\n"
1267                         "       ipfw state [add|delete|list|show]"
1268                         "\nsee ipfw manpage for details\n");
1269         exit(EX_USAGE);
1270 }
1271
1272 static void
1273 delete_nat_config(int ac, char *av[])
1274 {
1275         NEXT_ARG;
1276         int i = 0;
1277         if (ac > 0) {
1278                 i = atoi(*av);
1279         }
1280         if (do_set_x(IP_FW_NAT_DEL, &i, sizeof(i)) == -1)
1281                 err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_NAT_DEL");
1282 }
1283
1284 static void
1285 delete_rules(int ac, char *av[])
1286 {
1287         struct dn_ioc_pipe pipe;
1288         u_int32_t rulenum;
1289         int exitval = EX_OK;
1290         int do_set = 0;
1291         int i;
1292
1293         memset(&pipe, 0, sizeof pipe);
1294
1295         NEXT_ARG;
1296         if (ac > 0 && !strncmp(*av, "set", strlen(*av))) {
1297                 do_set = 1;     /* delete set */
1298                 NEXT_ARG;
1299         }
1300
1301         /* Rule number */
1302         while (ac && isdigit(**av)) {
1303                 i = atoi(*av);
1304                 NEXT_ARG;
1305                 if (do_pipe) {
1306                         if (do_pipe == 1)
1307                                 pipe.pipe_nr = i;
1308                         else
1309                                 pipe.fs.fs_nr = i;
1310
1311                         i = do_set_x(IP_DUMMYNET_DEL, &pipe, sizeof pipe);
1312                         if (i) {
1313                                 exitval = 1;
1314                                 warn("rule %u: setsockopt(IP_DUMMYNET_DEL)",
1315                                         do_pipe == 1 ? pipe.pipe_nr : pipe.fs.fs_nr);
1316                         }
1317                 } else {
1318                         rulenum = (i & 0xffff) | (do_set << 24);
1319                         i = do_set_x(IP_FW_DEL, &rulenum, sizeof rulenum);
1320                         if (i) {
1321                                 exitval = EX_UNAVAILABLE;
1322                                 warn("rule %u: setsockopt(IP_FW_DEL)",
1323                                         rulenum);
1324                         }
1325                 }
1326         }
1327         if (exitval != EX_OK)
1328                 exit(exitval);
1329 }
1330
1331
1332 static unsigned long
1333 getbw(const char *str, u_short *flags, int kb)
1334 {
1335         unsigned long val;
1336         int inbytes = 0;
1337         char *end;
1338
1339         val = strtoul(str, &end, 0);
1340         if (*end == 'k' || *end == 'K') {
1341                 ++end;
1342                 val *= kb;
1343         } else if (*end == 'm' || *end == 'M') {
1344                 ++end;
1345                 val *= kb * kb;
1346         }
1347
1348         /*
1349          * Deal with bits or bytes or b(bits) or B(bytes). If there is no
1350          * trailer assume bits.
1351          */
1352         if (strncasecmp(end, "bit", 3) == 0) {
1353                 ;
1354         } else if (strncasecmp(end, "byte", 4) == 0) {
1355                 inbytes = 1;
1356         } else if (*end == 'b') {
1357                 ;
1358         } else if (*end == 'B') {
1359                 inbytes = 1;
1360         }
1361
1362         /*
1363          * Return in bits if flags is NULL, else flag bits
1364          * or bytes in flags and return the unconverted value.
1365          */
1366         if (inbytes && flags)
1367                 *flags |= DN_QSIZE_IS_BYTES;
1368         else if (inbytes && flags == NULL)
1369                 val *= 8;
1370
1371         return(val);
1372 }
1373
1374 /*
1375  * config dummynet pipe/queue
1376  */
1377 static void
1378 config_dummynet(int ac, char **av)
1379 {
1380         struct dn_ioc_pipe pipe;
1381         u_int32_t a;
1382         void *par = NULL;
1383         int i;
1384         char *end;
1385
1386         NEXT_ARG;
1387         memset(&pipe, 0, sizeof pipe);
1388         /* Pipe number */
1389         if (ac && isdigit(**av)) {
1390                 i = atoi(*av);
1391                 NEXT_ARG;
1392                 if (do_pipe == 1)
1393                         pipe.pipe_nr = i;
1394                 else
1395                         pipe.fs.fs_nr = i;
1396         }
1397
1398         while (ac > 0) {
1399                 double d;
1400
1401                 int tok = match_token(dummynet_params, *av);
1402                 NEXT_ARG;
1403
1404                 switch(tok) {
1405                 case TOK_NOERROR:
1406                         pipe.fs.flags_fs |= DN_NOERROR;
1407                         break;
1408
1409                 case TOK_PLR:
1410                         NEED1("plr needs argument 0..1\n");
1411                         d = strtod(av[0], NULL);
1412                         if (d > 1)
1413                                 d = 1;
1414                         else if (d < 0)
1415                                 d = 0;
1416                         pipe.fs.plr = (int)(d*0x7fffffff);
1417                         NEXT_ARG;
1418                         break;
1419
1420                 case TOK_QUEUE:
1421                         NEED1("queue needs queue size\n");
1422                         end = NULL;
1423                         pipe.fs.qsize = getbw(av[0], &pipe.fs.flags_fs, 1024);
1424                         NEXT_ARG;
1425                         break;
1426
1427                 case TOK_BUCKETS:
1428                         NEED1("buckets needs argument\n");
1429                         pipe.fs.rq_size = strtoul(av[0], NULL, 0);
1430                         NEXT_ARG;
1431                         break;
1432
1433                 case TOK_MASK:
1434                         NEED1("mask needs mask specifier\n");
1435                         /*
1436                          * per-flow queue, mask is dst_ip, dst_port,
1437                          * src_ip, src_port, proto measured in bits
1438                          */
1439                         par = NULL;
1440
1441                         pipe.fs.flow_mask.type = ETHERTYPE_IP;
1442                         pipe.fs.flow_mask.u.ip.dst_ip = 0;
1443                         pipe.fs.flow_mask.u.ip.src_ip = 0;
1444                         pipe.fs.flow_mask.u.ip.dst_port = 0;
1445                         pipe.fs.flow_mask.u.ip.src_port = 0;
1446                         pipe.fs.flow_mask.u.ip.proto = 0;
1447                         end = NULL;
1448
1449                         while (ac >= 1) {
1450                                 u_int32_t *p32 = NULL;
1451                                 u_int16_t *p16 = NULL;
1452
1453                                 tok = match_token(dummynet_params, *av);
1454                                 NEXT_ARG;
1455                                 switch(tok) {
1456                                 case TOK_ALL:
1457                                         /*
1458                                          * special case, all bits significant
1459                                          */
1460                                         pipe.fs.flow_mask.u.ip.dst_ip = ~0;
1461                                         pipe.fs.flow_mask.u.ip.src_ip = ~0;
1462                                         pipe.fs.flow_mask.u.ip.dst_port = ~0;
1463                                         pipe.fs.flow_mask.u.ip.src_port = ~0;
1464                                         pipe.fs.flow_mask.u.ip.proto = ~0;
1465                                         pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
1466                                         goto end_mask;
1467
1468                                 case TOK_DSTIP:
1469                                         p32 = &pipe.fs.flow_mask.u.ip.dst_ip;
1470                                         break;
1471
1472                                 case TOK_SRCIP:
1473                                         p32 = &pipe.fs.flow_mask.u.ip.src_ip;
1474                                         break;
1475
1476                                 case TOK_DSTPORT:
1477                                         p16 = &pipe.fs.flow_mask.u.ip.dst_port;
1478                                         break;
1479
1480                                 case TOK_SRCPORT:
1481                                         p16 = &pipe.fs.flow_mask.u.ip.src_port;
1482                                         break;
1483
1484                                 case TOK_PROTO:
1485                                         break;
1486
1487                                 default:
1488                                         NEXT_ARG;
1489                                         goto end_mask;
1490                                 }
1491                                 if (ac < 1)
1492                                         errx(EX_USAGE, "mask: value missing");
1493                                 if (*av[0] == '/') {
1494                                         a = strtoul(av[0]+1, &end, 0);
1495                                         a = (a == 32) ? ~0 : (1 << a) - 1;
1496                                 } else
1497                                         a = strtoul(av[0], &end, 0);
1498                                 if (p32 != NULL)
1499                                         *p32 = a;
1500                                 else if (p16 != NULL) {
1501                                         if (a > 65535)
1502                                                 errx(EX_DATAERR,
1503                                                 "mask: must be 16 bit");
1504                                         *p16 = (u_int16_t)a;
1505                                 } else {
1506                                         if (a > 255)
1507                                                 errx(EX_DATAERR,
1508                                                 "mask: must be 8 bit");
1509                                         pipe.fs.flow_mask.u.ip.proto = (uint8_t)a;
1510                                 }
1511                                 if (a != 0)
1512                                         pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
1513                                 NEXT_ARG;
1514                         } /* end while, config masks */
1515
1516 end_mask:
1517                         break;
1518
1519                 case TOK_RED:
1520                 case TOK_GRED:
1521                         NEED1("red/gred needs w_q/min_th/max_th/max_p\n");
1522                         pipe.fs.flags_fs |= DN_IS_RED;
1523                         if (tok == TOK_GRED)
1524                                 pipe.fs.flags_fs |= DN_IS_GENTLE_RED;
1525                         /*
1526                          * the format for parameters is w_q/min_th/max_th/max_p
1527                          */
1528                         if ((end = strsep(&av[0], "/"))) {
1529                                 double w_q = strtod(end, NULL);
1530                                 if (w_q > 1 || w_q <= 0)
1531                                 errx(EX_DATAERR, "0 < w_q <= 1");
1532                                 pipe.fs.w_q = (int) (w_q * (1 << SCALE_RED));
1533                         }
1534                         if ((end = strsep(&av[0], "/"))) {
1535                                 pipe.fs.min_th = strtoul(end, &end, 0);
1536                                 if (*end == 'K' || *end == 'k')
1537                                 pipe.fs.min_th *= 1024;
1538                         }
1539                         if ((end = strsep(&av[0], "/"))) {
1540                                 pipe.fs.max_th = strtoul(end, &end, 0);
1541                                 if (*end == 'K' || *end == 'k')
1542                                 pipe.fs.max_th *= 1024;
1543                         }
1544                         if ((end = strsep(&av[0], "/"))) {
1545                                 double max_p = strtod(end, NULL);
1546                                 if (max_p > 1 || max_p <= 0)
1547                                 errx(EX_DATAERR, "0 < max_p <= 1");
1548                                 pipe.fs.max_p = (int)(max_p * (1 << SCALE_RED));
1549                         }
1550                         NEXT_ARG;
1551                         break;
1552
1553                 case TOK_DROPTAIL:
1554                         pipe.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED);
1555                         break;
1556
1557                 case TOK_BW:
1558                         NEED1("bw needs bandwidth\n");
1559                         if (do_pipe != 1)
1560                                 errx(EX_DATAERR, "bandwidth only valid for pipes");
1561                         /*
1562                          * set bandwidth value
1563                          */
1564                         pipe.bandwidth = getbw(av[0], NULL, 1000);
1565                         if (pipe.bandwidth < 0)
1566                                 errx(EX_DATAERR, "bandwidth too large");
1567                         NEXT_ARG;
1568                         break;
1569
1570                 case TOK_DELAY:
1571                         if (do_pipe != 1)
1572                                 errx(EX_DATAERR, "delay only valid for pipes");
1573                         NEED1("delay needs argument 0..10000ms\n");
1574                         pipe.delay = strtoul(av[0], NULL, 0);
1575                         NEXT_ARG;
1576                         break;
1577
1578                 case TOK_WEIGHT:
1579                         if (do_pipe == 1)
1580                                 errx(EX_DATAERR, "weight only valid for queues");
1581                         NEED1("weight needs argument 0..100\n");
1582                         pipe.fs.weight = strtoul(av[0], &end, 0);
1583                         NEXT_ARG;
1584                         break;
1585
1586                 case TOK_PIPE:
1587                         if (do_pipe == 1)
1588                                 errx(EX_DATAERR, "pipe only valid for queues");
1589                         NEED1("pipe needs pipe_number\n");
1590                         pipe.fs.parent_nr = strtoul(av[0], &end, 0);
1591                         NEXT_ARG;
1592                         break;
1593
1594                 default:
1595                         errx(EX_DATAERR, "unrecognised option ``%s''", *av);
1596                 }
1597         }
1598         if (do_pipe == 1) {
1599                 if (pipe.pipe_nr == 0)
1600                         errx(EX_DATAERR, "pipe_nr must be > 0");
1601                 if (pipe.delay > 10000)
1602                         errx(EX_DATAERR, "delay must be < 10000");
1603         } else { /* do_pipe == 2, queue */
1604                 if (pipe.fs.parent_nr == 0)
1605                         errx(EX_DATAERR, "pipe must be > 0");
1606                 if (pipe.fs.weight >100)
1607                         errx(EX_DATAERR, "weight must be <= 100");
1608         }
1609         if (pipe.fs.flags_fs & DN_QSIZE_IS_BYTES) {
1610                 if (pipe.fs.qsize > 1024*1024)
1611                         errx(EX_DATAERR, "queue size must be < 1MB");
1612         } else {
1613                 if (pipe.fs.qsize > 100)
1614                         errx(EX_DATAERR, "2 <= queue size <= 100");
1615         }
1616         if (pipe.fs.flags_fs & DN_IS_RED) {
1617                 size_t len;
1618                 int lookup_depth, avg_pkt_size;
1619                 double s, idle, weight, w_q;
1620                 int clock_hz;
1621                 int t;
1622
1623                 if (pipe.fs.min_th >= pipe.fs.max_th)
1624                         errx(EX_DATAERR, "min_th %d must be < than max_th %d",
1625                         pipe.fs.min_th, pipe.fs.max_th);
1626                 if (pipe.fs.max_th == 0)
1627                         errx(EX_DATAERR, "max_th must be > 0");
1628
1629                 len = sizeof(int);
1630                 if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
1631                         &lookup_depth, &len, NULL, 0) == -1)
1632
1633                         errx(1, "sysctlbyname(\"%s\")",
1634                                 "net.inet.ip.dummynet.red_lookup_depth");
1635                 if (lookup_depth == 0)
1636                         errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth"
1637                                 " must be greater than zero");
1638
1639                 len = sizeof(int);
1640                 if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
1641                         &avg_pkt_size, &len, NULL, 0) == -1)
1642
1643                         errx(1, "sysctlbyname(\"%s\")",
1644                                 "net.inet.ip.dummynet.red_avg_pkt_size");
1645                 if (avg_pkt_size == 0)
1646                         errx(EX_DATAERR,
1647                                 "net.inet.ip.dummynet.red_avg_pkt_size must"
1648                                 " be greater than zero");
1649
1650                 len = sizeof(clock_hz);
1651                 if (sysctlbyname("net.inet.ip.dummynet.hz", &clock_hz, &len,
1652                                  NULL, 0) == -1) {
1653                         errx(1, "sysctlbyname(\"%s\")",
1654                                  "net.inet.ip.dummynet.hz");
1655                 }
1656
1657                 /*
1658                  * Ticks needed for sending a medium-sized packet.
1659                  * Unfortunately, when we are configuring a WF2Q+ queue, we
1660                  * do not have bandwidth information, because that is stored
1661                  * in the parent pipe, and also we have multiple queues
1662                  * competing for it. So we set s=0, which is not very
1663                  * correct. But on the other hand, why do we want RED with
1664                  * WF2Q+ ?
1665                  */
1666                 if (pipe.bandwidth == 0) /* this is a WF2Q+ queue */
1667                         s = 0;
1668                 else
1669                         s = clock_hz * avg_pkt_size * 8 / pipe.bandwidth;
1670
1671                 /*
1672                  * max idle time (in ticks) before avg queue size becomes 0.
1673                  * NOTA: (3/w_q) is approx the value x so that
1674                  * (1-w_q)^x < 10^-3.
1675                  */
1676                 w_q = ((double)pipe.fs.w_q) / (1 << SCALE_RED);
1677                 idle = s * 3. / w_q;
1678                 pipe.fs.lookup_step = (int)idle / lookup_depth;
1679                 if (!pipe.fs.lookup_step)
1680                         pipe.fs.lookup_step = 1;
1681                 weight = 1 - w_q;
1682                 for (t = pipe.fs.lookup_step; t > 0; --t)
1683                         weight *= weight;
1684                 pipe.fs.lookup_weight = (int)(weight * (1 << SCALE_RED));
1685         }
1686         i = do_set_x(IP_DUMMYNET_CONFIGURE, &pipe, sizeof pipe);
1687         if (i)
1688                 err(1, "do_set_x(%s)", "IP_DUMMYNET_CONFIGURE");
1689 }
1690
1691 /*
1692  * helper function, updates the pointer to cmd with the length
1693  * of the current command, and also cleans up the first word of
1694  * the new command in case it has been clobbered before.
1695  */
1696 static ipfw_insn*
1697 next_cmd(ipfw_insn *cmd)
1698 {
1699         cmd += F_LEN(cmd);
1700         bzero(cmd, sizeof(*cmd));
1701         return cmd;
1702 }
1703
1704 /*
1705  * Parse arguments and assemble the microinstructions which make up a rule.
1706  * Rules are added into the 'rulebuf' and then copied in the correct order
1707  * into the actual rule.
1708  *
1709  *
1710  */
1711 static void
1712 add(int ac, char *av[])
1713 {
1714         /*
1715          * rules are added into the 'rulebuf' and then copied in
1716          * the correct order into the actual rule.
1717          * Some things that need to go out of order (prob, action etc.)
1718          * go into actbuf[].
1719          */
1720         static uint32_t rulebuf[IPFW_RULE_SIZE_MAX];
1721         static uint32_t actbuf[IPFW_RULE_SIZE_MAX];
1722         static uint32_t othbuf[IPFW_RULE_SIZE_MAX];
1723         static uint32_t cmdbuf[IPFW_RULE_SIZE_MAX];
1724
1725         ipfw_insn *src, *dst, *cmd, *action, *other;
1726         ipfw_insn *the_comment = NULL;
1727         struct ipfw_ioc_rule *rule;
1728         struct ipfw_keyword *key;
1729         struct ipfw_mapping *map;
1730         parser_func fn;
1731         int i, j;
1732
1733         bzero(actbuf, sizeof(actbuf));          /* actions go here */
1734         bzero(othbuf, sizeof(actbuf));          /* others */
1735         bzero(cmdbuf, sizeof(cmdbuf));          /* filters */
1736         bzero(rulebuf, sizeof(rulebuf));
1737
1738         rule = (struct ipfw_ioc_rule *)rulebuf;
1739         cmd = (ipfw_insn *)cmdbuf;
1740         action = (ipfw_insn *)actbuf;
1741         other = (ipfw_insn *)othbuf;
1742
1743         NEED2("need more parameters");
1744         NEXT_ARG;
1745
1746         /* [rule N]     -- Rule number optional */
1747         if (ac && isdigit(**av)) {
1748                 rule->rulenum = atoi(*av);
1749                 NEXT_ARG;
1750         }
1751
1752         /* [set N]      -- set number (0..30), optional */
1753         if (ac > 1 && !strncmp(*av, "set", strlen(*av))) {
1754                 int set = strtoul(av[1], NULL, 10);
1755                 if (set < 0 || set > 30)
1756                         errx(EX_DATAERR, "illegal set %s", av[1]);
1757                 rule->set = set;
1758                 av += 2; ac -= 2;
1759         }
1760
1761         /*
1762          * parse others
1763          */
1764         for (;;) {
1765                 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
1766                         if (key->type == IPFW_KEYWORD_TYPE_OTHERS &&
1767                                 strcmp(key->word, *av) == 0) {
1768                                 for (j = 0, map = mappings;
1769                                         j < MAPPING_SIZE; j++, map++) {
1770                                         if (map->type == IPFW_MAPPING_TYPE_IN_USE &&
1771                                                 map->module == key->module &&
1772                                                 map->opcode == key->opcode ) {
1773                                                 fn = map->parser;
1774                                                 (*fn)(&other, &ac, &av);
1775                                                 break;
1776                                         }
1777                                 }
1778                                 break;
1779                         }
1780                 }
1781                 if (i >= KEYWORD_SIZE) {
1782                         break;
1783                 } else if (F_LEN(other) > 0) {
1784                         if (other->module == MODULE_BASIC_ID &&
1785                                 other->opcode == O_BASIC_CHECK_STATE) {
1786                                 other = next_cmd(other);
1787                                 goto done;
1788                         }
1789                         other = next_cmd(other);
1790                 }
1791         }
1792
1793         /*
1794          * parse actions
1795          *
1796          * only accept 1 action
1797          */
1798         NEED1("missing action");
1799         for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
1800                 if (ac > 0 && key->type == IPFW_KEYWORD_TYPE_ACTION &&
1801                         strcmp(key->word, *av) == 0) {
1802                         for (j = 0, map = mappings; j<MAPPING_SIZE; j++, map++) {
1803                                 if (map->type == IPFW_MAPPING_TYPE_IN_USE &&
1804                                         map->module == key->module &&
1805                                         map->opcode == key->opcode) {
1806                                         fn = map->parser;
1807                                         (*fn)(&action, &ac, &av);
1808                                         break;
1809                                 }
1810                         }
1811                         break;
1812                 }
1813         }
1814         if (F_LEN(action) > 0)
1815                 action = next_cmd(action);
1816
1817         /*
1818          * parse protocol
1819          */
1820         if (strcmp(*av, "proto") == 0){
1821                 NEXT_ARG;
1822         }
1823
1824         NEED1("missing protocol");
1825         for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
1826                 if (key->type == IPFW_KEYWORD_TYPE_FILTER &&
1827                         strcmp(key->word, "proto") == 0) {
1828                         for (j = 0, map = mappings; j<MAPPING_SIZE; j++, map++) {
1829                                 if (map->type == IPFW_MAPPING_TYPE_IN_USE &&
1830                                         map->module == key->module &&
1831                                         map->opcode == key->opcode ) {
1832                                         fn = map->parser;
1833                                         (*fn)(&cmd, &ac, &av);
1834                                         break;
1835                                 }
1836                         }
1837                         break;
1838                 }
1839         }
1840         if (F_LEN(cmd) > 0)
1841                 cmd = next_cmd(cmd);
1842
1843         /*
1844          * other filters
1845          */
1846         while (ac > 0) {
1847                 char *s;
1848                 ipfw_insn_u32 *cmd32;   /* alias for cmd */
1849
1850                 s = *av;
1851                 cmd32 = (ipfw_insn_u32 *)cmd;
1852                 if (strcmp(*av, "not") == 0) {
1853                         if (cmd->len & F_NOT)
1854                                 errx(EX_USAGE, "double \"not\" not allowed\n");
1855                         cmd->len = F_NOT;
1856                         NEXT_ARG;
1857                         continue;
1858                 }
1859                 if (*s == '!') {        /* alternate syntax for NOT */
1860                         if (cmd->len & F_NOT)
1861                                 errx(EX_USAGE, "double \"not\" not allowed");
1862                         cmd->len = F_NOT;
1863                         s++;
1864                 }
1865                 for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
1866                         if (key->type == IPFW_KEYWORD_TYPE_FILTER &&
1867                                 strcmp(key->word, s) == 0) {
1868                                 for (j = 0, map = mappings;
1869                                         j< MAPPING_SIZE; j++, map++) {
1870                                         if (map->type == IPFW_MAPPING_TYPE_IN_USE &&
1871                                                 map->module == key->module &&
1872                                                 map->opcode == key->opcode ) {
1873                                                 fn = map->parser;
1874                                                 (*fn)(&cmd, &ac, &av);
1875                                                 break;
1876                                         }
1877                                 }
1878                                 break;
1879                         } else if (i == KEYWORD_SIZE-1) {
1880                                 errx(EX_USAGE, "bad command `%s'", s);
1881                         }
1882                 }
1883                 if (i >= KEYWORD_SIZE) {
1884                         break;
1885                 } else if (F_LEN(cmd) > 0) {
1886                         cmd = next_cmd(cmd);
1887                 }
1888         }
1889
1890 done:
1891         if (ac>0)
1892                 errx(EX_USAGE, "bad command `%s'", *av);
1893
1894         /*
1895          * Now copy stuff into the rule.
1896          * [filters][others][action][comment]
1897          */
1898         dst = (ipfw_insn *)rule->cmd;
1899         /*
1900          * copy all filters, except comment
1901          */
1902         src = (ipfw_insn *)cmdbuf;
1903         for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) {
1904                 /* pick comment out */
1905                 i = F_LEN(src);
1906                 if (src->module == MODULE_BASIC_ID && src->opcode == O_BASIC_COMMENT) {
1907                         the_comment=src;
1908                 } else {
1909                         bcopy(src, dst, i * sizeof(u_int32_t));
1910                         dst = (ipfw_insn *)((uint32_t *)dst + i);
1911                 }
1912         }
1913
1914         /*
1915          * start action section, it begin with others
1916          */
1917         rule->act_ofs = (uint32_t *)dst - (uint32_t *)(rule->cmd);
1918
1919         /*
1920          * copy all other others
1921          */
1922         for (src = (ipfw_insn *)othbuf; src != other; src += i) {
1923                 i = F_LEN(src);
1924                 bcopy(src, dst, i * sizeof(u_int32_t));
1925                 dst = (ipfw_insn *)((uint32_t *)dst + i);
1926         }
1927
1928         /* copy the action to the end of rule */
1929         src = (ipfw_insn *)actbuf;
1930         i = F_LEN(src);
1931         bcopy(src, dst, i * sizeof(u_int32_t));
1932         dst = (ipfw_insn *)((uint32_t *)dst + i);
1933
1934         /*
1935          * comment place behind the action
1936          */
1937         if (the_comment != NULL) {
1938                 i = F_LEN(the_comment);
1939                 bcopy(the_comment, dst, i * sizeof(u_int32_t));
1940                 dst = (ipfw_insn *)((uint32_t *)dst + i);
1941         }
1942
1943         rule->cmd_len = (u_int32_t *)dst - (u_int32_t *)(rule->cmd);
1944         i = (void *)dst - (void *)rule;
1945         if (do_set_x(IP_FW_ADD, (void *)rule, i) == -1) {
1946                 err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD");
1947         }
1948         if (!do_quiet)
1949                 show_rules(rule, 10, 10);
1950 }
1951
1952 static void
1953 zero(int ac, char *av[])
1954 {
1955         int rulenum;
1956         int failed = EX_OK;
1957
1958         NEXT_ARG;
1959
1960         if (!ac) {
1961                 /* clear all entries */
1962                 if (do_set_x(IP_FW_ZERO, NULL, 0) < 0)
1963                         err(EX_UNAVAILABLE, "do_set_x(IP_FW_ZERO)");
1964                 if (!do_quiet)
1965                         printf("Accounting cleared.\n");
1966                 return;
1967         }
1968
1969         while (ac) {
1970                 /* Rule number */
1971                 if (isdigit(**av)) {
1972                         rulenum = atoi(*av);
1973                         NEXT_ARG;
1974                         if (do_set_x(IP_FW_ZERO, &rulenum, sizeof rulenum)) {
1975                                 warn("rule %u: do_set_x(IP_FW_ZERO)", rulenum);
1976                                 failed = EX_UNAVAILABLE;
1977                         } else if (!do_quiet)
1978                                 printf("Entry %d cleared\n", rulenum);
1979                 } else {
1980                         errx(EX_USAGE, "invalid rule number ``%s''", *av);
1981                 }
1982         }
1983         if (failed != EX_OK)
1984                 exit(failed);
1985 }
1986
1987 static void
1988 resetlog(int ac, char *av[])
1989 {
1990         int rulenum;
1991         int failed = EX_OK;
1992
1993         NEXT_ARG;
1994
1995         if (!ac) {
1996                 /* clear all entries */
1997                 if (setsockopt(ipfw_socket, IPPROTO_IP, IP_FW_RESETLOG, NULL, 0) < 0)
1998                         err(EX_UNAVAILABLE, "setsockopt(IP_FW_RESETLOG)");
1999                 if (!do_quiet)
2000                         printf("Logging counts reset.\n");
2001
2002                 return;
2003         }
2004
2005         while (ac) {
2006                 /* Rule number */
2007                 if (isdigit(**av)) {
2008                         rulenum = atoi(*av);
2009                         NEXT_ARG;
2010                         if (setsockopt(ipfw_socket, IPPROTO_IP,
2011                                 IP_FW_RESETLOG, &rulenum, sizeof rulenum)) {
2012                                 warn("rule %u: setsockopt(IP_FW_RESETLOG)", rulenum);
2013                                 failed = EX_UNAVAILABLE;
2014                         } else if (!do_quiet)
2015                                 printf("Entry %d logging count reset\n", rulenum);
2016                 } else {
2017                         errx(EX_DATAERR, "invalid rule number ``%s''", *av);
2018                 }
2019         }
2020         if (failed != EX_OK)
2021                 exit(failed);
2022 }
2023
2024 static void
2025 flush(void)
2026 {
2027         int cmd = IP_FW_FLUSH;
2028         if (do_pipe) {
2029                 cmd = IP_DUMMYNET_FLUSH;
2030         } else if (do_nat) {
2031                 cmd = IP_FW_NAT_FLUSH;
2032         }
2033         if (!do_force) {
2034                 int c;
2035
2036                 printf("Are you sure? [yn] ");
2037                 fflush(stdout);
2038                 do {
2039                         c = toupper(getc(stdin));
2040                         while (c != '\n' && getc(stdin) != '\n')
2041                                 if (feof(stdin))
2042                                         return; /* and do not flush */
2043                 } while (c != 'Y' && c != 'N');
2044                 if (c == 'N')   /* user said no */
2045                         return;
2046         }
2047         if (do_set_x(cmd, NULL, 0) < 0 ) {
2048                 err(EX_UNAVAILABLE, "do_set_x(%s)",
2049                         do_pipe? "IP_DUMMYNET_FLUSH":
2050                         (do_nat? "IP_FW_NAT_FLUSH": "IP_FW_FLUSH"));
2051         }
2052         if (!do_quiet) {
2053                 printf("Flushed all %s.\n", do_pipe ? "pipes":
2054                                 (do_nat?"nat configurations":"rules"));
2055         }
2056 }
2057
2058 static void
2059 str2addr(const char* str, struct in_addr* addr)
2060 {
2061         struct hostent* hp;
2062
2063         if (inet_aton (str, addr))
2064                 return;
2065
2066         hp = gethostbyname (str);
2067         if (!hp)
2068                 errx (1, "unknown host %s", str);
2069
2070         memcpy (addr, hp->h_addr, sizeof (struct in_addr));
2071 }
2072
2073 static int
2074 str2portrange(const char* str, const char* proto, port_range *portRange)
2075 {
2076         struct servent* sp;
2077         char*   sep;
2078         char*   end;
2079         u_short loPort, hiPort;
2080
2081         /* First see if this is a service, return corresponding port if so. */
2082         sp = getservbyname (str, proto);
2083         if (sp) {
2084                 SETLOPORT(*portRange, ntohs(sp->s_port));
2085                 SETNUMPORTS(*portRange, 1);
2086                 return 0;
2087         }
2088
2089         /* Not a service, see if it's a single port or port range. */
2090         sep = strchr (str, '-');
2091         if (sep == NULL) {
2092                 SETLOPORT(*portRange, strtol(str, &end, 10));
2093                 if (end != str) {
2094                         /* Single port. */
2095                         SETNUMPORTS(*portRange, 1);
2096                         return 0;
2097                 }
2098
2099                 /* Error in port range field. */
2100                 errx (EX_DATAERR, "%s/%s: unknown service", str, proto);
2101         }
2102
2103         /* Port range, get the values and sanity check. */
2104         sscanf (str, "%hu-%hu", &loPort, &hiPort);
2105         SETLOPORT(*portRange, loPort);
2106         SETNUMPORTS(*portRange, 0);     /* Error by default */
2107         if (loPort <= hiPort)
2108                 SETNUMPORTS(*portRange, hiPort - loPort + 1);
2109
2110         if (GETNUMPORTS(*portRange) == 0)
2111                 errx (EX_DATAERR, "invalid port range %s", str);
2112
2113         return 0;
2114 }
2115
2116 static int
2117 str2proto(const char* str)
2118 {
2119         if (!strcmp (str, "tcp"))
2120                 return IPPROTO_TCP;
2121         if (!strcmp (str, "udp"))
2122                 return IPPROTO_UDP;
2123         errx (EX_DATAERR, "unknown protocol %s. Expected tcp or udp", str);
2124 }
2125
2126 static int
2127 str2addr_portrange (const char* str, struct in_addr* addr,
2128         char* proto, port_range *portRange)
2129 {
2130         char*   ptr;
2131
2132         ptr = strchr (str, ':');
2133         if (!ptr)
2134                 errx (EX_DATAERR, "%s is missing port number", str);
2135
2136         *ptr = '\0';
2137         ++ptr;
2138
2139         str2addr (str, addr);
2140         return str2portrange (ptr, proto, portRange);
2141 }
2142
2143 /*
2144  * Search for interface with name "ifn", and fill n accordingly:
2145  *
2146  * n->ip                ip address of interface "ifn"
2147  * n->if_name copy of interface name "ifn"
2148  */
2149 static void
2150 set_addr_dynamic(const char *ifn, struct cfg_nat *n)
2151 {
2152         struct if_msghdr *ifm;
2153         struct ifa_msghdr *ifam;
2154         struct sockaddr_dl *sdl;
2155         struct sockaddr_in *sin;
2156         char *buf, *lim, *next;
2157         size_t needed;
2158         int mib[6];
2159         int ifIndex, ifMTU;
2160
2161         mib[0] = CTL_NET;
2162         mib[1] = PF_ROUTE;
2163         mib[2] = 0;
2164         mib[3] = AF_INET;
2165         mib[4] = NET_RT_IFLIST;
2166         mib[5] = 0;
2167
2168         /*
2169          * Get interface data.
2170          */
2171         if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
2172                 err(1, "iflist-sysctl-estimate");
2173         if ((buf = malloc(needed)) == NULL)
2174                 errx(1, "malloc failed");
2175         if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
2176                 err(1, "iflist-sysctl-get");
2177         lim = buf + needed;
2178         /*
2179          * Loop through interfaces until one with
2180          * given name is found. This is done to
2181          * find correct interface index for routing
2182          * message processing.
2183          */
2184         ifIndex = 0;
2185         next = buf;
2186         while (next < lim) {
2187                 ifm = (struct if_msghdr *)next;
2188                 next += ifm->ifm_msglen;
2189                 if (ifm->ifm_version != RTM_VERSION) {
2190                         if (verbose)
2191                                 warnx("routing message version %d "
2192                                         "not understood", ifm->ifm_version);
2193                         continue;
2194                 }
2195                 if (ifm->ifm_type == RTM_IFINFO) {
2196                         sdl = (struct sockaddr_dl *)(ifm + 1);
2197                         if (strlen(ifn) == sdl->sdl_nlen &&
2198                                 strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
2199                                 ifIndex = ifm->ifm_index;
2200                                 ifMTU = ifm->ifm_data.ifi_mtu;
2201                                 break;
2202                         }
2203                 }
2204         }
2205         if (!ifIndex)
2206                 errx(1, "unknown interface name %s", ifn);
2207         /*
2208          * Get interface address.
2209          */
2210         sin = NULL;
2211         while (next < lim) {
2212                 ifam = (struct ifa_msghdr *)next;
2213                 next += ifam->ifam_msglen;
2214                 if (ifam->ifam_version != RTM_VERSION) {
2215                         if (verbose)
2216                                 warnx("routing message version %d "
2217                                         "not understood", ifam->ifam_version);
2218                         continue;
2219                 }
2220                 if (ifam->ifam_type != RTM_NEWADDR)
2221                         break;
2222                 if (ifam->ifam_addrs & RTA_IFA) {
2223                         int i;
2224                         char *cp = (char *)(ifam + 1);
2225
2226                         for (i = 1; i < RTA_IFA; i <<= 1) {
2227                                 if (ifam->ifam_addrs & i)
2228                                         cp += SA_SIZE((struct sockaddr *)cp);
2229                         }
2230                         if (((struct sockaddr *)cp)->sa_family == AF_INET) {
2231                                 sin = (struct sockaddr_in *)cp;
2232                                 break;
2233                         }
2234                 }
2235         }
2236         if (sin == NULL)
2237                 errx(1, "%s: cannot get interface address", ifn);
2238
2239         n->ip = sin->sin_addr;
2240         strncpy(n->if_name, ifn, IF_NAMESIZE);
2241
2242         free(buf);
2243 }
2244
2245 static int
2246 setup_redir_addr(char *spool_buf, int len, int *_ac, char ***_av)
2247 {
2248         struct cfg_redir *r;
2249         struct cfg_spool *tmp;
2250         char **av, *sep;
2251         char tmp_spool_buf[NAT_BUF_LEN];
2252         int ac, i, space, lsnat;
2253
2254         i=0;
2255         av = *_av;
2256         ac = *_ac;
2257         space = 0;
2258         lsnat = 0;
2259         if (len >= SOF_REDIR) {
2260                 r = (struct cfg_redir *)spool_buf;
2261                 /* Skip cfg_redir at beginning of buf. */
2262                 spool_buf = &spool_buf[SOF_REDIR];
2263                 space = SOF_REDIR;
2264                 len -= SOF_REDIR;
2265         } else {
2266                 goto nospace;
2267         }
2268
2269         r->mode = REDIR_ADDR;
2270         /* Extract local address. */
2271         if (ac == 0)
2272                 errx(EX_DATAERR, "redirect_addr: missing local address");
2273
2274         sep = strchr(*av, ',');
2275         if (sep) {              /* LSNAT redirection syntax. */
2276                 r->laddr.s_addr = INADDR_NONE;
2277                 /* Preserve av, copy spool servers to tmp_spool_buf. */
2278                 strncpy(tmp_spool_buf, *av, strlen(*av)+1);
2279                 lsnat = 1;
2280         } else {
2281                 str2addr(*av, &r->laddr);
2282         }
2283         INC_ARGCV();
2284
2285         /* Extract public address. */
2286         if (ac == 0)
2287                 errx(EX_DATAERR, "redirect_addr: missing public address");
2288
2289         str2addr(*av, &r->paddr);
2290         INC_ARGCV();
2291
2292         /* Setup LSNAT server pool. */
2293         if (sep) {
2294                 sep = strtok(tmp_spool_buf, ", ");
2295                 while (sep != NULL) {
2296                         tmp = (struct cfg_spool *)spool_buf;
2297                         if (len < SOF_SPOOL)
2298                                 goto nospace;
2299
2300                         len -= SOF_SPOOL;
2301                         space += SOF_SPOOL;
2302                         str2addr(sep, &tmp->addr);
2303                         tmp->port = ~0;
2304                         r->spool_cnt++;
2305                         /* Point to the next possible cfg_spool. */
2306                         spool_buf = &spool_buf[SOF_SPOOL];
2307                         sep = strtok(NULL, ", ");
2308                 }
2309         }
2310         return(space);
2311
2312 nospace:
2313         errx(EX_DATAERR, "redirect_addr: buf is too small\n");
2314 }
2315
2316 static int
2317 setup_redir_port(char *spool_buf, int len, int *_ac, char ***_av)
2318 {
2319         char **av, *sep, *protoName;
2320         char tmp_spool_buf[NAT_BUF_LEN];
2321         int ac, space, lsnat;
2322         struct cfg_redir *r;
2323         struct cfg_spool *tmp;
2324         u_short numLocalPorts;
2325         port_range portRange;
2326
2327         av = *_av;
2328         ac = *_ac;
2329         space = 0;
2330         lsnat = 0;
2331         numLocalPorts = 0;
2332
2333         if (len >= SOF_REDIR) {
2334                 r = (struct cfg_redir *)spool_buf;
2335                 /* Skip cfg_redir at beginning of buf. */
2336                 spool_buf = &spool_buf[SOF_REDIR];
2337                 space = SOF_REDIR;
2338                 len -= SOF_REDIR;
2339         } else {
2340                 goto nospace;
2341         }
2342
2343         r->mode = REDIR_PORT;
2344         /*
2345          * Extract protocol.
2346          */
2347         if (ac == 0)
2348                 errx (EX_DATAERR, "redirect_port: missing protocol");
2349
2350         r->proto = str2proto(*av);
2351         protoName = *av;
2352         INC_ARGCV();
2353
2354         /*
2355          * Extract local address.
2356          */
2357         if (ac == 0)
2358                 errx (EX_DATAERR, "redirect_port: missing local address");
2359
2360         sep = strchr(*av, ',');
2361         /* LSNAT redirection syntax. */
2362         if (sep) {
2363                 r->laddr.s_addr = INADDR_NONE;
2364                 r->lport = ~0;
2365                 numLocalPorts = 1;
2366                 /* Preserve av, copy spool servers to tmp_spool_buf. */
2367                 strncpy(tmp_spool_buf, *av, strlen(*av)+1);
2368                 lsnat = 1;
2369         } else {
2370                 if (str2addr_portrange (*av, &r->laddr, protoName, &portRange) != 0)
2371                         errx(EX_DATAERR, "redirect_port:"
2372                                 "invalid local port range");
2373
2374                 r->lport = GETLOPORT(portRange);
2375                 numLocalPorts = GETNUMPORTS(portRange);
2376         }
2377         INC_ARGCV();
2378
2379         /*
2380          * Extract public port and optionally address.
2381          */
2382         if (ac == 0)
2383                 errx (EX_DATAERR, "redirect_port: missing public port");
2384
2385         sep = strchr (*av, ':');
2386         if (sep) {
2387                 if (str2addr_portrange (*av, &r->paddr, protoName, &portRange) != 0)
2388                         errx(EX_DATAERR, "redirect_port:"
2389                                 "invalid public port range");
2390         } else {
2391                 r->paddr.s_addr = INADDR_ANY;
2392                 if (str2portrange(*av, protoName, &portRange) != 0)
2393                         errx(EX_DATAERR, "redirect_port:"
2394                                 "invalid public port range");
2395         }
2396
2397         r->pport = GETLOPORT(portRange);
2398         r->pport_cnt = GETNUMPORTS(portRange);
2399         INC_ARGCV();
2400
2401         /*
2402          * Extract remote address and optionally port.
2403          */
2404         /*
2405          * NB: isalpha(**av) => we've to check that next parameter is really an
2406          * option for this redirect entry, else stop here processing arg[cv].
2407          */
2408         if (ac != 0 && !isalpha(**av)) {
2409                 sep = strchr (*av, ':');
2410                 if (sep) {
2411                         if (str2addr_portrange (*av, &r->raddr,
2412                                 protoName, &portRange) != 0)
2413                                 errx(EX_DATAERR, "redirect_port:"
2414                                         "invalid remote port range");
2415                 } else {
2416                         SETLOPORT(portRange, 0);
2417                         SETNUMPORTS(portRange, 1);
2418                         str2addr (*av, &r->raddr);
2419                 }
2420                 INC_ARGCV();
2421         } else {
2422                 SETLOPORT(portRange, 0);
2423                 SETNUMPORTS(portRange, 1);
2424                 r->raddr.s_addr = INADDR_ANY;
2425         }
2426         r->rport = GETLOPORT(portRange);
2427         r->rport_cnt = GETNUMPORTS(portRange);
2428
2429         /*
2430          * Make sure port ranges match up, then add the redirect ports.
2431          */
2432         if (numLocalPorts != r->pport_cnt)
2433                 errx(EX_DATAERR, "redirect_port:"
2434                         "port ranges must be equal in size");
2435
2436         /* Remote port range is allowed to be '0' which means all ports. */
2437         if (r->rport_cnt != numLocalPorts &&
2438                 (r->rport_cnt != 1 || r->rport != 0))
2439                         errx(EX_DATAERR, "redirect_port: remote port must"
2440                                 "be 0 or equal to local port range in size");
2441
2442         /*
2443          * Setup LSNAT server pool.
2444          */
2445         if (lsnat) {
2446                 sep = strtok(tmp_spool_buf, ", ");
2447                 while (sep != NULL) {
2448                         tmp = (struct cfg_spool *)spool_buf;
2449                         if (len < SOF_SPOOL)
2450                                 goto nospace;
2451
2452                         len -= SOF_SPOOL;
2453                         space += SOF_SPOOL;
2454                         if (str2addr_portrange(sep,
2455                                 &tmp->addr, protoName, &portRange) != 0)
2456                                 errx(EX_DATAERR, "redirect_port:"
2457                                         "invalid local port range");
2458                         if (GETNUMPORTS(portRange) != 1)
2459                                 errx(EX_DATAERR, "redirect_port: local port"
2460                                         "must be single in this context");
2461                         tmp->port = GETLOPORT(portRange);
2462                         r->spool_cnt++;
2463                         /* Point to the next possible cfg_spool. */
2464                         spool_buf = &spool_buf[SOF_SPOOL];
2465                         sep = strtok(NULL, ", ");
2466                 }
2467         }
2468         return (space);
2469
2470 nospace:
2471         errx(EX_DATAERR, "redirect_port: buf is too small\n");
2472 }
2473
2474 static int
2475 setup_redir_proto(char *spool_buf, int len, int *_ac, char ***_av)
2476 {
2477         struct protoent *protoent;
2478         struct cfg_redir *r;
2479         int ac, i, space;
2480         char **av;
2481
2482         i=0;
2483         av = *_av;
2484         ac = *_ac;
2485         if (len >= SOF_REDIR) {
2486                 r = (struct cfg_redir *)spool_buf;
2487                 /* Skip cfg_redir at beginning of buf. */
2488                 spool_buf = &spool_buf[SOF_REDIR];
2489                 space = SOF_REDIR;
2490                 len -= SOF_REDIR;
2491         } else {
2492                 goto nospace;
2493         }
2494         r->mode = REDIR_PROTO;
2495         /*
2496          * Extract protocol.
2497          */
2498         if (ac == 0)
2499                 errx(EX_DATAERR, "redirect_proto: missing protocol");
2500
2501         protoent = getprotobyname(*av);
2502         if (protoent == NULL)
2503                 errx(EX_DATAERR, "redirect_proto: unknown protocol %s", *av);
2504         else
2505                 r->proto = protoent->p_proto;
2506
2507         INC_ARGCV();
2508
2509         /*
2510          * Extract local address.
2511          */
2512         if (ac == 0)
2513                 errx(EX_DATAERR, "redirect_proto: missing local address");
2514         else
2515                 str2addr(*av, &r->laddr);
2516         INC_ARGCV();
2517
2518         /*
2519          * Extract optional public address.
2520          */
2521         if (ac == 0) {
2522                 r->paddr.s_addr = INADDR_ANY;
2523                 r->raddr.s_addr = INADDR_ANY;
2524         } else {
2525                 /* see above in setup_redir_port() */
2526                 if (!isalpha(**av)) {
2527                         str2addr(*av, &r->paddr);
2528                         INC_ARGCV();
2529
2530                         /*
2531                          * Extract optional remote address.
2532                          */
2533                         /* see above in setup_redir_port() */
2534                         if (ac != 0 && !isalpha(**av)) {
2535                                 str2addr(*av, &r->raddr);
2536                                 INC_ARGCV();
2537                         }
2538                 }
2539         }
2540         return (space);
2541
2542 nospace:
2543         errx(EX_DATAERR, "redirect_proto: buf is too small\n");
2544 }
2545
2546 static void
2547 show_nat_config(char *buf) {
2548         struct cfg_nat *n;
2549         struct cfg_redir *t;
2550         struct cfg_spool *s;
2551         struct protoent *p;
2552         int i, cnt, flag, off;
2553
2554         n = (struct cfg_nat *)buf;
2555         flag = 1;
2556         off = sizeof(*n);
2557         printf("ipfw nat %u config", n->id);
2558         if (strlen(n->if_name) != 0)
2559                 printf(" if %s", n->if_name);
2560         else if (n->ip.s_addr != 0)
2561                 printf(" ip %s", inet_ntoa(n->ip));
2562         while (n->mode != 0) {
2563                 if (n->mode & PKT_ALIAS_LOG) {
2564                         printf(" log");
2565                         n->mode &= ~PKT_ALIAS_LOG;
2566                 } else if (n->mode & PKT_ALIAS_DENY_INCOMING) {
2567                         printf(" deny_in");
2568                         n->mode &= ~PKT_ALIAS_DENY_INCOMING;
2569                 } else if (n->mode & PKT_ALIAS_SAME_PORTS) {
2570                         printf(" same_ports");
2571                         n->mode &= ~PKT_ALIAS_SAME_PORTS;
2572                 } else if (n->mode & PKT_ALIAS_UNREGISTERED_ONLY) {
2573                         printf(" unreg_only");
2574                         n->mode &= ~PKT_ALIAS_UNREGISTERED_ONLY;
2575                 } else if (n->mode & PKT_ALIAS_RESET_ON_ADDR_CHANGE) {
2576                         printf(" reset");
2577                         n->mode &= ~PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2578                 } else if (n->mode & PKT_ALIAS_REVERSE) {
2579                         printf(" reverse");
2580                         n->mode &= ~PKT_ALIAS_REVERSE;
2581                 } else if (n->mode & PKT_ALIAS_PROXY_ONLY) {
2582                         printf(" proxy_only");
2583                         n->mode &= ~PKT_ALIAS_PROXY_ONLY;
2584                 }
2585         }
2586         /* Print all the redirect's data configuration. */
2587         for (cnt = 0; cnt < n->redir_cnt; cnt++) {
2588                 t = (struct cfg_redir *)&buf[off];
2589                 off += SOF_REDIR;
2590                 switch (t->mode) {
2591                 case REDIR_ADDR:
2592                         printf(" redirect_addr");
2593                         if (t->spool_cnt == 0)
2594                                 printf(" %s", inet_ntoa(t->laddr));
2595                         else
2596                                 for (i = 0; i < t->spool_cnt; i++) {
2597                                         s = (struct cfg_spool *)&buf[off];
2598                                         if (i)
2599                                                 printf(", ");
2600                                         else
2601                                                 printf(" ");
2602                                         printf("%s", inet_ntoa(s->addr));
2603                                         off += SOF_SPOOL;
2604                                 }
2605                         printf(" %s", inet_ntoa(t->paddr));
2606                         break;
2607                 case REDIR_PORT:
2608                         p = getprotobynumber(t->proto);
2609                         printf(" redirect_port %s ", p->p_name);
2610                         if (!t->spool_cnt) {
2611                                 printf("%s:%u", inet_ntoa(t->laddr), t->lport);
2612                                 if (t->pport_cnt > 1)
2613                                         printf("-%u", t->lport + t->pport_cnt - 1);
2614                         } else
2615                                 for (i=0; i < t->spool_cnt; i++) {
2616                                         s = (struct cfg_spool *)&buf[off];
2617                                         if (i)
2618                                                 printf(", ");
2619                                         printf("%s:%u", inet_ntoa(s->addr), s->port);
2620                                         off += SOF_SPOOL;
2621                                 }
2622
2623                         printf(" ");
2624                         if (t->paddr.s_addr)
2625                                 printf("%s:", inet_ntoa(t->paddr));
2626                         printf("%u", t->pport);
2627                         if (!t->spool_cnt && t->pport_cnt > 1)
2628                                 printf("-%u", t->pport + t->pport_cnt - 1);
2629
2630                         if (t->raddr.s_addr) {
2631                                 printf(" %s", inet_ntoa(t->raddr));
2632                                 if (t->rport) {
2633                                         printf(":%u", t->rport);
2634                                         if (!t->spool_cnt && t->rport_cnt > 1)
2635                                                 printf("-%u", t->rport +
2636                                                         t->rport_cnt - 1);
2637                                 }
2638                         }
2639                         break;
2640                 case REDIR_PROTO:
2641                         p = getprotobynumber(t->proto);
2642                         printf(" redirect_proto %s %s", p->p_name,
2643                                 inet_ntoa(t->laddr));
2644                         if (t->paddr.s_addr != 0) {
2645                                 printf(" %s", inet_ntoa(t->paddr));
2646                                 if (t->raddr.s_addr)
2647                                         printf(" %s", inet_ntoa(t->raddr));
2648                         }
2649                         break;
2650                 default:
2651                         errx(EX_DATAERR, "unknown redir mode");
2652                         break;
2653                 }
2654         }
2655         printf("\n");
2656 }
2657
2658
2659 static void
2660 show_nat(int ac, char **av) {
2661         struct cfg_nat *n;
2662         struct cfg_redir *e;
2663         int i, nbytes, nalloc, size;
2664         int nat_cnt, redir_cnt, nat_id;
2665         uint8_t *data;
2666
2667         nalloc = 1024;
2668         size = 0;
2669         data = NULL;
2670
2671         NEXT_ARG;
2672
2673         if (ac == 0)
2674                 nat_id = 0;
2675         else
2676                 nat_id = strtoul(*av, NULL, 10);
2677
2678         nbytes = nalloc;
2679         while (nbytes >= nalloc) {
2680                 nalloc = nalloc * 2;
2681                 nbytes = nalloc;
2682                 if ((data = realloc(data, nbytes)) == NULL) {
2683                         err(EX_OSERR, "realloc");
2684                 }
2685                 if (do_get_x(IP_FW_NAT_GET, data, &nbytes) < 0) {
2686                         err(EX_OSERR, "do_get_x(IP_FW_NAT_GET)");
2687                 }
2688         }
2689
2690         if (nbytes == 0) {
2691                 exit(EX_OK);
2692         }
2693
2694         nat_cnt = *((int *)data);
2695         for (i = sizeof(nat_cnt); nat_cnt; nat_cnt--) {
2696                 n = (struct cfg_nat *)&data[i];
2697                 if (n->id >= 0 && n->id <= IPFW_DEFAULT_RULE) {
2698                         if (nat_id == 0 || n->id == nat_id)
2699                                 show_nat_config(&data[i]);
2700                 }
2701                 i += sizeof(struct cfg_nat);
2702                 for (redir_cnt = 0; redir_cnt < n->redir_cnt; redir_cnt++) {
2703                         e = (struct cfg_redir *)&data[i];
2704                         i += sizeof(struct cfg_redir) +
2705                                 e->spool_cnt * sizeof(struct cfg_spool);
2706                 }
2707         }
2708 }
2709
2710 /*
2711  * do_set_x - extended version og do_set
2712  * insert a x_header in the beginning of the rule buf
2713  * and call setsockopt() with IP_FW_X.
2714  */
2715 int
2716 do_set_x(int optname, void *rule, int optlen)
2717 {
2718         int len;
2719
2720         ip_fw_x_header *x_header;
2721         if (ipfw_socket < 0) {
2722                 err(EX_UNAVAILABLE, "socket");
2723         }
2724         bzero(new_rule_buf, IPFW_RULE_SIZE_MAX);
2725         x_header = (ip_fw_x_header *)new_rule_buf;
2726         x_header->opcode = optname;
2727         /* copy the rule into the newbuf, just after the x_header*/
2728         bcopy(rule, ++x_header, optlen);
2729         len = optlen + sizeof(ip_fw_x_header);
2730         return setsockopt(ipfw_socket, IPPROTO_IP, IP_FW_X, new_rule_buf, len);
2731 }
2732
2733 /*
2734  * same as do_set_x
2735  */
2736 int
2737 do_get_x(int optname, void *rule, int *optlen)
2738 {
2739         int len, retval;
2740
2741         ip_fw_x_header *x_header;
2742         if (ipfw_socket < 0) {
2743                 err(EX_UNAVAILABLE, "socket");
2744         }
2745         bzero(new_rule_buf, IPFW_RULE_SIZE_MAX);
2746         x_header = (ip_fw_x_header *)new_rule_buf;
2747         x_header->opcode = optname;
2748         /* copy the rule into the newbuf, just after the x_header*/
2749         bcopy(rule, ++x_header, *optlen);
2750         len = *optlen + sizeof(ip_fw_x_header);
2751         retval = getsockopt(ipfw_socket, IPPROTO_IP, IP_FW_X, new_rule_buf, &len);
2752         bcopy(new_rule_buf, rule, len);
2753         *optlen=len;
2754         return retval;
2755 }
2756
2757 static void
2758 config_nat(int ac, char **av)
2759 {
2760         struct cfg_nat *n;                       /* Nat instance configuration. */
2761         int i, len, off, tok;
2762         char *id, buf[NAT_BUF_LEN];     /* Buffer for serialized data. */
2763
2764         len = NAT_BUF_LEN;
2765         /* Offset in buf: save space for n at the beginning. */
2766         off = sizeof(struct cfg_nat);
2767         memset(buf, 0, sizeof(buf));
2768         n = (struct cfg_nat *)buf;
2769
2770         NEXT_ARG;
2771         /* Nat id. */
2772         if (ac && isdigit(**av)) {
2773                 id = *av;
2774                 i = atoi(*av);
2775                 NEXT_ARG;
2776                 n->id = i;
2777         } else
2778                 errx(EX_DATAERR, "missing nat id");
2779         if (ac == 0)
2780                 errx(EX_DATAERR, "missing option");
2781
2782         while (ac > 0) {
2783                 tok = match_token(nat_params, *av);
2784                 NEXT_ARG;
2785                 switch (tok) {
2786                 case TOK_IP:
2787                         if (ac == 0)
2788                                 errx(EX_DATAERR, "missing option");
2789                         if (!inet_aton(av[0], &(n->ip)))
2790                                 errx(EX_DATAERR, "bad ip address ``%s''",
2791                                         av[0]);
2792                         NEXT_ARG;
2793                         break;
2794                 case TOK_IF:
2795                         if (ac == 0)
2796                                 errx(EX_DATAERR, "missing option");
2797                         set_addr_dynamic(av[0], n);
2798                         NEXT_ARG;
2799                         break;
2800                 case TOK_ALOG:
2801                         n->mode |= PKT_ALIAS_LOG;
2802                         break;
2803                 case TOK_DENY_INC:
2804                         n->mode |= PKT_ALIAS_DENY_INCOMING;
2805                         break;
2806                 case TOK_SAME_PORTS:
2807                         n->mode |= PKT_ALIAS_SAME_PORTS;
2808                         break;
2809                 case TOK_UNREG_ONLY:
2810                         n->mode |= PKT_ALIAS_UNREGISTERED_ONLY;
2811                         break;
2812                 case TOK_RESET_ADDR:
2813                         n->mode |= PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2814                         break;
2815                 case TOK_ALIAS_REV:
2816                         n->mode |= PKT_ALIAS_REVERSE;
2817                         break;
2818                 case TOK_PROXY_ONLY:
2819                         n->mode |= PKT_ALIAS_PROXY_ONLY;
2820                         break;
2821                         /*
2822                          * All the setup_redir_* functions work directly in the final
2823                          * buffer, see above for details.
2824                          */
2825                 case TOK_REDIR_ADDR:
2826                 case TOK_REDIR_PORT:
2827                 case TOK_REDIR_PROTO:
2828                         switch (tok) {
2829                         case TOK_REDIR_ADDR:
2830                                 i = setup_redir_addr(&buf[off], len, &ac, &av);
2831                                 break;
2832                         case TOK_REDIR_PORT:
2833                                 i = setup_redir_port(&buf[off], len, &ac, &av);
2834                                 break;
2835                         case TOK_REDIR_PROTO:
2836                                 i = setup_redir_proto(&buf[off], len, &ac, &av);
2837                                 break;
2838                         }
2839                         n->redir_cnt++;
2840                         off += i;
2841                         len -= i;
2842                         break;
2843                 default:
2844                         errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]);
2845                 }
2846         }
2847         i = do_set_x(IP_FW_NAT_CFG, buf, off);
2848         if (i)
2849                 err(1, "do_set_x(%s)", "IP_FW_NAT_CFG");
2850
2851         /* After every modification, we show the resultant rule. */
2852         int _ac = 2;
2853         char *_av[] = {"config", id};
2854         show_nat(_ac, _av);
2855 }
2856
2857
2858 static int
2859 ipfw_main(int ac, char **av)
2860 {
2861         int ch;
2862
2863         if (ac == 1)
2864                 help();
2865
2866         /* Set the force flag for non-interactive processes */
2867         do_force = !isatty(STDIN_FILENO);
2868
2869         optind = optreset = 1;
2870         while ((ch = getopt(ac, av, "hs:acdDefNStTv")) != -1)
2871                 switch (ch) {
2872                 case 'h': /* help */
2873                         help();
2874                         break;  /* NOTREACHED */
2875
2876                 case 's': /* sort */
2877                         do_sort = atoi(optarg);
2878                         break;
2879                 case 'a':
2880                         do_acct = 1;
2881                         break;
2882                 case 'c':
2883                         do_compact = 1;
2884                         break;
2885                 case 'd':
2886                         do_dynamic = 1;
2887                         break;
2888                 case 'D':
2889                         do_dynamic = 2;
2890                         break;
2891                 case 'e':
2892                         do_expired = 1;
2893                         break;
2894                 case 'f':
2895                         do_force = 1;
2896                         break;
2897                 case 'N':
2898                         do_resolv = 1;
2899                         break;
2900                 case 'S':
2901                         show_sets = 1;
2902                         break;
2903                 case 't':
2904                         do_time = 1;
2905                         break;
2906                 case 'T':
2907                         do_time = 2;
2908                         break;
2909                 case 'v':
2910                         do_quiet = 0;
2911                         verbose++;
2912                         break;
2913                 default:
2914                         help();
2915                 }
2916
2917         ac -= optind;
2918         av += optind;
2919         NEED1("bad arguments, for usage summary ``ipfw''");
2920
2921         /*
2922          * optional: pipe or queue or nat
2923          */
2924         do_nat = 0;
2925         do_pipe = 0;
2926         if (!strncmp(*av, "nat", strlen(*av)))
2927                 do_nat = 1;
2928         else if (!strncmp(*av, "pipe", strlen(*av))) {
2929                 do_pipe = 1;
2930         } else if (!strncmp(*av, "queue", strlen(*av))) {
2931                 do_pipe = 2;
2932         }
2933         NEED1("missing command");
2934
2935         /*
2936          * for pipes and queues and nat we normally say 'pipe NN config'
2937          * but the code is easier to parse as 'pipe config NN'
2938          * so we swap the two arguments.
2939          */
2940         if ((do_pipe || do_nat) && ac > 2 && isdigit(*(av[1]))) {
2941                 char *p = av[1];
2942                 av[1] = av[2];
2943                 av[2] = p;
2944         }
2945
2946         if (!strncmp(*av, "add", strlen(*av))) {
2947                 load_modules();
2948                 add(ac, av);
2949         } else if (!strncmp(*av, "delete", strlen(*av))) {
2950                 delete_rules(ac, av);
2951         } else if (!strncmp(*av, "flush", strlen(*av))) {
2952                 flush();
2953         } else if (!strncmp(*av, "list", strlen(*av))) {
2954                 load_modules();
2955                 list(ac, av);
2956         } else if (!strncmp(*av, "show", strlen(*av))) {
2957                 do_acct++;
2958                 load_modules();
2959                 list(ac, av);
2960         } else if (!strncmp(*av, "zero", strlen(*av))) {
2961                 zero(ac, av);
2962         } else if (!strncmp(*av, "set", strlen(*av))) {
2963                 sets_handler(ac, av);
2964         } else if (!strncmp(*av, "module", strlen(*av))) {
2965                 NEXT_ARG;
2966                 if (!strncmp(*av, "show", strlen(*av)) ||
2967                         !strncmp(*av, "show", strlen(*av))) {
2968                         list_modules(ac, av);
2969                 } else {
2970                         errx(EX_USAGE, "bad ipfw module command `%s'", *av);
2971                 }
2972         } else if (!strncmp(*av, "resetlog", strlen(*av))) {
2973                 resetlog(ac, av);
2974         } else if (!strncmp(*av, "log", strlen(*av))) {
2975                 NEXT_ARG;
2976                 if (!strncmp(*av, "reset", strlen(*av))) {
2977                         resetlog(ac, av);
2978                 } else if (!strncmp(*av, "off", strlen(*av))) {
2979
2980                 } else if (!strncmp(*av, "on", strlen(*av))) {
2981
2982                 } else {
2983                         errx(EX_USAGE, "bad command `%s'", *av);
2984                 }
2985         } else if (!strncmp(*av, "nat", strlen(*av))) {
2986                 NEXT_ARG;
2987                 if (!strncmp(*av, "config", strlen(*av))) {
2988                         config_nat(ac, av);
2989                 } else if (!strncmp(*av, "flush", strlen(*av))) {
2990                         flush();
2991                 } else if (!strncmp(*av, "show", strlen(*av)) ||
2992                                 !strncmp(*av, "list", strlen(*av))) {
2993                         show_nat(ac, av);
2994                 } else if (!strncmp(*av, "delete", strlen(*av))) {
2995                         delete_nat_config(ac, av);
2996                 } else {
2997                         errx(EX_USAGE, "bad ipfw nat command `%s'", *av);
2998                 }
2999         } else if (!strncmp(*av, "pipe", strlen(*av)) ||
3000                 !strncmp(*av, "queue", strlen(*av))) {
3001                 NEXT_ARG;
3002                 if (!strncmp(*av, "config", strlen(*av))) {
3003                         config_dummynet(ac, av);
3004                 } else if (!strncmp(*av, "flush", strlen(*av))) {
3005                         flush();
3006                 } else if (!strncmp(*av, "show", strlen(*av))) {
3007                         show_dummynet(ac, av);
3008                 } else {
3009                         errx(EX_USAGE, "bad ipfw pipe command `%s'", *av);
3010                 }
3011         } else if (!strncmp(*av, "state", strlen(*av))) {
3012                 NEXT_ARG;
3013                 if (!strncmp(*av, "add", strlen(*av))) {
3014                         add_state(ac, av);
3015                 } else if (!strncmp(*av, "delete", strlen(*av))) {
3016                         delete_state(ac, av);
3017                 } else if (!strncmp(*av, "flush", strlen(*av))) {
3018                         flush_state(ac, av);
3019                 } else if (!strncmp(*av, "list", strlen(*av))) {
3020                         do_dynamic = 2;
3021                         list(ac, av);
3022                 } else if (!strncmp(*av, "show", strlen(*av))) {
3023                         do_acct = 1;
3024                         do_dynamic =2;
3025                         list(ac, av);
3026                 } else {
3027                         errx(EX_USAGE, "bad ipfw state command `%s'", *av);
3028                 }
3029         } else {
3030                 errx(EX_USAGE, "bad ipfw command `%s'", *av);
3031         }
3032         return 0;
3033 }
3034
3035 static void
3036 ipfw_readfile(int ac, char *av[])
3037 {
3038         char    buf[BUFSIZ];
3039         char    *a, *p, *args[MAX_ARGS], *cmd = NULL;
3040         char    linename[10];
3041         int     i=0, lineno=0, qflag=0, pflag=0, status;
3042         FILE    *f = NULL;
3043         pid_t   preproc = 0;
3044         int     c;
3045
3046         while ((c = getopt(ac, av, "D:U:p:q")) != -1)
3047                 switch (c) {
3048                         case 'D':
3049                                 if (!pflag)
3050                                         errx(EX_USAGE, "-D requires -p");
3051                                 if (i > MAX_ARGS - 2)
3052                                         errx(EX_USAGE,
3053                                                         "too many -D or -U options");
3054                                 args[i++] = "-D";
3055                                 args[i++] = optarg;
3056                                 break;
3057
3058                         case 'U':
3059                                 if (!pflag)
3060                                         errx(EX_USAGE, "-U requires -p");
3061                                 if (i > MAX_ARGS - 2)
3062                                         errx(EX_USAGE,
3063                                                         "too many -D or -U options");
3064                                 args[i++] = "-U";
3065                                 args[i++] = optarg;
3066                                 break;
3067
3068                         case 'p':
3069                                 pflag = 1;
3070                                 cmd = optarg;
3071                                 args[0] = cmd;
3072                                 i = 1;
3073                                 break;
3074
3075                         case 'q':
3076                                 qflag = 1;
3077                                 break;
3078
3079                         default:
3080                                 errx(EX_USAGE, "bad arguments, for usage"
3081                                                 " summary ``ipfw''");
3082                 }
3083
3084         av += optind;
3085         ac -= optind;
3086         if (ac != 1)
3087                 errx(EX_USAGE, "extraneous filename arguments");
3088
3089         if ((f = fopen(av[0], "r")) == NULL)
3090                 err(EX_UNAVAILABLE, "fopen: %s", av[0]);
3091
3092         if (pflag) {
3093                 /* pipe through preprocessor (cpp or m4) */
3094                 int pipedes[2];
3095
3096                 args[i] = NULL;
3097
3098                 if (pipe(pipedes) == -1)
3099                         err(EX_OSERR, "cannot create pipe");
3100
3101                 switch ((preproc = fork())) {
3102                         case -1:
3103                                 err(EX_OSERR, "cannot fork");
3104
3105                         case 0:
3106                                 /* child */
3107                                 if (dup2(fileno(f), 0) == -1 ||
3108                                         dup2(pipedes[1], 1) == -1) {
3109                                         err(EX_OSERR, "dup2()");
3110                                 }
3111                                 fclose(f);
3112                                 close(pipedes[1]);
3113                                 close(pipedes[0]);
3114                                 execvp(cmd, args);
3115                                 err(EX_OSERR, "execvp(%s) failed", cmd);
3116
3117                         default:
3118                                 /* parent */
3119                                 fclose(f);
3120                                 close(pipedes[1]);
3121                                 if ((f = fdopen(pipedes[0], "r")) == NULL) {
3122                                         int savederrno = errno;
3123
3124                                         kill(preproc, SIGTERM);
3125                                         errno = savederrno;
3126                                         err(EX_OSERR, "fdopen()");
3127                                 }
3128                 }
3129         }
3130
3131         while (fgets(buf, BUFSIZ, f)) {
3132                 lineno++;
3133                 sprintf(linename, "Line %d", lineno);
3134                 args[0] = linename;
3135
3136                 if (*buf == '#')
3137                         continue;
3138                 if ((p = strchr(buf, '#')) != NULL)
3139                         *p = '\0';
3140                 i = 1;
3141                 if (qflag)
3142                         args[i++] = "-q";
3143                 for (a = strtok(buf, WHITESP); a && i < MAX_ARGS;
3144                         a = strtok(NULL, WHITESP), i++) {
3145                         args[i] = a;
3146                 }
3147
3148                 if (i == (qflag? 2: 1))
3149                         continue;
3150                 if (i == MAX_ARGS)
3151                         errx(EX_USAGE, "%s: too many arguments", linename);
3152
3153                 args[i] = NULL;
3154                 ipfw_main(i, args);
3155         }
3156         fclose(f);
3157         if (pflag) {
3158                 if (waitpid(preproc, &status, 0) == -1)
3159                         errx(EX_OSERR, "waitpid()");
3160                 if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK)
3161                         errx(EX_UNAVAILABLE, "preprocessor exited with status %d",
3162                                 WEXITSTATUS(status));
3163                 else if (WIFSIGNALED(status))
3164                         errx(EX_UNAVAILABLE, "preprocessor exited with signal %d",
3165                                 WTERMSIG(status));
3166         }
3167 }
3168
3169 int
3170 main(int ac, char *av[])
3171 {
3172         ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
3173         if (ipfw_socket < 0)
3174                 err(EX_UNAVAILABLE, "socket");
3175
3176         memset(keywords, 0, sizeof(struct ipfw_keyword) * KEYWORD_SIZE);
3177         memset(mappings, 0, sizeof(struct ipfw_mapping) * MAPPING_SIZE);
3178
3179         prepare_default_funcs();
3180
3181         if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0)
3182                 ipfw_readfile(ac, av);
3183         else
3184                 ipfw_main(ac, av);
3185         return EX_OK;
3186 }