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