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