]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/ipfw/ipfw2.c
This commit was generated by cvs2svn to compensate for changes in r150765,
[FreeBSD/FreeBSD.git] / sbin / ipfw / ipfw2.c
1 /*
2  * Copyright (c) 2002-2003 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$
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 #include <sys/queue.h>
31
32 #include <ctype.h>
33 #include <err.h>
34 #include <errno.h>
35 #include <grp.h>
36 #include <limits.h>
37 #include <netdb.h>
38 #include <pwd.h>
39 #include <signal.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <stdarg.h>
43 #include <string.h>
44 #include <timeconv.h>   /* XXX do we need this ? */
45 #include <unistd.h>
46 #include <sysexits.h>
47 #include <unistd.h>
48 #include <fcntl.h>
49
50 #include <net/if.h>
51 #include <net/pfvar.h>
52 #include <net/route.h> /* def. of struct route */
53 #include <netinet/in.h>
54 #include <netinet/in_systm.h>
55 #include <netinet/ip.h>
56 #include <netinet/ip_icmp.h>
57 #include <netinet/icmp6.h>
58 #include <netinet/ip_fw.h>
59 #include <netinet/ip_dummynet.h>
60 #include <netinet/tcp.h>
61 #include <arpa/inet.h>
62
63 int
64                 do_resolv,              /* Would try to resolve all */
65                 do_time,                /* Show time stamps */
66                 do_quiet,               /* Be quiet in add and flush */
67                 do_pipe,                /* this cmd refers to a pipe */
68                 do_sort,                /* field to sort results (0 = no) */
69                 do_dynamic,             /* display dynamic rules */
70                 do_expired,             /* display expired dynamic rules */
71                 do_compact,             /* show rules in compact mode */
72                 do_force,               /* do not ask for confirmation */
73                 show_sets,              /* display rule sets */
74                 test_only,              /* only check syntax */
75                 comment_only,           /* only print action and comment */
76                 verbose;
77
78 #define IP_MASK_ALL     0xffffffff
79 /*
80  * the following macro returns an error message if we run out of
81  * arguments.
82  */
83 #define NEED1(msg)      {if (!ac) errx(EX_USAGE, msg);}
84
85 /*
86  * _s_x is a structure that stores a string <-> token pairs, used in
87  * various places in the parser. Entries are stored in arrays,
88  * with an entry with s=NULL as terminator.
89  * The search routines are match_token() and match_value().
90  * Often, an element with x=0 contains an error string.
91  *
92  */
93 struct _s_x {
94         char const *s;
95         int x;
96 };
97
98 static struct _s_x f_tcpflags[] = {
99         { "syn", TH_SYN },
100         { "fin", TH_FIN },
101         { "ack", TH_ACK },
102         { "psh", TH_PUSH },
103         { "rst", TH_RST },
104         { "urg", TH_URG },
105         { "tcp flag", 0 },
106         { NULL, 0 }
107 };
108
109 static struct _s_x f_tcpopts[] = {
110         { "mss",        IP_FW_TCPOPT_MSS },
111         { "maxseg",     IP_FW_TCPOPT_MSS },
112         { "window",     IP_FW_TCPOPT_WINDOW },
113         { "sack",       IP_FW_TCPOPT_SACK },
114         { "ts",         IP_FW_TCPOPT_TS },
115         { "timestamp",  IP_FW_TCPOPT_TS },
116         { "cc",         IP_FW_TCPOPT_CC },
117         { "tcp option", 0 },
118         { NULL, 0 }
119 };
120
121 /*
122  * IP options span the range 0 to 255 so we need to remap them
123  * (though in fact only the low 5 bits are significant).
124  */
125 static struct _s_x f_ipopts[] = {
126         { "ssrr",       IP_FW_IPOPT_SSRR},
127         { "lsrr",       IP_FW_IPOPT_LSRR},
128         { "rr",         IP_FW_IPOPT_RR},
129         { "ts",         IP_FW_IPOPT_TS},
130         { "ip option",  0 },
131         { NULL, 0 }
132 };
133
134 static struct _s_x f_iptos[] = {
135         { "lowdelay",   IPTOS_LOWDELAY},
136         { "throughput", IPTOS_THROUGHPUT},
137         { "reliability", IPTOS_RELIABILITY},
138         { "mincost",    IPTOS_MINCOST},
139         { "congestion", IPTOS_CE},
140         { "ecntransport", IPTOS_ECT},
141         { "ip tos option", 0},
142         { NULL, 0 }
143 };
144
145 static struct _s_x limit_masks[] = {
146         {"all",         DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT},
147         {"src-addr",    DYN_SRC_ADDR},
148         {"src-port",    DYN_SRC_PORT},
149         {"dst-addr",    DYN_DST_ADDR},
150         {"dst-port",    DYN_DST_PORT},
151         {NULL,          0}
152 };
153
154 /*
155  * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines
156  * This is only used in this code.
157  */
158 #define IPPROTO_ETHERTYPE       0x1000
159 static struct _s_x ether_types[] = {
160     /*
161      * Note, we cannot use "-:&/" in the names because they are field
162      * separators in the type specifications. Also, we use s = NULL as
163      * end-delimiter, because a type of 0 can be legal.
164      */
165         { "ip",         0x0800 },
166         { "ipv4",       0x0800 },
167         { "ipv6",       0x86dd },
168         { "arp",        0x0806 },
169         { "rarp",       0x8035 },
170         { "vlan",       0x8100 },
171         { "loop",       0x9000 },
172         { "trail",      0x1000 },
173         { "at",         0x809b },
174         { "atalk",      0x809b },
175         { "aarp",       0x80f3 },
176         { "pppoe_disc", 0x8863 },
177         { "pppoe_sess", 0x8864 },
178         { "ipx_8022",   0x00E0 },
179         { "ipx_8023",   0x0000 },
180         { "ipx_ii",     0x8137 },
181         { "ipx_snap",   0x8137 },
182         { "ipx",        0x8137 },
183         { "ns",         0x0600 },
184         { NULL,         0 }
185 };
186
187 static void show_usage(void);
188
189 enum tokens {
190         TOK_NULL=0,
191
192         TOK_OR,
193         TOK_NOT,
194         TOK_STARTBRACE,
195         TOK_ENDBRACE,
196
197         TOK_ACCEPT,
198         TOK_COUNT,
199         TOK_PIPE,
200         TOK_QUEUE,
201         TOK_DIVERT,
202         TOK_TEE,
203         TOK_NETGRAPH,
204         TOK_NGTEE,
205         TOK_FORWARD,
206         TOK_SKIPTO,
207         TOK_DENY,
208         TOK_REJECT,
209         TOK_RESET,
210         TOK_UNREACH,
211         TOK_CHECKSTATE,
212
213         TOK_ALTQ,
214         TOK_LOG,
215
216         TOK_UID,
217         TOK_GID,
218         TOK_JAIL,
219         TOK_IN,
220         TOK_LIMIT,
221         TOK_KEEPSTATE,
222         TOK_LAYER2,
223         TOK_OUT,
224         TOK_DIVERTED,
225         TOK_DIVERTEDLOOPBACK,
226         TOK_DIVERTEDOUTPUT,
227         TOK_XMIT,
228         TOK_RECV,
229         TOK_VIA,
230         TOK_FRAG,
231         TOK_IPOPTS,
232         TOK_IPLEN,
233         TOK_IPID,
234         TOK_IPPRECEDENCE,
235         TOK_IPTOS,
236         TOK_IPTTL,
237         TOK_IPVER,
238         TOK_ESTAB,
239         TOK_SETUP,
240         TOK_TCPDATALEN,
241         TOK_TCPFLAGS,
242         TOK_TCPOPTS,
243         TOK_TCPSEQ,
244         TOK_TCPACK,
245         TOK_TCPWIN,
246         TOK_ICMPTYPES,
247         TOK_MAC,
248         TOK_MACTYPE,
249         TOK_VERREVPATH,
250         TOK_VERSRCREACH,
251         TOK_ANTISPOOF,
252         TOK_IPSEC,
253         TOK_COMMENT,
254
255         TOK_PLR,
256         TOK_NOERROR,
257         TOK_BUCKETS,
258         TOK_DSTIP,
259         TOK_SRCIP,
260         TOK_DSTPORT,
261         TOK_SRCPORT,
262         TOK_ALL,
263         TOK_MASK,
264         TOK_BW,
265         TOK_DELAY,
266         TOK_RED,
267         TOK_GRED,
268         TOK_DROPTAIL,
269         TOK_PROTO,
270         TOK_WEIGHT,
271
272         TOK_IPV6,
273         TOK_FLOWID,
274         TOK_ICMP6TYPES,
275         TOK_EXT6HDR,
276         TOK_DSTIP6,
277         TOK_SRCIP6,
278
279         TOK_IPV4,
280         TOK_UNREACH6,
281         TOK_RESET6,
282 };
283
284 struct _s_x dummynet_params[] = {
285         { "plr",                TOK_PLR },
286         { "noerror",            TOK_NOERROR },
287         { "buckets",            TOK_BUCKETS },
288         { "dst-ip",             TOK_DSTIP },
289         { "src-ip",             TOK_SRCIP },
290         { "dst-port",           TOK_DSTPORT },
291         { "src-port",           TOK_SRCPORT },
292         { "proto",              TOK_PROTO },
293         { "weight",             TOK_WEIGHT },
294         { "all",                TOK_ALL },
295         { "mask",               TOK_MASK },
296         { "droptail",           TOK_DROPTAIL },
297         { "red",                TOK_RED },
298         { "gred",               TOK_GRED },
299         { "bw",                 TOK_BW },
300         { "bandwidth",          TOK_BW },
301         { "delay",              TOK_DELAY },
302         { "pipe",               TOK_PIPE },
303         { "queue",              TOK_QUEUE },
304         { "flow-id",            TOK_FLOWID},
305         { "dst-ipv6",           TOK_DSTIP6},
306         { "dst-ip6",            TOK_DSTIP6},
307         { "src-ipv6",           TOK_SRCIP6},
308         { "src-ip6",            TOK_SRCIP6},
309         { "dummynet-params",    TOK_NULL },
310         { NULL, 0 }     /* terminator */
311 };
312
313 struct _s_x rule_actions[] = {
314         { "accept",             TOK_ACCEPT },
315         { "pass",               TOK_ACCEPT },
316         { "allow",              TOK_ACCEPT },
317         { "permit",             TOK_ACCEPT },
318         { "count",              TOK_COUNT },
319         { "pipe",               TOK_PIPE },
320         { "queue",              TOK_QUEUE },
321         { "divert",             TOK_DIVERT },
322         { "tee",                TOK_TEE },
323         { "netgraph",           TOK_NETGRAPH },
324         { "ngtee",              TOK_NGTEE },
325         { "fwd",                TOK_FORWARD },
326         { "forward",            TOK_FORWARD },
327         { "skipto",             TOK_SKIPTO },
328         { "deny",               TOK_DENY },
329         { "drop",               TOK_DENY },
330         { "reject",             TOK_REJECT },
331         { "reset6",             TOK_RESET6 },
332         { "reset",              TOK_RESET },
333         { "unreach6",           TOK_UNREACH6 },
334         { "unreach",            TOK_UNREACH },
335         { "check-state",        TOK_CHECKSTATE },
336         { "//",                 TOK_COMMENT },
337         { NULL, 0 }     /* terminator */
338 };
339
340 struct _s_x rule_action_params[] = {
341         { "altq",               TOK_ALTQ },
342         { "log",                TOK_LOG },
343         { NULL, 0 }     /* terminator */
344 };
345
346 struct _s_x rule_options[] = {
347         { "uid",                TOK_UID },
348         { "gid",                TOK_GID },
349         { "jail",               TOK_JAIL },
350         { "in",                 TOK_IN },
351         { "limit",              TOK_LIMIT },
352         { "keep-state",         TOK_KEEPSTATE },
353         { "bridged",            TOK_LAYER2 },
354         { "layer2",             TOK_LAYER2 },
355         { "out",                TOK_OUT },
356         { "diverted",           TOK_DIVERTED },
357         { "diverted-loopback",  TOK_DIVERTEDLOOPBACK },
358         { "diverted-output",    TOK_DIVERTEDOUTPUT },
359         { "xmit",               TOK_XMIT },
360         { "recv",               TOK_RECV },
361         { "via",                TOK_VIA },
362         { "fragment",           TOK_FRAG },
363         { "frag",               TOK_FRAG },
364         { "ipoptions",          TOK_IPOPTS },
365         { "ipopts",             TOK_IPOPTS },
366         { "iplen",              TOK_IPLEN },
367         { "ipid",               TOK_IPID },
368         { "ipprecedence",       TOK_IPPRECEDENCE },
369         { "iptos",              TOK_IPTOS },
370         { "ipttl",              TOK_IPTTL },
371         { "ipversion",          TOK_IPVER },
372         { "ipver",              TOK_IPVER },
373         { "estab",              TOK_ESTAB },
374         { "established",        TOK_ESTAB },
375         { "setup",              TOK_SETUP },
376         { "tcpdatalen",         TOK_TCPDATALEN },
377         { "tcpflags",           TOK_TCPFLAGS },
378         { "tcpflgs",            TOK_TCPFLAGS },
379         { "tcpoptions",         TOK_TCPOPTS },
380         { "tcpopts",            TOK_TCPOPTS },
381         { "tcpseq",             TOK_TCPSEQ },
382         { "tcpack",             TOK_TCPACK },
383         { "tcpwin",             TOK_TCPWIN },
384         { "icmptype",           TOK_ICMPTYPES },
385         { "icmptypes",          TOK_ICMPTYPES },
386         { "dst-ip",             TOK_DSTIP },
387         { "src-ip",             TOK_SRCIP },
388         { "dst-port",           TOK_DSTPORT },
389         { "src-port",           TOK_SRCPORT },
390         { "proto",              TOK_PROTO },
391         { "MAC",                TOK_MAC },
392         { "mac",                TOK_MAC },
393         { "mac-type",           TOK_MACTYPE },
394         { "verrevpath",         TOK_VERREVPATH },
395         { "versrcreach",        TOK_VERSRCREACH },
396         { "antispoof",          TOK_ANTISPOOF },
397         { "ipsec",              TOK_IPSEC },
398         { "icmp6type",          TOK_ICMP6TYPES },
399         { "icmp6types",         TOK_ICMP6TYPES },
400         { "ext6hdr",            TOK_EXT6HDR},
401         { "flow-id",            TOK_FLOWID},
402         { "ipv6",               TOK_IPV6},
403         { "ip6",                TOK_IPV6},
404         { "ipv4",               TOK_IPV4},
405         { "ip4",                TOK_IPV4},
406         { "dst-ipv6",           TOK_DSTIP6},
407         { "dst-ip6",            TOK_DSTIP6},
408         { "src-ipv6",           TOK_SRCIP6},
409         { "src-ip6",            TOK_SRCIP6},
410         { "//",                 TOK_COMMENT },
411
412         { "not",                TOK_NOT },              /* pseudo option */
413         { "!", /* escape ? */   TOK_NOT },              /* pseudo option */
414         { "or",                 TOK_OR },               /* pseudo option */
415         { "|", /* escape */     TOK_OR },               /* pseudo option */
416         { "{",                  TOK_STARTBRACE },       /* pseudo option */
417         { "(",                  TOK_STARTBRACE },       /* pseudo option */
418         { "}",                  TOK_ENDBRACE },         /* pseudo option */
419         { ")",                  TOK_ENDBRACE },         /* pseudo option */
420         { NULL, 0 }     /* terminator */
421 };
422
423 static __inline uint64_t
424 align_uint64(uint64_t *pll) {
425         uint64_t ret;
426
427         bcopy (pll, &ret, sizeof(ret));
428         return ret;
429 }
430
431 /*
432  * conditionally runs the command.
433  */
434 static int
435 do_cmd(int optname, void *optval, uintptr_t optlen)
436 {
437         static int s = -1;      /* the socket */
438         int i;
439
440         if (test_only)
441                 return 0;
442
443         if (s == -1)
444                 s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
445         if (s < 0)
446                 err(EX_UNAVAILABLE, "socket");
447
448         if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET ||
449             optname == IP_FW_ADD || optname == IP_FW_TABLE_LIST ||
450             optname == IP_FW_TABLE_GETSIZE)
451                 i = getsockopt(s, IPPROTO_IP, optname, optval,
452                         (socklen_t *)optlen);
453         else
454                 i = setsockopt(s, IPPROTO_IP, optname, optval, optlen);
455         return i;
456 }
457
458 /**
459  * match_token takes a table and a string, returns the value associated
460  * with the string (-1 in case of failure).
461  */
462 static int
463 match_token(struct _s_x *table, char *string)
464 {
465         struct _s_x *pt;
466         uint i = strlen(string);
467
468         for (pt = table ; i && pt->s != NULL ; pt++)
469                 if (strlen(pt->s) == i && !bcmp(string, pt->s, i))
470                         return pt->x;
471         return -1;
472 }
473
474 /**
475  * match_value takes a table and a value, returns the string associated
476  * with the value (NULL in case of failure).
477  */
478 static char const *
479 match_value(struct _s_x *p, int value)
480 {
481         for (; p->s != NULL; p++)
482                 if (p->x == value)
483                         return p->s;
484         return NULL;
485 }
486
487 /*
488  * _substrcmp takes two strings and returns 1 if they do not match,
489  * and 0 if they match exactly or the first string is a sub-string
490  * of the second.  A warning is printed to stderr in the case that the
491  * first string is a sub-string of the second.
492  *
493  * This function will be removed in the future through the usual
494  * deprecation process.
495  */
496 static int
497 _substrcmp(const char *str1, const char* str2)
498 {
499         
500         if (strncmp(str1, str2, strlen(str1)) != 0)
501                 return 1;
502
503         if (strlen(str1) != strlen(str2))
504                 warnx("DEPRECATED: '%s' matched '%s' as a sub-string",
505                     str1, str2);
506         return 0;
507 }
508
509 /*
510  * _substrcmp2 takes three strings and returns 1 if the first two do not match,
511  * and 0 if they match exactly or the second string is a sub-string
512  * of the first.  A warning is printed to stderr in the case that the
513  * first string does not match the third.
514  *
515  * This function exists to warn about the bizzare construction
516  * strncmp(str, "by", 2) which is used to allow people to use a shotcut
517  * for "bytes".  The problem is that in addition to accepting "by",
518  * "byt", "byte", and "bytes", it also excepts "by_rabid_dogs" and any
519  * other string beginning with "by".
520  *
521  * This function will be removed in the future through the usual
522  * deprecation process.
523  */
524 static int
525 _substrcmp2(const char *str1, const char* str2, const char* str3)
526 {
527         
528         if (strncmp(str1, str2, strlen(str2)) != 0)
529                 return 1;
530
531         if (strcmp(str1, str3) != 0)
532                 warnx("DEPRECATED: '%s' matched '%s'",
533                     str1, str3);
534         return 0;
535 }
536
537 /*
538  * prints one port, symbolic or numeric
539  */
540 static void
541 print_port(int proto, uint16_t port)
542 {
543
544         if (proto == IPPROTO_ETHERTYPE) {
545                 char const *s;
546
547                 if (do_resolv && (s = match_value(ether_types, port)) )
548                         printf("%s", s);
549                 else
550                         printf("0x%04x", port);
551         } else {
552                 struct servent *se = NULL;
553                 if (do_resolv) {
554                         struct protoent *pe = getprotobynumber(proto);
555
556                         se = getservbyport(htons(port), pe ? pe->p_name : NULL);
557                 }
558                 if (se)
559                         printf("%s", se->s_name);
560                 else
561                         printf("%d", port);
562         }
563 }
564
565 struct _s_x _port_name[] = {
566         {"dst-port",    O_IP_DSTPORT},
567         {"src-port",    O_IP_SRCPORT},
568         {"ipid",        O_IPID},
569         {"iplen",       O_IPLEN},
570         {"ipttl",       O_IPTTL},
571         {"mac-type",    O_MAC_TYPE},
572         {"tcpdatalen",  O_TCPDATALEN},
573         {NULL,          0}
574 };
575
576 /*
577  * Print the values in a list 16-bit items of the types above.
578  * XXX todo: add support for mask.
579  */
580 static void
581 print_newports(ipfw_insn_u16 *cmd, int proto, int opcode)
582 {
583         uint16_t *p = cmd->ports;
584         int i;
585         char const *sep;
586
587         if (cmd->o.len & F_NOT)
588                 printf(" not");
589         if (opcode != 0) {
590                 sep = match_value(_port_name, opcode);
591                 if (sep == NULL)
592                         sep = "???";
593                 printf (" %s", sep);
594         }
595         sep = " ";
596         for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) {
597                 printf(sep);
598                 print_port(proto, p[0]);
599                 if (p[0] != p[1]) {
600                         printf("-");
601                         print_port(proto, p[1]);
602                 }
603                 sep = ",";
604         }
605 }
606
607 /*
608  * Like strtol, but also translates service names into port numbers
609  * for some protocols.
610  * In particular:
611  *      proto == -1 disables the protocol check;
612  *      proto == IPPROTO_ETHERTYPE looks up an internal table
613  *      proto == <some value in /etc/protocols> matches the values there.
614  * Returns *end == s in case the parameter is not found.
615  */
616 static int
617 strtoport(char *s, char **end, int base, int proto)
618 {
619         char *p, *buf;
620         char *s1;
621         int i;
622
623         *end = s;               /* default - not found */
624         if (*s == '\0')
625                 return 0;       /* not found */
626
627         if (isdigit(*s))
628                 return strtol(s, end, base);
629
630         /*
631          * find separator. '\\' escapes the next char.
632          */
633         for (s1 = s; *s1 && (isalnum(*s1) || *s1 == '\\') ; s1++)
634                 if (*s1 == '\\' && s1[1] != '\0')
635                         s1++;
636
637         buf = malloc(s1 - s + 1);
638         if (buf == NULL)
639                 return 0;
640
641         /*
642          * copy into a buffer skipping backslashes
643          */
644         for (p = s, i = 0; p != s1 ; p++)
645                 if (*p != '\\')
646                         buf[i++] = *p;
647         buf[i++] = '\0';
648
649         if (proto == IPPROTO_ETHERTYPE) {
650                 i = match_token(ether_types, buf);
651                 free(buf);
652                 if (i != -1) {  /* found */
653                         *end = s1;
654                         return i;
655                 }
656         } else {
657                 struct protoent *pe = NULL;
658                 struct servent *se;
659
660                 if (proto != 0)
661                         pe = getprotobynumber(proto);
662                 setservent(1);
663                 se = getservbyname(buf, pe ? pe->p_name : NULL);
664                 free(buf);
665                 if (se != NULL) {
666                         *end = s1;
667                         return ntohs(se->s_port);
668                 }
669         }
670         return 0;       /* not found */
671 }
672
673 /*
674  * Map between current altq queue id numbers and names.
675  */
676 static int altq_fetched = 0;
677 static TAILQ_HEAD(, pf_altq) altq_entries = 
678         TAILQ_HEAD_INITIALIZER(altq_entries);
679
680 static void
681 altq_set_enabled(int enabled)
682 {
683         int pffd;
684
685         pffd = open("/dev/pf", O_RDWR);
686         if (pffd == -1)
687                 err(EX_UNAVAILABLE,
688                     "altq support opening pf(4) control device");
689         if (enabled) {
690                 if (ioctl(pffd, DIOCSTARTALTQ) != 0 && errno != EEXIST)
691                         err(EX_UNAVAILABLE, "enabling altq");
692         } else {
693                 if (ioctl(pffd, DIOCSTOPALTQ) != 0 && errno != ENOENT)
694                         err(EX_UNAVAILABLE, "disabling altq");
695         }
696         close(pffd);
697 }
698
699 static void
700 altq_fetch()
701 {
702         struct pfioc_altq pfioc;
703         struct pf_altq *altq;
704         int pffd, mnr;
705
706         if (altq_fetched)
707                 return;
708         altq_fetched = 1;
709         pffd = open("/dev/pf", O_RDONLY);
710         if (pffd == -1) {
711                 warn("altq support opening pf(4) control device");
712                 return;
713         }
714         bzero(&pfioc, sizeof(pfioc));
715         if (ioctl(pffd, DIOCGETALTQS, &pfioc) != 0) {
716                 warn("altq support getting queue list");
717                 close(pffd);
718                 return;
719         }
720         mnr = pfioc.nr;
721         for (pfioc.nr = 0; pfioc.nr < mnr; pfioc.nr++) {
722                 if (ioctl(pffd, DIOCGETALTQ, &pfioc) != 0) {
723                         if (errno == EBUSY)
724                                 break;
725                         warn("altq support getting queue list");
726                         close(pffd);
727                         return;
728                 }
729                 if (pfioc.altq.qid == 0)
730                         continue;
731                 altq = malloc(sizeof(*altq));
732                 if (altq == NULL)
733                         err(EX_OSERR, "malloc");
734                 *altq = pfioc.altq;
735                 TAILQ_INSERT_TAIL(&altq_entries, altq, entries);
736         }
737         close(pffd);
738 }
739
740 static u_int32_t
741 altq_name_to_qid(const char *name)
742 {
743         struct pf_altq *altq;
744
745         altq_fetch();
746         TAILQ_FOREACH(altq, &altq_entries, entries)
747                 if (strcmp(name, altq->qname) == 0)
748                         break;
749         if (altq == NULL)
750                 errx(EX_DATAERR, "altq has no queue named `%s'", name);
751         return altq->qid;
752 }
753
754 static const char *
755 altq_qid_to_name(u_int32_t qid)
756 {
757         struct pf_altq *altq;
758
759         altq_fetch();
760         TAILQ_FOREACH(altq, &altq_entries, entries)
761                 if (qid == altq->qid)
762                         break;
763         if (altq == NULL)
764                 return NULL;
765         return altq->qname;
766 }
767
768 static void
769 fill_altq_qid(u_int32_t *qid, const char *av)
770 {
771         *qid = altq_name_to_qid(av);
772 }
773
774 /*
775  * Fill the body of the command with the list of port ranges.
776  */
777 static int
778 fill_newports(ipfw_insn_u16 *cmd, char *av, int proto)
779 {
780         uint16_t a, b, *p = cmd->ports;
781         int i = 0;
782         char *s = av;
783
784         while (*s) {
785                 a = strtoport(av, &s, 0, proto);
786                 if (s == av) /* no parameter */
787                         break;
788                 if (*s == '-') { /* a range */
789                         av = s+1;
790                         b = strtoport(av, &s, 0, proto);
791                         if (s == av) /* no parameter */
792                                 break;
793                         p[0] = a;
794                         p[1] = b;
795                 } else if (*s == ',' || *s == '\0' )
796                         p[0] = p[1] = a;
797                 else    /* invalid separator */
798                         errx(EX_DATAERR, "invalid separator <%c> in <%s>\n",
799                                 *s, av);
800                 i++;
801                 p += 2;
802                 av = s+1;
803         }
804         if (i > 0) {
805                 if (i+1 > F_LEN_MASK)
806                         errx(EX_DATAERR, "too many ports/ranges\n");
807                 cmd->o.len |= i+1; /* leave F_NOT and F_OR untouched */
808         }
809         return i;
810 }
811
812 static struct _s_x icmpcodes[] = {
813       { "net",                  ICMP_UNREACH_NET },
814       { "host",                 ICMP_UNREACH_HOST },
815       { "protocol",             ICMP_UNREACH_PROTOCOL },
816       { "port",                 ICMP_UNREACH_PORT },
817       { "needfrag",             ICMP_UNREACH_NEEDFRAG },
818       { "srcfail",              ICMP_UNREACH_SRCFAIL },
819       { "net-unknown",          ICMP_UNREACH_NET_UNKNOWN },
820       { "host-unknown",         ICMP_UNREACH_HOST_UNKNOWN },
821       { "isolated",             ICMP_UNREACH_ISOLATED },
822       { "net-prohib",           ICMP_UNREACH_NET_PROHIB },
823       { "host-prohib",          ICMP_UNREACH_HOST_PROHIB },
824       { "tosnet",               ICMP_UNREACH_TOSNET },
825       { "toshost",              ICMP_UNREACH_TOSHOST },
826       { "filter-prohib",        ICMP_UNREACH_FILTER_PROHIB },
827       { "host-precedence",      ICMP_UNREACH_HOST_PRECEDENCE },
828       { "precedence-cutoff",    ICMP_UNREACH_PRECEDENCE_CUTOFF },
829       { NULL, 0 }
830 };
831
832 static void
833 fill_reject_code(u_short *codep, char *str)
834 {
835         int val;
836         char *s;
837
838         val = strtoul(str, &s, 0);
839         if (s == str || *s != '\0' || val >= 0x100)
840                 val = match_token(icmpcodes, str);
841         if (val < 0)
842                 errx(EX_DATAERR, "unknown ICMP unreachable code ``%s''", str);
843         *codep = val;
844         return;
845 }
846
847 static void
848 print_reject_code(uint16_t code)
849 {
850         char const *s = match_value(icmpcodes, code);
851
852         if (s != NULL)
853                 printf("unreach %s", s);
854         else
855                 printf("unreach %u", code);
856 }
857
858 static struct _s_x icmp6codes[] = {
859       { "no-route",             ICMP6_DST_UNREACH_NOROUTE },
860       { "admin-prohib",         ICMP6_DST_UNREACH_ADMIN },
861       { "address",              ICMP6_DST_UNREACH_ADDR },
862       { "port",                 ICMP6_DST_UNREACH_NOPORT },
863       { NULL, 0 }
864 };
865
866 static void
867 fill_unreach6_code(u_short *codep, char *str)
868 {
869         int val;
870         char *s;
871
872         val = strtoul(str, &s, 0);
873         if (s == str || *s != '\0' || val >= 0x100)
874                 val = match_token(icmp6codes, str);
875         if (val < 0)
876                 errx(EX_DATAERR, "unknown ICMPv6 unreachable code ``%s''", str);
877         *codep = val;
878         return;
879 }
880
881 static void
882 print_unreach6_code(uint16_t code)
883 {
884         char const *s = match_value(icmp6codes, code);
885
886         if (s != NULL)
887                 printf("unreach6 %s", s);
888         else
889                 printf("unreach6 %u", code);
890 }
891
892 /*
893  * Returns the number of bits set (from left) in a contiguous bitmask,
894  * or -1 if the mask is not contiguous.
895  * XXX this needs a proper fix.
896  * This effectively works on masks in big-endian (network) format.
897  * when compiled on little endian architectures.
898  *
899  * First bit is bit 7 of the first byte -- note, for MAC addresses,
900  * the first bit on the wire is bit 0 of the first byte.
901  * len is the max length in bits.
902  */
903 static int
904 contigmask(uint8_t *p, int len)
905 {
906         int i, n;
907
908         for (i=0; i<len ; i++)
909                 if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */
910                         break;
911         for (n=i+1; n < len; n++)
912                 if ( (p[n/8] & (1 << (7 - (n%8)))) != 0)
913                         return -1; /* mask not contiguous */
914         return i;
915 }
916
917 /*
918  * print flags set/clear in the two bitmasks passed as parameters.
919  * There is a specialized check for f_tcpflags.
920  */
921 static void
922 print_flags(char const *name, ipfw_insn *cmd, struct _s_x *list)
923 {
924         char const *comma = "";
925         int i;
926         uint8_t set = cmd->arg1 & 0xff;
927         uint8_t clear = (cmd->arg1 >> 8) & 0xff;
928
929         if (list == f_tcpflags && set == TH_SYN && clear == TH_ACK) {
930                 printf(" setup");
931                 return;
932         }
933
934         printf(" %s ", name);
935         for (i=0; list[i].x != 0; i++) {
936                 if (set & list[i].x) {
937                         set &= ~list[i].x;
938                         printf("%s%s", comma, list[i].s);
939                         comma = ",";
940                 }
941                 if (clear & list[i].x) {
942                         clear &= ~list[i].x;
943                         printf("%s!%s", comma, list[i].s);
944                         comma = ",";
945                 }
946         }
947 }
948
949 /*
950  * Print the ip address contained in a command.
951  */
952 static void
953 print_ip(ipfw_insn_ip *cmd, char const *s)
954 {
955         struct hostent *he = NULL;
956         int len = F_LEN((ipfw_insn *)cmd);
957         uint32_t *a = ((ipfw_insn_u32 *)cmd)->d;
958
959         printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s);
960
961         if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) {
962                 printf("me");
963                 return;
964         }
965         if (cmd->o.opcode == O_IP_SRC_LOOKUP ||
966             cmd->o.opcode == O_IP_DST_LOOKUP) {
967                 printf("table(%u", ((ipfw_insn *)cmd)->arg1);
968                 if (len == F_INSN_SIZE(ipfw_insn_u32))
969                         printf(",%u", *a);
970                 printf(")");
971                 return;
972         }
973         if (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) {
974                 uint32_t x, *map = (uint32_t *)&(cmd->mask);
975                 int i, j;
976                 char comma = '{';
977
978                 x = cmd->o.arg1 - 1;
979                 x = htonl( ~x );
980                 cmd->addr.s_addr = htonl(cmd->addr.s_addr);
981                 printf("%s/%d", inet_ntoa(cmd->addr),
982                         contigmask((uint8_t *)&x, 32));
983                 x = cmd->addr.s_addr = htonl(cmd->addr.s_addr);
984                 x &= 0xff; /* base */
985                 /*
986                  * Print bits and ranges.
987                  * Locate first bit set (i), then locate first bit unset (j).
988                  * If we have 3+ consecutive bits set, then print them as a
989                  * range, otherwise only print the initial bit and rescan.
990                  */
991                 for (i=0; i < cmd->o.arg1; i++)
992                         if (map[i/32] & (1<<(i & 31))) {
993                                 for (j=i+1; j < cmd->o.arg1; j++)
994                                         if (!(map[ j/32] & (1<<(j & 31))))
995                                                 break;
996                                 printf("%c%d", comma, i+x);
997                                 if (j>i+2) { /* range has at least 3 elements */
998                                         printf("-%d", j-1+x);
999                                         i = j-1;
1000                                 }
1001                                 comma = ',';
1002                         }
1003                 printf("}");
1004                 return;
1005         }
1006         /*
1007          * len == 2 indicates a single IP, whereas lists of 1 or more
1008          * addr/mask pairs have len = (2n+1). We convert len to n so we
1009          * use that to count the number of entries.
1010          */
1011     for (len = len / 2; len > 0; len--, a += 2) {
1012         int mb =        /* mask length */
1013             (cmd->o.opcode == O_IP_SRC || cmd->o.opcode == O_IP_DST) ?
1014                 32 : contigmask((uint8_t *)&(a[1]), 32);
1015         if (mb == 32 && do_resolv)
1016                 he = gethostbyaddr((char *)&(a[0]), sizeof(u_long), AF_INET);
1017         if (he != NULL)         /* resolved to name */
1018                 printf("%s", he->h_name);
1019         else if (mb == 0)       /* any */
1020                 printf("any");
1021         else {          /* numeric IP followed by some kind of mask */
1022                 printf("%s", inet_ntoa( *((struct in_addr *)&a[0]) ) );
1023                 if (mb < 0)
1024                         printf(":%s", inet_ntoa( *((struct in_addr *)&a[1]) ) );
1025                 else if (mb < 32)
1026                         printf("/%d", mb);
1027         }
1028         if (len > 1)
1029                 printf(",");
1030     }
1031 }
1032
1033 /*
1034  * prints a MAC address/mask pair
1035  */
1036 static void
1037 print_mac(uint8_t *addr, uint8_t *mask)
1038 {
1039         int l = contigmask(mask, 48);
1040
1041         if (l == 0)
1042                 printf(" any");
1043         else {
1044                 printf(" %02x:%02x:%02x:%02x:%02x:%02x",
1045                     addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
1046                 if (l == -1)
1047                         printf("&%02x:%02x:%02x:%02x:%02x:%02x",
1048                             mask[0], mask[1], mask[2],
1049                             mask[3], mask[4], mask[5]);
1050                 else if (l < 48)
1051                         printf("/%d", l);
1052         }
1053 }
1054
1055 static void
1056 fill_icmptypes(ipfw_insn_u32 *cmd, char *av)
1057 {
1058         uint8_t type;
1059
1060         cmd->d[0] = 0;
1061         while (*av) {
1062                 if (*av == ',')
1063                         av++;
1064
1065                 type = strtoul(av, &av, 0);
1066
1067                 if (*av != ',' && *av != '\0')
1068                         errx(EX_DATAERR, "invalid ICMP type");
1069
1070                 if (type > 31)
1071                         errx(EX_DATAERR, "ICMP type out of range");
1072
1073                 cmd->d[0] |= 1 << type;
1074         }
1075         cmd->o.opcode = O_ICMPTYPE;
1076         cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32);
1077 }
1078
1079 static void
1080 print_icmptypes(ipfw_insn_u32 *cmd)
1081 {
1082         int i;
1083         char sep= ' ';
1084
1085         printf(" icmptypes");
1086         for (i = 0; i < 32; i++) {
1087                 if ( (cmd->d[0] & (1 << (i))) == 0)
1088                         continue;
1089                 printf("%c%d", sep, i);
1090                 sep = ',';
1091         }
1092 }
1093
1094 /* 
1095  * Print the ip address contained in a command.
1096  */
1097 static void
1098 print_ip6(ipfw_insn_ip6 *cmd, char const *s)
1099 {
1100        struct hostent *he = NULL;
1101        int len = F_LEN((ipfw_insn *) cmd) - 1;
1102        struct in6_addr *a = &(cmd->addr6);
1103        char trad[255];
1104
1105        printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s);
1106
1107        if (cmd->o.opcode == O_IP6_SRC_ME || cmd->o.opcode == O_IP6_DST_ME) {
1108                printf("me6");
1109                return;
1110        }
1111        if (cmd->o.opcode == O_IP6) {
1112                printf(" ipv6");
1113                return;
1114        }
1115
1116        /*
1117         * len == 4 indicates a single IP, whereas lists of 1 or more
1118         * addr/mask pairs have len = (2n+1). We convert len to n so we
1119         * use that to count the number of entries.
1120         */
1121
1122        for (len = len / 4; len > 0; len -= 2, a += 2) {
1123            int mb =        /* mask length */
1124                (cmd->o.opcode == O_IP6_SRC || cmd->o.opcode == O_IP6_DST) ?
1125                128 : contigmask((uint8_t *)&(a[1]), 128);
1126
1127            if (mb == 128 && do_resolv)
1128                he = gethostbyaddr((char *)a, sizeof(*a), AF_INET6);
1129            if (he != NULL)             /* resolved to name */
1130                printf("%s", he->h_name);
1131            else if (mb == 0)           /* any */
1132                printf("any");
1133            else {          /* numeric IP followed by some kind of mask */
1134                if (inet_ntop(AF_INET6,  a, trad, sizeof( trad ) ) == NULL)
1135                    printf("Error ntop in print_ip6\n");
1136                printf("%s",  trad );
1137                if (mb < 0)     /* XXX not really legal... */
1138                    printf(":%s",
1139                        inet_ntop(AF_INET6, &a[1], trad, sizeof(trad)));
1140                else if (mb < 128)
1141                    printf("/%d", mb);
1142            }
1143            if (len > 2)
1144                printf(",");
1145        }
1146 }
1147
1148 static void
1149 fill_icmp6types(ipfw_insn_icmp6 *cmd, char *av)
1150 {
1151        uint8_t type;
1152
1153        cmd->d[0] = 0;
1154        while (*av) {
1155            if (*av == ',')
1156                av++;
1157            type = strtoul(av, &av, 0);
1158            if (*av != ',' && *av != '\0')
1159                errx(EX_DATAERR, "invalid ICMP6 type");
1160            /*
1161             * XXX: shouldn't this be 0xFF?  I can't see any reason why
1162             * we shouldn't be able to filter all possiable values
1163             * regardless of the ability of the rest of the kernel to do
1164             * anything useful with them.
1165             */
1166            if (type > ICMP6_MAXTYPE)
1167                errx(EX_DATAERR, "ICMP6 type out of range");
1168            cmd->d[type / 32] |= ( 1 << (type % 32));
1169        }
1170        cmd->o.opcode = O_ICMP6TYPE;
1171        cmd->o.len |= F_INSN_SIZE(ipfw_insn_icmp6);
1172 }
1173
1174
1175 static void
1176 print_icmp6types(ipfw_insn_u32 *cmd)
1177 {
1178        int i, j;
1179        char sep= ' ';
1180
1181        printf(" ipv6 icmp6types");
1182        for (i = 0; i < 7; i++)
1183                for (j=0; j < 32; ++j) {
1184                        if ( (cmd->d[i] & (1 << (j))) == 0)
1185                                continue;
1186                        printf("%c%d", sep, (i*32 + j));
1187                        sep = ',';
1188                }
1189 }
1190
1191 static void
1192 print_flow6id( ipfw_insn_u32 *cmd)
1193 {
1194        uint16_t i, limit = cmd->o.arg1;
1195        char sep = ',';
1196
1197        printf(" flow-id ");
1198        for( i=0; i < limit; ++i) {
1199                if (i == limit - 1)
1200                        sep = ' ';
1201                printf("%d%c", cmd->d[i], sep);
1202        }
1203 }
1204
1205 /* structure and define for the extension header in ipv6 */
1206 static struct _s_x ext6hdrcodes[] = {
1207        { "frag",       EXT_FRAGMENT },
1208        { "hopopt",     EXT_HOPOPTS },
1209        { "route",      EXT_ROUTING },
1210        { "dstopt",     EXT_DSTOPTS },
1211        { "ah",         EXT_AH },
1212        { "esp",        EXT_ESP },
1213        { NULL,         0 }
1214 };
1215
1216 /* fills command for the extension header filtering */
1217 int
1218 fill_ext6hdr( ipfw_insn *cmd, char *av)
1219 {
1220        int tok;
1221        char *s = av;
1222
1223        cmd->arg1 = 0;
1224
1225        while(s) {
1226            av = strsep( &s, ",") ;
1227            tok = match_token(ext6hdrcodes, av);
1228            switch (tok) {
1229            case EXT_FRAGMENT:
1230                cmd->arg1 |= EXT_FRAGMENT;
1231                break;
1232
1233            case EXT_HOPOPTS:
1234                cmd->arg1 |= EXT_HOPOPTS;
1235                break;
1236
1237            case EXT_ROUTING:
1238                cmd->arg1 |= EXT_ROUTING;
1239                break;
1240
1241            case EXT_DSTOPTS:
1242                cmd->arg1 |= EXT_DSTOPTS;
1243                break;
1244
1245            case EXT_AH:
1246                cmd->arg1 |= EXT_AH;
1247                break;
1248
1249            case EXT_ESP:
1250                cmd->arg1 |= EXT_ESP;
1251                break;
1252
1253            default:
1254                errx( EX_DATAERR, "invalid option for ipv6 exten header" );
1255                break;
1256            }
1257        }
1258        if (cmd->arg1 == 0 )
1259            return 0;
1260        cmd->opcode = O_EXT_HDR;
1261        cmd->len |= F_INSN_SIZE( ipfw_insn );
1262        return 1;
1263 }
1264
1265 void
1266 print_ext6hdr( ipfw_insn *cmd )
1267 {
1268        char sep = ' ';
1269
1270        printf(" extension header:");
1271        if (cmd->arg1 & EXT_FRAGMENT ) {
1272            printf("%cfragmentation", sep);
1273            sep = ',';
1274        }
1275        if (cmd->arg1 & EXT_HOPOPTS ) {
1276            printf("%chop options", sep);
1277            sep = ',';
1278        }
1279        if (cmd->arg1 & EXT_ROUTING ) {
1280            printf("%crouting options", sep);
1281            sep = ',';
1282        }
1283        if (cmd->arg1 & EXT_DSTOPTS ) {
1284            printf("%cdestination options", sep);
1285            sep = ',';
1286        }
1287        if (cmd->arg1 & EXT_AH ) {
1288            printf("%cauthentication header", sep);
1289            sep = ',';
1290        }
1291        if (cmd->arg1 & EXT_ESP ) {
1292            printf("%cencapsulated security payload", sep);
1293        }
1294 }
1295
1296 /*
1297  * show_ipfw() prints the body of an ipfw rule.
1298  * Because the standard rule has at least proto src_ip dst_ip, we use
1299  * a helper function to produce these entries if not provided explicitly.
1300  * The first argument is the list of fields we have, the second is
1301  * the list of fields we want to be printed.
1302  *
1303  * Special cases if we have provided a MAC header:
1304  *   + if the rule does not contain IP addresses/ports, do not print them;
1305  *   + if the rule does not contain an IP proto, print "all" instead of "ip";
1306  *
1307  * Once we have 'have_options', IP header fields are printed as options.
1308  */
1309 #define HAVE_PROTO      0x0001
1310 #define HAVE_SRCIP      0x0002
1311 #define HAVE_DSTIP      0x0004
1312 #define HAVE_MAC        0x0008
1313 #define HAVE_MACTYPE    0x0010
1314 #define HAVE_PROTO4     0x0040
1315 #define HAVE_PROTO6     0x0080
1316 #define HAVE_OPTIONS    0x8000
1317
1318 #define HAVE_IP         (HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP)
1319 static void
1320 show_prerequisites(int *flags, int want, int cmd)
1321 {
1322         if (comment_only)
1323                 return;
1324         if ( (*flags & HAVE_IP) == HAVE_IP)
1325                 *flags |= HAVE_OPTIONS;
1326
1327         if ( (*flags & (HAVE_MAC|HAVE_MACTYPE|HAVE_OPTIONS)) == HAVE_MAC &&
1328              cmd != O_MAC_TYPE) {
1329                 /*
1330                  * mac-type was optimized out by the compiler,
1331                  * restore it
1332                  */
1333                 printf(" any");
1334                 *flags |= HAVE_MACTYPE | HAVE_OPTIONS;
1335                 return;
1336         }
1337         if ( !(*flags & HAVE_OPTIONS)) {
1338                 if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO))
1339                         if ( (*flags & HAVE_PROTO4))
1340                                 printf(" ip4");
1341                         else if ( (*flags & HAVE_PROTO6))
1342                                 printf(" ip6");
1343                         else
1344                                 printf(" ip");
1345
1346                 if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP))
1347                         printf(" from any");
1348                 if ( !(*flags & HAVE_DSTIP) && (want & HAVE_DSTIP))
1349                         printf(" to any");
1350         }
1351         *flags |= want;
1352 }
1353
1354 static void
1355 show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
1356 {
1357         static int twidth = 0;
1358         int l;
1359         ipfw_insn *cmd;
1360         char *comment = NULL;   /* ptr to comment if we have one */
1361         int proto = 0;          /* default */
1362         int flags = 0;  /* prerequisites */
1363         ipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */
1364         ipfw_insn_altq *altqptr = NULL; /* set if we find an O_ALTQ */
1365         int or_block = 0;       /* we are in an or block */
1366         uint32_t set_disable;
1367
1368         bcopy(&rule->next_rule, &set_disable, sizeof(set_disable));
1369
1370         if (set_disable & (1 << rule->set)) { /* disabled */
1371                 if (!show_sets)
1372                         return;
1373                 else
1374                         printf("# DISABLED ");
1375         }
1376         printf("%05u ", rule->rulenum);
1377
1378         if (pcwidth>0 || bcwidth>0)
1379                 printf("%*llu %*llu ", pcwidth, align_uint64(&rule->pcnt),
1380                     bcwidth, align_uint64(&rule->bcnt));
1381
1382         if (do_time == 2)
1383                 printf("%10u ", rule->timestamp);
1384         else if (do_time == 1) {
1385                 char timestr[30];
1386                 time_t t = (time_t)0;
1387
1388                 if (twidth == 0) {
1389                         strcpy(timestr, ctime(&t));
1390                         *strchr(timestr, '\n') = '\0';
1391                         twidth = strlen(timestr);
1392                 }
1393                 if (rule->timestamp) {
1394 #if _FreeBSD_version < 500000 /* XXX check */
1395 #define _long_to_time(x)        (time_t)(x)
1396 #endif
1397                         t = _long_to_time(rule->timestamp);
1398
1399                         strcpy(timestr, ctime(&t));
1400                         *strchr(timestr, '\n') = '\0';
1401                         printf("%s ", timestr);
1402                 } else {
1403                         printf("%*s", twidth, " ");
1404                 }
1405         }
1406
1407         if (show_sets)
1408                 printf("set %d ", rule->set);
1409
1410         /*
1411          * print the optional "match probability"
1412          */
1413         if (rule->cmd_len > 0) {
1414                 cmd = rule->cmd ;
1415                 if (cmd->opcode == O_PROB) {
1416                         ipfw_insn_u32 *p = (ipfw_insn_u32 *)cmd;
1417                         double d = 1.0 * p->d[0];
1418
1419                         d = (d / 0x7fffffff);
1420                         printf("prob %f ", d);
1421                 }
1422         }
1423
1424         /*
1425          * first print actions
1426          */
1427         for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule);
1428                         l > 0 ; l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
1429                 switch(cmd->opcode) {
1430                 case O_CHECK_STATE:
1431                         printf("check-state");
1432                         flags = HAVE_IP; /* avoid printing anything else */
1433                         break;
1434
1435                 case O_ACCEPT:
1436                         printf("allow");
1437                         break;
1438
1439                 case O_COUNT:
1440                         printf("count");
1441                         break;
1442
1443                 case O_DENY:
1444                         printf("deny");
1445                         break;
1446
1447                 case O_REJECT:
1448                         if (cmd->arg1 == ICMP_REJECT_RST)
1449                                 printf("reset");
1450                         else if (cmd->arg1 == ICMP_UNREACH_HOST)
1451                                 printf("reject");
1452                         else
1453                                 print_reject_code(cmd->arg1);
1454                         break;
1455
1456                 case O_UNREACH6:
1457                         if (cmd->arg1 == ICMP6_UNREACH_RST)
1458                                 printf("reset6");
1459                         else
1460                                 print_unreach6_code(cmd->arg1);
1461                         break;
1462
1463                 case O_SKIPTO:
1464                         printf("skipto %u", cmd->arg1);
1465                         break;
1466
1467                 case O_PIPE:
1468                         printf("pipe %u", cmd->arg1);
1469                         break;
1470
1471                 case O_QUEUE:
1472                         printf("queue %u", cmd->arg1);
1473                         break;
1474
1475                 case O_DIVERT:
1476                         printf("divert %u", cmd->arg1);
1477                         break;
1478
1479                 case O_TEE:
1480                         printf("tee %u", cmd->arg1);
1481                         break;
1482
1483                 case O_NETGRAPH:
1484                         printf("netgraph %u", cmd->arg1);
1485                         break;
1486
1487                 case O_NGTEE:
1488                         printf("ngtee %u", cmd->arg1);
1489                         break;
1490
1491                 case O_FORWARD_IP:
1492                     {
1493                         ipfw_insn_sa *s = (ipfw_insn_sa *)cmd;
1494
1495                         printf("fwd %s", inet_ntoa(s->sa.sin_addr));
1496                         if (s->sa.sin_port)
1497                                 printf(",%d", s->sa.sin_port);
1498                     }
1499                         break;
1500
1501                 case O_LOG: /* O_LOG is printed last */
1502                         logptr = (ipfw_insn_log *)cmd;
1503                         break;
1504
1505                 case O_ALTQ: /* O_ALTQ is printed after O_LOG */
1506                         altqptr = (ipfw_insn_altq *)cmd;
1507                         break;
1508
1509                 default:
1510                         printf("** unrecognized action %d len %d ",
1511                                 cmd->opcode, cmd->len);
1512                 }
1513         }
1514         if (logptr) {
1515                 if (logptr->max_log > 0)
1516                         printf(" log logamount %d", logptr->max_log);
1517                 else
1518                         printf(" log");
1519         }
1520         if (altqptr) {
1521                 const char *qname;
1522
1523                 qname = altq_qid_to_name(altqptr->qid);
1524                 if (qname == NULL)
1525                         printf(" altq ?<%u>", altqptr->qid);
1526                 else
1527                         printf(" altq %s", qname);
1528         }
1529
1530         /*
1531          * then print the body.
1532          */
1533         for (l = rule->act_ofs, cmd = rule->cmd ;
1534                         l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) {
1535                 if ((cmd->len & F_OR) || (cmd->len & F_NOT))
1536                         continue;
1537                 if (cmd->opcode == O_IP4) {
1538                         flags |= HAVE_PROTO4;
1539                         break;
1540                 } else if (cmd->opcode == O_IP6) {
1541                         flags |= HAVE_PROTO6;
1542                         break;
1543                 }                       
1544         }
1545         if (rule->_pad & 1) {   /* empty rules before options */
1546                 if (!do_compact) {
1547                         show_prerequisites(&flags, HAVE_PROTO, 0);
1548                         printf(" from any to any");
1549                 }
1550                 flags |= HAVE_IP | HAVE_OPTIONS;
1551         }
1552
1553         if (comment_only)
1554                 comment = "...";
1555
1556         for (l = rule->act_ofs, cmd = rule->cmd ;
1557                         l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) {
1558                 /* useful alias */
1559                 ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;
1560
1561                 if (comment_only) {
1562                         if (cmd->opcode != O_NOP)
1563                                 continue;
1564                         printf(" // %s\n", (char *)(cmd + 1));
1565                         return;
1566                 }
1567
1568                 show_prerequisites(&flags, 0, cmd->opcode);
1569
1570                 switch(cmd->opcode) {
1571                 case O_PROB:
1572                         break;  /* done already */
1573
1574                 case O_PROBE_STATE:
1575                         break; /* no need to print anything here */
1576
1577                 case O_MACADDR2: {
1578                         ipfw_insn_mac *m = (ipfw_insn_mac *)cmd;
1579
1580                         if ((cmd->len & F_OR) && !or_block)
1581                                 printf(" {");
1582                         if (cmd->len & F_NOT)
1583                                 printf(" not");
1584                         printf(" MAC");
1585                         flags |= HAVE_MAC;
1586                         print_mac(m->addr, m->mask);
1587                         print_mac(m->addr + 6, m->mask + 6);
1588                         }
1589                         break;
1590
1591                 case O_MAC_TYPE:
1592                         if ((cmd->len & F_OR) && !or_block)
1593                                 printf(" {");
1594                         print_newports((ipfw_insn_u16 *)cmd, IPPROTO_ETHERTYPE,
1595                                 (flags & HAVE_OPTIONS) ? cmd->opcode : 0);
1596                         flags |= HAVE_MAC | HAVE_MACTYPE | HAVE_OPTIONS;
1597                         break;
1598
1599                 case O_IP_SRC:
1600                 case O_IP_SRC_LOOKUP:
1601                 case O_IP_SRC_MASK:
1602                 case O_IP_SRC_ME:
1603                 case O_IP_SRC_SET:
1604                         show_prerequisites(&flags, HAVE_PROTO, 0);
1605                         if (!(flags & HAVE_SRCIP))
1606                                 printf(" from");
1607                         if ((cmd->len & F_OR) && !or_block)
1608                                 printf(" {");
1609                         print_ip((ipfw_insn_ip *)cmd,
1610                                 (flags & HAVE_OPTIONS) ? " src-ip" : "");
1611                         flags |= HAVE_SRCIP;
1612                         break;
1613
1614                 case O_IP_DST:
1615                 case O_IP_DST_LOOKUP:
1616                 case O_IP_DST_MASK:
1617                 case O_IP_DST_ME:
1618                 case O_IP_DST_SET:
1619                         show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0);
1620                         if (!(flags & HAVE_DSTIP))
1621                                 printf(" to");
1622                         if ((cmd->len & F_OR) && !or_block)
1623                                 printf(" {");
1624                         print_ip((ipfw_insn_ip *)cmd,
1625                                 (flags & HAVE_OPTIONS) ? " dst-ip" : "");
1626                         flags |= HAVE_DSTIP;
1627                         break;
1628
1629                 case O_IP6_SRC:
1630                 case O_IP6_SRC_MASK:
1631                 case O_IP6_SRC_ME:
1632                         show_prerequisites(&flags, HAVE_PROTO, 0);
1633                         if (!(flags & HAVE_SRCIP))
1634                                 printf(" from");
1635                         if ((cmd->len & F_OR) && !or_block)
1636                                 printf(" {");
1637                         print_ip6((ipfw_insn_ip6 *)cmd,
1638                             (flags & HAVE_OPTIONS) ? " src-ip6" : "");
1639                         flags |= HAVE_SRCIP | HAVE_PROTO;
1640                         break;
1641
1642                 case O_IP6_DST:
1643                 case O_IP6_DST_MASK:
1644                 case O_IP6_DST_ME:
1645                         show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0);
1646                         if (!(flags & HAVE_DSTIP))
1647                                 printf(" to");
1648                         if ((cmd->len & F_OR) && !or_block)
1649                                 printf(" {");
1650                         print_ip6((ipfw_insn_ip6 *)cmd,
1651                             (flags & HAVE_OPTIONS) ? " dst-ip6" : "");
1652                         flags |= HAVE_DSTIP;
1653                         break;
1654
1655                 case O_FLOW6ID:
1656                 print_flow6id( (ipfw_insn_u32 *) cmd );
1657                 flags |= HAVE_OPTIONS;
1658                 break;
1659
1660                 case O_IP_DSTPORT:
1661                         show_prerequisites(&flags, HAVE_IP, 0);
1662                 case O_IP_SRCPORT:
1663                         show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0);
1664                         if ((cmd->len & F_OR) && !or_block)
1665                                 printf(" {");
1666                         print_newports((ipfw_insn_u16 *)cmd, proto,
1667                                 (flags & HAVE_OPTIONS) ? cmd->opcode : 0);
1668                         break;
1669
1670                 case O_PROTO: {
1671                         struct protoent *pe = NULL;
1672
1673                         if ((cmd->len & F_OR) && !or_block)
1674                                 printf(" {");
1675                         if (cmd->len & F_NOT)
1676                                 printf(" not");
1677                         proto = cmd->arg1;
1678                         pe = getprotobynumber(cmd->arg1);
1679                         if ((flags & (HAVE_PROTO4 | HAVE_PROTO6)) &&
1680                             !(flags & HAVE_PROTO))
1681                                 show_prerequisites(&flags,
1682                                     HAVE_IP | HAVE_OPTIONS, 0);
1683                         if (flags & HAVE_OPTIONS)
1684                                 printf(" proto");
1685                         if (pe)
1686                                 printf(" %s", pe->p_name);
1687                         else
1688                                 printf(" %u", cmd->arg1);
1689                         }
1690                         flags |= HAVE_PROTO;
1691                         break;
1692
1693                 default: /*options ... */
1694                         if (!(cmd->len & (F_OR|F_NOT)))
1695                                 if (((cmd->opcode == O_IP6) &&
1696                                     (flags & HAVE_PROTO6)) ||
1697                                     ((cmd->opcode == O_IP4) &&
1698                                     (flags & HAVE_PROTO4)))
1699                                         break;
1700                         show_prerequisites(&flags, HAVE_IP | HAVE_OPTIONS, 0);
1701                         if ((cmd->len & F_OR) && !or_block)
1702                                 printf(" {");
1703                         if (cmd->len & F_NOT && cmd->opcode != O_IN)
1704                                 printf(" not");
1705                         switch(cmd->opcode) {
1706                         case O_FRAG:
1707                                 printf(" frag");
1708                                 break;
1709
1710                         case O_IN:
1711                                 printf(cmd->len & F_NOT ? " out" : " in");
1712                                 break;
1713
1714                         case O_DIVERTED:
1715                                 switch (cmd->arg1) {
1716                                 case 3:
1717                                         printf(" diverted");
1718                                         break;
1719                                 case 1:
1720                                         printf(" diverted-loopback");
1721                                         break;
1722                                 case 2:
1723                                         printf(" diverted-output");
1724                                         break;
1725                                 default:
1726                                         printf(" diverted-?<%u>", cmd->arg1);
1727                                         break;
1728                                 }
1729                                 break;
1730
1731                         case O_LAYER2:
1732                                 printf(" layer2");
1733                                 break;
1734                         case O_XMIT:
1735                         case O_RECV:
1736                         case O_VIA:
1737                             {
1738                                 char const *s;
1739                                 ipfw_insn_if *cmdif = (ipfw_insn_if *)cmd;
1740
1741                                 if (cmd->opcode == O_XMIT)
1742                                         s = "xmit";
1743                                 else if (cmd->opcode == O_RECV)
1744                                         s = "recv";
1745                                 else /* if (cmd->opcode == O_VIA) */
1746                                         s = "via";
1747                                 if (cmdif->name[0] == '\0')
1748                                         printf(" %s %s", s,
1749                                             inet_ntoa(cmdif->p.ip));
1750                                 else
1751                                         printf(" %s %s", s, cmdif->name);
1752
1753                                 break;
1754                             }
1755                         case O_IPID:
1756                                 if (F_LEN(cmd) == 1)
1757                                     printf(" ipid %u", cmd->arg1 );
1758                                 else
1759                                     print_newports((ipfw_insn_u16 *)cmd, 0,
1760                                         O_IPID);
1761                                 break;
1762
1763                         case O_IPTTL:
1764                                 if (F_LEN(cmd) == 1)
1765                                     printf(" ipttl %u", cmd->arg1 );
1766                                 else
1767                                     print_newports((ipfw_insn_u16 *)cmd, 0,
1768                                         O_IPTTL);
1769                                 break;
1770
1771                         case O_IPVER:
1772                                 printf(" ipver %u", cmd->arg1 );
1773                                 break;
1774
1775                         case O_IPPRECEDENCE:
1776                                 printf(" ipprecedence %u", (cmd->arg1) >> 5 );
1777                                 break;
1778
1779                         case O_IPLEN:
1780                                 if (F_LEN(cmd) == 1)
1781                                     printf(" iplen %u", cmd->arg1 );
1782                                 else
1783                                     print_newports((ipfw_insn_u16 *)cmd, 0,
1784                                         O_IPLEN);
1785                                 break;
1786
1787                         case O_IPOPT:
1788                                 print_flags("ipoptions", cmd, f_ipopts);
1789                                 break;
1790
1791                         case O_IPTOS:
1792                                 print_flags("iptos", cmd, f_iptos);
1793                                 break;
1794
1795                         case O_ICMPTYPE:
1796                                 print_icmptypes((ipfw_insn_u32 *)cmd);
1797                                 break;
1798
1799                         case O_ESTAB:
1800                                 printf(" established");
1801                                 break;
1802
1803                         case O_TCPDATALEN:
1804                                 if (F_LEN(cmd) == 1)
1805                                     printf(" tcpdatalen %u", cmd->arg1 );
1806                                 else
1807                                     print_newports((ipfw_insn_u16 *)cmd, 0,
1808                                         O_TCPDATALEN);
1809                                 break;
1810
1811                         case O_TCPFLAGS:
1812                                 print_flags("tcpflags", cmd, f_tcpflags);
1813                                 break;
1814
1815                         case O_TCPOPTS:
1816                                 print_flags("tcpoptions", cmd, f_tcpopts);
1817                                 break;
1818
1819                         case O_TCPWIN:
1820                                 printf(" tcpwin %d", ntohs(cmd->arg1));
1821                                 break;
1822
1823                         case O_TCPACK:
1824                                 printf(" tcpack %d", ntohl(cmd32->d[0]));
1825                                 break;
1826
1827                         case O_TCPSEQ:
1828                                 printf(" tcpseq %d", ntohl(cmd32->d[0]));
1829                                 break;
1830
1831                         case O_UID:
1832                             {
1833                                 struct passwd *pwd = getpwuid(cmd32->d[0]);
1834
1835                                 if (pwd)
1836                                         printf(" uid %s", pwd->pw_name);
1837                                 else
1838                                         printf(" uid %u", cmd32->d[0]);
1839                             }
1840                                 break;
1841
1842                         case O_GID:
1843                             {
1844                                 struct group *grp = getgrgid(cmd32->d[0]);
1845
1846                                 if (grp)
1847                                         printf(" gid %s", grp->gr_name);
1848                                 else
1849                                         printf(" gid %u", cmd32->d[0]);
1850                             }
1851                                 break;
1852
1853                         case O_JAIL:
1854                                 printf(" jail %d", cmd32->d[0]);
1855                                 break;
1856
1857                         case O_VERREVPATH:
1858                                 printf(" verrevpath");
1859                                 break;
1860
1861                         case O_VERSRCREACH:
1862                                 printf(" versrcreach");
1863                                 break;
1864
1865                         case O_ANTISPOOF:
1866                                 printf(" antispoof");
1867                                 break;
1868
1869                         case O_IPSEC:
1870                                 printf(" ipsec");
1871                                 break;
1872
1873                         case O_NOP:
1874                                 comment = (char *)(cmd + 1);
1875                                 break;
1876
1877                         case O_KEEP_STATE:
1878                                 printf(" keep-state");
1879                                 break;
1880
1881                         case O_LIMIT:
1882                             {
1883                                 struct _s_x *p = limit_masks;
1884                                 ipfw_insn_limit *c = (ipfw_insn_limit *)cmd;
1885                                 uint8_t x = c->limit_mask;
1886                                 char const *comma = " ";
1887
1888                                 printf(" limit");
1889                                 for (; p->x != 0 ; p++)
1890                                         if ((x & p->x) == p->x) {
1891                                                 x &= ~p->x;
1892                                                 printf("%s%s", comma, p->s);
1893                                                 comma = ",";
1894                                         }
1895                                 printf(" %d", c->conn_limit);
1896                             }
1897                                 break;
1898
1899                         case O_IP6:
1900                                 printf(" ipv6");
1901                                 break;
1902
1903                         case O_IP4:
1904                                 printf(" ipv4");
1905                                 break;
1906
1907                         case O_ICMP6TYPE:
1908                                 print_icmp6types((ipfw_insn_u32 *)cmd);
1909                                 break;
1910
1911                         case O_EXT_HDR:
1912                                 print_ext6hdr( (ipfw_insn *) cmd );
1913                                 break;
1914
1915                         default:
1916                                 printf(" [opcode %d len %d]",
1917                                     cmd->opcode, cmd->len);
1918                         }
1919                 }
1920                 if (cmd->len & F_OR) {
1921                         printf(" or");
1922                         or_block = 1;
1923                 } else if (or_block) {
1924                         printf(" }");
1925                         or_block = 0;
1926                 }
1927         }
1928         show_prerequisites(&flags, HAVE_IP, 0);
1929         if (comment)
1930                 printf(" // %s", comment);
1931         printf("\n");
1932 }
1933
1934 static void
1935 show_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth)
1936 {
1937         struct protoent *pe;
1938         struct in_addr a;
1939         uint16_t rulenum;
1940
1941         if (!do_expired) {
1942                 if (!d->expire && !(d->dyn_type == O_LIMIT_PARENT))
1943                         return;
1944         }
1945         bcopy(&d->rule, &rulenum, sizeof(rulenum));
1946         printf("%05d", rulenum);
1947         if (pcwidth>0 || bcwidth>0)
1948             printf(" %*llu %*llu (%ds)", pcwidth,
1949                 align_uint64(&d->pcnt), bcwidth,
1950                 align_uint64(&d->bcnt), d->expire);
1951         switch (d->dyn_type) {
1952         case O_LIMIT_PARENT:
1953                 printf(" PARENT %d", d->count);
1954                 break;
1955         case O_LIMIT:
1956                 printf(" LIMIT");
1957                 break;
1958         case O_KEEP_STATE: /* bidir, no mask */
1959                 printf(" STATE");
1960                 break;
1961         }
1962
1963         if ((pe = getprotobynumber(d->id.proto)) != NULL)
1964                 printf(" %s", pe->p_name);
1965         else
1966                 printf(" proto %u", d->id.proto);
1967
1968         a.s_addr = htonl(d->id.src_ip);
1969         printf(" %s %d", inet_ntoa(a), d->id.src_port);
1970
1971         a.s_addr = htonl(d->id.dst_ip);
1972         printf(" <-> %s %d", inet_ntoa(a), d->id.dst_port);
1973         printf("\n");
1974 }
1975
1976 static int
1977 sort_q(const void *pa, const void *pb)
1978 {
1979         int rev = (do_sort < 0);
1980         int field = rev ? -do_sort : do_sort;
1981         long long res = 0;
1982         const struct dn_flow_queue *a = pa;
1983         const struct dn_flow_queue *b = pb;
1984
1985         switch (field) {
1986         case 1: /* pkts */
1987                 res = a->len - b->len;
1988                 break;
1989         case 2: /* bytes */
1990                 res = a->len_bytes - b->len_bytes;
1991                 break;
1992
1993         case 3: /* tot pkts */
1994                 res = a->tot_pkts - b->tot_pkts;
1995                 break;
1996
1997         case 4: /* tot bytes */
1998                 res = a->tot_bytes - b->tot_bytes;
1999                 break;
2000         }
2001         if (res < 0)
2002                 res = -1;
2003         if (res > 0)
2004                 res = 1;
2005         return (int)(rev ? res : -res);
2006 }
2007
2008 static void
2009 list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q)
2010 {
2011         int l;
2012         int index_printed, indexes = 0;
2013         char buff[255];
2014         struct protoent *pe;
2015
2016         if (fs->rq_elements == 0)
2017                 return;
2018
2019         if (do_sort != 0)
2020                 heapsort(q, fs->rq_elements, sizeof *q, sort_q);
2021
2022         /* Print IPv4 flows */
2023         index_printed = 0;
2024         for (l = 0; l < fs->rq_elements; l++) {
2025                 struct in_addr ina;
2026
2027                 /* XXX: Should check for IPv4 flows */
2028                 if (IS_IP6_FLOW_ID(&(q[l].id)))
2029                         continue;
2030
2031                 if (!index_printed) {
2032                         index_printed = 1;
2033                         if (indexes > 0)        /* currently a no-op */
2034                                 printf("\n");
2035                         indexes++;
2036                         printf("    "
2037                             "mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
2038                             fs->flow_mask.proto,
2039                             fs->flow_mask.src_ip, fs->flow_mask.src_port,
2040                             fs->flow_mask.dst_ip, fs->flow_mask.dst_port);
2041
2042                         printf("BKT Prot ___Source IP/port____ "
2043                             "____Dest. IP/port____ "
2044                             "Tot_pkt/bytes Pkt/Byte Drp\n");
2045                 }
2046
2047                 printf("%3d ", q[l].hash_slot);
2048                 pe = getprotobynumber(q[l].id.proto);
2049                 if (pe)
2050                         printf("%-4s ", pe->p_name);
2051                 else
2052                         printf("%4u ", q[l].id.proto);
2053                 ina.s_addr = htonl(q[l].id.src_ip);
2054                 printf("%15s/%-5d ",
2055                     inet_ntoa(ina), q[l].id.src_port);
2056                 ina.s_addr = htonl(q[l].id.dst_ip);
2057                 printf("%15s/%-5d ",
2058                     inet_ntoa(ina), q[l].id.dst_port);
2059                 printf("%4qu %8qu %2u %4u %3u\n",
2060                     q[l].tot_pkts, q[l].tot_bytes,
2061                     q[l].len, q[l].len_bytes, q[l].drops);
2062                 if (verbose)
2063                         printf("   S %20qd  F %20qd\n",
2064                             q[l].S, q[l].F);
2065         }
2066
2067         /* Print IPv6 flows */
2068         index_printed = 0;
2069         for (l = 0; l < fs->rq_elements; l++) {
2070                 if (!IS_IP6_FLOW_ID(&(q[l].id)))
2071                         continue;
2072
2073                 if (!index_printed) {
2074                         index_printed = 1;
2075                         if (indexes > 0)
2076                                 printf("\n");
2077                         indexes++;
2078                         printf("\n        mask: proto: 0x%02x, flow_id: 0x%08x,  ",
2079                             fs->flow_mask.proto, fs->flow_mask.flow_id6);
2080                         inet_ntop(AF_INET6, &(fs->flow_mask.src_ip6),
2081                             buff, sizeof(buff));
2082                         printf("%s/0x%04x -> ", buff, fs->flow_mask.src_port);
2083                         inet_ntop( AF_INET6, &(fs->flow_mask.dst_ip6),
2084                             buff, sizeof(buff) );
2085                         printf("%s/0x%04x\n", buff, fs->flow_mask.dst_port);
2086
2087                         printf("BKT ___Prot___ _flow-id_ "
2088                             "______________Source IPv6/port_______________ "
2089                             "_______________Dest. IPv6/port_______________ "
2090                             "Tot_pkt/bytes Pkt/Byte Drp\n");
2091                 }
2092                 printf("%3d ", q[l].hash_slot);
2093                 pe = getprotobynumber(q[l].id.proto);
2094                 if (pe != NULL)
2095                         printf("%9s ", pe->p_name);
2096                 else
2097                         printf("%9u ", q[l].id.proto);
2098                 printf("%7d  %39s/%-5d ", q[l].id.flow_id6,
2099                     inet_ntop(AF_INET6, &(q[l].id.src_ip6), buff, sizeof(buff)),
2100                     q[l].id.src_port);
2101                 printf(" %39s/%-5d ",
2102                     inet_ntop(AF_INET6, &(q[l].id.dst_ip6), buff, sizeof(buff)),
2103                     q[l].id.dst_port);
2104                 printf(" %4qu %8qu %2u %4u %3u\n",
2105                     q[l].tot_pkts, q[l].tot_bytes,
2106                     q[l].len, q[l].len_bytes, q[l].drops);
2107                 if (verbose)
2108                         printf("   S %20qd  F %20qd\n", q[l].S, q[l].F);
2109         }
2110 }
2111
2112 static void
2113 print_flowset_parms(struct dn_flow_set *fs, char *prefix)
2114 {
2115         int l;
2116         char qs[30];
2117         char plr[30];
2118         char red[90];   /* Display RED parameters */
2119
2120         l = fs->qsize;
2121         if (fs->flags_fs & DN_QSIZE_IS_BYTES) {
2122                 if (l >= 8192)
2123                         sprintf(qs, "%d KB", l / 1024);
2124                 else
2125                         sprintf(qs, "%d B", l);
2126         } else
2127                 sprintf(qs, "%3d sl.", l);
2128         if (fs->plr)
2129                 sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff));
2130         else
2131                 plr[0] = '\0';
2132         if (fs->flags_fs & DN_IS_RED)   /* RED parameters */
2133                 sprintf(red,
2134                     "\n\t  %cRED w_q %f min_th %d max_th %d max_p %f",
2135                     (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ',
2136                     1.0 * fs->w_q / (double)(1 << SCALE_RED),
2137                     SCALE_VAL(fs->min_th),
2138                     SCALE_VAL(fs->max_th),
2139                     1.0 * fs->max_p / (double)(1 << SCALE_RED));
2140         else
2141                 sprintf(red, "droptail");
2142
2143         printf("%s %s%s %d queues (%d buckets) %s\n",
2144             prefix, qs, plr, fs->rq_elements, fs->rq_size, red);
2145 }
2146
2147 static void
2148 list_pipes(void *data, uint nbytes, int ac, char *av[])
2149 {
2150         int rulenum;
2151         void *next = data;
2152         struct dn_pipe *p = (struct dn_pipe *) data;
2153         struct dn_flow_set *fs;
2154         struct dn_flow_queue *q;
2155         int l;
2156
2157         if (ac > 0)
2158                 rulenum = strtoul(*av++, NULL, 10);
2159         else
2160                 rulenum = 0;
2161         for (; nbytes >= sizeof *p; p = (struct dn_pipe *)next) {
2162                 double b = p->bandwidth;
2163                 char buf[30];
2164                 char prefix[80];
2165
2166                 if (p->next != (struct dn_pipe *)DN_IS_PIPE)
2167                         break;  /* done with pipes, now queues */
2168
2169                 /*
2170                  * compute length, as pipe have variable size
2171                  */
2172                 l = sizeof(*p) + p->fs.rq_elements * sizeof(*q);
2173                 next = (char *)p + l;
2174                 nbytes -= l;
2175
2176                 if ((rulenum != 0 && rulenum != p->pipe_nr) || do_pipe == 2)
2177                         continue;
2178
2179                 /*
2180                  * Print rate (or clocking interface)
2181                  */
2182                 if (p->if_name[0] != '\0')
2183                         sprintf(buf, "%s", p->if_name);
2184                 else if (b == 0)
2185                         sprintf(buf, "unlimited");
2186                 else if (b >= 1000000)
2187                         sprintf(buf, "%7.3f Mbit/s", b/1000000);
2188                 else if (b >= 1000)
2189                         sprintf(buf, "%7.3f Kbit/s", b/1000);
2190                 else
2191                         sprintf(buf, "%7.3f bit/s ", b);
2192
2193                 sprintf(prefix, "%05d: %s %4d ms ",
2194                     p->pipe_nr, buf, p->delay);
2195                 print_flowset_parms(&(p->fs), prefix);
2196                 if (verbose)
2197                         printf("   V %20qd\n", p->V >> MY_M);
2198
2199                 q = (struct dn_flow_queue *)(p+1);
2200                 list_queues(&(p->fs), q);
2201         }
2202         for (fs = next; nbytes >= sizeof *fs; fs = next) {
2203                 char prefix[80];
2204
2205                 if (fs->next != (struct dn_flow_set *)DN_IS_QUEUE)
2206                         break;
2207                 l = sizeof(*fs) + fs->rq_elements * sizeof(*q);
2208                 next = (char *)fs + l;
2209                 nbytes -= l;
2210
2211                 if (rulenum != 0 && ((rulenum != fs->fs_nr && do_pipe == 2) ||
2212                     (rulenum != fs->parent_nr && do_pipe == 1))) {
2213                         continue;
2214                 }
2215
2216                 q = (struct dn_flow_queue *)(fs+1);
2217                 sprintf(prefix, "q%05d: weight %d pipe %d ",
2218                     fs->fs_nr, fs->weight, fs->parent_nr);
2219                 print_flowset_parms(fs, prefix);
2220                 list_queues(fs, q);
2221         }
2222 }
2223
2224 /*
2225  * This one handles all set-related commands
2226  *      ipfw set { show | enable | disable }
2227  *      ipfw set swap X Y
2228  *      ipfw set move X to Y
2229  *      ipfw set move rule X to Y
2230  */
2231 static void
2232 sets_handler(int ac, char *av[])
2233 {
2234         uint32_t set_disable, masks[2];
2235         int i, nbytes;
2236         uint16_t rulenum;
2237         uint8_t cmd, new_set;
2238
2239         ac--;
2240         av++;
2241
2242         if (!ac)
2243                 errx(EX_USAGE, "set needs command");
2244         if (_substrcmp(*av, "show") == 0) {
2245                 void *data;
2246                 char const *msg;
2247
2248                 nbytes = sizeof(struct ip_fw);
2249                 if ((data = calloc(1, nbytes)) == NULL)
2250                         err(EX_OSERR, "calloc");
2251                 if (do_cmd(IP_FW_GET, data, (uintptr_t)&nbytes) < 0)
2252                         err(EX_OSERR, "getsockopt(IP_FW_GET)");
2253                 bcopy(&((struct ip_fw *)data)->next_rule,
2254                         &set_disable, sizeof(set_disable));
2255
2256                 for (i = 0, msg = "disable" ; i < RESVD_SET; i++)
2257                         if ((set_disable & (1<<i))) {
2258                                 printf("%s %d", msg, i);
2259                                 msg = "";
2260                         }
2261                 msg = (set_disable) ? " enable" : "enable";
2262                 for (i = 0; i < RESVD_SET; i++)
2263                         if (!(set_disable & (1<<i))) {
2264                                 printf("%s %d", msg, i);
2265                                 msg = "";
2266                         }
2267                 printf("\n");
2268         } else if (_substrcmp(*av, "swap") == 0) {
2269                 ac--; av++;
2270                 if (ac != 2)
2271                         errx(EX_USAGE, "set swap needs 2 set numbers\n");
2272                 rulenum = atoi(av[0]);
2273                 new_set = atoi(av[1]);
2274                 if (!isdigit(*(av[0])) || rulenum > RESVD_SET)
2275                         errx(EX_DATAERR, "invalid set number %s\n", av[0]);
2276                 if (!isdigit(*(av[1])) || new_set > RESVD_SET)
2277                         errx(EX_DATAERR, "invalid set number %s\n", av[1]);
2278                 masks[0] = (4 << 24) | (new_set << 16) | (rulenum);
2279                 i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t));
2280         } else if (_substrcmp(*av, "move") == 0) {
2281                 ac--; av++;
2282                 if (ac && _substrcmp(*av, "rule") == 0) {
2283                         cmd = 2;
2284                         ac--; av++;
2285                 } else
2286                         cmd = 3;
2287                 if (ac != 3 || _substrcmp(av[1], "to") != 0)
2288                         errx(EX_USAGE, "syntax: set move [rule] X to Y\n");
2289                 rulenum = atoi(av[0]);
2290                 new_set = atoi(av[2]);
2291                 if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > RESVD_SET) ||
2292                         (cmd == 2 && rulenum == 65535) )
2293                         errx(EX_DATAERR, "invalid source number %s\n", av[0]);
2294                 if (!isdigit(*(av[2])) || new_set > RESVD_SET)
2295                         errx(EX_DATAERR, "invalid dest. set %s\n", av[1]);
2296                 masks[0] = (cmd << 24) | (new_set << 16) | (rulenum);
2297                 i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t));
2298         } else if (_substrcmp(*av, "disable") == 0 ||
2299                    _substrcmp(*av, "enable") == 0 ) {
2300                 int which = _substrcmp(*av, "enable") == 0 ? 1 : 0;
2301
2302                 ac--; av++;
2303                 masks[0] = masks[1] = 0;
2304
2305                 while (ac) {
2306                         if (isdigit(**av)) {
2307                                 i = atoi(*av);
2308                                 if (i < 0 || i > RESVD_SET)
2309                                         errx(EX_DATAERR,
2310                                             "invalid set number %d\n", i);
2311                                 masks[which] |= (1<<i);
2312                         } else if (_substrcmp(*av, "disable") == 0)
2313                                 which = 0;
2314                         else if (_substrcmp(*av, "enable") == 0)
2315                                 which = 1;
2316                         else
2317                                 errx(EX_DATAERR,
2318                                         "invalid set command %s\n", *av);
2319                         av++; ac--;
2320                 }
2321                 if ( (masks[0] & masks[1]) != 0 )
2322                         errx(EX_DATAERR,
2323                             "cannot enable and disable the same set\n");
2324
2325                 i = do_cmd(IP_FW_DEL, masks, sizeof(masks));
2326                 if (i)
2327                         warn("set enable/disable: setsockopt(IP_FW_DEL)");
2328         } else
2329                 errx(EX_USAGE, "invalid set command %s\n", *av);
2330 }
2331
2332 static void
2333 sysctl_handler(int ac, char *av[], int which)
2334 {
2335         ac--;
2336         av++;
2337
2338         if (ac == 0) {
2339                 warnx("missing keyword to enable/disable\n");
2340         } else if (_substrcmp(*av, "firewall") == 0) {
2341                 sysctlbyname("net.inet.ip.fw.enable", NULL, 0,
2342                     &which, sizeof(which));
2343         } else if (_substrcmp(*av, "one_pass") == 0) {
2344                 sysctlbyname("net.inet.ip.fw.one_pass", NULL, 0,
2345                     &which, sizeof(which));
2346         } else if (_substrcmp(*av, "debug") == 0) {
2347                 sysctlbyname("net.inet.ip.fw.debug", NULL, 0,
2348                     &which, sizeof(which));
2349         } else if (_substrcmp(*av, "verbose") == 0) {
2350                 sysctlbyname("net.inet.ip.fw.verbose", NULL, 0,
2351                     &which, sizeof(which));
2352         } else if (_substrcmp(*av, "dyn_keepalive") == 0) {
2353                 sysctlbyname("net.inet.ip.fw.dyn_keepalive", NULL, 0,
2354                     &which, sizeof(which));
2355         } else if (_substrcmp(*av, "altq") == 0) {
2356                 altq_set_enabled(which);
2357         } else {
2358                 warnx("unrecognize enable/disable keyword: %s\n", *av);
2359         }
2360 }
2361
2362 static void
2363 list(int ac, char *av[], int show_counters)
2364 {
2365         struct ip_fw *r;
2366         ipfw_dyn_rule *dynrules, *d;
2367
2368 #define NEXT(r) ((struct ip_fw *)((char *)r + RULESIZE(r)))
2369         char *lim;
2370         void *data = NULL;
2371         int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width;
2372         int exitval = EX_OK;
2373         int lac;
2374         char **lav;
2375         u_long rnum, last;
2376         char *endptr;
2377         int seen = 0;
2378
2379         const int ocmd = do_pipe ? IP_DUMMYNET_GET : IP_FW_GET;
2380         int nalloc = 1024;      /* start somewhere... */
2381
2382         last = 0;
2383
2384         if (test_only) {
2385                 fprintf(stderr, "Testing only, list disabled\n");
2386                 return;
2387         }
2388
2389         ac--;
2390         av++;
2391
2392         /* get rules or pipes from kernel, resizing array as necessary */
2393         nbytes = nalloc;
2394
2395         while (nbytes >= nalloc) {
2396                 nalloc = nalloc * 2 + 200;
2397                 nbytes = nalloc;
2398                 if ((data = realloc(data, nbytes)) == NULL)
2399                         err(EX_OSERR, "realloc");
2400                 if (do_cmd(ocmd, data, (uintptr_t)&nbytes) < 0)
2401                         err(EX_OSERR, "getsockopt(IP_%s_GET)",
2402                                 do_pipe ? "DUMMYNET" : "FW");
2403         }
2404
2405         if (do_pipe) {
2406                 list_pipes(data, nbytes, ac, av);
2407                 goto done;
2408         }
2409
2410         /*
2411          * Count static rules. They have variable size so we
2412          * need to scan the list to count them.
2413          */
2414         for (nstat = 1, r = data, lim = (char *)data + nbytes;
2415                     r->rulenum < 65535 && (char *)r < lim;
2416                     ++nstat, r = NEXT(r) )
2417                 ; /* nothing */
2418
2419         /*
2420          * Count dynamic rules. This is easier as they have
2421          * fixed size.
2422          */
2423         r = NEXT(r);
2424         dynrules = (ipfw_dyn_rule *)r ;
2425         n = (char *)r - (char *)data;
2426         ndyn = (nbytes - n) / sizeof *dynrules;
2427
2428         /* if showing stats, figure out column widths ahead of time */
2429         bcwidth = pcwidth = 0;
2430         if (show_counters) {
2431                 for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) {
2432                         /* packet counter */
2433                         width = snprintf(NULL, 0, "%llu",
2434                             align_uint64(&r->pcnt));
2435                         if (width > pcwidth)
2436                                 pcwidth = width;
2437
2438                         /* byte counter */
2439                         width = snprintf(NULL, 0, "%llu",
2440                             align_uint64(&r->bcnt));
2441                         if (width > bcwidth)
2442                                 bcwidth = width;
2443                 }
2444         }
2445         if (do_dynamic && ndyn) {
2446                 for (n = 0, d = dynrules; n < ndyn; n++, d++) {
2447                         width = snprintf(NULL, 0, "%llu",
2448                             align_uint64(&d->pcnt));
2449                         if (width > pcwidth)
2450                                 pcwidth = width;
2451
2452                         width = snprintf(NULL, 0, "%llu",
2453                             align_uint64(&d->bcnt));
2454                         if (width > bcwidth)
2455                                 bcwidth = width;
2456                 }
2457         }
2458         /* if no rule numbers were specified, list all rules */
2459         if (ac == 0) {
2460                 for (n = 0, r = data; n < nstat; n++, r = NEXT(r) )
2461                         show_ipfw(r, pcwidth, bcwidth);
2462
2463                 if (do_dynamic && ndyn) {
2464                         printf("## Dynamic rules (%d):\n", ndyn);
2465                         for (n = 0, d = dynrules; n < ndyn; n++, d++)
2466                                 show_dyn_ipfw(d, pcwidth, bcwidth);
2467                 }
2468                 goto done;
2469         }
2470
2471         /* display specific rules requested on command line */
2472
2473         for (lac = ac, lav = av; lac != 0; lac--) {
2474                 /* convert command line rule # */
2475                 last = rnum = strtoul(*lav++, &endptr, 10);
2476                 if (*endptr == '-')
2477                         last = strtoul(endptr+1, &endptr, 10);
2478                 if (*endptr) {
2479                         exitval = EX_USAGE;
2480                         warnx("invalid rule number: %s", *(lav - 1));
2481                         continue;
2482                 }
2483                 for (n = seen = 0, r = data; n < nstat; n++, r = NEXT(r) ) {
2484                         if (r->rulenum > last)
2485                                 break;
2486                         if (r->rulenum >= rnum && r->rulenum <= last) {
2487                                 show_ipfw(r, pcwidth, bcwidth);
2488                                 seen = 1;
2489                         }
2490                 }
2491                 if (!seen) {
2492                         /* give precedence to other error(s) */
2493                         if (exitval == EX_OK)
2494                                 exitval = EX_UNAVAILABLE;
2495                         warnx("rule %lu does not exist", rnum);
2496                 }
2497         }
2498
2499         if (do_dynamic && ndyn) {
2500                 printf("## Dynamic rules:\n");
2501                 for (lac = ac, lav = av; lac != 0; lac--) {
2502                         last = rnum = strtoul(*lav++, &endptr, 10);
2503                         if (*endptr == '-')
2504                                 last = strtoul(endptr+1, &endptr, 10);
2505                         if (*endptr)
2506                                 /* already warned */
2507                                 continue;
2508                         for (n = 0, d = dynrules; n < ndyn; n++, d++) {
2509                                 uint16_t rulenum;
2510
2511                                 bcopy(&d->rule, &rulenum, sizeof(rulenum));
2512                                 if (rulenum > rnum)
2513                                         break;
2514                                 if (r->rulenum >= rnum && r->rulenum <= last)
2515                                         show_dyn_ipfw(d, pcwidth, bcwidth);
2516                         }
2517                 }
2518         }
2519
2520         ac = 0;
2521
2522 done:
2523         free(data);
2524
2525         if (exitval != EX_OK)
2526                 exit(exitval);
2527 #undef NEXT
2528 }
2529
2530 static void
2531 show_usage(void)
2532 {
2533         fprintf(stderr, "usage: ipfw [options]\n"
2534 "do \"ipfw -h\" or see ipfw manpage for details\n"
2535 );
2536         exit(EX_USAGE);
2537 }
2538
2539 static void
2540 help(void)
2541 {
2542         fprintf(stderr,
2543 "ipfw syntax summary (but please do read the ipfw(8) manpage):\n"
2544 "ipfw [-abcdefhnNqStTv] <command> where <command> is one of:\n"
2545 "add [num] [set N] [prob x] RULE-BODY\n"
2546 "{pipe|queue} N config PIPE-BODY\n"
2547 "[pipe|queue] {zero|delete|show} [N{,N}]\n"
2548 "set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\n"
2549 "table N {add ip[/bits] [value] | delete ip[/bits] | flush | list}\n"
2550 "\n"
2551 "RULE-BODY:     check-state [PARAMS] | ACTION [PARAMS] ADDR [OPTION_LIST]\n"
2552 "ACTION:        check-state | allow | count | deny | unreach{,6} CODE |\n"
2553 "               skipto N | {divert|tee} PORT | forward ADDR |\n"
2554 "               pipe N | queue N\n"
2555 "PARAMS:        [log [logamount LOGLIMIT]] [altq QUEUE_NAME]\n"
2556 "ADDR:          [ MAC dst src ether_type ] \n"
2557 "               [ ip from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n"
2558 "               [ ipv6|ip6 from IP6ADDR [ PORT ] to IP6ADDR [ PORTLIST ] ]\n"
2559 "IPADDR:        [not] { any | me | ip/bits{x,y,z} | table(t[,v]) | IPLIST }\n"
2560 "IP6ADDR:       [not] { any | me | me6 | ip6/bits | IP6LIST }\n"
2561 "IP6LIST:       { ip6 | ip6/bits }[,IP6LIST]\n"
2562 "IPLIST:        { ip | ip/bits | ip:mask }[,IPLIST]\n"
2563 "OPTION_LIST:   OPTION [OPTION_LIST]\n"
2564 "OPTION:        bridged | diverted | diverted-loopback | diverted-output |\n"
2565 "       {dst-ip|src-ip} IPADDR | {dst-ip6|src-ip6|dst-ipv6|src-ipv6} IP6ADDR |\n"
2566 "       {dst-port|src-port} LIST |\n"
2567 "       estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n"
2568 "       iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n"
2569 "       ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n"
2570 "       icmp6types LIST | ext6hdr LIST | flow-id N[,N] |\n"
2571 "       mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n"
2572 "       setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n"
2573 "       tcpdatalen LIST | verrevpath | versrcreach | antispoof\n"
2574 );
2575 exit(0);
2576 }
2577
2578
2579 static int
2580 lookup_host (char *host, struct in_addr *ipaddr)
2581 {
2582         struct hostent *he;
2583
2584         if (!inet_aton(host, ipaddr)) {
2585                 if ((he = gethostbyname(host)) == NULL)
2586                         return(-1);
2587                 *ipaddr = *(struct in_addr *)he->h_addr_list[0];
2588         }
2589         return(0);
2590 }
2591
2592 /*
2593  * fills the addr and mask fields in the instruction as appropriate from av.
2594  * Update length as appropriate.
2595  * The following formats are allowed:
2596  *      me      returns O_IP_*_ME
2597  *      1.2.3.4         single IP address
2598  *      1.2.3.4:5.6.7.8 address:mask
2599  *      1.2.3.4/24      address/mask
2600  *      1.2.3.4/26{1,6,5,4,23}  set of addresses in a subnet
2601  * We can have multiple comma-separated address/mask entries.
2602  */
2603 static void
2604 fill_ip(ipfw_insn_ip *cmd, char *av)
2605 {
2606         int len = 0;
2607         uint32_t *d = ((ipfw_insn_u32 *)cmd)->d;
2608
2609         cmd->o.len &= ~F_LEN_MASK;      /* zero len */
2610
2611         if (_substrcmp(av, "any") == 0)
2612                 return;
2613
2614         if (_substrcmp(av, "me") == 0) {
2615                 cmd->o.len |= F_INSN_SIZE(ipfw_insn);
2616                 return;
2617         }
2618
2619         if (strncmp(av, "table(", 6) == 0) {
2620                 char *p = strchr(av + 6, ',');
2621
2622                 if (p)
2623                         *p++ = '\0';
2624                 cmd->o.opcode = O_IP_DST_LOOKUP;
2625                 cmd->o.arg1 = strtoul(av + 6, NULL, 0);
2626                 if (p) {
2627                         cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32);
2628                         d[0] = strtoul(p, NULL, 0);
2629                 } else
2630                         cmd->o.len |= F_INSN_SIZE(ipfw_insn);
2631                 return;
2632         }
2633
2634     while (av) {
2635         /*
2636          * After the address we can have '/' or ':' indicating a mask,
2637          * ',' indicating another address follows, '{' indicating a
2638          * set of addresses of unspecified size.
2639          */
2640         char *p = strpbrk(av, "/:,{");
2641         int masklen;
2642         char md;
2643
2644         if (p) {
2645                 md = *p;
2646                 *p++ = '\0';
2647         } else
2648                 md = '\0';
2649
2650         if (lookup_host(av, (struct in_addr *)&d[0]) != 0)
2651                 errx(EX_NOHOST, "hostname ``%s'' unknown", av);
2652         switch (md) {
2653         case ':':
2654                 if (!inet_aton(p, (struct in_addr *)&d[1]))
2655                         errx(EX_DATAERR, "bad netmask ``%s''", p);
2656                 break;
2657         case '/':
2658                 masklen = atoi(p);
2659                 if (masklen == 0)
2660                         d[1] = htonl(0);        /* mask */
2661                 else if (masklen > 32)
2662                         errx(EX_DATAERR, "bad width ``%s''", p);
2663                 else
2664                         d[1] = htonl(~0 << (32 - masklen));
2665                 break;
2666         case '{':       /* no mask, assume /24 and put back the '{' */
2667                 d[1] = htonl(~0 << (32 - 24));
2668                 *(--p) = md;
2669                 break;
2670
2671         case ',':       /* single address plus continuation */
2672                 *(--p) = md;
2673                 /* FALLTHROUGH */
2674         case 0:         /* initialization value */
2675         default:
2676                 d[1] = htonl(~0);       /* force /32 */
2677                 break;
2678         }
2679         d[0] &= d[1];           /* mask base address with mask */
2680         /* find next separator */
2681         if (p)
2682                 p = strpbrk(p, ",{");
2683         if (p && *p == '{') {
2684                 /*
2685                  * We have a set of addresses. They are stored as follows:
2686                  *   arg1       is the set size (powers of 2, 2..256)
2687                  *   addr       is the base address IN HOST FORMAT
2688                  *   mask..     is an array of arg1 bits (rounded up to
2689                  *              the next multiple of 32) with bits set
2690                  *              for each host in the map.
2691                  */
2692                 uint32_t *map = (uint32_t *)&cmd->mask;
2693                 int low, high;
2694                 int i = contigmask((uint8_t *)&(d[1]), 32);
2695
2696                 if (len > 0)
2697                         errx(EX_DATAERR, "address set cannot be in a list");
2698                 if (i < 24 || i > 31)
2699                         errx(EX_DATAERR, "invalid set with mask %d\n", i);
2700                 cmd->o.arg1 = 1<<(32-i);        /* map length           */
2701                 d[0] = ntohl(d[0]);             /* base addr in host format */
2702                 cmd->o.opcode = O_IP_DST_SET;   /* default */
2703                 cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + (cmd->o.arg1+31)/32;
2704                 for (i = 0; i < (cmd->o.arg1+31)/32 ; i++)
2705                         map[i] = 0;     /* clear map */
2706
2707                 av = p + 1;
2708                 low = d[0] & 0xff;
2709                 high = low + cmd->o.arg1 - 1;
2710                 /*
2711                  * Here, i stores the previous value when we specify a range
2712                  * of addresses within a mask, e.g. 45-63. i = -1 means we
2713                  * have no previous value.
2714                  */
2715                 i = -1; /* previous value in a range */
2716                 while (isdigit(*av)) {
2717                         char *s;
2718                         int a = strtol(av, &s, 0);
2719
2720                         if (s == av) { /* no parameter */
2721                             if (*av != '}')
2722                                 errx(EX_DATAERR, "set not closed\n");
2723                             if (i != -1)
2724                                 errx(EX_DATAERR, "incomplete range %d-", i);
2725                             break;
2726                         }
2727                         if (a < low || a > high)
2728                             errx(EX_DATAERR, "addr %d out of range [%d-%d]\n",
2729                                 a, low, high);
2730                         a -= low;
2731                         if (i == -1)    /* no previous in range */
2732                             i = a;
2733                         else {          /* check that range is valid */
2734                             if (i > a)
2735                                 errx(EX_DATAERR, "invalid range %d-%d",
2736                                         i+low, a+low);
2737                             if (*s == '-')
2738                                 errx(EX_DATAERR, "double '-' in range");
2739                         }
2740                         for (; i <= a; i++)
2741                             map[i/32] |= 1<<(i & 31);
2742                         i = -1;
2743                         if (*s == '-')
2744                             i = a;
2745                         else if (*s == '}')
2746                             break;
2747                         av = s+1;
2748                 }
2749                 return;
2750         }
2751         av = p;
2752         if (av)                 /* then *av must be a ',' */
2753                 av++;
2754
2755         /* Check this entry */
2756         if (d[1] == 0) { /* "any", specified as x.x.x.x/0 */
2757                 /*
2758                  * 'any' turns the entire list into a NOP.
2759                  * 'not any' never matches, so it is removed from the
2760                  * list unless it is the only item, in which case we
2761                  * report an error.
2762                  */
2763                 if (cmd->o.len & F_NOT) {       /* "not any" never matches */
2764                         if (av == NULL && len == 0) /* only this entry */
2765                                 errx(EX_DATAERR, "not any never matches");
2766                 }
2767                 /* else do nothing and skip this entry */
2768                 return;
2769         }
2770         /* A single IP can be stored in an optimized format */
2771         if (d[1] == IP_MASK_ALL && av == NULL && len == 0) {
2772                 cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32);
2773                 return;
2774         }
2775         len += 2;       /* two words... */
2776         d += 2;
2777     } /* end while */
2778     cmd->o.len |= len+1;
2779 }
2780
2781
2782 /* Try to find ipv6 address by hostname */
2783 static int
2784 lookup_host6 (char *host, struct in6_addr *ip6addr)
2785 {
2786         struct hostent *he;
2787
2788         if (!inet_pton(AF_INET6, host, ip6addr)) {
2789                 if ((he = gethostbyname2(host, AF_INET6)) == NULL)
2790                         return(-1);
2791                 memcpy(ip6addr, he->h_addr_list[0], sizeof( struct in6_addr));
2792         }
2793         return(0);
2794 }
2795
2796
2797 /* n2mask sets n bits of the mask */
2798 static void
2799 n2mask(struct in6_addr *mask, int n)
2800 {
2801         static int      minimask[9] =
2802             { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
2803         u_char          *p;
2804
2805         memset(mask, 0, sizeof(struct in6_addr));
2806         p = (u_char *) mask;
2807         for (; n > 0; p++, n -= 8) {
2808                 if (n >= 8)
2809                         *p = 0xff;
2810                 else
2811                         *p = minimask[n];
2812         }
2813         return;
2814 }
2815  
2816
2817 /*
2818  * fill the addr and mask fields in the instruction as appropriate from av.
2819  * Update length as appropriate.
2820  * The following formats are allowed:
2821  *     any     matches any IP6. Actually returns an empty instruction.
2822  *     me      returns O_IP6_*_ME
2823  *
2824  *     03f1::234:123:0342                single IP6 addres
2825  *     03f1::234:123:0342/24            address/mask
2826  *     03f1::234:123:0342/24,03f1::234:123:0343/               List of address
2827  *
2828  * Set of address (as in ipv6) not supported because ipv6 address
2829  * are typically random past the initial prefix.
2830  * Return 1 on success, 0 on failure.
2831  */
2832 static int
2833 fill_ip6(ipfw_insn_ip6 *cmd, char *av)
2834 {
2835         int len = 0;
2836         struct in6_addr *d = &(cmd->addr6);
2837         /*
2838          * Needed for multiple address.
2839          * Note d[1] points to struct in6_add r mask6 of cmd
2840          */
2841
2842        cmd->o.len &= ~F_LEN_MASK;       /* zero len */
2843
2844        if (strcmp(av, "any") == 0)
2845                return (1);
2846
2847
2848        if (strcmp(av, "me") == 0) {     /* Set the data for "me" opt*/
2849                cmd->o.len |= F_INSN_SIZE(ipfw_insn);
2850                return (1);
2851        }
2852
2853        if (strcmp(av, "me6") == 0) {    /* Set the data for "me" opt*/
2854                cmd->o.len |= F_INSN_SIZE(ipfw_insn);
2855                return (1);
2856        }
2857
2858        av = strdup(av);
2859        while (av) {
2860                 /*
2861                  * After the address we can have '/' indicating a mask,
2862                  * or ',' indicating another address follows.
2863                  */
2864
2865                 char *p;
2866                 int masklen;
2867                 char md = '\0';
2868
2869                 if ((p = strpbrk(av, "/,")) ) {
2870                         md = *p;        /* save the separator */
2871                         *p = '\0';      /* terminate address string */
2872                         p++;            /* and skip past it */
2873                 }
2874                 /* now p points to NULL, mask or next entry */
2875
2876                 /* lookup stores address in *d as a side effect */
2877                 if (lookup_host6(av, d) != 0) {
2878                         /* XXX: failed. Free memory and go */
2879                         errx(EX_DATAERR, "bad address \"%s\"", av);
2880                 }
2881                 /* next, look at the mask, if any */
2882                 masklen = (md == '/') ? atoi(p) : 128;
2883                 if (masklen > 128 || masklen < 0)
2884                         errx(EX_DATAERR, "bad width \"%s\''", p);
2885                 else
2886                         n2mask(&d[1], masklen);
2887
2888                 APPLY_MASK(d, &d[1])   /* mask base address with mask */
2889
2890                 /* find next separator */
2891
2892                 if (md == '/') {        /* find separator past the mask */
2893                         p = strpbrk(p, ",");
2894                         if (p != NULL)
2895                                 p++;
2896                 }
2897                 av = p;
2898
2899                 /* Check this entry */
2900                 if (masklen == 0) {
2901                         /*
2902                          * 'any' turns the entire list into a NOP.
2903                          * 'not any' never matches, so it is removed from the
2904                          * list unless it is the only item, in which case we
2905                          * report an error.
2906                          */
2907                         if (cmd->o.len & F_NOT && av == NULL && len == 0)
2908                                 errx(EX_DATAERR, "not any never matches");
2909                         continue;
2910                 }
2911
2912                 /*
2913                  * A single IP can be stored alone
2914                  */
2915                 if (masklen == 128 && av == NULL && len == 0) {
2916                         len = F_INSN_SIZE(struct in6_addr);
2917                         break;
2918                 }
2919
2920                 /* Update length and pointer to arguments */
2921                 len += F_INSN_SIZE(struct in6_addr)*2;
2922                 d += 2;
2923         } /* end while */
2924
2925         /*
2926          * Total length of the command, remember that 1 is the size of
2927          * the base command.
2928          */
2929         cmd->o.len |= len+1;
2930         free(av);
2931         return (1);
2932 }
2933
2934 /*
2935  * fills command for ipv6 flow-id filtering
2936  * note that the 20 bit flow number is stored in a array of u_int32_t
2937  * it's supported lists of flow-id, so in the o.arg1 we store how many
2938  * additional flow-id we want to filter, the basic is 1
2939  */
2940 void
2941 fill_flow6( ipfw_insn_u32 *cmd, char *av )
2942 {
2943         u_int32_t type;  /* Current flow number */
2944         u_int16_t nflow = 0;    /* Current flow index */
2945         char *s = av;
2946         cmd->d[0] = 0;    /* Initializing the base number*/
2947
2948         while (s) {
2949                 av = strsep( &s, ",") ;
2950                 type = strtoul(av, &av, 0);
2951                 if (*av != ',' && *av != '\0')
2952                         errx(EX_DATAERR, "invalid ipv6 flow number %s", av);
2953                 if (type > 0xfffff)
2954                         errx(EX_DATAERR, "flow number out of range %s", av);
2955                 cmd->d[nflow] |= type;
2956                 nflow++;
2957         }
2958         if( nflow > 0 ) {
2959                 cmd->o.opcode = O_FLOW6ID;
2960                 cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + nflow;
2961                 cmd->o.arg1 = nflow;
2962         }
2963         else {
2964                 errx(EX_DATAERR, "invalid ipv6 flow number %s", av);
2965         }
2966 }
2967
2968 static ipfw_insn *
2969 add_srcip6(ipfw_insn *cmd, char *av)
2970 {
2971
2972         fill_ip6((ipfw_insn_ip6 *)cmd, av);
2973         if (F_LEN(cmd) == 0)                            /* any */
2974                 ;
2975         if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) {     /* "me" */
2976                 cmd->opcode = O_IP6_SRC_ME;
2977         } else if (F_LEN(cmd) ==
2978             (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) {
2979                 /* single IP, no mask*/
2980                 cmd->opcode = O_IP6_SRC;
2981         } else {                                        /* addr/mask opt */
2982                 cmd->opcode = O_IP6_SRC_MASK;
2983         }
2984         return cmd;
2985 }
2986
2987 static ipfw_insn *
2988 add_dstip6(ipfw_insn *cmd, char *av)
2989 {
2990
2991         fill_ip6((ipfw_insn_ip6 *)cmd, av);
2992         if (F_LEN(cmd) == 0)                            /* any */
2993                 ;
2994         if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn)) {     /* "me" */
2995                 cmd->opcode = O_IP6_DST_ME;
2996         } else if (F_LEN(cmd) ==
2997             (F_INSN_SIZE(struct in6_addr) + F_INSN_SIZE(ipfw_insn))) {
2998                 /* single IP, no mask*/
2999                 cmd->opcode = O_IP6_DST;
3000         } else {                                        /* addr/mask opt */
3001                 cmd->opcode = O_IP6_DST_MASK;
3002         }
3003         return cmd;
3004 }
3005
3006
3007 /*
3008  * helper function to process a set of flags and set bits in the
3009  * appropriate masks.
3010  */
3011 static void
3012 fill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode,
3013         struct _s_x *flags, char *p)
3014 {
3015         uint8_t set=0, clear=0;
3016
3017         while (p && *p) {
3018                 char *q;        /* points to the separator */
3019                 int val;
3020                 uint8_t *which; /* mask we are working on */
3021
3022                 if (*p == '!') {
3023                         p++;
3024                         which = &clear;
3025                 } else
3026                         which = &set;
3027                 q = strchr(p, ',');
3028                 if (q)
3029                         *q++ = '\0';
3030                 val = match_token(flags, p);
3031                 if (val <= 0)
3032                         errx(EX_DATAERR, "invalid flag %s", p);
3033                 *which |= (uint8_t)val;
3034                 p = q;
3035         }
3036         cmd->opcode = opcode;
3037         cmd->len =  (cmd->len & (F_NOT | F_OR)) | 1;
3038         cmd->arg1 = (set & 0xff) | ( (clear & 0xff) << 8);
3039 }
3040
3041
3042 static void
3043 delete(int ac, char *av[])
3044 {
3045         uint32_t rulenum;
3046         struct dn_pipe p;
3047         int i;
3048         int exitval = EX_OK;
3049         int do_set = 0;
3050
3051         memset(&p, 0, sizeof p);
3052
3053         av++; ac--;
3054         NEED1("missing rule specification");
3055         if (ac > 0 && _substrcmp(*av, "set") == 0) {
3056                 do_set = 1;     /* delete set */
3057                 ac--; av++;
3058         }
3059
3060         /* Rule number */
3061         while (ac && isdigit(**av)) {
3062                 i = atoi(*av); av++; ac--;
3063                 if (do_pipe) {
3064                         if (do_pipe == 1)
3065                                 p.pipe_nr = i;
3066                         else
3067                                 p.fs.fs_nr = i;
3068                         i = do_cmd(IP_DUMMYNET_DEL, &p, sizeof p);
3069                         if (i) {
3070                                 exitval = 1;
3071                                 warn("rule %u: setsockopt(IP_DUMMYNET_DEL)",
3072                                     do_pipe == 1 ? p.pipe_nr : p.fs.fs_nr);
3073                         }
3074                 } else {
3075                         rulenum =  (i & 0xffff) | (do_set << 24);
3076                         i = do_cmd(IP_FW_DEL, &rulenum, sizeof rulenum);
3077                         if (i) {
3078                                 exitval = EX_UNAVAILABLE;
3079                                 warn("rule %u: setsockopt(IP_FW_DEL)",
3080                                     rulenum);
3081                         }
3082                 }
3083         }
3084         if (exitval != EX_OK)
3085                 exit(exitval);
3086 }
3087
3088
3089 /*
3090  * fill the interface structure. We do not check the name as we can
3091  * create interfaces dynamically, so checking them at insert time
3092  * makes relatively little sense.
3093  * Interface names containing '*', '?', or '[' are assumed to be shell 
3094  * patterns which match interfaces.
3095  */
3096 static void
3097 fill_iface(ipfw_insn_if *cmd, char *arg)
3098 {
3099         cmd->name[0] = '\0';
3100         cmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
3101
3102         /* Parse the interface or address */
3103         if (strcmp(arg, "any") == 0)
3104                 cmd->o.len = 0;         /* effectively ignore this command */
3105         else if (!isdigit(*arg)) {
3106                 strlcpy(cmd->name, arg, sizeof(cmd->name));
3107                 cmd->p.glob = strpbrk(arg, "*?[") != NULL ? 1 : 0;
3108         } else if (!inet_aton(arg, &cmd->p.ip))
3109                 errx(EX_DATAERR, "bad ip address ``%s''", arg);
3110 }
3111
3112 static void
3113 config_pipe(int ac, char **av)
3114 {
3115         struct dn_pipe p;
3116         int i;
3117         char *end;
3118         void *par = NULL;
3119
3120         memset(&p, 0, sizeof p);
3121
3122         av++; ac--;
3123         /* Pipe number */
3124         if (ac && isdigit(**av)) {
3125                 i = atoi(*av); av++; ac--;
3126                 if (do_pipe == 1)
3127                         p.pipe_nr = i;
3128                 else
3129                         p.fs.fs_nr = i;
3130         }
3131         while (ac > 0) {
3132                 double d;
3133                 int tok = match_token(dummynet_params, *av);
3134                 ac--; av++;
3135
3136                 switch(tok) {
3137                 case TOK_NOERROR:
3138                         p.fs.flags_fs |= DN_NOERROR;
3139                         break;
3140
3141                 case TOK_PLR:
3142                         NEED1("plr needs argument 0..1\n");
3143                         d = strtod(av[0], NULL);
3144                         if (d > 1)
3145                                 d = 1;
3146                         else if (d < 0)
3147                                 d = 0;
3148                         p.fs.plr = (int)(d*0x7fffffff);
3149                         ac--; av++;
3150                         break;
3151
3152                 case TOK_QUEUE:
3153                         NEED1("queue needs queue size\n");
3154                         end = NULL;
3155                         p.fs.qsize = strtoul(av[0], &end, 0);
3156                         if (*end == 'K' || *end == 'k') {
3157                                 p.fs.flags_fs |= DN_QSIZE_IS_BYTES;
3158                                 p.fs.qsize *= 1024;
3159                         } else if (*end == 'B' ||
3160                             _substrcmp2(end, "by", "bytes") == 0) {
3161                                 p.fs.flags_fs |= DN_QSIZE_IS_BYTES;
3162                         }
3163                         ac--; av++;
3164                         break;
3165
3166                 case TOK_BUCKETS:
3167                         NEED1("buckets needs argument\n");
3168                         p.fs.rq_size = strtoul(av[0], NULL, 0);
3169                         ac--; av++;
3170                         break;
3171
3172                 case TOK_MASK:
3173                         NEED1("mask needs mask specifier\n");
3174                         /*
3175                          * per-flow queue, mask is dst_ip, dst_port,
3176                          * src_ip, src_port, proto measured in bits
3177                          */
3178                         par = NULL;
3179
3180                         bzero(&p.fs.flow_mask, sizeof(p.fs.flow_mask));
3181                         end = NULL;
3182
3183                         while (ac >= 1) {
3184                             uint32_t *p32 = NULL;
3185                             uint16_t *p16 = NULL;
3186                             uint32_t *p20 = NULL;
3187                             struct in6_addr *pa6 = NULL;
3188                             uint32_t a;
3189
3190                             tok = match_token(dummynet_params, *av);
3191                             ac--; av++;
3192                             switch(tok) {
3193                             case TOK_ALL:
3194                                     /*
3195                                      * special case, all bits significant
3196                                      */
3197                                     p.fs.flow_mask.dst_ip = ~0;
3198                                     p.fs.flow_mask.src_ip = ~0;
3199                                     p.fs.flow_mask.dst_port = ~0;
3200                                     p.fs.flow_mask.src_port = ~0;
3201                                     p.fs.flow_mask.proto = ~0;
3202                                     n2mask(&(p.fs.flow_mask.dst_ip6), 128);
3203                                     n2mask(&(p.fs.flow_mask.src_ip6), 128);
3204                                     p.fs.flow_mask.flow_id6 = ~0;
3205                                     p.fs.flags_fs |= DN_HAVE_FLOW_MASK;
3206                                     goto end_mask;
3207
3208                             case TOK_DSTIP:
3209                                     p32 = &p.fs.flow_mask.dst_ip;
3210                                     break;
3211
3212                             case TOK_SRCIP:
3213                                     p32 = &p.fs.flow_mask.src_ip;
3214                                     break;
3215
3216                             case TOK_DSTIP6:
3217                                     pa6 = &(p.fs.flow_mask.dst_ip6);
3218                                     break;
3219                             
3220                             case TOK_SRCIP6:
3221                                     pa6 = &(p.fs.flow_mask.src_ip6);
3222                                     break;
3223
3224                             case TOK_FLOWID:
3225                                     p20 = &p.fs.flow_mask.flow_id6;
3226                                     break;
3227
3228                             case TOK_DSTPORT:
3229                                     p16 = &p.fs.flow_mask.dst_port;
3230                                     break;
3231
3232                             case TOK_SRCPORT:
3233                                     p16 = &p.fs.flow_mask.src_port;
3234                                     break;
3235
3236                             case TOK_PROTO:
3237                                     break;
3238
3239                             default:
3240                                     ac++; av--; /* backtrack */
3241                                     goto end_mask;
3242                             }
3243                             if (ac < 1)
3244                                     errx(EX_USAGE, "mask: value missing");
3245                             if (*av[0] == '/') {
3246                                     a = strtoul(av[0]+1, &end, 0);
3247                                     if (pa6 == NULL)
3248                                             a = (a == 32) ? ~0 : (1 << a) - 1;
3249                             } else
3250                                     a = strtoul(av[0], &end, 0);
3251                             if (p32 != NULL)
3252                                     *p32 = a;
3253                             else if (p16 != NULL) {
3254                                     if (a > 0xFFFF)
3255                                             errx(EX_DATAERR,
3256                                                 "port mask must be 16 bit");
3257                                     *p16 = (uint16_t)a;
3258                             } else if (p20 != NULL) {
3259                                     if (a > 0xfffff)
3260                                         errx(EX_DATAERR,
3261                                             "flow_id mask must be 20 bit");
3262                                     *p20 = (uint32_t)a;
3263                             } else if (pa6 != NULL) {
3264                                     if (a < 0 || a > 128)
3265                                         errx(EX_DATAERR,
3266                                             "in6addr invalid mask len");
3267                                     else
3268                                         n2mask(pa6, a);
3269                             } else {
3270                                     if (a > 0xFF)
3271                                             errx(EX_DATAERR,
3272                                                 "proto mask must be 8 bit");
3273                                     p.fs.flow_mask.proto = (uint8_t)a;
3274                             }
3275                             if (a != 0)
3276                                     p.fs.flags_fs |= DN_HAVE_FLOW_MASK;
3277                             ac--; av++;
3278                         } /* end while, config masks */
3279 end_mask:
3280                         break;
3281
3282                 case TOK_RED:
3283                 case TOK_GRED:
3284                         NEED1("red/gred needs w_q/min_th/max_th/max_p\n");
3285                         p.fs.flags_fs |= DN_IS_RED;
3286                         if (tok == TOK_GRED)
3287                                 p.fs.flags_fs |= DN_IS_GENTLE_RED;
3288                         /*
3289                          * the format for parameters is w_q/min_th/max_th/max_p
3290                          */
3291                         if ((end = strsep(&av[0], "/"))) {
3292                             double w_q = strtod(end, NULL);
3293                             if (w_q > 1 || w_q <= 0)
3294                                 errx(EX_DATAERR, "0 < w_q <= 1");
3295                             p.fs.w_q = (int) (w_q * (1 << SCALE_RED));
3296                         }
3297                         if ((end = strsep(&av[0], "/"))) {
3298                             p.fs.min_th = strtoul(end, &end, 0);
3299                             if (*end == 'K' || *end == 'k')
3300                                 p.fs.min_th *= 1024;
3301                         }
3302                         if ((end = strsep(&av[0], "/"))) {
3303                             p.fs.max_th = strtoul(end, &end, 0);
3304                             if (*end == 'K' || *end == 'k')
3305                                 p.fs.max_th *= 1024;
3306                         }
3307                         if ((end = strsep(&av[0], "/"))) {
3308                             double max_p = strtod(end, NULL);
3309                             if (max_p > 1 || max_p <= 0)
3310                                 errx(EX_DATAERR, "0 < max_p <= 1");
3311                             p.fs.max_p = (int)(max_p * (1 << SCALE_RED));
3312                         }
3313                         ac--; av++;
3314                         break;
3315
3316                 case TOK_DROPTAIL:
3317                         p.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED);
3318                         break;
3319
3320                 case TOK_BW:
3321                         NEED1("bw needs bandwidth or interface\n");
3322                         if (do_pipe != 1)
3323                             errx(EX_DATAERR, "bandwidth only valid for pipes");
3324                         /*
3325                          * set clocking interface or bandwidth value
3326                          */
3327                         if (av[0][0] >= 'a' && av[0][0] <= 'z') {
3328                             int l = sizeof(p.if_name)-1;
3329                             /* interface name */
3330                             strncpy(p.if_name, av[0], l);
3331                             p.if_name[l] = '\0';
3332                             p.bandwidth = 0;
3333                         } else {
3334                             p.if_name[0] = '\0';
3335                             p.bandwidth = strtoul(av[0], &end, 0);
3336                             if (*end == 'K' || *end == 'k') {
3337                                 end++;
3338                                 p.bandwidth *= 1000;
3339                             } else if (*end == 'M') {
3340                                 end++;
3341                                 p.bandwidth *= 1000000;
3342                             }
3343                             if (*end == 'B' ||
3344                                 _substrcmp2(end, "by", "bytes") == 0)
3345                                 p.bandwidth *= 8;
3346                             if (p.bandwidth < 0)
3347                                 errx(EX_DATAERR, "bandwidth too large");
3348                         }
3349                         ac--; av++;
3350                         break;
3351
3352                 case TOK_DELAY:
3353                         if (do_pipe != 1)
3354                                 errx(EX_DATAERR, "delay only valid for pipes");
3355                         NEED1("delay needs argument 0..10000ms\n");
3356                         p.delay = strtoul(av[0], NULL, 0);
3357                         ac--; av++;
3358                         break;
3359
3360                 case TOK_WEIGHT:
3361                         if (do_pipe == 1)
3362                                 errx(EX_DATAERR,"weight only valid for queues");
3363                         NEED1("weight needs argument 0..100\n");
3364                         p.fs.weight = strtoul(av[0], &end, 0);
3365                         ac--; av++;
3366                         break;
3367
3368                 case TOK_PIPE:
3369                         if (do_pipe == 1)
3370                                 errx(EX_DATAERR,"pipe only valid for queues");
3371                         NEED1("pipe needs pipe_number\n");
3372                         p.fs.parent_nr = strtoul(av[0], &end, 0);
3373                         ac--; av++;
3374                         break;
3375
3376                 default:
3377                         errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]);
3378                 }
3379         }
3380         if (do_pipe == 1) {
3381                 if (p.pipe_nr == 0)
3382                         errx(EX_DATAERR, "pipe_nr must be > 0");
3383                 if (p.delay > 10000)
3384                         errx(EX_DATAERR, "delay must be < 10000");
3385         } else { /* do_pipe == 2, queue */
3386                 if (p.fs.parent_nr == 0)
3387                         errx(EX_DATAERR, "pipe must be > 0");
3388                 if (p.fs.weight >100)
3389                         errx(EX_DATAERR, "weight must be <= 100");
3390         }
3391         if (p.fs.flags_fs & DN_QSIZE_IS_BYTES) {
3392                 if (p.fs.qsize > 1024*1024)
3393                         errx(EX_DATAERR, "queue size must be < 1MB");
3394         } else {
3395                 if (p.fs.qsize > 100)
3396                         errx(EX_DATAERR, "2 <= queue size <= 100");
3397         }
3398         if (p.fs.flags_fs & DN_IS_RED) {
3399                 size_t len;
3400                 int lookup_depth, avg_pkt_size;
3401                 double s, idle, weight, w_q;
3402                 struct clockinfo ck;
3403                 int t;
3404
3405                 if (p.fs.min_th >= p.fs.max_th)
3406                     errx(EX_DATAERR, "min_th %d must be < than max_th %d",
3407                         p.fs.min_th, p.fs.max_th);
3408                 if (p.fs.max_th == 0)
3409                     errx(EX_DATAERR, "max_th must be > 0");
3410
3411                 len = sizeof(int);
3412                 if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
3413                         &lookup_depth, &len, NULL, 0) == -1)
3414
3415                     errx(1, "sysctlbyname(\"%s\")",
3416                         "net.inet.ip.dummynet.red_lookup_depth");
3417                 if (lookup_depth == 0)
3418                     errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth"
3419                         " must be greater than zero");
3420
3421                 len = sizeof(int);
3422                 if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
3423                         &avg_pkt_size, &len, NULL, 0) == -1)
3424
3425                     errx(1, "sysctlbyname(\"%s\")",
3426                         "net.inet.ip.dummynet.red_avg_pkt_size");
3427                 if (avg_pkt_size == 0)
3428                         errx(EX_DATAERR,
3429                             "net.inet.ip.dummynet.red_avg_pkt_size must"
3430                             " be greater than zero");
3431
3432                 len = sizeof(struct clockinfo);
3433                 if (sysctlbyname("kern.clockrate", &ck, &len, NULL, 0) == -1)
3434                         errx(1, "sysctlbyname(\"%s\")", "kern.clockrate");
3435
3436                 /*
3437                  * Ticks needed for sending a medium-sized packet.
3438                  * Unfortunately, when we are configuring a WF2Q+ queue, we
3439                  * do not have bandwidth information, because that is stored
3440                  * in the parent pipe, and also we have multiple queues
3441                  * competing for it. So we set s=0, which is not very
3442                  * correct. But on the other hand, why do we want RED with
3443                  * WF2Q+ ?
3444                  */
3445                 if (p.bandwidth==0) /* this is a WF2Q+ queue */
3446                         s = 0;
3447                 else
3448                         s = ck.hz * avg_pkt_size * 8 / p.bandwidth;
3449
3450                 /*
3451                  * max idle time (in ticks) before avg queue size becomes 0.
3452                  * NOTA:  (3/w_q) is approx the value x so that
3453                  * (1-w_q)^x < 10^-3.
3454                  */
3455                 w_q = ((double)p.fs.w_q) / (1 << SCALE_RED);
3456                 idle = s * 3. / w_q;
3457                 p.fs.lookup_step = (int)idle / lookup_depth;
3458                 if (!p.fs.lookup_step)
3459                         p.fs.lookup_step = 1;
3460                 weight = 1 - w_q;
3461                 for (t = p.fs.lookup_step; t > 0; --t)
3462                         weight *= weight;
3463                 p.fs.lookup_weight = (int)(weight * (1 << SCALE_RED));
3464         }
3465         i = do_cmd(IP_DUMMYNET_CONFIGURE, &p, sizeof p);
3466         if (i)
3467                 err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE");
3468 }
3469
3470 static void
3471 get_mac_addr_mask(char *p, uint8_t *addr, uint8_t *mask)
3472 {
3473         int i, l;
3474
3475         for (i=0; i<6; i++)
3476                 addr[i] = mask[i] = 0;
3477         if (strcmp(p, "any") == 0)
3478                 return;
3479
3480         for (i=0; *p && i<6;i++, p++) {
3481                 addr[i] = strtol(p, &p, 16);
3482                 if (*p != ':') /* we start with the mask */
3483                         break;
3484         }
3485         if (*p == '/') { /* mask len */
3486                 l = strtol(p+1, &p, 0);
3487                 for (i=0; l>0; l -=8, i++)
3488                         mask[i] = (l >=8) ? 0xff : (~0) << (8-l);
3489         } else if (*p == '&') { /* mask */
3490                 for (i=0, p++; *p && i<6;i++, p++) {
3491                         mask[i] = strtol(p, &p, 16);
3492                         if (*p != ':')
3493                                 break;
3494                 }
3495         } else if (*p == '\0') {
3496                 for (i=0; i<6; i++)
3497                         mask[i] = 0xff;
3498         }
3499         for (i=0; i<6; i++)
3500                 addr[i] &= mask[i];
3501 }
3502
3503 /*
3504  * helper function, updates the pointer to cmd with the length
3505  * of the current command, and also cleans up the first word of
3506  * the new command in case it has been clobbered before.
3507  */
3508 static ipfw_insn *
3509 next_cmd(ipfw_insn *cmd)
3510 {
3511         cmd += F_LEN(cmd);
3512         bzero(cmd, sizeof(*cmd));
3513         return cmd;
3514 }
3515
3516 /*
3517  * Takes arguments and copies them into a comment
3518  */
3519 static void
3520 fill_comment(ipfw_insn *cmd, int ac, char **av)
3521 {
3522         int i, l;
3523         char *p = (char *)(cmd + 1);
3524
3525         cmd->opcode = O_NOP;
3526         cmd->len =  (cmd->len & (F_NOT | F_OR));
3527
3528         /* Compute length of comment string. */
3529         for (i = 0, l = 0; i < ac; i++)
3530                 l += strlen(av[i]) + 1;
3531         if (l == 0)
3532                 return;
3533         if (l > 84)
3534                 errx(EX_DATAERR,
3535                     "comment too long (max 80 chars)");
3536         l = 1 + (l+3)/4;
3537         cmd->len =  (cmd->len & (F_NOT | F_OR)) | l;
3538         for (i = 0; i < ac; i++) {
3539                 strcpy(p, av[i]);
3540                 p += strlen(av[i]);
3541                 *p++ = ' ';
3542         }
3543         *(--p) = '\0';
3544 }
3545
3546 /*
3547  * A function to fill simple commands of size 1.
3548  * Existing flags are preserved.
3549  */
3550 static void
3551 fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int flags, uint16_t arg)
3552 {
3553         cmd->opcode = opcode;
3554         cmd->len =  ((cmd->len | flags) & (F_NOT | F_OR)) | 1;
3555         cmd->arg1 = arg;
3556 }
3557
3558 /*
3559  * Fetch and add the MAC address and type, with masks. This generates one or
3560  * two microinstructions, and returns the pointer to the last one.
3561  */
3562 static ipfw_insn *
3563 add_mac(ipfw_insn *cmd, int ac, char *av[])
3564 {
3565         ipfw_insn_mac *mac;
3566
3567         if (ac < 2)
3568                 errx(EX_DATAERR, "MAC dst src");
3569
3570         cmd->opcode = O_MACADDR2;
3571         cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac);
3572
3573         mac = (ipfw_insn_mac *)cmd;
3574         get_mac_addr_mask(av[0], mac->addr, mac->mask); /* dst */
3575         get_mac_addr_mask(av[1], &(mac->addr[6]), &(mac->mask[6])); /* src */
3576         return cmd;
3577 }
3578
3579 static ipfw_insn *
3580 add_mactype(ipfw_insn *cmd, int ac, char *av)
3581 {
3582         if (ac < 1)
3583                 errx(EX_DATAERR, "missing MAC type");
3584         if (strcmp(av, "any") != 0) { /* we have a non-null type */
3585                 fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE);
3586                 cmd->opcode = O_MAC_TYPE;
3587                 return cmd;
3588         } else
3589                 return NULL;
3590 }
3591
3592 static ipfw_insn *
3593 add_proto(ipfw_insn *cmd, char *av, u_char *proto)
3594 {
3595         struct protoent *pe;
3596
3597         *proto = IPPROTO_IP;
3598
3599         if (_substrcmp(av, "all") == 0)
3600                 ; /* do not set O_IP4 nor O_IP6 */
3601         else if (strcmp(av, "ipv4") == 0 || strcmp(av, "ip4") == 0)
3602                 /* explicit "just IPv4" rule */
3603                 fill_cmd(cmd, O_IP4, 0, 0);
3604         else if (strcmp(av, "ipv6") == 0 || strcmp(av, "ip6") == 0) {
3605                 /* explicit "just IPv6" rule */
3606                 *proto = IPPROTO_IPV6;
3607                 fill_cmd(cmd, O_IP6, 0, 0);
3608         } else if ((*proto = atoi(av)) > 0)
3609                 ; /* all done! */
3610         else if ((pe = getprotobyname(av)) != NULL)
3611                 *proto = pe->p_proto;
3612         else
3613                 return NULL;
3614         if (*proto != IPPROTO_IP && *proto != IPPROTO_IPV6)
3615                 fill_cmd(cmd, O_PROTO, 0, *proto);
3616
3617         return cmd;
3618 }
3619
3620 static ipfw_insn *
3621 add_srcip(ipfw_insn *cmd, char *av)
3622 {
3623         fill_ip((ipfw_insn_ip *)cmd, av);
3624         if (cmd->opcode == O_IP_DST_SET)                        /* set */
3625                 cmd->opcode = O_IP_SRC_SET;
3626         else if (cmd->opcode == O_IP_DST_LOOKUP)                /* table */
3627                 cmd->opcode = O_IP_SRC_LOOKUP;
3628         else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn))          /* me */
3629                 cmd->opcode = O_IP_SRC_ME;
3630         else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32))      /* one IP */
3631                 cmd->opcode = O_IP_SRC;
3632         else                                                    /* addr/mask */
3633                 cmd->opcode = O_IP_SRC_MASK;
3634         return cmd;
3635 }
3636
3637 static ipfw_insn *
3638 add_dstip(ipfw_insn *cmd, char *av)
3639 {
3640         fill_ip((ipfw_insn_ip *)cmd, av);
3641         if (cmd->opcode == O_IP_DST_SET)                        /* set */
3642                 ;
3643         else if (cmd->opcode == O_IP_DST_LOOKUP)                /* table */
3644                 ;
3645         else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn))          /* me */
3646                 cmd->opcode = O_IP_DST_ME;
3647         else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32))      /* one IP */
3648                 cmd->opcode = O_IP_DST;
3649         else                                                    /* addr/mask */
3650                 cmd->opcode = O_IP_DST_MASK;
3651         return cmd;
3652 }
3653
3654 static ipfw_insn *
3655 add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode)
3656 {
3657         if (_substrcmp(av, "any") == 0) {
3658                 return NULL;
3659         } else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto)) {
3660                 /* XXX todo: check that we have a protocol with ports */
3661                 cmd->opcode = opcode;
3662                 return cmd;
3663         }
3664         return NULL;
3665 }
3666
3667 static ipfw_insn *
3668 add_src(ipfw_insn *cmd, char *av, u_char proto)
3669 {
3670         struct in6_addr a;
3671
3672         if (proto == IPPROTO_IPV6  || strcmp(av, "me6") == 0 ||
3673             inet_pton(AF_INET6, av, &a))
3674                 return add_srcip6(cmd, av);
3675         /* XXX: should check for IPv4, not !IPv6 */
3676         if (proto == IPPROTO_IP || strcmp(av, "me") == 0 ||
3677             !inet_pton(AF_INET6, av, &a))
3678                 return add_srcip(cmd, av);
3679         if (strcmp(av, "any") != 0)
3680                 return cmd;
3681
3682         return NULL;
3683 }
3684
3685 static ipfw_insn *
3686 add_dst(ipfw_insn *cmd, char *av, u_char proto)
3687 {
3688         struct in6_addr a;
3689
3690         if (proto == IPPROTO_IPV6  || strcmp(av, "me6") == 0 ||
3691             inet_pton(AF_INET6, av, &a))
3692                 return add_dstip6(cmd, av);
3693         /* XXX: should check for IPv4, not !IPv6 */
3694         if (proto == IPPROTO_IP || strcmp(av, "me") == 0 ||
3695             !inet_pton(AF_INET6, av, &a))
3696                 return add_dstip(cmd, av);
3697         if (strcmp(av, "any") != 0)
3698                 return cmd;
3699
3700         return NULL;
3701 }
3702
3703 /*
3704  * Parse arguments and assemble the microinstructions which make up a rule.
3705  * Rules are added into the 'rulebuf' and then copied in the correct order
3706  * into the actual rule.
3707  *
3708  * The syntax for a rule starts with the action, followed by
3709  * optional action parameters, and the various match patterns.
3710  * In the assembled microcode, the first opcode must be an O_PROBE_STATE
3711  * (generated if the rule includes a keep-state option), then the
3712  * various match patterns, log/altq actions, and the actual action.
3713  *
3714  */
3715 static void
3716 add(int ac, char *av[])
3717 {
3718         /*
3719          * rules are added into the 'rulebuf' and then copied in
3720          * the correct order into the actual rule.
3721          * Some things that need to go out of order (prob, action etc.)
3722          * go into actbuf[].
3723          */
3724         static uint32_t rulebuf[255], actbuf[255], cmdbuf[255];
3725
3726         ipfw_insn *src, *dst, *cmd, *action, *prev=NULL;
3727         ipfw_insn *first_cmd;   /* first match pattern */
3728
3729         struct ip_fw *rule;
3730
3731         /*
3732          * various flags used to record that we entered some fields.
3733          */
3734         ipfw_insn *have_state = NULL;   /* check-state or keep-state */
3735         ipfw_insn *have_log = NULL, *have_altq = NULL;
3736         size_t len;
3737
3738         int i;
3739
3740         int open_par = 0;       /* open parenthesis ( */
3741
3742         /* proto is here because it is used to fetch ports */
3743         u_char proto = IPPROTO_IP;      /* default protocol */
3744
3745         double match_prob = 1; /* match probability, default is always match */
3746
3747         bzero(actbuf, sizeof(actbuf));          /* actions go here */
3748         bzero(cmdbuf, sizeof(cmdbuf));
3749         bzero(rulebuf, sizeof(rulebuf));
3750
3751         rule = (struct ip_fw *)rulebuf;
3752         cmd = (ipfw_insn *)cmdbuf;
3753         action = (ipfw_insn *)actbuf;
3754
3755         av++; ac--;
3756
3757         /* [rule N]     -- Rule number optional */
3758         if (ac && isdigit(**av)) {
3759                 rule->rulenum = atoi(*av);
3760                 av++;
3761                 ac--;
3762         }
3763
3764         /* [set N]      -- set number (0..RESVD_SET), optional */
3765         if (ac > 1 && _substrcmp(*av, "set") == 0) {
3766                 int set = strtoul(av[1], NULL, 10);
3767                 if (set < 0 || set > RESVD_SET)
3768                         errx(EX_DATAERR, "illegal set %s", av[1]);
3769                 rule->set = set;
3770                 av += 2; ac -= 2;
3771         }
3772
3773         /* [prob D]     -- match probability, optional */
3774         if (ac > 1 && _substrcmp(*av, "prob") == 0) {
3775                 match_prob = strtod(av[1], NULL);
3776
3777                 if (match_prob <= 0 || match_prob > 1)
3778                         errx(EX_DATAERR, "illegal match prob. %s", av[1]);
3779                 av += 2; ac -= 2;
3780         }
3781
3782         /* action       -- mandatory */
3783         NEED1("missing action");
3784         i = match_token(rule_actions, *av);
3785         ac--; av++;
3786         action->len = 1;        /* default */
3787         switch(i) {
3788         case TOK_CHECKSTATE:
3789                 have_state = action;
3790                 action->opcode = O_CHECK_STATE;
3791                 break;
3792
3793         case TOK_ACCEPT:
3794                 action->opcode = O_ACCEPT;
3795                 break;
3796
3797         case TOK_DENY:
3798                 action->opcode = O_DENY;
3799                 action->arg1 = 0;
3800                 break;
3801
3802         case TOK_REJECT:
3803                 action->opcode = O_REJECT;
3804                 action->arg1 = ICMP_UNREACH_HOST;
3805                 break;
3806
3807         case TOK_RESET:
3808                 action->opcode = O_REJECT;
3809                 action->arg1 = ICMP_REJECT_RST;
3810                 break;
3811
3812         case TOK_RESET6:
3813                 action->opcode = O_UNREACH6;
3814                 action->arg1 = ICMP6_UNREACH_RST;
3815                 break;
3816
3817         case TOK_UNREACH:
3818                 action->opcode = O_REJECT;
3819                 NEED1("missing reject code");
3820                 fill_reject_code(&action->arg1, *av);
3821                 ac--; av++;
3822                 break;
3823
3824         case TOK_UNREACH6:
3825                 action->opcode = O_UNREACH6;
3826                 NEED1("missing unreach code");
3827                 fill_unreach6_code(&action->arg1, *av);
3828                 ac--; av++;
3829                 break;
3830
3831         case TOK_COUNT:
3832                 action->opcode = O_COUNT;
3833                 break;
3834
3835         case TOK_QUEUE:
3836         case TOK_PIPE:
3837                 action->len = F_INSN_SIZE(ipfw_insn_pipe);
3838         case TOK_SKIPTO:
3839                 if (i == TOK_QUEUE)
3840                         action->opcode = O_QUEUE;
3841                 else if (i == TOK_PIPE)
3842                         action->opcode = O_PIPE;
3843                 else if (i == TOK_SKIPTO)
3844                         action->opcode = O_SKIPTO;
3845                 NEED1("missing skipto/pipe/queue number");
3846                 action->arg1 = strtoul(*av, NULL, 10);
3847                 av++; ac--;
3848                 break;
3849
3850         case TOK_DIVERT:
3851         case TOK_TEE:
3852                 action->opcode = (i == TOK_DIVERT) ? O_DIVERT : O_TEE;
3853                 NEED1("missing divert/tee port");
3854                 action->arg1 = strtoul(*av, NULL, 0);
3855                 if (action->arg1 == 0) {
3856                         struct servent *s;
3857                         setservent(1);
3858                         s = getservbyname(av[0], "divert");
3859                         if (s != NULL)
3860                                 action->arg1 = ntohs(s->s_port);
3861                         else
3862                                 errx(EX_DATAERR, "illegal divert/tee port");
3863                 }
3864                 ac--; av++;
3865                 break;
3866
3867         case TOK_NETGRAPH:
3868         case TOK_NGTEE:
3869                 action->opcode = (i == TOK_NETGRAPH ) ? O_NETGRAPH : O_NGTEE;
3870                 NEED1("missing netgraph cookie");
3871                 action->arg1 = strtoul(*av, NULL, 0);
3872                 if (action->arg1 == 0)
3873                         errx(EX_DATAERR, "illegal netgraph cookie");
3874                 ac--; av++;
3875                 break;
3876
3877         case TOK_FORWARD: {
3878                 ipfw_insn_sa *p = (ipfw_insn_sa *)action;
3879                 char *s, *end;
3880
3881                 NEED1("missing forward address[:port]");
3882
3883                 action->opcode = O_FORWARD_IP;
3884                 action->len = F_INSN_SIZE(ipfw_insn_sa);
3885
3886                 p->sa.sin_len = sizeof(struct sockaddr_in);
3887                 p->sa.sin_family = AF_INET;
3888                 p->sa.sin_port = 0;
3889                 /*
3890                  * locate the address-port separator (':' or ',')
3891                  */
3892                 s = strchr(*av, ':');
3893                 if (s == NULL)
3894                         s = strchr(*av, ',');
3895                 if (s != NULL) {
3896                         *(s++) = '\0';
3897                         i = strtoport(s, &end, 0 /* base */, 0 /* proto */);
3898                         if (s == end)
3899                                 errx(EX_DATAERR,
3900                                     "illegal forwarding port ``%s''", s);
3901                         p->sa.sin_port = (u_short)i;
3902                 }
3903                 lookup_host(*av, &(p->sa.sin_addr));
3904                 }
3905                 ac--; av++;
3906                 break;
3907
3908         case TOK_COMMENT:
3909                 /* pretend it is a 'count' rule followed by the comment */
3910                 action->opcode = O_COUNT;
3911                 ac++; av--;     /* go back... */
3912                 break;
3913
3914         default:
3915                 errx(EX_DATAERR, "invalid action %s\n", av[-1]);
3916         }
3917         action = next_cmd(action);
3918
3919         /*
3920          * [altq queuename] -- altq tag, optional
3921          * [log [logamount N]]  -- log, optional
3922          *
3923          * If they exist, it go first in the cmdbuf, but then it is
3924          * skipped in the copy section to the end of the buffer.
3925          */
3926         while (ac != 0 && (i = match_token(rule_action_params, *av)) != -1) {
3927                 ac--; av++;
3928                 switch (i) {
3929                 case TOK_LOG:
3930                     {
3931                         ipfw_insn_log *c = (ipfw_insn_log *)cmd;
3932                         int l;
3933
3934                         if (have_log)
3935                                 errx(EX_DATAERR,
3936                                     "log cannot be specified more than once");
3937                         have_log = (ipfw_insn *)c;
3938                         cmd->len = F_INSN_SIZE(ipfw_insn_log);
3939                         cmd->opcode = O_LOG;
3940                         if (ac && _substrcmp(*av, "logamount") == 0) {
3941                                 ac--; av++;
3942                                 NEED1("logamount requires argument");
3943                                 l = atoi(*av);
3944                                 if (l < 0)
3945                                         errx(EX_DATAERR,
3946                                             "logamount must be positive");
3947                                 c->max_log = l;
3948                                 ac--; av++;
3949                         } else {
3950                                 len = sizeof(c->max_log);
3951                                 if (sysctlbyname("net.inet.ip.fw.verbose_limit",
3952                                     &c->max_log, &len, NULL, 0) == -1)
3953                                         errx(1, "sysctlbyname(\"%s\")",
3954                                             "net.inet.ip.fw.verbose_limit");
3955                         }
3956                     }
3957                         break;
3958
3959                 case TOK_ALTQ:
3960                     {
3961                         ipfw_insn_altq *a = (ipfw_insn_altq *)cmd;
3962
3963                         NEED1("missing altq queue name");
3964                         if (have_altq)
3965                                 errx(EX_DATAERR,
3966                                     "altq cannot be specified more than once");
3967                         have_altq = (ipfw_insn *)a;
3968                         cmd->len = F_INSN_SIZE(ipfw_insn_altq);
3969                         cmd->opcode = O_ALTQ;
3970                         fill_altq_qid(&a->qid, *av);
3971                         ac--; av++;
3972                     }
3973                         break;
3974
3975                 default:
3976                         abort();
3977                 }
3978                 cmd = next_cmd(cmd);
3979         }
3980
3981         if (have_state) /* must be a check-state, we are done */
3982                 goto done;
3983
3984 #define OR_START(target)                                        \
3985         if (ac && (*av[0] == '(' || *av[0] == '{')) {           \
3986                 if (open_par)                                   \
3987                         errx(EX_USAGE, "nested \"(\" not allowed\n"); \
3988                 prev = NULL;                                    \
3989                 open_par = 1;                                   \
3990                 if ( (av[0])[1] == '\0') {                      \
3991                         ac--; av++;                             \
3992                 } else                                          \
3993                         (*av)++;                                \
3994         }                                                       \
3995         target:                                                 \
3996
3997
3998 #define CLOSE_PAR                                               \
3999         if (open_par) {                                         \
4000                 if (ac && (                                     \
4001                     strcmp(*av, ")") == 0 ||                    \
4002                     strcmp(*av, "}") == 0)) {                   \
4003                         prev = NULL;                            \
4004                         open_par = 0;                           \
4005                         ac--; av++;                             \
4006                 } else                                          \
4007                         errx(EX_USAGE, "missing \")\"\n");      \
4008         }
4009
4010 #define NOT_BLOCK                                               \
4011         if (ac && _substrcmp(*av, "not") == 0) {                \
4012                 if (cmd->len & F_NOT)                           \
4013                         errx(EX_USAGE, "double \"not\" not allowed\n"); \
4014                 cmd->len |= F_NOT;                              \
4015                 ac--; av++;                                     \
4016         }
4017
4018 #define OR_BLOCK(target)                                        \
4019         if (ac && _substrcmp(*av, "or") == 0) {         \
4020                 if (prev == NULL || open_par == 0)              \
4021                         errx(EX_DATAERR, "invalid OR block");   \
4022                 prev->len |= F_OR;                              \
4023                 ac--; av++;                                     \
4024                 goto target;                                    \
4025         }                                                       \
4026         CLOSE_PAR;
4027
4028         first_cmd = cmd;
4029
4030 #if 0
4031         /*
4032          * MAC addresses, optional.
4033          * If we have this, we skip the part "proto from src to dst"
4034          * and jump straight to the option parsing.
4035          */
4036         NOT_BLOCK;
4037         NEED1("missing protocol");
4038         if (_substrcmp(*av, "MAC") == 0 ||
4039             _substrcmp(*av, "mac") == 0) {
4040                 ac--; av++;     /* the "MAC" keyword */
4041                 add_mac(cmd, ac, av); /* exits in case of errors */
4042                 cmd = next_cmd(cmd);
4043                 ac -= 2; av += 2;       /* dst-mac and src-mac */
4044                 NOT_BLOCK;
4045                 NEED1("missing mac type");
4046                 if (add_mactype(cmd, ac, av[0]))
4047                         cmd = next_cmd(cmd);
4048                 ac--; av++;     /* any or mac-type */
4049                 goto read_options;
4050         }
4051 #endif
4052
4053         /*
4054          * protocol, mandatory
4055          */
4056     OR_START(get_proto);
4057         NOT_BLOCK;
4058         NEED1("missing protocol");
4059         if (add_proto(cmd, *av, &proto)) {
4060                 av++; ac--;
4061                 if (F_LEN(cmd) != 0) {
4062                         prev = cmd;
4063                         cmd = next_cmd(cmd);
4064                 }
4065         } else if (first_cmd != cmd) {
4066                 errx(EX_DATAERR, "invalid protocol ``%s''", *av);
4067         } else
4068                 goto read_options;
4069     OR_BLOCK(get_proto);
4070
4071         /*
4072          * "from", mandatory
4073          */
4074         if (!ac || _substrcmp(*av, "from") != 0)
4075                 errx(EX_USAGE, "missing ``from''");
4076         ac--; av++;
4077
4078         /*
4079          * source IP, mandatory
4080          */
4081     OR_START(source_ip);
4082         NOT_BLOCK;      /* optional "not" */
4083         NEED1("missing source address");
4084         if (add_src(cmd, *av, proto)) {
4085                 ac--; av++;
4086                 if (F_LEN(cmd) != 0) {  /* ! any */
4087                         prev = cmd;
4088                         cmd = next_cmd(cmd);
4089                 }
4090         } else
4091                 errx(EX_USAGE, "bad source address %s", *av);
4092     OR_BLOCK(source_ip);
4093
4094         /*
4095          * source ports, optional
4096          */
4097         NOT_BLOCK;      /* optional "not" */
4098         if (ac) {
4099                 if (_substrcmp(*av, "any") == 0 ||
4100                     add_ports(cmd, *av, proto, O_IP_SRCPORT)) {
4101                         ac--; av++;
4102                         if (F_LEN(cmd) != 0)
4103                                 cmd = next_cmd(cmd);
4104                 }
4105         }
4106
4107         /*
4108          * "to", mandatory
4109          */
4110         if (!ac || _substrcmp(*av, "to") != 0)
4111                 errx(EX_USAGE, "missing ``to''");
4112         av++; ac--;
4113
4114         /*
4115          * destination, mandatory
4116          */
4117     OR_START(dest_ip);
4118         NOT_BLOCK;      /* optional "not" */
4119         NEED1("missing dst address");
4120         if (add_dst(cmd, *av, proto)) {
4121                 ac--; av++;
4122                 if (F_LEN(cmd) != 0) {  /* ! any */
4123                         prev = cmd;
4124                         cmd = next_cmd(cmd);
4125                 }
4126         } else
4127                 errx( EX_USAGE, "bad destination address %s", *av);
4128     OR_BLOCK(dest_ip);
4129
4130         /*
4131          * dest. ports, optional
4132          */
4133         NOT_BLOCK;      /* optional "not" */
4134         if (ac) {
4135                 if (_substrcmp(*av, "any") == 0 ||
4136                     add_ports(cmd, *av, proto, O_IP_DSTPORT)) {
4137                         ac--; av++;
4138                         if (F_LEN(cmd) != 0)
4139                                 cmd = next_cmd(cmd);
4140                 }
4141         }
4142
4143 read_options:
4144         if (ac && first_cmd == cmd) {
4145                 /*
4146                  * nothing specified so far, store in the rule to ease
4147                  * printout later.
4148                  */
4149                  rule->_pad = 1;
4150         }
4151         prev = NULL;
4152         while (ac) {
4153                 char *s;
4154                 ipfw_insn_u32 *cmd32;   /* alias for cmd */
4155
4156                 s = *av;
4157                 cmd32 = (ipfw_insn_u32 *)cmd;
4158
4159                 if (*s == '!') {        /* alternate syntax for NOT */
4160                         if (cmd->len & F_NOT)
4161                                 errx(EX_USAGE, "double \"not\" not allowed\n");
4162                         cmd->len = F_NOT;
4163                         s++;
4164                 }
4165                 i = match_token(rule_options, s);
4166                 ac--; av++;
4167                 switch(i) {
4168                 case TOK_NOT:
4169                         if (cmd->len & F_NOT)
4170                                 errx(EX_USAGE, "double \"not\" not allowed\n");
4171                         cmd->len = F_NOT;
4172                         break;
4173
4174                 case TOK_OR:
4175                         if (open_par == 0 || prev == NULL)
4176                                 errx(EX_USAGE, "invalid \"or\" block\n");
4177                         prev->len |= F_OR;
4178                         break;
4179
4180                 case TOK_STARTBRACE:
4181                         if (open_par)
4182                                 errx(EX_USAGE, "+nested \"(\" not allowed\n");
4183                         open_par = 1;
4184                         break;
4185
4186                 case TOK_ENDBRACE:
4187                         if (!open_par)
4188                                 errx(EX_USAGE, "+missing \")\"\n");
4189                         open_par = 0;
4190                         prev = NULL;
4191                         break;
4192
4193                 case TOK_IN:
4194                         fill_cmd(cmd, O_IN, 0, 0);
4195                         break;
4196
4197                 case TOK_OUT:
4198                         cmd->len ^= F_NOT; /* toggle F_NOT */
4199                         fill_cmd(cmd, O_IN, 0, 0);
4200                         break;
4201
4202                 case TOK_DIVERTED:
4203                         fill_cmd(cmd, O_DIVERTED, 0, 3);
4204                         break;
4205
4206                 case TOK_DIVERTEDLOOPBACK:
4207                         fill_cmd(cmd, O_DIVERTED, 0, 1);
4208                         break;
4209
4210                 case TOK_DIVERTEDOUTPUT:
4211                         fill_cmd(cmd, O_DIVERTED, 0, 2);
4212                         break;
4213
4214                 case TOK_FRAG:
4215                         fill_cmd(cmd, O_FRAG, 0, 0);
4216                         break;
4217
4218                 case TOK_LAYER2:
4219                         fill_cmd(cmd, O_LAYER2, 0, 0);
4220                         break;
4221
4222                 case TOK_XMIT:
4223                 case TOK_RECV:
4224                 case TOK_VIA:
4225                         NEED1("recv, xmit, via require interface name"
4226                                 " or address");
4227                         fill_iface((ipfw_insn_if *)cmd, av[0]);
4228                         ac--; av++;
4229                         if (F_LEN(cmd) == 0)    /* not a valid address */
4230                                 break;
4231                         if (i == TOK_XMIT)
4232                                 cmd->opcode = O_XMIT;
4233                         else if (i == TOK_RECV)
4234                                 cmd->opcode = O_RECV;
4235                         else if (i == TOK_VIA)
4236                                 cmd->opcode = O_VIA;
4237                         break;
4238
4239                 case TOK_ICMPTYPES:
4240                         NEED1("icmptypes requires list of types");
4241                         fill_icmptypes((ipfw_insn_u32 *)cmd, *av);
4242                         av++; ac--;
4243                         break;
4244                 
4245                 case TOK_ICMP6TYPES:
4246                         NEED1("icmptypes requires list of types");
4247                         fill_icmp6types((ipfw_insn_icmp6 *)cmd, *av);
4248                         av++; ac--;
4249                         break;
4250
4251                 case TOK_IPTTL:
4252                         NEED1("ipttl requires TTL");
4253                         if (strpbrk(*av, "-,")) {
4254                             if (!add_ports(cmd, *av, 0, O_IPTTL))
4255                                 errx(EX_DATAERR, "invalid ipttl %s", *av);
4256                         } else
4257                             fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0));
4258                         ac--; av++;
4259                         break;
4260
4261                 case TOK_IPID:
4262                         NEED1("ipid requires id");
4263                         if (strpbrk(*av, "-,")) {
4264                             if (!add_ports(cmd, *av, 0, O_IPID))
4265                                 errx(EX_DATAERR, "invalid ipid %s", *av);
4266                         } else
4267                             fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0));
4268                         ac--; av++;
4269                         break;
4270
4271                 case TOK_IPLEN:
4272                         NEED1("iplen requires length");
4273                         if (strpbrk(*av, "-,")) {
4274                             if (!add_ports(cmd, *av, 0, O_IPLEN))
4275                                 errx(EX_DATAERR, "invalid ip len %s", *av);
4276                         } else
4277                             fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0));
4278                         ac--; av++;
4279                         break;
4280
4281                 case TOK_IPVER:
4282                         NEED1("ipver requires version");
4283                         fill_cmd(cmd, O_IPVER, 0, strtoul(*av, NULL, 0));
4284                         ac--; av++;
4285                         break;
4286
4287                 case TOK_IPPRECEDENCE:
4288                         NEED1("ipprecedence requires value");
4289                         fill_cmd(cmd, O_IPPRECEDENCE, 0,
4290                             (strtoul(*av, NULL, 0) & 7) << 5);
4291                         ac--; av++;
4292                         break;
4293
4294                 case TOK_IPOPTS:
4295                         NEED1("missing argument for ipoptions");
4296                         fill_flags(cmd, O_IPOPT, f_ipopts, *av);
4297                         ac--; av++;
4298                         break;
4299
4300                 case TOK_IPTOS:
4301                         NEED1("missing argument for iptos");
4302                         fill_flags(cmd, O_IPTOS, f_iptos, *av);
4303                         ac--; av++;
4304                         break;
4305
4306                 case TOK_UID:
4307                         NEED1("uid requires argument");
4308                     {
4309                         char *end;
4310                         uid_t uid;
4311                         struct passwd *pwd;
4312
4313                         cmd->opcode = O_UID;
4314                         uid = strtoul(*av, &end, 0);
4315                         pwd = (*end == '\0') ? getpwuid(uid) : getpwnam(*av);
4316                         if (pwd == NULL)
4317                                 errx(EX_DATAERR, "uid \"%s\" nonexistent", *av);
4318                         cmd32->d[0] = pwd->pw_uid;
4319                         cmd->len |= F_INSN_SIZE(ipfw_insn_u32);
4320                         ac--; av++;
4321                     }
4322                         break;
4323
4324                 case TOK_GID:
4325                         NEED1("gid requires argument");
4326                     {
4327                         char *end;
4328                         gid_t gid;
4329                         struct group *grp;
4330
4331                         cmd->opcode = O_GID;
4332                         gid = strtoul(*av, &end, 0);
4333                         grp = (*end == '\0') ? getgrgid(gid) : getgrnam(*av);
4334                         if (grp == NULL)
4335                                 errx(EX_DATAERR, "gid \"%s\" nonexistent", *av);
4336                         cmd32->d[0] = grp->gr_gid;
4337                         cmd->len |= F_INSN_SIZE(ipfw_insn_u32);
4338                         ac--; av++;
4339                     }
4340                         break;
4341
4342                 case TOK_JAIL:
4343                         NEED1("jail requires argument");
4344                     {
4345                         char *end;
4346                         int jid;
4347
4348                         cmd->opcode = O_JAIL;
4349                         jid = (int)strtol(*av, &end, 0);
4350                         if (jid < 0 || *end != '\0')
4351                                 errx(EX_DATAERR, "jail requires prison ID");
4352                         cmd32->d[0] = (uint32_t)jid;
4353                         cmd->len |= F_INSN_SIZE(ipfw_insn_u32);
4354                         ac--; av++;
4355                     }
4356                         break;
4357
4358                 case TOK_ESTAB:
4359                         fill_cmd(cmd, O_ESTAB, 0, 0);
4360                         break;
4361
4362                 case TOK_SETUP:
4363                         fill_cmd(cmd, O_TCPFLAGS, 0,
4364                                 (TH_SYN) | ( (TH_ACK) & 0xff) <<8 );
4365                         break;
4366
4367                 case TOK_TCPDATALEN:
4368                         NEED1("tcpdatalen requires length");
4369                         if (strpbrk(*av, "-,")) {
4370                             if (!add_ports(cmd, *av, 0, O_TCPDATALEN))
4371                                 errx(EX_DATAERR, "invalid tcpdata len %s", *av);
4372                         } else
4373                             fill_cmd(cmd, O_TCPDATALEN, 0,
4374                                     strtoul(*av, NULL, 0));
4375                         ac--; av++;
4376                         break;
4377
4378                 case TOK_TCPOPTS:
4379                         NEED1("missing argument for tcpoptions");
4380                         fill_flags(cmd, O_TCPOPTS, f_tcpopts, *av);
4381                         ac--; av++;
4382                         break;
4383
4384                 case TOK_TCPSEQ:
4385                 case TOK_TCPACK:
4386                         NEED1("tcpseq/tcpack requires argument");
4387                         cmd->len = F_INSN_SIZE(ipfw_insn_u32);
4388                         cmd->opcode = (i == TOK_TCPSEQ) ? O_TCPSEQ : O_TCPACK;
4389                         cmd32->d[0] = htonl(strtoul(*av, NULL, 0));
4390                         ac--; av++;
4391                         break;
4392
4393                 case TOK_TCPWIN:
4394                         NEED1("tcpwin requires length");
4395                         fill_cmd(cmd, O_TCPWIN, 0,
4396                             htons(strtoul(*av, NULL, 0)));
4397                         ac--; av++;
4398                         break;
4399
4400                 case TOK_TCPFLAGS:
4401                         NEED1("missing argument for tcpflags");
4402                         cmd->opcode = O_TCPFLAGS;
4403                         fill_flags(cmd, O_TCPFLAGS, f_tcpflags, *av);
4404                         ac--; av++;
4405                         break;
4406
4407                 case TOK_KEEPSTATE:
4408                         if (open_par)
4409                                 errx(EX_USAGE, "keep-state cannot be part "
4410                                     "of an or block");
4411                         if (have_state)
4412                                 errx(EX_USAGE, "only one of keep-state "
4413                                         "and limit is allowed");
4414                         have_state = cmd;
4415                         fill_cmd(cmd, O_KEEP_STATE, 0, 0);
4416                         break;
4417
4418                 case TOK_LIMIT:
4419                         if (open_par)
4420                                 errx(EX_USAGE, "limit cannot be part "
4421                                     "of an or block");
4422                         if (have_state)
4423                                 errx(EX_USAGE, "only one of keep-state "
4424                                         "and limit is allowed");
4425                         NEED1("limit needs mask and # of connections");
4426                         have_state = cmd;
4427                     {
4428                         ipfw_insn_limit *c = (ipfw_insn_limit *)cmd;
4429
4430                         cmd->len = F_INSN_SIZE(ipfw_insn_limit);
4431                         cmd->opcode = O_LIMIT;
4432                         c->limit_mask = 0;
4433                         c->conn_limit = 0;
4434                         for (; ac >1 ;) {
4435                                 int val;
4436
4437                                 val = match_token(limit_masks, *av);
4438                                 if (val <= 0)
4439                                         break;
4440                                 c->limit_mask |= val;
4441                                 ac--; av++;
4442                         }
4443                         c->conn_limit = atoi(*av);
4444                         if (c->conn_limit == 0)
4445                                 errx(EX_USAGE, "limit: limit must be >0");
4446                         if (c->limit_mask == 0)
4447                                 errx(EX_USAGE, "missing limit mask");
4448                         ac--; av++;
4449                     }
4450                         break;
4451
4452                 case TOK_PROTO:
4453                         NEED1("missing protocol");
4454                         if (add_proto(cmd, *av, &proto)) {
4455                                 ac--; av++;
4456                         } else
4457                                 errx(EX_DATAERR, "invalid protocol ``%s''",
4458                                     *av);
4459                         break;
4460
4461                 case TOK_SRCIP:
4462                         NEED1("missing source IP");
4463                         if (add_srcip(cmd, *av)) {
4464                                 ac--; av++;
4465                         }
4466                         break;
4467
4468                 case TOK_DSTIP:
4469                         NEED1("missing destination IP");
4470                         if (add_dstip(cmd, *av)) {
4471                                 ac--; av++;
4472                         }
4473                         break;
4474
4475                 case TOK_SRCIP6:
4476                         NEED1("missing source IP6");
4477                         if (add_srcip6(cmd, *av)) {
4478                                 ac--; av++;
4479                         }
4480                         break;
4481                                 
4482                 case TOK_DSTIP6:
4483                         NEED1("missing destination IP6");
4484                         if (add_dstip6(cmd, *av)) {
4485                                 ac--; av++;
4486                         }
4487                         break;
4488
4489                 case TOK_SRCPORT:
4490                         NEED1("missing source port");
4491                         if (_substrcmp(*av, "any") == 0 ||
4492                             add_ports(cmd, *av, proto, O_IP_SRCPORT)) {
4493                                 ac--; av++;
4494                         } else
4495                                 errx(EX_DATAERR, "invalid source port %s", *av);
4496                         break;
4497
4498                 case TOK_DSTPORT:
4499                         NEED1("missing destination port");
4500                         if (_substrcmp(*av, "any") == 0 ||
4501                             add_ports(cmd, *av, proto, O_IP_DSTPORT)) {
4502                                 ac--; av++;
4503                         } else
4504                                 errx(EX_DATAERR, "invalid destination port %s",
4505                                     *av);
4506                         break;
4507
4508                 case TOK_MAC:
4509                         if (add_mac(cmd, ac, av)) {
4510                                 ac -= 2; av += 2;
4511                         }
4512                         break;
4513
4514                 case TOK_MACTYPE:
4515                         NEED1("missing mac type");
4516                         if (!add_mactype(cmd, ac, *av))
4517                                 errx(EX_DATAERR, "invalid mac type %s", *av);
4518                         ac--; av++;
4519                         break;
4520
4521                 case TOK_VERREVPATH:
4522                         fill_cmd(cmd, O_VERREVPATH, 0, 0);
4523                         break;
4524
4525                 case TOK_VERSRCREACH:
4526                         fill_cmd(cmd, O_VERSRCREACH, 0, 0);
4527                         break;
4528
4529                 case TOK_ANTISPOOF:
4530                         fill_cmd(cmd, O_ANTISPOOF, 0, 0);
4531                         break;
4532
4533                 case TOK_IPSEC:
4534                         fill_cmd(cmd, O_IPSEC, 0, 0);
4535                         break;
4536
4537                 case TOK_IPV6:
4538                         fill_cmd(cmd, O_IP6, 0, 0);
4539                         break;
4540
4541                 case TOK_IPV4:
4542                         fill_cmd(cmd, O_IP4, 0, 0);
4543                         break;
4544
4545                 case TOK_EXT6HDR:
4546                         fill_ext6hdr( cmd, *av );
4547                         ac--; av++;
4548                         break;
4549
4550                 case TOK_FLOWID:
4551                         if (proto != IPPROTO_IPV6 )
4552                                 errx( EX_USAGE, "flow-id filter is active "
4553                                     "only for ipv6 protocol\n");
4554                         fill_flow6( (ipfw_insn_u32 *) cmd, *av );
4555                         ac--; av++;
4556                         break;
4557
4558                 case TOK_COMMENT:
4559                         fill_comment(cmd, ac, av);
4560                         av += ac;
4561                         ac = 0;
4562                         break;
4563
4564                 default:
4565                         errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s);
4566                 }
4567                 if (F_LEN(cmd) > 0) {   /* prepare to advance */
4568                         prev = cmd;
4569                         cmd = next_cmd(cmd);
4570                 }
4571         }
4572
4573 done:
4574         /*
4575          * Now copy stuff into the rule.
4576          * If we have a keep-state option, the first instruction
4577          * must be a PROBE_STATE (which is generated here).
4578          * If we have a LOG option, it was stored as the first command,
4579          * and now must be moved to the top of the action part.
4580          */
4581         dst = (ipfw_insn *)rule->cmd;
4582
4583         /*
4584          * First thing to write into the command stream is the match probability.
4585          */
4586         if (match_prob != 1) { /* 1 means always match */
4587                 dst->opcode = O_PROB;
4588                 dst->len = 2;
4589                 *((int32_t *)(dst+1)) = (int32_t)(match_prob * 0x7fffffff);
4590                 dst += dst->len;
4591         }
4592
4593         /*
4594          * generate O_PROBE_STATE if necessary
4595          */
4596         if (have_state && have_state->opcode != O_CHECK_STATE) {
4597                 fill_cmd(dst, O_PROBE_STATE, 0, 0);
4598                 dst = next_cmd(dst);
4599         }
4600         /*
4601          * copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT, O_ALTQ
4602          */
4603         for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) {
4604                 i = F_LEN(src);
4605
4606                 switch (src->opcode) {
4607                 case O_LOG:
4608                 case O_KEEP_STATE:
4609                 case O_LIMIT:
4610                 case O_ALTQ:
4611                         break;
4612                 default:
4613                         bcopy(src, dst, i * sizeof(uint32_t));
4614                         dst += i;
4615                 }
4616         }
4617
4618         /*
4619          * put back the have_state command as last opcode
4620          */
4621         if (have_state && have_state->opcode != O_CHECK_STATE) {
4622                 i = F_LEN(have_state);
4623                 bcopy(have_state, dst, i * sizeof(uint32_t));
4624                 dst += i;
4625         }
4626         /*
4627          * start action section
4628          */
4629         rule->act_ofs = dst - rule->cmd;
4630
4631         /*
4632          * put back O_LOG, O_ALTQ if necessary
4633          */
4634         if (have_log) {
4635                 i = F_LEN(have_log);
4636                 bcopy(have_log, dst, i * sizeof(uint32_t));
4637                 dst += i;
4638         }
4639         if (have_altq) {
4640                 i = F_LEN(have_altq);
4641                 bcopy(have_altq, dst, i * sizeof(uint32_t));
4642                 dst += i;
4643         }
4644         /*
4645          * copy all other actions
4646          */
4647         for (src = (ipfw_insn *)actbuf; src != action; src += i) {
4648                 i = F_LEN(src);
4649                 bcopy(src, dst, i * sizeof(uint32_t));
4650                 dst += i;
4651         }
4652
4653         rule->cmd_len = (uint32_t *)dst - (uint32_t *)(rule->cmd);
4654         i = (char *)dst - (char *)rule;
4655         if (do_cmd(IP_FW_ADD, rule, (uintptr_t)&i) == -1)
4656                 err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD");
4657         if (!do_quiet)
4658                 show_ipfw(rule, 0, 0);
4659 }
4660
4661 static void
4662 zero(int ac, char *av[], int optname /* IP_FW_ZERO or IP_FW_RESETLOG */)
4663 {
4664         int rulenum;
4665         int failed = EX_OK;
4666         char const *name = optname == IP_FW_ZERO ?  "ZERO" : "RESETLOG";
4667
4668         av++; ac--;
4669
4670         if (!ac) {
4671                 /* clear all entries */
4672                 if (do_cmd(optname, NULL, 0) < 0)
4673                         err(EX_UNAVAILABLE, "setsockopt(IP_FW_%s)", name);
4674                 if (!do_quiet)
4675                         printf("%s.\n", optname == IP_FW_ZERO ?
4676                             "Accounting cleared":"Logging counts reset");
4677
4678                 return;
4679         }
4680
4681         while (ac) {
4682                 /* Rule number */
4683                 if (isdigit(**av)) {
4684                         rulenum = atoi(*av);
4685                         av++;
4686                         ac--;
4687                         if (do_cmd(optname, &rulenum, sizeof rulenum)) {
4688                                 warn("rule %u: setsockopt(IP_FW_%s)",
4689                                     rulenum, name);
4690                                 failed = EX_UNAVAILABLE;
4691                         } else if (!do_quiet)
4692                                 printf("Entry %d %s.\n", rulenum,
4693                                     optname == IP_FW_ZERO ?
4694                                         "cleared" : "logging count reset");
4695                 } else {
4696                         errx(EX_USAGE, "invalid rule number ``%s''", *av);
4697                 }
4698         }
4699         if (failed != EX_OK)
4700                 exit(failed);
4701 }
4702
4703 static void
4704 flush(int force)
4705 {
4706         int cmd = do_pipe ? IP_DUMMYNET_FLUSH : IP_FW_FLUSH;
4707
4708         if (!force && !do_quiet) { /* need to ask user */
4709                 int c;
4710
4711                 printf("Are you sure? [yn] ");
4712                 fflush(stdout);
4713                 do {
4714                         c = toupper(getc(stdin));
4715                         while (c != '\n' && getc(stdin) != '\n')
4716                                 if (feof(stdin))
4717                                         return; /* and do not flush */
4718                 } while (c != 'Y' && c != 'N');
4719                 printf("\n");
4720                 if (c == 'N')   /* user said no */
4721                         return;
4722         }
4723         if (do_cmd(cmd, NULL, 0) < 0)
4724                 err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)",
4725                     do_pipe ? "DUMMYNET" : "FW");
4726         if (!do_quiet)
4727                 printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules");
4728 }
4729
4730 /*
4731  * Free a the (locally allocated) copy of command line arguments.
4732  */
4733 static void
4734 free_args(int ac, char **av)
4735 {
4736         int i;
4737
4738         for (i=0; i < ac; i++)
4739                 free(av[i]);
4740         free(av);
4741 }
4742
4743 /*
4744  * This one handles all table-related commands
4745  *      ipfw table N add addr[/masklen] [value]
4746  *      ipfw table N delete addr[/masklen]
4747  *      ipfw table N flush
4748  *      ipfw table N list
4749  */
4750 static void
4751 table_handler(int ac, char *av[])
4752 {
4753         ipfw_table_entry ent;
4754         ipfw_table *tbl;
4755         int do_add;
4756         char *p;
4757         socklen_t l;
4758         uint32_t a;
4759
4760         ac--; av++;
4761         if (ac && isdigit(**av)) {
4762                 ent.tbl = atoi(*av);
4763                 ac--; av++;
4764         } else
4765                 errx(EX_USAGE, "table number required");
4766         NEED1("table needs command");
4767         if (_substrcmp(*av, "add") == 0 ||
4768             _substrcmp(*av, "delete") == 0) {
4769                 do_add = **av == 'a';
4770                 ac--; av++;
4771                 if (!ac)
4772                         errx(EX_USAGE, "IP address required");
4773                 p = strchr(*av, '/');
4774                 if (p) {
4775                         *p++ = '\0';
4776                         ent.masklen = atoi(p);
4777                         if (ent.masklen > 32)
4778                                 errx(EX_DATAERR, "bad width ``%s''", p);
4779                 } else
4780                         ent.masklen = 32;
4781                 if (lookup_host(*av, (struct in_addr *)&ent.addr) != 0)
4782                         errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
4783                 ac--; av++;
4784                 if (do_add && ac)
4785                         ent.value = strtoul(*av, NULL, 0);
4786                 else
4787                         ent.value = 0;
4788                 if (do_cmd(do_add ? IP_FW_TABLE_ADD : IP_FW_TABLE_DEL,
4789                     &ent, sizeof(ent)) < 0)
4790                         err(EX_OSERR, "setsockopt(IP_FW_TABLE_%s)",
4791                             do_add ? "ADD" : "DEL");
4792         } else if (_substrcmp(*av, "flush") == 0) {
4793                 if (do_cmd(IP_FW_TABLE_FLUSH, &ent.tbl, sizeof(ent.tbl)) < 0)
4794                         err(EX_OSERR, "setsockopt(IP_FW_TABLE_FLUSH)");
4795         } else if (_substrcmp(*av, "list") == 0) {
4796                 a = ent.tbl;
4797                 l = sizeof(a);
4798                 if (do_cmd(IP_FW_TABLE_GETSIZE, &a, (uintptr_t)&l) < 0)
4799                         err(EX_OSERR, "getsockopt(IP_FW_TABLE_GETSIZE)");
4800                 l = sizeof(*tbl) + a * sizeof(ipfw_table_entry);
4801                 tbl = malloc(l);
4802                 if (tbl == NULL)
4803                         err(EX_OSERR, "malloc");
4804                 tbl->tbl = ent.tbl;
4805                 if (do_cmd(IP_FW_TABLE_LIST, tbl, (uintptr_t)&l) < 0)
4806                         err(EX_OSERR, "getsockopt(IP_FW_TABLE_LIST)");
4807                 for (a = 0; a < tbl->cnt; a++) {
4808                         printf("%s/%u %u\n",
4809                             inet_ntoa(*(struct in_addr *)&tbl->ent[a].addr),
4810                             tbl->ent[a].masklen, tbl->ent[a].value);
4811                 }
4812         } else
4813                 errx(EX_USAGE, "invalid table command %s", *av);
4814 }
4815
4816 /*
4817  * Called with the arguments (excluding program name).
4818  * Returns 0 if successful, 1 if empty command, errx() in case of errors.
4819  */
4820 static int
4821 ipfw_main(int oldac, char **oldav)
4822 {
4823         int ch, ac, save_ac;
4824         char **av, **save_av;
4825         int do_acct = 0;                /* Show packet/byte count */
4826
4827 #define WHITESP         " \t\f\v\n\r"
4828         if (oldac == 0)
4829                 return 1;
4830         else if (oldac == 1) {
4831                 /*
4832                  * If we are called with a single string, try to split it into
4833                  * arguments for subsequent parsing.
4834                  * But first, remove spaces after a ',', by copying the string
4835                  * in-place.
4836                  */
4837                 char *arg = oldav[0];   /* The string... */
4838                 int l = strlen(arg);
4839                 int copy = 0;           /* 1 if we need to copy, 0 otherwise */
4840                 int i, j;
4841                 for (i = j = 0; i < l; i++) {
4842                         if (arg[i] == '#')      /* comment marker */
4843                                 break;
4844                         if (copy) {
4845                                 arg[j++] = arg[i];
4846                                 copy = !index("," WHITESP, arg[i]);
4847                         } else {
4848                                 copy = !index(WHITESP, arg[i]);
4849                                 if (copy)
4850                                         arg[j++] = arg[i];
4851                         }
4852                 }
4853                 if (!copy && j > 0)     /* last char was a 'blank', remove it */
4854                         j--;
4855                 l = j;                  /* the new argument length */
4856                 arg[j++] = '\0';
4857                 if (l == 0)             /* empty string! */
4858                         return 1;
4859
4860                 /*
4861                  * First, count number of arguments. Because of the previous
4862                  * processing, this is just the number of blanks plus 1.
4863                  */
4864                 for (i = 0, ac = 1; i < l; i++)
4865                         if (index(WHITESP, arg[i]) != NULL)
4866                                 ac++;
4867
4868                 av = calloc(ac, sizeof(char *));
4869
4870                 /*
4871                  * Second, copy arguments from cmd[] to av[]. For each one,
4872                  * j is the initial character, i is the one past the end.
4873                  */
4874                 for (ac = 0, i = j = 0; i < l; i++)
4875                         if (index(WHITESP, arg[i]) != NULL || i == l-1) {
4876                                 if (i == l-1)
4877                                         i++;
4878                                 av[ac] = calloc(i-j+1, 1);
4879                                 bcopy(arg+j, av[ac], i-j);
4880                                 ac++;
4881                                 j = i + 1;
4882                         }
4883         } else {
4884                 /*
4885                  * If an argument ends with ',' join with the next one.
4886                  */
4887                 int first, i, l;
4888
4889                 av = calloc(oldac, sizeof(char *));
4890                 for (first = i = ac = 0, l = 0; i < oldac; i++) {
4891                         char *arg = oldav[i];
4892                         int k = strlen(arg);
4893
4894                         l += k;
4895                         if (arg[k-1] != ',' || i == oldac-1) {
4896                                 /* Time to copy. */
4897                                 av[ac] = calloc(l+1, 1);
4898                                 for (l=0; first <= i; first++) {
4899                                         strcat(av[ac]+l, oldav[first]);
4900                                         l += strlen(oldav[first]);
4901                                 }
4902                                 ac++;
4903                                 l = 0;
4904                                 first = i+1;
4905                         }
4906                 }
4907         }
4908
4909         /* Set the force flag for non-interactive processes */
4910         if (!do_force)
4911                 do_force = !isatty(STDIN_FILENO);
4912
4913         /* Save arguments for final freeing of memory. */
4914         save_ac = ac;
4915         save_av = av;
4916
4917         optind = optreset = 0;
4918         while ((ch = getopt(ac, av, "abcdefhnNqs:STtv")) != -1)
4919                 switch (ch) {
4920                 case 'a':
4921                         do_acct = 1;
4922                         break;
4923
4924                 case 'b':
4925                         comment_only = 1;
4926                         do_compact = 1;
4927                         break;
4928
4929                 case 'c':
4930                         do_compact = 1;
4931                         break;
4932
4933                 case 'd':
4934                         do_dynamic = 1;
4935                         break;
4936
4937                 case 'e':
4938                         do_expired = 1;
4939                         break;
4940
4941                 case 'f':
4942                         do_force = 1;
4943                         break;
4944
4945                 case 'h': /* help */
4946                         free_args(save_ac, save_av);
4947                         help();
4948                         break;  /* NOTREACHED */
4949
4950                 case 'n':
4951                         test_only = 1;
4952                         break;
4953
4954                 case 'N':
4955                         do_resolv = 1;
4956                         break;
4957
4958                 case 'q':
4959                         do_quiet = 1;
4960                         break;
4961
4962                 case 's': /* sort */
4963                         do_sort = atoi(optarg);
4964                         break;
4965
4966                 case 'S':
4967                         show_sets = 1;
4968                         break;
4969
4970                 case 't':
4971                         do_time = 1;
4972                         break;
4973
4974                 case 'T':
4975                         do_time = 2;    /* numeric timestamp */
4976                         break;
4977
4978                 case 'v': /* verbose */
4979                         verbose = 1;
4980                         break;
4981
4982                 default:
4983                         free_args(save_ac, save_av);
4984                         return 1;
4985                 }
4986
4987         ac -= optind;
4988         av += optind;
4989         NEED1("bad arguments, for usage summary ``ipfw''");
4990
4991         /*
4992          * An undocumented behaviour of ipfw1 was to allow rule numbers first,
4993          * e.g. "100 add allow ..." instead of "add 100 allow ...".
4994          * In case, swap first and second argument to get the normal form.
4995          */
4996         if (ac > 1 && isdigit(*av[0])) {
4997                 char *p = av[0];
4998
4999                 av[0] = av[1];
5000                 av[1] = p;
5001         }
5002
5003         /*
5004          * optional: pipe or queue
5005          */
5006         do_pipe = 0;
5007         if (_substrcmp(*av, "pipe") == 0)
5008                 do_pipe = 1;
5009         else if (_substrcmp(*av, "queue") == 0)
5010                 do_pipe = 2;
5011         if (do_pipe) {
5012                 ac--;
5013                 av++;
5014         }
5015         NEED1("missing command");
5016
5017         /*
5018          * For pipes and queues we normally say 'pipe NN config'
5019          * but the code is easier to parse as 'pipe config NN'
5020          * so we swap the two arguments.
5021          */
5022         if (do_pipe > 0 && ac > 1 && isdigit(*av[0])) {
5023                 char *p = av[0];
5024
5025                 av[0] = av[1];
5026                 av[1] = p;
5027         }
5028
5029         if (_substrcmp(*av, "add") == 0)
5030                 add(ac, av);
5031         else if (do_pipe && _substrcmp(*av, "config") == 0)
5032                 config_pipe(ac, av);
5033         else if (_substrcmp(*av, "delete") == 0)
5034                 delete(ac, av);
5035         else if (_substrcmp(*av, "flush") == 0)
5036                 flush(do_force);
5037         else if (_substrcmp(*av, "zero") == 0)
5038                 zero(ac, av, IP_FW_ZERO);
5039         else if (_substrcmp(*av, "resetlog") == 0)
5040                 zero(ac, av, IP_FW_RESETLOG);
5041         else if (_substrcmp(*av, "print") == 0 ||
5042                  _substrcmp(*av, "list") == 0)
5043                 list(ac, av, do_acct);
5044         else if (_substrcmp(*av, "set") == 0)
5045                 sets_handler(ac, av);
5046         else if (_substrcmp(*av, "table") == 0)
5047                 table_handler(ac, av);
5048         else if (_substrcmp(*av, "enable") == 0)
5049                 sysctl_handler(ac, av, 1);
5050         else if (_substrcmp(*av, "disable") == 0)
5051                 sysctl_handler(ac, av, 0);
5052         else if (_substrcmp(*av, "show") == 0)
5053                 list(ac, av, 1 /* show counters */);
5054         else
5055                 errx(EX_USAGE, "bad command `%s'", *av);
5056
5057         /* Free memory allocated in the argument parsing. */
5058         free_args(save_ac, save_av);
5059         return 0;
5060 }
5061
5062
5063 static void
5064 ipfw_readfile(int ac, char *av[])
5065 {
5066 #define MAX_ARGS        32
5067         char    buf[BUFSIZ];
5068         char    *cmd = NULL, *filename = av[ac-1];
5069         int     c, lineno=0;
5070         FILE    *f = NULL;
5071         pid_t   preproc = 0;
5072
5073         filename = av[ac-1];
5074
5075         while ((c = getopt(ac, av, "cfNnp:qS")) != -1) {
5076                 switch(c) {
5077                 case 'c':
5078                         do_compact = 1;
5079                         break;
5080
5081                 case 'f':
5082                         do_force = 1;
5083                         break;
5084
5085                 case 'N':
5086                         do_resolv = 1;
5087                         break;
5088
5089                 case 'n':
5090                         test_only = 1;
5091                         break;
5092
5093                 case 'p':
5094                         cmd = optarg;
5095                         /*
5096                          * Skip previous args and delete last one, so we
5097                          * pass all but the last argument to the preprocessor
5098                          * via av[optind-1]
5099                          */
5100                         av += optind - 1;
5101                         ac -= optind - 1;
5102                         av[ac-1] = NULL;
5103                         fprintf(stderr, "command is %s\n", av[0]);
5104                         break;
5105
5106                 case 'q':
5107                         do_quiet = 1;
5108                         break;
5109
5110                 case 'S':
5111                         show_sets = 1;
5112                         break;
5113
5114                 default:
5115                         errx(EX_USAGE, "bad arguments, for usage"
5116                              " summary ``ipfw''");
5117                 }
5118
5119                 if (cmd != NULL)
5120                         break;
5121         }
5122
5123         if (cmd == NULL && ac != optind + 1) {
5124                 fprintf(stderr, "ac %d, optind %d\n", ac, optind);
5125                 errx(EX_USAGE, "extraneous filename arguments");
5126         }
5127
5128         if ((f = fopen(filename, "r")) == NULL)
5129                 err(EX_UNAVAILABLE, "fopen: %s", filename);
5130
5131         if (cmd != NULL) {                      /* pipe through preprocessor */
5132                 int pipedes[2];
5133
5134                 if (pipe(pipedes) == -1)
5135                         err(EX_OSERR, "cannot create pipe");
5136
5137                 preproc = fork();
5138                 if (preproc == -1)
5139                         err(EX_OSERR, "cannot fork");
5140
5141                 if (preproc == 0) {
5142                         /*
5143                          * Child, will run the preprocessor with the
5144                          * file on stdin and the pipe on stdout.
5145                          */
5146                         if (dup2(fileno(f), 0) == -1
5147                             || dup2(pipedes[1], 1) == -1)
5148                                 err(EX_OSERR, "dup2()");
5149                         fclose(f);
5150                         close(pipedes[1]);
5151                         close(pipedes[0]);
5152                         execvp(cmd, av);
5153                         err(EX_OSERR, "execvp(%s) failed", cmd);
5154                 } else { /* parent, will reopen f as the pipe */
5155                         fclose(f);
5156                         close(pipedes[1]);
5157                         if ((f = fdopen(pipedes[0], "r")) == NULL) {
5158                                 int savederrno = errno;
5159
5160                                 (void)kill(preproc, SIGTERM);
5161                                 errno = savederrno;
5162                                 err(EX_OSERR, "fdopen()");
5163                         }
5164                 }
5165         }
5166
5167         while (fgets(buf, BUFSIZ, f)) {         /* read commands */
5168                 char linename[10];
5169                 char *args[1];
5170
5171                 lineno++;
5172                 sprintf(linename, "Line %d", lineno);
5173                 setprogname(linename); /* XXX */
5174                 args[0] = buf;
5175                 ipfw_main(1, args);
5176         }
5177         fclose(f);
5178         if (cmd != NULL) {
5179                 int status;
5180
5181                 if (waitpid(preproc, &status, 0) == -1)
5182                         errx(EX_OSERR, "waitpid()");
5183                 if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK)
5184                         errx(EX_UNAVAILABLE,
5185                             "preprocessor exited with status %d",
5186                             WEXITSTATUS(status));
5187                 else if (WIFSIGNALED(status))
5188                         errx(EX_UNAVAILABLE,
5189                             "preprocessor exited with signal %d",
5190                             WTERMSIG(status));
5191         }
5192 }
5193
5194 int
5195 main(int ac, char *av[])
5196 {
5197         /*
5198          * If the last argument is an absolute pathname, interpret it
5199          * as a file to be preprocessed.
5200          */
5201
5202         if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0)
5203                 ipfw_readfile(ac, av);
5204         else {
5205                 if (ipfw_main(ac-1, av+1))
5206                         show_usage();
5207         }
5208         return EX_OK;
5209 }