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