ipfw2.c revision 121816
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 121816 2003-10-31 18:32:15Z brooks $
21 */
22
23#include <sys/param.h>
24#include <sys/mbuf.h>
25#include <sys/socket.h>
26#include <sys/sockio.h>
27#include <sys/sysctl.h>
28#include <sys/time.h>
29#include <sys/wait.h>
30
31#include <ctype.h>
32#include <err.h>
33#include <errno.h>
34#include <grp.h>
35#include <limits.h>
36#include <netdb.h>
37#include <pwd.h>
38#include <signal.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <stdarg.h>
42#include <string.h>
43#include <timeconv.h>	/* XXX do we need this ? */
44#include <unistd.h>
45#include <sysexits.h>
46
47#include <net/if.h>
48#include <netinet/in.h>
49#include <netinet/in_systm.h>
50#include <netinet/ip.h>
51#include <netinet/ip_icmp.h>
52#include <netinet/ip_fw.h>
53#include <netinet/ip_dummynet.h>
54#include <netinet/tcp.h>
55#include <arpa/inet.h>
56
57int
58		do_resolv,		/* Would try to resolve all */
59		do_time,		/* Show time stamps */
60		do_quiet,		/* Be quiet in add and flush */
61		do_pipe,		/* this cmd refers to a pipe */
62		do_sort,		/* field to sort results (0 = no) */
63		do_dynamic,		/* display dynamic rules */
64		do_expired,		/* display expired dynamic rules */
65		do_compact,		/* show rules in compact mode */
66		show_sets,		/* display rule sets */
67		test_only,		/* only check syntax */
68		verbose;
69
70#define	IP_MASK_ALL	0xffffffff
71
72/*
73 * _s_x is a structure that stores a string <-> token pairs, used in
74 * various places in the parser. Entries are stored in arrays,
75 * with an entry with s=NULL as terminator.
76 * The search routines are match_token() and match_value().
77 * Often, an element with x=0 contains an error string.
78 *
79 */
80struct _s_x {
81	char const *s;
82	int x;
83};
84
85static struct _s_x f_tcpflags[] = {
86	{ "syn", TH_SYN },
87	{ "fin", TH_FIN },
88	{ "ack", TH_ACK },
89	{ "psh", TH_PUSH },
90	{ "rst", TH_RST },
91	{ "urg", TH_URG },
92	{ "tcp flag", 0 },
93	{ NULL,	0 }
94};
95
96static struct _s_x f_tcpopts[] = {
97	{ "mss",	IP_FW_TCPOPT_MSS },
98	{ "maxseg",	IP_FW_TCPOPT_MSS },
99	{ "window",	IP_FW_TCPOPT_WINDOW },
100	{ "sack",	IP_FW_TCPOPT_SACK },
101	{ "ts",		IP_FW_TCPOPT_TS },
102	{ "timestamp",	IP_FW_TCPOPT_TS },
103	{ "cc",		IP_FW_TCPOPT_CC },
104	{ "tcp option",	0 },
105	{ NULL,	0 }
106};
107
108/*
109 * IP options span the range 0 to 255 so we need to remap them
110 * (though in fact only the low 5 bits are significant).
111 */
112static struct _s_x f_ipopts[] = {
113	{ "ssrr",	IP_FW_IPOPT_SSRR},
114	{ "lsrr",	IP_FW_IPOPT_LSRR},
115	{ "rr",		IP_FW_IPOPT_RR},
116	{ "ts",		IP_FW_IPOPT_TS},
117	{ "ip option",	0 },
118	{ NULL,	0 }
119};
120
121static struct _s_x f_iptos[] = {
122	{ "lowdelay",	IPTOS_LOWDELAY},
123	{ "throughput",	IPTOS_THROUGHPUT},
124	{ "reliability", IPTOS_RELIABILITY},
125	{ "mincost",	IPTOS_MINCOST},
126	{ "congestion",	IPTOS_CE},
127	{ "ecntransport", IPTOS_ECT},
128	{ "ip tos option", 0},
129	{ NULL,	0 }
130};
131
132static struct _s_x limit_masks[] = {
133	{"all",		DYN_SRC_ADDR|DYN_SRC_PORT|DYN_DST_ADDR|DYN_DST_PORT},
134	{"src-addr",	DYN_SRC_ADDR},
135	{"src-port",	DYN_SRC_PORT},
136	{"dst-addr",	DYN_DST_ADDR},
137	{"dst-port",	DYN_DST_PORT},
138	{NULL,		0}
139};
140
141/*
142 * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines
143 * This is only used in this code.
144 */
145#define IPPROTO_ETHERTYPE	0x1000
146static struct _s_x ether_types[] = {
147    /*
148     * Note, we cannot use "-:&/" in the names because they are field
149     * separators in the type specifications. Also, we use s = NULL as
150     * end-delimiter, because a type of 0 can be legal.
151     */
152	{ "ip",		0x0800 },
153	{ "ipv4",	0x0800 },
154	{ "ipv6",	0x86dd },
155	{ "arp",	0x0806 },
156	{ "rarp",	0x8035 },
157	{ "vlan",	0x8100 },
158	{ "loop",	0x9000 },
159	{ "trail",	0x1000 },
160	{ "at",		0x809b },
161	{ "atalk",	0x809b },
162	{ "aarp",	0x80f3 },
163	{ "pppoe_disc",	0x8863 },
164	{ "pppoe_sess",	0x8864 },
165	{ "ipx_8022",	0x00E0 },
166	{ "ipx_8023",	0x0000 },
167	{ "ipx_ii",	0x8137 },
168	{ "ipx_snap",	0x8137 },
169	{ "ipx",	0x8137 },
170	{ "ns",		0x0600 },
171	{ NULL,		0 }
172};
173
174static void show_usage(void);
175
176enum tokens {
177	TOK_NULL=0,
178
179	TOK_OR,
180	TOK_NOT,
181	TOK_STARTBRACE,
182	TOK_ENDBRACE,
183
184	TOK_ACCEPT,
185	TOK_COUNT,
186	TOK_PIPE,
187	TOK_QUEUE,
188	TOK_DIVERT,
189	TOK_TEE,
190	TOK_FORWARD,
191	TOK_SKIPTO,
192	TOK_DENY,
193	TOK_REJECT,
194	TOK_RESET,
195	TOK_UNREACH,
196	TOK_CHECKSTATE,
197
198	TOK_UID,
199	TOK_GID,
200	TOK_IN,
201	TOK_LIMIT,
202	TOK_KEEPSTATE,
203	TOK_LAYER2,
204	TOK_OUT,
205	TOK_XMIT,
206	TOK_RECV,
207	TOK_VIA,
208	TOK_FRAG,
209	TOK_IPOPTS,
210	TOK_IPLEN,
211	TOK_IPID,
212	TOK_IPPRECEDENCE,
213	TOK_IPTOS,
214	TOK_IPTTL,
215	TOK_IPVER,
216	TOK_ESTAB,
217	TOK_SETUP,
218	TOK_TCPFLAGS,
219	TOK_TCPOPTS,
220	TOK_TCPSEQ,
221	TOK_TCPACK,
222	TOK_TCPWIN,
223	TOK_ICMPTYPES,
224	TOK_MAC,
225	TOK_MACTYPE,
226	TOK_VERREVPATH,
227	TOK_IPSEC,
228	TOK_COMMENT,
229
230	TOK_PLR,
231	TOK_NOERROR,
232	TOK_BUCKETS,
233	TOK_DSTIP,
234	TOK_SRCIP,
235	TOK_DSTPORT,
236	TOK_SRCPORT,
237	TOK_ALL,
238	TOK_MASK,
239	TOK_BW,
240	TOK_DELAY,
241	TOK_RED,
242	TOK_GRED,
243	TOK_DROPTAIL,
244	TOK_PROTO,
245	TOK_WEIGHT,
246};
247
248struct _s_x dummynet_params[] = {
249	{ "plr",		TOK_PLR },
250	{ "noerror",		TOK_NOERROR },
251	{ "buckets",		TOK_BUCKETS },
252	{ "dst-ip",		TOK_DSTIP },
253	{ "src-ip",		TOK_SRCIP },
254	{ "dst-port",		TOK_DSTPORT },
255	{ "src-port",		TOK_SRCPORT },
256	{ "proto",		TOK_PROTO },
257	{ "weight",		TOK_WEIGHT },
258	{ "all",		TOK_ALL },
259	{ "mask",		TOK_MASK },
260	{ "droptail",		TOK_DROPTAIL },
261	{ "red",		TOK_RED },
262	{ "gred",		TOK_GRED },
263	{ "bw",			TOK_BW },
264	{ "bandwidth",		TOK_BW },
265	{ "delay",		TOK_DELAY },
266	{ "pipe",		TOK_PIPE },
267	{ "queue",		TOK_QUEUE },
268	{ "dummynet-params",	TOK_NULL },
269	{ NULL, 0 }	/* terminator */
270};
271
272struct _s_x rule_actions[] = {
273	{ "accept",		TOK_ACCEPT },
274	{ "pass",		TOK_ACCEPT },
275	{ "allow",		TOK_ACCEPT },
276	{ "permit",		TOK_ACCEPT },
277	{ "count",		TOK_COUNT },
278	{ "pipe",		TOK_PIPE },
279	{ "queue",		TOK_QUEUE },
280	{ "divert",		TOK_DIVERT },
281	{ "tee",		TOK_TEE },
282	{ "fwd",		TOK_FORWARD },
283	{ "forward",		TOK_FORWARD },
284	{ "skipto",		TOK_SKIPTO },
285	{ "deny",		TOK_DENY },
286	{ "drop",		TOK_DENY },
287	{ "reject",		TOK_REJECT },
288	{ "reset",		TOK_RESET },
289	{ "unreach",		TOK_UNREACH },
290	{ "check-state",	TOK_CHECKSTATE },
291	{ "//",			TOK_COMMENT },
292	{ NULL, 0 }	/* terminator */
293};
294
295struct _s_x rule_options[] = {
296	{ "uid",		TOK_UID },
297	{ "gid",		TOK_GID },
298	{ "in",			TOK_IN },
299	{ "limit",		TOK_LIMIT },
300	{ "keep-state",		TOK_KEEPSTATE },
301	{ "bridged",		TOK_LAYER2 },
302	{ "layer2",		TOK_LAYER2 },
303	{ "out",		TOK_OUT },
304	{ "xmit",		TOK_XMIT },
305	{ "recv",		TOK_RECV },
306	{ "via",		TOK_VIA },
307	{ "fragment",		TOK_FRAG },
308	{ "frag",		TOK_FRAG },
309	{ "ipoptions",		TOK_IPOPTS },
310	{ "ipopts",		TOK_IPOPTS },
311	{ "iplen",		TOK_IPLEN },
312	{ "ipid",		TOK_IPID },
313	{ "ipprecedence",	TOK_IPPRECEDENCE },
314	{ "iptos",		TOK_IPTOS },
315	{ "ipttl",		TOK_IPTTL },
316	{ "ipversion",		TOK_IPVER },
317	{ "ipver",		TOK_IPVER },
318	{ "estab",		TOK_ESTAB },
319	{ "established",	TOK_ESTAB },
320	{ "setup",		TOK_SETUP },
321	{ "tcpflags",		TOK_TCPFLAGS },
322	{ "tcpflgs",		TOK_TCPFLAGS },
323	{ "tcpoptions",		TOK_TCPOPTS },
324	{ "tcpopts",		TOK_TCPOPTS },
325	{ "tcpseq",		TOK_TCPSEQ },
326	{ "tcpack",		TOK_TCPACK },
327	{ "tcpwin",		TOK_TCPWIN },
328	{ "icmptype",		TOK_ICMPTYPES },
329	{ "icmptypes",		TOK_ICMPTYPES },
330	{ "dst-ip",		TOK_DSTIP },
331	{ "src-ip",		TOK_SRCIP },
332	{ "dst-port",		TOK_DSTPORT },
333	{ "src-port",		TOK_SRCPORT },
334	{ "proto",		TOK_PROTO },
335	{ "MAC",		TOK_MAC },
336	{ "mac",		TOK_MAC },
337	{ "mac-type",		TOK_MACTYPE },
338	{ "verrevpath",		TOK_VERREVPATH },
339	{ "ipsec",		TOK_IPSEC },
340	{ "//",			TOK_COMMENT },
341
342	{ "not",		TOK_NOT },		/* pseudo option */
343	{ "!", /* escape ? */	TOK_NOT },		/* pseudo option */
344	{ "or",			TOK_OR },		/* pseudo option */
345	{ "|", /* escape */	TOK_OR },		/* pseudo option */
346	{ "{",			TOK_STARTBRACE },	/* pseudo option */
347	{ "(",			TOK_STARTBRACE },	/* pseudo option */
348	{ "}",			TOK_ENDBRACE },		/* pseudo option */
349	{ ")",			TOK_ENDBRACE },		/* pseudo option */
350	{ NULL, 0 }	/* terminator */
351};
352
353static __inline uint64_t
354align_uint64(uint64_t *pll) {
355	uint64_t ret;
356
357	bcopy (pll, &ret, sizeof(ret));
358	return ret;
359};
360
361/*
362 * conditionally runs the command.
363 */
364static int
365do_cmd(int optname, void *optval, uintptr_t optlen)
366{
367	static int s = -1;	/* the socket */
368	int i;
369
370	if (test_only)
371		return 0;
372
373	if (s == -1)
374		s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
375	if (s < 0)
376		err(EX_UNAVAILABLE, "socket");
377
378	if (optname == IP_FW_GET || optname == IP_DUMMYNET_GET ||
379	    optname == IP_FW_ADD)
380		i = getsockopt(s, IPPROTO_IP, optname, optval,
381			(socklen_t *)optlen);
382	else
383		i = setsockopt(s, IPPROTO_IP, optname, optval, optlen);
384	return i;
385}
386
387/**
388 * match_token takes a table and a string, returns the value associated
389 * with the string (-1 in case of failure).
390 */
391static int
392match_token(struct _s_x *table, char *string)
393{
394	struct _s_x *pt;
395	uint i = strlen(string);
396
397	for (pt = table ; i && pt->s != NULL ; pt++)
398		if (strlen(pt->s) == i && !bcmp(string, pt->s, i))
399			return pt->x;
400	return -1;
401};
402
403/**
404 * match_value takes a table and a value, returns the string associated
405 * with the value (NULL in case of failure).
406 */
407static char const *
408match_value(struct _s_x *p, int value)
409{
410	for (; p->s != NULL; p++)
411		if (p->x == value)
412			return p->s;
413	return NULL;
414}
415
416/*
417 * prints one port, symbolic or numeric
418 */
419static void
420print_port(int proto, uint16_t port)
421{
422
423	if (proto == IPPROTO_ETHERTYPE) {
424		char const *s;
425
426		if (do_resolv && (s = match_value(ether_types, port)) )
427			printf("%s", s);
428		else
429			printf("0x%04x", port);
430	} else {
431		struct servent *se = NULL;
432		if (do_resolv) {
433			struct protoent *pe = getprotobynumber(proto);
434
435			se = getservbyport(htons(port), pe ? pe->p_name : NULL);
436		}
437		if (se)
438			printf("%s", se->s_name);
439		else
440			printf("%d", port);
441	}
442}
443
444struct _s_x _port_name[] = {
445	{"dst-port",	O_IP_DSTPORT},
446	{"src-port",	O_IP_SRCPORT},
447	{"ipid",	O_IPID},
448	{"iplen",	O_IPLEN},
449	{"ipttl",	O_IPTTL},
450	{"mac-type",	O_MAC_TYPE},
451	{NULL,		0}
452};
453
454/*
455 * Print the values in a list 16-bit items of the types above.
456 * XXX todo: add support for mask.
457 */
458static void
459print_newports(ipfw_insn_u16 *cmd, int proto, int opcode)
460{
461	uint16_t *p = cmd->ports;
462	int i;
463	char const *sep;
464
465	if (cmd->o.len & F_NOT)
466		printf(" not");
467	if (opcode != 0) {
468		sep = match_value(_port_name, opcode);
469		if (sep == NULL)
470			sep = "???";
471		printf (" %s", sep);
472	}
473	sep = " ";
474	for (i = F_LEN((ipfw_insn *)cmd) - 1; i > 0; i--, p += 2) {
475		printf(sep);
476		print_port(proto, p[0]);
477		if (p[0] != p[1]) {
478			printf("-");
479			print_port(proto, p[1]);
480		}
481		sep = ",";
482	}
483}
484
485/*
486 * Like strtol, but also translates service names into port numbers
487 * for some protocols.
488 * In particular:
489 *	proto == -1 disables the protocol check;
490 *	proto == IPPROTO_ETHERTYPE looks up an internal table
491 *	proto == <some value in /etc/protocols> matches the values there.
492 * Returns *end == s in case the parameter is not found.
493 */
494static int
495strtoport(char *s, char **end, int base, int proto)
496{
497	char *p, *buf;
498	char *s1;
499	int i;
500
501	*end = s;		/* default - not found */
502	if (*s == '\0')
503		return 0;	/* not found */
504
505	if (isdigit(*s))
506		return strtol(s, end, base);
507
508	/*
509	 * find separator. '\\' escapes the next char.
510	 */
511	for (s1 = s; *s1 && (isalnum(*s1) || *s1 == '\\') ; s1++)
512		if (*s1 == '\\' && s1[1] != '\0')
513			s1++;
514
515	buf = malloc(s1 - s + 1);
516	if (buf == NULL)
517		return 0;
518
519	/*
520	 * copy into a buffer skipping backslashes
521	 */
522	for (p = s, i = 0; p != s1 ; p++)
523		if (*p != '\\')
524			buf[i++] = *p;
525	buf[i++] = '\0';
526
527	if (proto == IPPROTO_ETHERTYPE) {
528		i = match_token(ether_types, buf);
529		free(buf);
530		if (i != -1) {	/* found */
531			*end = s1;
532			return i;
533		}
534	} else {
535		struct protoent *pe = NULL;
536		struct servent *se;
537
538		if (proto != 0)
539			pe = getprotobynumber(proto);
540		setservent(1);
541		se = getservbyname(buf, pe ? pe->p_name : NULL);
542		free(buf);
543		if (se != NULL) {
544			*end = s1;
545			return ntohs(se->s_port);
546		}
547	}
548	return 0;	/* not found */
549}
550
551/*
552 * Fill the body of the command with the list of port ranges.
553 */
554static int
555fill_newports(ipfw_insn_u16 *cmd, char *av, int proto)
556{
557	uint16_t a, b, *p = cmd->ports;
558	int i = 0;
559	char *s = av;
560
561	while (*s) {
562		a = strtoport(av, &s, 0, proto);
563		if (s == av) /* no parameter */
564			break;
565		if (*s == '-') { /* a range */
566			av = s+1;
567			b = strtoport(av, &s, 0, proto);
568			if (s == av) /* no parameter */
569				break;
570			p[0] = a;
571			p[1] = b;
572		} else if (*s == ',' || *s == '\0' )
573			p[0] = p[1] = a;
574		else 	/* invalid separator */
575			errx(EX_DATAERR, "invalid separator <%c> in <%s>\n",
576				*s, av);
577		i++;
578		p += 2;
579		av = s+1;
580	}
581	if (i > 0) {
582		if (i+1 > F_LEN_MASK)
583			errx(EX_DATAERR, "too many ports/ranges\n");
584		cmd->o.len |= i+1; /* leave F_NOT and F_OR untouched */
585	}
586	return i;
587}
588
589static struct _s_x icmpcodes[] = {
590      { "net",			ICMP_UNREACH_NET },
591      { "host",			ICMP_UNREACH_HOST },
592      { "protocol",		ICMP_UNREACH_PROTOCOL },
593      { "port",			ICMP_UNREACH_PORT },
594      { "needfrag",		ICMP_UNREACH_NEEDFRAG },
595      { "srcfail",		ICMP_UNREACH_SRCFAIL },
596      { "net-unknown",		ICMP_UNREACH_NET_UNKNOWN },
597      { "host-unknown",		ICMP_UNREACH_HOST_UNKNOWN },
598      { "isolated",		ICMP_UNREACH_ISOLATED },
599      { "net-prohib",		ICMP_UNREACH_NET_PROHIB },
600      { "host-prohib",		ICMP_UNREACH_HOST_PROHIB },
601      { "tosnet",		ICMP_UNREACH_TOSNET },
602      { "toshost",		ICMP_UNREACH_TOSHOST },
603      { "filter-prohib",	ICMP_UNREACH_FILTER_PROHIB },
604      { "host-precedence",	ICMP_UNREACH_HOST_PRECEDENCE },
605      { "precedence-cutoff",	ICMP_UNREACH_PRECEDENCE_CUTOFF },
606      { NULL, 0 }
607};
608
609static void
610fill_reject_code(u_short *codep, char *str)
611{
612	int val;
613	char *s;
614
615	val = strtoul(str, &s, 0);
616	if (s == str || *s != '\0' || val >= 0x100)
617		val = match_token(icmpcodes, str);
618	if (val < 0)
619		errx(EX_DATAERR, "unknown ICMP unreachable code ``%s''", str);
620	*codep = val;
621	return;
622}
623
624static void
625print_reject_code(uint16_t code)
626{
627	char const *s = match_value(icmpcodes, code);
628
629	if (s != NULL)
630		printf("unreach %s", s);
631	else
632		printf("unreach %u", code);
633}
634
635/*
636 * Returns the number of bits set (from left) in a contiguous bitmask,
637 * or -1 if the mask is not contiguous.
638 * XXX this needs a proper fix.
639 * This effectively works on masks in big-endian (network) format.
640 * when compiled on little endian architectures.
641 *
642 * First bit is bit 7 of the first byte -- note, for MAC addresses,
643 * the first bit on the wire is bit 0 of the first byte.
644 * len is the max length in bits.
645 */
646static int
647contigmask(uint8_t *p, int len)
648{
649	int i, n;
650
651	for (i=0; i<len ; i++)
652		if ( (p[i/8] & (1 << (7 - (i%8)))) == 0) /* first bit unset */
653			break;
654	for (n=i+1; n < len; n++)
655		if ( (p[n/8] & (1 << (7 - (n%8)))) != 0)
656			return -1; /* mask not contiguous */
657	return i;
658}
659
660/*
661 * print flags set/clear in the two bitmasks passed as parameters.
662 * There is a specialized check for f_tcpflags.
663 */
664static void
665print_flags(char const *name, ipfw_insn *cmd, struct _s_x *list)
666{
667	char const *comma = "";
668	int i;
669	uint8_t set = cmd->arg1 & 0xff;
670	uint8_t clear = (cmd->arg1 >> 8) & 0xff;
671
672	if (list == f_tcpflags && set == TH_SYN && clear == TH_ACK) {
673		printf(" setup");
674		return;
675	}
676
677	printf(" %s ", name);
678	for (i=0; list[i].x != 0; i++) {
679		if (set & list[i].x) {
680			set &= ~list[i].x;
681			printf("%s%s", comma, list[i].s);
682			comma = ",";
683		}
684		if (clear & list[i].x) {
685			clear &= ~list[i].x;
686			printf("%s!%s", comma, list[i].s);
687			comma = ",";
688		}
689	}
690}
691
692/*
693 * Print the ip address contained in a command.
694 */
695static void
696print_ip(ipfw_insn_ip *cmd, char const *s)
697{
698	struct hostent *he = NULL;
699	int len = F_LEN((ipfw_insn *)cmd);
700	uint32_t *a = ((ipfw_insn_u32 *)cmd)->d;
701
702	printf("%s%s ", cmd->o.len & F_NOT ? " not": "", s);
703
704	if (cmd->o.opcode == O_IP_SRC_ME || cmd->o.opcode == O_IP_DST_ME) {
705		printf("me");
706		return;
707	}
708	if (cmd->o.opcode == O_IP_SRC_SET || cmd->o.opcode == O_IP_DST_SET) {
709		uint32_t x, *map = (uint32_t *)&(cmd->mask);
710		int i, j;
711		char comma = '{';
712
713		x = cmd->o.arg1 - 1;
714		x = htonl( ~x );
715		cmd->addr.s_addr = htonl(cmd->addr.s_addr);
716		printf("%s/%d", inet_ntoa(cmd->addr),
717			contigmask((uint8_t *)&x, 32));
718		x = cmd->addr.s_addr = htonl(cmd->addr.s_addr);
719		x &= 0xff; /* base */
720		/*
721		 * Print bits and ranges.
722		 * Locate first bit set (i), then locate first bit unset (j).
723		 * If we have 3+ consecutive bits set, then print them as a
724		 * range, otherwise only print the initial bit and rescan.
725		 */
726		for (i=0; i < cmd->o.arg1; i++)
727			if (map[i/32] & (1<<(i & 31))) {
728				for (j=i+1; j < cmd->o.arg1; j++)
729					if (!(map[ j/32] & (1<<(j & 31))))
730						break;
731				printf("%c%d", comma, i+x);
732				if (j>i+2) { /* range has at least 3 elements */
733					printf("-%d", j-1+x);
734					i = j-1;
735				}
736				comma = ',';
737			}
738		printf("}");
739		return;
740	}
741	/*
742	 * len == 2 indicates a single IP, whereas lists of 1 or more
743	 * addr/mask pairs have len = (2n+1). We convert len to n so we
744	 * use that to count the number of entries.
745	 */
746    for (len = len / 2; len > 0; len--, a += 2) {
747	int mb =	/* mask length */
748	    (cmd->o.opcode == O_IP_SRC || cmd->o.opcode == O_IP_DST) ?
749		32 : contigmask((uint8_t *)&(a[1]), 32);
750	if (mb == 32 && do_resolv)
751		he = gethostbyaddr((char *)&(a[0]), sizeof(u_long), AF_INET);
752	if (he != NULL)		/* resolved to name */
753		printf("%s", he->h_name);
754	else if (mb == 0)	/* any */
755		printf("any");
756	else {		/* numeric IP followed by some kind of mask */
757		printf("%s", inet_ntoa( *((struct in_addr *)&a[0]) ) );
758		if (mb < 0)
759			printf(":%s", inet_ntoa( *((struct in_addr *)&a[1]) ) );
760		else if (mb < 32)
761			printf("/%d", mb);
762	}
763	if (len > 1)
764		printf(",");
765    }
766}
767
768/*
769 * prints a MAC address/mask pair
770 */
771static void
772print_mac(uint8_t *addr, uint8_t *mask)
773{
774	int l = contigmask(mask, 48);
775
776	if (l == 0)
777		printf(" any");
778	else {
779		printf(" %02x:%02x:%02x:%02x:%02x:%02x",
780		    addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
781		if (l == -1)
782			printf("&%02x:%02x:%02x:%02x:%02x:%02x",
783			    mask[0], mask[1], mask[2],
784			    mask[3], mask[4], mask[5]);
785		else if (l < 48)
786			printf("/%d", l);
787	}
788}
789
790static void
791fill_icmptypes(ipfw_insn_u32 *cmd, char *av)
792{
793	uint8_t type;
794
795	cmd->d[0] = 0;
796	while (*av) {
797		if (*av == ',')
798			av++;
799
800		type = strtoul(av, &av, 0);
801
802		if (*av != ',' && *av != '\0')
803			errx(EX_DATAERR, "invalid ICMP type");
804
805		if (type > 31)
806			errx(EX_DATAERR, "ICMP type out of range");
807
808		cmd->d[0] |= 1 << type;
809	}
810	cmd->o.opcode = O_ICMPTYPE;
811	cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32);
812}
813
814static void
815print_icmptypes(ipfw_insn_u32 *cmd)
816{
817	int i;
818	char sep= ' ';
819
820	printf(" icmptypes");
821	for (i = 0; i < 32; i++) {
822		if ( (cmd->d[0] & (1 << (i))) == 0)
823			continue;
824		printf("%c%d", sep, i);
825		sep = ',';
826	}
827}
828
829/*
830 * show_ipfw() prints the body of an ipfw rule.
831 * Because the standard rule has at least proto src_ip dst_ip, we use
832 * a helper function to produce these entries if not provided explicitly.
833 * The first argument is the list of fields we have, the second is
834 * the list of fields we want to be printed.
835 *
836 * Special cases if we have provided a MAC header:
837 *   + if the rule does not contain IP addresses/ports, do not print them;
838 *   + if the rule does not contain an IP proto, print "all" instead of "ip";
839 *
840 * Once we have 'have_options', IP header fields are printed as options.
841 */
842#define	HAVE_PROTO	0x0001
843#define	HAVE_SRCIP	0x0002
844#define	HAVE_DSTIP	0x0004
845#define	HAVE_MAC	0x0008
846#define	HAVE_MACTYPE	0x0010
847#define	HAVE_OPTIONS	0x8000
848
849#define	HAVE_IP		(HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP)
850static void
851show_prerequisites(int *flags, int want, int cmd)
852{
853	if ( (*flags & HAVE_IP) == HAVE_IP)
854		*flags |= HAVE_OPTIONS;
855
856	if ( (*flags & (HAVE_MAC|HAVE_MACTYPE|HAVE_OPTIONS)) == HAVE_MAC &&
857	     cmd != O_MAC_TYPE) {
858		/*
859		 * mac-type was optimized out by the compiler,
860		 * restore it
861		 */
862		printf(" any");
863		*flags |= HAVE_MACTYPE | HAVE_OPTIONS;
864		return;
865	}
866	if ( !(*flags & HAVE_OPTIONS)) {
867		if ( !(*flags & HAVE_PROTO) && (want & HAVE_PROTO))
868			printf(" ip");
869		if ( !(*flags & HAVE_SRCIP) && (want & HAVE_SRCIP))
870			printf(" from any");
871		if ( !(*flags & HAVE_DSTIP) && (want & HAVE_DSTIP))
872			printf(" to any");
873	}
874	*flags |= want;
875}
876
877static void
878show_ipfw(struct ip_fw *rule, int pcwidth, int bcwidth)
879{
880	static int twidth = 0;
881	int l;
882	ipfw_insn *cmd;
883	char *comment = NULL;	/* ptr to comment if we have one */
884	int proto = 0;		/* default */
885	int flags = 0;	/* prerequisites */
886	ipfw_insn_log *logptr = NULL; /* set if we find an O_LOG */
887	int or_block = 0;	/* we are in an or block */
888	uint32_t set_disable;
889
890	bcopy(&rule->next_rule, &set_disable, sizeof(set_disable));
891
892	if (set_disable & (1 << rule->set)) { /* disabled */
893		if (!show_sets)
894			return;
895		else
896			printf("# DISABLED ");
897	}
898	printf("%05u ", rule->rulenum);
899
900	if (pcwidth>0 || bcwidth>0)
901		printf("%*llu %*llu ", pcwidth, align_uint64(&rule->pcnt),
902		    bcwidth, align_uint64(&rule->bcnt));
903
904	if (do_time == 2)
905		printf("%10u ", rule->timestamp);
906	else if (do_time == 1) {
907		char timestr[30];
908		time_t t = (time_t)0;
909
910		if (twidth == 0) {
911			strcpy(timestr, ctime(&t));
912			*strchr(timestr, '\n') = '\0';
913			twidth = strlen(timestr);
914		}
915		if (rule->timestamp) {
916#if _FreeBSD_version < 500000 /* XXX check */
917#define	_long_to_time(x)	(time_t)(x)
918#endif
919			t = _long_to_time(rule->timestamp);
920
921			strcpy(timestr, ctime(&t));
922			*strchr(timestr, '\n') = '\0';
923			printf("%s ", timestr);
924		} else {
925			printf("%*s", twidth, " ");
926		}
927	}
928
929	if (show_sets)
930		printf("set %d ", rule->set);
931
932	/*
933	 * print the optional "match probability"
934	 */
935	if (rule->cmd_len > 0) {
936		cmd = rule->cmd ;
937		if (cmd->opcode == O_PROB) {
938			ipfw_insn_u32 *p = (ipfw_insn_u32 *)cmd;
939			double d = 1.0 * p->d[0];
940
941			d = (d / 0x7fffffff);
942			printf("prob %f ", d);
943		}
944	}
945
946	/*
947	 * first print actions
948	 */
949        for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule);
950			l > 0 ; l -= F_LEN(cmd), cmd += F_LEN(cmd)) {
951		switch(cmd->opcode) {
952		case O_CHECK_STATE:
953			printf("check-state");
954			flags = HAVE_IP; /* avoid printing anything else */
955			break;
956
957		case O_ACCEPT:
958			printf("allow");
959			break;
960
961		case O_COUNT:
962			printf("count");
963			break;
964
965		case O_DENY:
966			printf("deny");
967			break;
968
969		case O_REJECT:
970			if (cmd->arg1 == ICMP_REJECT_RST)
971				printf("reset");
972			else if (cmd->arg1 == ICMP_UNREACH_HOST)
973				printf("reject");
974			else
975				print_reject_code(cmd->arg1);
976			break;
977
978		case O_SKIPTO:
979			printf("skipto %u", cmd->arg1);
980			break;
981
982		case O_PIPE:
983			printf("pipe %u", cmd->arg1);
984			break;
985
986		case O_QUEUE:
987			printf("queue %u", cmd->arg1);
988			break;
989
990		case O_DIVERT:
991			printf("divert %u", cmd->arg1);
992			break;
993
994		case O_TEE:
995			printf("tee %u", cmd->arg1);
996			break;
997
998		case O_FORWARD_IP:
999		    {
1000			ipfw_insn_sa *s = (ipfw_insn_sa *)cmd;
1001
1002			printf("fwd %s", inet_ntoa(s->sa.sin_addr));
1003			if (s->sa.sin_port)
1004				printf(",%d", s->sa.sin_port);
1005		    }
1006			break;
1007
1008		case O_LOG: /* O_LOG is printed last */
1009			logptr = (ipfw_insn_log *)cmd;
1010			break;
1011
1012		default:
1013			printf("** unrecognized action %d len %d",
1014				cmd->opcode, cmd->len);
1015		}
1016	}
1017	if (logptr) {
1018		if (logptr->max_log > 0)
1019			printf(" log logamount %d", logptr->max_log);
1020		else
1021			printf(" log");
1022	}
1023
1024	/*
1025	 * then print the body.
1026	 */
1027	if (rule->_pad & 1) {	/* empty rules before options */
1028		if (!do_compact)
1029			printf(" ip from any to any");
1030		flags |= HAVE_IP | HAVE_OPTIONS;
1031	}
1032
1033        for (l = rule->act_ofs, cmd = rule->cmd ;
1034			l > 0 ; l -= F_LEN(cmd) , cmd += F_LEN(cmd)) {
1035		/* useful alias */
1036		ipfw_insn_u32 *cmd32 = (ipfw_insn_u32 *)cmd;
1037
1038		show_prerequisites(&flags, 0, cmd->opcode);
1039
1040		switch(cmd->opcode) {
1041		case O_PROB:
1042			break;	/* done already */
1043
1044		case O_PROBE_STATE:
1045			break; /* no need to print anything here */
1046
1047		case O_MACADDR2: {
1048			ipfw_insn_mac *m = (ipfw_insn_mac *)cmd;
1049
1050			if ((cmd->len & F_OR) && !or_block)
1051				printf(" {");
1052			if (cmd->len & F_NOT)
1053				printf(" not");
1054			printf(" MAC");
1055			flags |= HAVE_MAC;
1056			print_mac(m->addr, m->mask);
1057			print_mac(m->addr + 6, m->mask + 6);
1058			}
1059			break;
1060
1061		case O_MAC_TYPE:
1062			if ((cmd->len & F_OR) && !or_block)
1063				printf(" {");
1064			print_newports((ipfw_insn_u16 *)cmd, IPPROTO_ETHERTYPE,
1065				(flags & HAVE_OPTIONS) ? cmd->opcode : 0);
1066			flags |= HAVE_MAC | HAVE_MACTYPE | HAVE_OPTIONS;
1067			break;
1068
1069		case O_IP_SRC:
1070		case O_IP_SRC_MASK:
1071		case O_IP_SRC_ME:
1072		case O_IP_SRC_SET:
1073			show_prerequisites(&flags, HAVE_PROTO, 0);
1074			if (!(flags & HAVE_SRCIP))
1075				printf(" from");
1076			if ((cmd->len & F_OR) && !or_block)
1077				printf(" {");
1078			print_ip((ipfw_insn_ip *)cmd,
1079				(flags & HAVE_OPTIONS) ? " src-ip" : "");
1080			flags |= HAVE_SRCIP;
1081			break;
1082
1083		case O_IP_DST:
1084		case O_IP_DST_MASK:
1085		case O_IP_DST_ME:
1086		case O_IP_DST_SET:
1087			show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0);
1088			if (!(flags & HAVE_DSTIP))
1089				printf(" to");
1090			if ((cmd->len & F_OR) && !or_block)
1091				printf(" {");
1092			print_ip((ipfw_insn_ip *)cmd,
1093				(flags & HAVE_OPTIONS) ? " dst-ip" : "");
1094			flags |= HAVE_DSTIP;
1095			break;
1096
1097		case O_IP_DSTPORT:
1098			show_prerequisites(&flags, HAVE_IP, 0);
1099		case O_IP_SRCPORT:
1100			show_prerequisites(&flags, HAVE_PROTO|HAVE_SRCIP, 0);
1101			if ((cmd->len & F_OR) && !or_block)
1102				printf(" {");
1103			print_newports((ipfw_insn_u16 *)cmd, proto,
1104				(flags & HAVE_OPTIONS) ? cmd->opcode : 0);
1105			break;
1106
1107		case O_PROTO: {
1108			struct protoent *pe;
1109
1110			if ((cmd->len & F_OR) && !or_block)
1111				printf(" {");
1112			if (cmd->len & F_NOT)
1113				printf(" not");
1114			proto = cmd->arg1;
1115			pe = getprotobynumber(cmd->arg1);
1116			if (flags & HAVE_OPTIONS)
1117				printf(" proto");
1118			if (pe)
1119				printf(" %s", pe->p_name);
1120			else
1121				printf(" %u", cmd->arg1);
1122			}
1123			flags |= HAVE_PROTO;
1124			break;
1125
1126		default: /*options ... */
1127			show_prerequisites(&flags, HAVE_IP | HAVE_OPTIONS, 0);
1128			if ((cmd->len & F_OR) && !or_block)
1129				printf(" {");
1130			if (cmd->len & F_NOT && cmd->opcode != O_IN)
1131				printf(" not");
1132			switch(cmd->opcode) {
1133			case O_FRAG:
1134				printf(" frag");
1135				break;
1136
1137			case O_IN:
1138				printf(cmd->len & F_NOT ? " out" : " in");
1139				break;
1140
1141			case O_LAYER2:
1142				printf(" layer2");
1143				break;
1144			case O_XMIT:
1145			case O_RECV:
1146			case O_VIA: {
1147				char const *s;
1148				ipfw_insn_if *cmdif = (ipfw_insn_if *)cmd;
1149
1150				if (cmd->opcode == O_XMIT)
1151					s = "xmit";
1152				else if (cmd->opcode == O_RECV)
1153					s = "recv";
1154				else /* if (cmd->opcode == O_VIA) */
1155					s = "via";
1156				if (cmdif->name[0] == '\0')
1157					printf(" %s %s", s,
1158					    inet_ntoa(cmdif->p.ip));
1159				printf(" %s %s", s, cmdif->name);
1160				}
1161				break;
1162
1163			case O_IPID:
1164				if (F_LEN(cmd) == 1)
1165				    printf(" ipid %u", cmd->arg1 );
1166				else
1167				    print_newports((ipfw_insn_u16 *)cmd, 0,
1168					O_IPID);
1169				break;
1170
1171			case O_IPTTL:
1172				if (F_LEN(cmd) == 1)
1173				    printf(" ipttl %u", cmd->arg1 );
1174				else
1175				    print_newports((ipfw_insn_u16 *)cmd, 0,
1176					O_IPTTL);
1177				break;
1178
1179			case O_IPVER:
1180				printf(" ipver %u", cmd->arg1 );
1181				break;
1182
1183			case O_IPPRECEDENCE:
1184				printf(" ipprecedence %u", (cmd->arg1) >> 5 );
1185				break;
1186
1187			case O_IPLEN:
1188				if (F_LEN(cmd) == 1)
1189				    printf(" iplen %u", cmd->arg1 );
1190				else
1191				    print_newports((ipfw_insn_u16 *)cmd, 0,
1192					O_IPLEN);
1193				break;
1194
1195			case O_IPOPT:
1196				print_flags("ipoptions", cmd, f_ipopts);
1197				break;
1198
1199			case O_IPTOS:
1200				print_flags("iptos", cmd, f_iptos);
1201				break;
1202
1203			case O_ICMPTYPE:
1204				print_icmptypes((ipfw_insn_u32 *)cmd);
1205				break;
1206
1207			case O_ESTAB:
1208				printf(" established");
1209				break;
1210
1211			case O_TCPFLAGS:
1212				print_flags("tcpflags", cmd, f_tcpflags);
1213				break;
1214
1215			case O_TCPOPTS:
1216				print_flags("tcpoptions", cmd, f_tcpopts);
1217				break;
1218
1219			case O_TCPWIN:
1220				printf(" tcpwin %d", ntohs(cmd->arg1));
1221				break;
1222
1223			case O_TCPACK:
1224				printf(" tcpack %d", ntohl(cmd32->d[0]));
1225				break;
1226
1227			case O_TCPSEQ:
1228				printf(" tcpseq %d", ntohl(cmd32->d[0]));
1229				break;
1230
1231			case O_UID:
1232			    {
1233				struct passwd *pwd = getpwuid(cmd32->d[0]);
1234
1235				if (pwd)
1236					printf(" uid %s", pwd->pw_name);
1237				else
1238					printf(" uid %u", cmd32->d[0]);
1239			    }
1240				break;
1241
1242			case O_GID:
1243			    {
1244				struct group *grp = getgrgid(cmd32->d[0]);
1245
1246				if (grp)
1247					printf(" gid %s", grp->gr_name);
1248				else
1249					printf(" gid %u", cmd32->d[0]);
1250			    }
1251				break;
1252
1253			case O_VERREVPATH:
1254				printf(" verrevpath");
1255				break;
1256
1257			case O_IPSEC:
1258				printf(" ipsec");
1259				break;
1260
1261			case O_NOP:
1262				comment = (char *)(cmd + 1);
1263				break;
1264
1265			case O_KEEP_STATE:
1266				printf(" keep-state");
1267				break;
1268
1269			case O_LIMIT:
1270			    {
1271				struct _s_x *p = limit_masks;
1272				ipfw_insn_limit *c = (ipfw_insn_limit *)cmd;
1273				uint8_t x = c->limit_mask;
1274				char const *comma = " ";
1275
1276				printf(" limit");
1277				for (; p->x != 0 ; p++)
1278					if ((x & p->x) == p->x) {
1279						x &= ~p->x;
1280						printf("%s%s", comma, p->s);
1281						comma = ",";
1282					}
1283				printf(" %d", c->conn_limit);
1284			    }
1285				break;
1286
1287			default:
1288				printf(" [opcode %d len %d]",
1289				    cmd->opcode, cmd->len);
1290			}
1291		}
1292		if (cmd->len & F_OR) {
1293			printf(" or");
1294			or_block = 1;
1295		} else if (or_block) {
1296			printf(" }");
1297			or_block = 0;
1298		}
1299	}
1300	show_prerequisites(&flags, HAVE_IP, 0);
1301	if (comment)
1302		printf(" // %s", comment);
1303	printf("\n");
1304}
1305
1306static void
1307show_dyn_ipfw(ipfw_dyn_rule *d, int pcwidth, int bcwidth)
1308{
1309	struct protoent *pe;
1310	struct in_addr a;
1311	uint16_t rulenum;
1312
1313	if (!do_expired) {
1314		if (!d->expire && !(d->dyn_type == O_LIMIT_PARENT))
1315			return;
1316	}
1317	bcopy(&d->rule, &rulenum, sizeof(rulenum));
1318	printf("%05d", rulenum);
1319	if (pcwidth>0 || bcwidth>0)
1320	    printf(" %*llu %*llu (%ds)", pcwidth,
1321		align_uint64(&d->pcnt), bcwidth,
1322		align_uint64(&d->bcnt), d->expire);
1323	switch (d->dyn_type) {
1324	case O_LIMIT_PARENT:
1325		printf(" PARENT %d", d->count);
1326		break;
1327	case O_LIMIT:
1328		printf(" LIMIT");
1329		break;
1330	case O_KEEP_STATE: /* bidir, no mask */
1331		printf(" STATE");
1332		break;
1333	}
1334
1335	if ((pe = getprotobynumber(d->id.proto)) != NULL)
1336		printf(" %s", pe->p_name);
1337	else
1338		printf(" proto %u", d->id.proto);
1339
1340	a.s_addr = htonl(d->id.src_ip);
1341	printf(" %s %d", inet_ntoa(a), d->id.src_port);
1342
1343	a.s_addr = htonl(d->id.dst_ip);
1344	printf(" <-> %s %d", inet_ntoa(a), d->id.dst_port);
1345	printf("\n");
1346}
1347
1348static int
1349sort_q(const void *pa, const void *pb)
1350{
1351	int rev = (do_sort < 0);
1352	int field = rev ? -do_sort : do_sort;
1353	long long res = 0;
1354	const struct dn_flow_queue *a = pa;
1355	const struct dn_flow_queue *b = pb;
1356
1357	switch (field) {
1358	case 1: /* pkts */
1359		res = a->len - b->len;
1360		break;
1361	case 2: /* bytes */
1362		res = a->len_bytes - b->len_bytes;
1363		break;
1364
1365	case 3: /* tot pkts */
1366		res = a->tot_pkts - b->tot_pkts;
1367		break;
1368
1369	case 4: /* tot bytes */
1370		res = a->tot_bytes - b->tot_bytes;
1371		break;
1372	}
1373	if (res < 0)
1374		res = -1;
1375	if (res > 0)
1376		res = 1;
1377	return (int)(rev ? res : -res);
1378}
1379
1380static void
1381list_queues(struct dn_flow_set *fs, struct dn_flow_queue *q)
1382{
1383	int l;
1384
1385	printf("    mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
1386	    fs->flow_mask.proto,
1387	    fs->flow_mask.src_ip, fs->flow_mask.src_port,
1388	    fs->flow_mask.dst_ip, fs->flow_mask.dst_port);
1389	if (fs->rq_elements == 0)
1390		return;
1391
1392	printf("BKT Prot ___Source IP/port____ "
1393	    "____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
1394	if (do_sort != 0)
1395		heapsort(q, fs->rq_elements, sizeof *q, sort_q);
1396	for (l = 0; l < fs->rq_elements; l++) {
1397		struct in_addr ina;
1398		struct protoent *pe;
1399
1400		ina.s_addr = htonl(q[l].id.src_ip);
1401		printf("%3d ", q[l].hash_slot);
1402		pe = getprotobynumber(q[l].id.proto);
1403		if (pe)
1404			printf("%-4s ", pe->p_name);
1405		else
1406			printf("%4u ", q[l].id.proto);
1407		printf("%15s/%-5d ",
1408		    inet_ntoa(ina), q[l].id.src_port);
1409		ina.s_addr = htonl(q[l].id.dst_ip);
1410		printf("%15s/%-5d ",
1411		    inet_ntoa(ina), q[l].id.dst_port);
1412		printf("%4qu %8qu %2u %4u %3u\n",
1413		    q[l].tot_pkts, q[l].tot_bytes,
1414		    q[l].len, q[l].len_bytes, q[l].drops);
1415		if (verbose)
1416			printf("   S %20qd  F %20qd\n",
1417			    q[l].S, q[l].F);
1418	}
1419}
1420
1421static void
1422print_flowset_parms(struct dn_flow_set *fs, char *prefix)
1423{
1424	int l;
1425	char qs[30];
1426	char plr[30];
1427	char red[90];	/* Display RED parameters */
1428
1429	l = fs->qsize;
1430	if (fs->flags_fs & DN_QSIZE_IS_BYTES) {
1431		if (l >= 8192)
1432			sprintf(qs, "%d KB", l / 1024);
1433		else
1434			sprintf(qs, "%d B", l);
1435	} else
1436		sprintf(qs, "%3d sl.", l);
1437	if (fs->plr)
1438		sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff));
1439	else
1440		plr[0] = '\0';
1441	if (fs->flags_fs & DN_IS_RED)	/* RED parameters */
1442		sprintf(red,
1443		    "\n\t  %cRED w_q %f min_th %d max_th %d max_p %f",
1444		    (fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ',
1445		    1.0 * fs->w_q / (double)(1 << SCALE_RED),
1446		    SCALE_VAL(fs->min_th),
1447		    SCALE_VAL(fs->max_th),
1448		    1.0 * fs->max_p / (double)(1 << SCALE_RED));
1449	else
1450		sprintf(red, "droptail");
1451
1452	printf("%s %s%s %d queues (%d buckets) %s\n",
1453	    prefix, qs, plr, fs->rq_elements, fs->rq_size, red);
1454}
1455
1456static void
1457list_pipes(void *data, uint nbytes, int ac, char *av[])
1458{
1459	int rulenum;
1460	void *next = data;
1461	struct dn_pipe *p = (struct dn_pipe *) data;
1462	struct dn_flow_set *fs;
1463	struct dn_flow_queue *q;
1464	int l;
1465
1466	if (ac > 0)
1467		rulenum = strtoul(*av++, NULL, 10);
1468	else
1469		rulenum = 0;
1470	for (; nbytes >= sizeof *p; p = (struct dn_pipe *)next) {
1471		double b = p->bandwidth;
1472		char buf[30];
1473		char prefix[80];
1474
1475		if (p->next != (struct dn_pipe *)DN_IS_PIPE)
1476			break;	/* done with pipes, now queues */
1477
1478		/*
1479		 * compute length, as pipe have variable size
1480		 */
1481		l = sizeof(*p) + p->fs.rq_elements * sizeof(*q);
1482		next = (char *)p + l;
1483		nbytes -= l;
1484
1485		if (rulenum != 0 && rulenum != p->pipe_nr)
1486			continue;
1487
1488		/*
1489		 * Print rate (or clocking interface)
1490		 */
1491		if (p->if_name[0] != '\0')
1492			sprintf(buf, "%s", p->if_name);
1493		else if (b == 0)
1494			sprintf(buf, "unlimited");
1495		else if (b >= 1000000)
1496			sprintf(buf, "%7.3f Mbit/s", b/1000000);
1497		else if (b >= 1000)
1498			sprintf(buf, "%7.3f Kbit/s", b/1000);
1499		else
1500			sprintf(buf, "%7.3f bit/s ", b);
1501
1502		sprintf(prefix, "%05d: %s %4d ms ",
1503		    p->pipe_nr, buf, p->delay);
1504		print_flowset_parms(&(p->fs), prefix);
1505		if (verbose)
1506			printf("   V %20qd\n", p->V >> MY_M);
1507
1508		q = (struct dn_flow_queue *)(p+1);
1509		list_queues(&(p->fs), q);
1510	}
1511	for (fs = next; nbytes >= sizeof *fs; fs = next) {
1512		char prefix[80];
1513
1514		if (fs->next != (struct dn_flow_set *)DN_IS_QUEUE)
1515			break;
1516		l = sizeof(*fs) + fs->rq_elements * sizeof(*q);
1517		next = (char *)fs + l;
1518		nbytes -= l;
1519		q = (struct dn_flow_queue *)(fs+1);
1520		sprintf(prefix, "q%05d: weight %d pipe %d ",
1521		    fs->fs_nr, fs->weight, fs->parent_nr);
1522		print_flowset_parms(fs, prefix);
1523		list_queues(fs, q);
1524	}
1525}
1526
1527/*
1528 * This one handles all set-related commands
1529 * 	ipfw set { show | enable | disable }
1530 * 	ipfw set swap X Y
1531 * 	ipfw set move X to Y
1532 * 	ipfw set move rule X to Y
1533 */
1534static void
1535sets_handler(int ac, char *av[])
1536{
1537	uint32_t set_disable, masks[2];
1538	int i, nbytes;
1539	uint16_t rulenum;
1540	uint8_t cmd, new_set;
1541
1542	ac--;
1543	av++;
1544
1545	if (!ac)
1546		errx(EX_USAGE, "set needs command");
1547	if (!strncmp(*av, "show", strlen(*av)) ) {
1548		void *data;
1549		char const *msg;
1550
1551		nbytes = sizeof(struct ip_fw);
1552		if ((data = calloc(1, nbytes)) == NULL)
1553			err(EX_OSERR, "calloc");
1554		if (do_cmd(IP_FW_GET, data, (uintptr_t)&nbytes) < 0)
1555			err(EX_OSERR, "getsockopt(IP_FW_GET)");
1556		bcopy(&((struct ip_fw *)data)->next_rule,
1557			&set_disable, sizeof(set_disable));
1558
1559		for (i = 0, msg = "disable" ; i < RESVD_SET; i++)
1560			if ((set_disable & (1<<i))) {
1561				printf("%s %d", msg, i);
1562				msg = "";
1563			}
1564		msg = (set_disable) ? " enable" : "enable";
1565		for (i = 0; i < RESVD_SET; i++)
1566			if (!(set_disable & (1<<i))) {
1567				printf("%s %d", msg, i);
1568				msg = "";
1569			}
1570		printf("\n");
1571	} else if (!strncmp(*av, "swap", strlen(*av))) {
1572		ac--; av++;
1573		if (ac != 2)
1574			errx(EX_USAGE, "set swap needs 2 set numbers\n");
1575		rulenum = atoi(av[0]);
1576		new_set = atoi(av[1]);
1577		if (!isdigit(*(av[0])) || rulenum > RESVD_SET)
1578			errx(EX_DATAERR, "invalid set number %s\n", av[0]);
1579		if (!isdigit(*(av[1])) || new_set > RESVD_SET)
1580			errx(EX_DATAERR, "invalid set number %s\n", av[1]);
1581		masks[0] = (4 << 24) | (new_set << 16) | (rulenum);
1582		i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t));
1583	} else if (!strncmp(*av, "move", strlen(*av))) {
1584		ac--; av++;
1585		if (ac && !strncmp(*av, "rule", strlen(*av))) {
1586			cmd = 2;
1587			ac--; av++;
1588		} else
1589			cmd = 3;
1590		if (ac != 3 || strncmp(av[1], "to", strlen(*av)))
1591			errx(EX_USAGE, "syntax: set move [rule] X to Y\n");
1592		rulenum = atoi(av[0]);
1593		new_set = atoi(av[2]);
1594		if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > RESVD_SET) ||
1595			(cmd == 2 && rulenum == 65535) )
1596			errx(EX_DATAERR, "invalid source number %s\n", av[0]);
1597		if (!isdigit(*(av[2])) || new_set > RESVD_SET)
1598			errx(EX_DATAERR, "invalid dest. set %s\n", av[1]);
1599		masks[0] = (cmd << 24) | (new_set << 16) | (rulenum);
1600		i = do_cmd(IP_FW_DEL, masks, sizeof(uint32_t));
1601	} else if (!strncmp(*av, "disable", strlen(*av)) ||
1602		   !strncmp(*av, "enable",  strlen(*av)) ) {
1603		int which = !strncmp(*av, "enable",  strlen(*av)) ? 1 : 0;
1604
1605		ac--; av++;
1606		masks[0] = masks[1] = 0;
1607
1608		while (ac) {
1609			if (isdigit(**av)) {
1610				i = atoi(*av);
1611				if (i < 0 || i > RESVD_SET)
1612					errx(EX_DATAERR,
1613					    "invalid set number %d\n", i);
1614				masks[which] |= (1<<i);
1615			} else if (!strncmp(*av, "disable", strlen(*av)))
1616				which = 0;
1617			else if (!strncmp(*av, "enable", strlen(*av)))
1618				which = 1;
1619			else
1620				errx(EX_DATAERR,
1621					"invalid set command %s\n", *av);
1622			av++; ac--;
1623		}
1624		if ( (masks[0] & masks[1]) != 0 )
1625			errx(EX_DATAERR,
1626			    "cannot enable and disable the same set\n");
1627
1628		i = do_cmd(IP_FW_DEL, masks, sizeof(masks));
1629		if (i)
1630			warn("set enable/disable: setsockopt(IP_FW_DEL)");
1631	} else
1632		errx(EX_USAGE, "invalid set command %s\n", *av);
1633}
1634
1635static void
1636sysctl_handler(int ac, char *av[], int which)
1637{
1638	ac--;
1639	av++;
1640
1641	if (ac == 0) {
1642		warnx("missing keyword to enable/disable\n");
1643	} else if (strncmp(*av, "firewall", strlen(*av)) == 0) {
1644		sysctlbyname("net.inet.ip.fw.enable", NULL, 0,
1645		    &which, sizeof(which));
1646	} else if (strncmp(*av, "one_pass", strlen(*av)) == 0) {
1647		sysctlbyname("net.inet.ip.fw.one_pass", NULL, 0,
1648		    &which, sizeof(which));
1649	} else if (strncmp(*av, "debug", strlen(*av)) == 0) {
1650		sysctlbyname("net.inet.ip.fw.debug", NULL, 0,
1651		    &which, sizeof(which));
1652	} else if (strncmp(*av, "verbose", strlen(*av)) == 0) {
1653		sysctlbyname("net.inet.ip.fw.verbose", NULL, 0,
1654		    &which, sizeof(which));
1655	} else if (strncmp(*av, "dyn_keepalive", strlen(*av)) == 0) {
1656		sysctlbyname("net.inet.ip.fw.dyn_keepalive", NULL, 0,
1657		    &which, sizeof(which));
1658	} else {
1659		warnx("unrecognize enable/disable keyword: %s\n", *av);
1660	}
1661}
1662
1663static void
1664list(int ac, char *av[], int show_counters)
1665{
1666	struct ip_fw *r;
1667	ipfw_dyn_rule *dynrules, *d;
1668
1669#define NEXT(r)	((struct ip_fw *)((char *)r + RULESIZE(r)))
1670	char *lim;
1671	void *data = NULL;
1672	int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width;
1673	int exitval = EX_OK;
1674	int lac;
1675	char **lav;
1676	u_long rnum, last;
1677	char *endptr;
1678	int seen = 0;
1679
1680	const int ocmd = do_pipe ? IP_DUMMYNET_GET : IP_FW_GET;
1681	int nalloc = 1024;	/* start somewhere... */
1682
1683	if (test_only) {
1684		fprintf(stderr, "Testing only, list disabled\n");
1685		return;
1686	}
1687
1688	ac--;
1689	av++;
1690
1691	/* get rules or pipes from kernel, resizing array as necessary */
1692	nbytes = nalloc;
1693
1694	while (nbytes >= nalloc) {
1695		nalloc = nalloc * 2 + 200;
1696		nbytes = nalloc;
1697		if ((data = realloc(data, nbytes)) == NULL)
1698			err(EX_OSERR, "realloc");
1699		if (do_cmd(ocmd, data, (uintptr_t)&nbytes) < 0)
1700			err(EX_OSERR, "getsockopt(IP_%s_GET)",
1701				do_pipe ? "DUMMYNET" : "FW");
1702	}
1703
1704	if (do_pipe) {
1705		list_pipes(data, nbytes, ac, av);
1706		goto done;
1707	}
1708
1709	/*
1710	 * Count static rules. They have variable size so we
1711	 * need to scan the list to count them.
1712	 */
1713	for (nstat = 1, r = data, lim = (char *)data + nbytes;
1714		    r->rulenum < 65535 && (char *)r < lim;
1715		    ++nstat, r = NEXT(r) )
1716		; /* nothing */
1717
1718	/*
1719	 * Count dynamic rules. This is easier as they have
1720	 * fixed size.
1721	 */
1722	r = NEXT(r);
1723	dynrules = (ipfw_dyn_rule *)r ;
1724	n = (char *)r - (char *)data;
1725	ndyn = (nbytes - n) / sizeof *dynrules;
1726
1727	/* if showing stats, figure out column widths ahead of time */
1728	bcwidth = pcwidth = 0;
1729	if (show_counters) {
1730		for (n = 0, r = data; n < nstat; n++, r = NEXT(r)) {
1731			/* packet counter */
1732			width = snprintf(NULL, 0, "%llu",
1733			    align_uint64(&r->pcnt));
1734			if (width > pcwidth)
1735				pcwidth = width;
1736
1737			/* byte counter */
1738			width = snprintf(NULL, 0, "%llu",
1739			    align_uint64(&r->bcnt));
1740			if (width > bcwidth)
1741				bcwidth = width;
1742		}
1743	}
1744	if (do_dynamic && ndyn) {
1745		for (n = 0, d = dynrules; n < ndyn; n++, d++) {
1746			width = snprintf(NULL, 0, "%llu",
1747			    align_uint64(&d->pcnt));
1748			if (width > pcwidth)
1749				pcwidth = width;
1750
1751			width = snprintf(NULL, 0, "%llu",
1752			    align_uint64(&d->bcnt));
1753			if (width > bcwidth)
1754				bcwidth = width;
1755		}
1756	}
1757	/* if no rule numbers were specified, list all rules */
1758	if (ac == 0) {
1759		for (n = 0, r = data; n < nstat; n++, r = NEXT(r) )
1760			show_ipfw(r, pcwidth, bcwidth);
1761
1762		if (do_dynamic && ndyn) {
1763			printf("## Dynamic rules (%d):\n", ndyn);
1764			for (n = 0, d = dynrules; n < ndyn; n++, d++)
1765				show_dyn_ipfw(d, pcwidth, bcwidth);
1766		}
1767		goto done;
1768	}
1769
1770	/* display specific rules requested on command line */
1771
1772	for (lac = ac, lav = av; lac != 0; lac--) {
1773		/* convert command line rule # */
1774		last = rnum = strtoul(*lav++, &endptr, 10);
1775		if (*endptr == '-')
1776			last = strtoul(endptr+1, &endptr, 10);
1777		if (*endptr) {
1778			exitval = EX_USAGE;
1779			warnx("invalid rule number: %s", *(lav - 1));
1780			continue;
1781		}
1782		for (n = seen = 0, r = data; n < nstat; n++, r = NEXT(r) ) {
1783			if (r->rulenum > last)
1784				break;
1785			if (r->rulenum >= rnum && r->rulenum <= last) {
1786				show_ipfw(r, pcwidth, bcwidth);
1787				seen = 1;
1788			}
1789		}
1790		if (!seen) {
1791			/* give precedence to other error(s) */
1792			if (exitval == EX_OK)
1793				exitval = EX_UNAVAILABLE;
1794			warnx("rule %lu does not exist", rnum);
1795		}
1796	}
1797
1798	if (do_dynamic && ndyn) {
1799		printf("## Dynamic rules:\n");
1800		for (lac = ac, lav = av; lac != 0; lac--) {
1801			rnum = strtoul(*lav++, &endptr, 10);
1802			if (*endptr == '-')
1803				last = strtoul(endptr+1, &endptr, 10);
1804			if (*endptr)
1805				/* already warned */
1806				continue;
1807			for (n = 0, d = dynrules; n < ndyn; n++, d++) {
1808				uint16_t rulenum;
1809
1810				bcopy(&d->rule, &rulenum, sizeof(rulenum));
1811				if (rulenum > rnum)
1812					break;
1813				if (r->rulenum >= rnum && r->rulenum <= last)
1814					show_dyn_ipfw(d, pcwidth, bcwidth);
1815			}
1816		}
1817	}
1818
1819	ac = 0;
1820
1821done:
1822	free(data);
1823
1824	if (exitval != EX_OK)
1825		exit(exitval);
1826#undef NEXT
1827}
1828
1829static void
1830show_usage(void)
1831{
1832	fprintf(stderr, "usage: ipfw [options]\n"
1833"do \"ipfw -h\" or see ipfw manpage for details\n"
1834);
1835	exit(EX_USAGE);
1836}
1837
1838static void
1839help(void)
1840{
1841	fprintf(stderr,
1842"ipfw syntax summary (but please do read the ipfw(8) manpage):\n"
1843"ipfw [-acdeftTnNpqS] <command> where <command> is one of:\n"
1844"add [num] [set N] [prob x] RULE-BODY\n"
1845"{pipe|queue} N config PIPE-BODY\n"
1846"[pipe|queue] {zero|delete|show} [N{,N}]\n"
1847"set [disable N... enable N...] | move [rule] X to Y | swap X Y | show\n"
1848"\n"
1849"RULE-BODY:	check-state [LOG] | ACTION [LOG] ADDR [OPTION_LIST]\n"
1850"ACTION:	check-state | allow | count | deny | reject | skipto N |\n"
1851"		{divert|tee} PORT | forward ADDR | pipe N | queue N\n"
1852"ADDR:		[ MAC dst src ether_type ] \n"
1853"		[ from IPADDR [ PORT ] to IPADDR [ PORTLIST ] ]\n"
1854"IPADDR:	[not] { any | me | ip/bits{x,y,z} | IPLIST }\n"
1855"IPLIST:	{ ip | ip/bits | ip:mask }[,IPLIST]\n"
1856"OPTION_LIST:	OPTION [OPTION_LIST]\n"
1857"OPTION:	bridged | {dst-ip|src-ip} ADDR | {dst-port|src-port} LIST |\n"
1858"	estab | frag | {gid|uid} N | icmptypes LIST | in | out | ipid LIST |\n"
1859"	iplen LIST | ipoptions SPEC | ipprecedence | ipsec | iptos SPEC |\n"
1860"	ipttl LIST | ipversion VER | keep-state | layer2 | limit ... |\n"
1861"	mac ... | mac-type LIST | proto LIST | {recv|xmit|via} {IF|IPADDR} |\n"
1862"	setup | {tcpack|tcpseq|tcpwin} NN | tcpflags SPEC | tcpoptions SPEC |\n"
1863"	verrevpath\n"
1864);
1865exit(0);
1866}
1867
1868
1869static int
1870lookup_host (char *host, struct in_addr *ipaddr)
1871{
1872	struct hostent *he;
1873
1874	if (!inet_aton(host, ipaddr)) {
1875		if ((he = gethostbyname(host)) == NULL)
1876			return(-1);
1877		*ipaddr = *(struct in_addr *)he->h_addr_list[0];
1878	}
1879	return(0);
1880}
1881
1882/*
1883 * fills the addr and mask fields in the instruction as appropriate from av.
1884 * Update length as appropriate.
1885 * The following formats are allowed:
1886 *	any	matches any IP. Actually returns an empty instruction.
1887 *	me	returns O_IP_*_ME
1888 *	1.2.3.4		single IP address
1889 *	1.2.3.4:5.6.7.8	address:mask
1890 *	1.2.3.4/24	address/mask
1891 *	1.2.3.4/26{1,6,5,4,23}	set of addresses in a subnet
1892 * We can have multiple comma-separated address/mask entries.
1893 */
1894static void
1895fill_ip(ipfw_insn_ip *cmd, char *av)
1896{
1897	int len = 0;
1898	uint32_t *d = ((ipfw_insn_u32 *)cmd)->d;
1899
1900	cmd->o.len &= ~F_LEN_MASK;	/* zero len */
1901
1902	if (!strncmp(av, "any", strlen(av)))
1903		return;
1904
1905	if (!strncmp(av, "me", strlen(av))) {
1906		cmd->o.len |= F_INSN_SIZE(ipfw_insn);
1907		return;
1908	}
1909
1910    while (av) {
1911	/*
1912	 * After the address we can have '/' or ':' indicating a mask,
1913	 * ',' indicating another address follows, '{' indicating a
1914	 * set of addresses of unspecified size.
1915	 */
1916	char *p = strpbrk(av, "/:,{");
1917	int masklen;
1918	char md;
1919
1920	if (p) {
1921		md = *p;
1922		*p++ = '\0';
1923	} else
1924		md = '\0';
1925
1926	if (lookup_host(av, (struct in_addr *)&d[0]) != 0)
1927		errx(EX_NOHOST, "hostname ``%s'' unknown", av);
1928	switch (md) {
1929	case ':':
1930		if (!inet_aton(p, (struct in_addr *)&d[1]))
1931			errx(EX_DATAERR, "bad netmask ``%s''", p);
1932		break;
1933	case '/':
1934		masklen = atoi(p);
1935		if (masklen == 0)
1936			d[1] = htonl(0);	/* mask */
1937		else if (masklen > 32)
1938			errx(EX_DATAERR, "bad width ``%s''", p);
1939		else
1940			d[1] = htonl(~0 << (32 - masklen));
1941		break;
1942	case '{':	/* no mask, assume /24 and put back the '{' */
1943		d[1] = htonl(~0 << (32 - 24));
1944		*(--p) = md;
1945		break;
1946
1947	case ',':	/* single address plus continuation */
1948		*(--p) = md;
1949		/* FALLTHROUGH */
1950	case 0:		/* initialization value */
1951	default:
1952		d[1] = htonl(~0);	/* force /32 */
1953		break;
1954	}
1955	d[0] &= d[1];		/* mask base address with mask */
1956	/* find next separator */
1957	if (p)
1958		p = strpbrk(p, ",{");
1959	if (p && *p == '{') {
1960		/*
1961		 * We have a set of addresses. They are stored as follows:
1962		 *   arg1	is the set size (powers of 2, 2..256)
1963		 *   addr	is the base address IN HOST FORMAT
1964		 *   mask..	is an array of arg1 bits (rounded up to
1965		 *		the next multiple of 32) with bits set
1966		 *		for each host in the map.
1967		 */
1968		uint32_t *map = (uint32_t *)&cmd->mask;
1969		int low, high;
1970		int i = contigmask((uint8_t *)&(d[1]), 32);
1971
1972		if (len > 0)
1973			errx(EX_DATAERR, "address set cannot be in a list");
1974		if (i < 24 || i > 31)
1975			errx(EX_DATAERR, "invalid set with mask %d\n", i);
1976		cmd->o.arg1 = 1<<(32-i);	/* map length		*/
1977		d[0] = ntohl(d[0]);		/* base addr in host format */
1978		cmd->o.opcode = O_IP_DST_SET;	/* default */
1979		cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32) + (cmd->o.arg1+31)/32;
1980		for (i = 0; i < (cmd->o.arg1+31)/32 ; i++)
1981			map[i] = 0;	/* clear map */
1982
1983		av = p + 1;
1984		low = d[0] & 0xff;
1985		high = low + cmd->o.arg1 - 1;
1986		/*
1987		 * Here, i stores the previous value when we specify a range
1988		 * of addresses within a mask, e.g. 45-63. i = -1 means we
1989		 * have no previous value.
1990		 */
1991		i = -1;	/* previous value in a range */
1992		while (isdigit(*av)) {
1993			char *s;
1994			int a = strtol(av, &s, 0);
1995
1996			if (s == av) { /* no parameter */
1997			    if (*av != '}')
1998				errx(EX_DATAERR, "set not closed\n");
1999			    if (i != -1)
2000				errx(EX_DATAERR, "incomplete range %d-", i);
2001			    break;
2002			}
2003			if (a < low || a > high)
2004			    errx(EX_DATAERR, "addr %d out of range [%d-%d]\n",
2005				a, low, high);
2006			a -= low;
2007			if (i == -1)	/* no previous in range */
2008			    i = a;
2009			else {		/* check that range is valid */
2010			    if (i > a)
2011				errx(EX_DATAERR, "invalid range %d-%d",
2012					i+low, a+low);
2013			    if (*s == '-')
2014				errx(EX_DATAERR, "double '-' in range");
2015			}
2016			for (; i <= a; i++)
2017			    map[i/32] |= 1<<(i & 31);
2018			i = -1;
2019			if (*s == '-')
2020			    i = a;
2021			else if (*s == '}')
2022			    break;
2023			av = s+1;
2024		}
2025		return;
2026	}
2027	av = p;
2028	if (av)			/* then *av must be a ',' */
2029		av++;
2030
2031	/* Check this entry */
2032	if (d[1] == 0) { /* "any", specified as x.x.x.x/0 */
2033		/*
2034		 * 'any' turns the entire list into a NOP.
2035		 * 'not any' never matches, so it is removed from the
2036		 * list unless it is the only item, in which case we
2037		 * report an error.
2038		 */
2039		if (cmd->o.len & F_NOT) {	/* "not any" never matches */
2040			if (av == NULL && len == 0) /* only this entry */
2041				errx(EX_DATAERR, "not any never matches");
2042		}
2043		/* else do nothing and skip this entry */
2044		continue;
2045	}
2046	/* A single IP can be stored in an optimized format */
2047	if (d[1] == IP_MASK_ALL && av == NULL && len == 0) {
2048		cmd->o.len |= F_INSN_SIZE(ipfw_insn_u32);
2049		return;
2050	}
2051	len += 2;	/* two words... */
2052	d += 2;
2053    } /* end while */
2054    cmd->o.len |= len+1;
2055}
2056
2057
2058/*
2059 * helper function to process a set of flags and set bits in the
2060 * appropriate masks.
2061 */
2062static void
2063fill_flags(ipfw_insn *cmd, enum ipfw_opcodes opcode,
2064	struct _s_x *flags, char *p)
2065{
2066	uint8_t set=0, clear=0;
2067
2068	while (p && *p) {
2069		char *q;	/* points to the separator */
2070		int val;
2071		uint8_t *which;	/* mask we are working on */
2072
2073		if (*p == '!') {
2074			p++;
2075			which = &clear;
2076		} else
2077			which = &set;
2078		q = strchr(p, ',');
2079		if (q)
2080			*q++ = '\0';
2081		val = match_token(flags, p);
2082		if (val <= 0)
2083			errx(EX_DATAERR, "invalid flag %s", p);
2084		*which |= (uint8_t)val;
2085		p = q;
2086	}
2087        cmd->opcode = opcode;
2088        cmd->len =  (cmd->len & (F_NOT | F_OR)) | 1;
2089        cmd->arg1 = (set & 0xff) | ( (clear & 0xff) << 8);
2090}
2091
2092
2093static void
2094delete(int ac, char *av[])
2095{
2096	uint32_t rulenum;
2097	struct dn_pipe p;
2098	int i;
2099	int exitval = EX_OK;
2100	int do_set = 0;
2101
2102	memset(&p, 0, sizeof p);
2103
2104	av++; ac--;
2105	if (ac > 0 && !strncmp(*av, "set", strlen(*av))) {
2106		do_set = 1;	/* delete set */
2107		ac--; av++;
2108	}
2109
2110	/* Rule number */
2111	while (ac && isdigit(**av)) {
2112		i = atoi(*av); av++; ac--;
2113		if (do_pipe) {
2114			if (do_pipe == 1)
2115				p.pipe_nr = i;
2116			else
2117				p.fs.fs_nr = i;
2118			i = do_cmd(IP_DUMMYNET_DEL, &p, sizeof p);
2119			if (i) {
2120				exitval = 1;
2121				warn("rule %u: setsockopt(IP_DUMMYNET_DEL)",
2122				    do_pipe == 1 ? p.pipe_nr : p.fs.fs_nr);
2123			}
2124		} else {
2125			rulenum =  (i & 0xffff) | (do_set << 24);
2126			i = do_cmd(IP_FW_DEL, &rulenum, sizeof rulenum);
2127			if (i) {
2128				exitval = EX_UNAVAILABLE;
2129				warn("rule %u: setsockopt(IP_FW_DEL)",
2130				    rulenum);
2131			}
2132		}
2133	}
2134	if (exitval != EX_OK)
2135		exit(exitval);
2136}
2137
2138
2139/*
2140 * fill the interface structure. We do not check the name as we can
2141 * create interfaces dynamically, so checking them at insert time
2142 * makes relatively little sense.
2143 * Interface names containing '*', '?', or '[' are assumed to be shell
2144 * patterns which match interfaces.
2145 */
2146static void
2147fill_iface(ipfw_insn_if *cmd, char *arg)
2148{
2149	cmd->name[0] = '\0';
2150	cmd->o.len |= F_INSN_SIZE(ipfw_insn_if);
2151
2152	/* Parse the interface or address */
2153	if (!strcmp(arg, "any"))
2154		cmd->o.len = 0;		/* effectively ignore this command */
2155	else if (!isdigit(*arg)) {
2156		strlcpy(cmd->name, arg, sizeof(cmd->name));
2157		cmd->p.glob = strpbrk(arg, "*?[") != NULL ? 1 : 0;
2158	} else if (!inet_aton(arg, &cmd->p.ip))
2159		errx(EX_DATAERR, "bad ip address ``%s''", arg);
2160}
2161
2162/*
2163 * the following macro returns an error message if we run out of
2164 * arguments.
2165 */
2166#define	NEED1(msg)	{if (!ac) errx(EX_USAGE, msg);}
2167
2168static void
2169config_pipe(int ac, char **av)
2170{
2171	struct dn_pipe p;
2172	int i;
2173	char *end;
2174	uint32_t a;
2175	void *par = NULL;
2176
2177	memset(&p, 0, sizeof p);
2178
2179	av++; ac--;
2180	/* Pipe number */
2181	if (ac && isdigit(**av)) {
2182		i = atoi(*av); av++; ac--;
2183		if (do_pipe == 1)
2184			p.pipe_nr = i;
2185		else
2186			p.fs.fs_nr = i;
2187	}
2188	while (ac > 0) {
2189		double d;
2190		int tok = match_token(dummynet_params, *av);
2191		ac--; av++;
2192
2193		switch(tok) {
2194		case TOK_NOERROR:
2195			p.fs.flags_fs |= DN_NOERROR;
2196			break;
2197
2198		case TOK_PLR:
2199			NEED1("plr needs argument 0..1\n");
2200			d = strtod(av[0], NULL);
2201			if (d > 1)
2202				d = 1;
2203			else if (d < 0)
2204				d = 0;
2205			p.fs.plr = (int)(d*0x7fffffff);
2206			ac--; av++;
2207			break;
2208
2209		case TOK_QUEUE:
2210			NEED1("queue needs queue size\n");
2211			end = NULL;
2212			p.fs.qsize = strtoul(av[0], &end, 0);
2213			if (*end == 'K' || *end == 'k') {
2214				p.fs.flags_fs |= DN_QSIZE_IS_BYTES;
2215				p.fs.qsize *= 1024;
2216			} else if (*end == 'B' || !strncmp(end, "by", 2)) {
2217				p.fs.flags_fs |= DN_QSIZE_IS_BYTES;
2218			}
2219			ac--; av++;
2220			break;
2221
2222		case TOK_BUCKETS:
2223			NEED1("buckets needs argument\n");
2224			p.fs.rq_size = strtoul(av[0], NULL, 0);
2225			ac--; av++;
2226			break;
2227
2228		case TOK_MASK:
2229			NEED1("mask needs mask specifier\n");
2230			/*
2231			 * per-flow queue, mask is dst_ip, dst_port,
2232			 * src_ip, src_port, proto measured in bits
2233			 */
2234			par = NULL;
2235
2236			p.fs.flow_mask.dst_ip = 0;
2237			p.fs.flow_mask.src_ip = 0;
2238			p.fs.flow_mask.dst_port = 0;
2239			p.fs.flow_mask.src_port = 0;
2240			p.fs.flow_mask.proto = 0;
2241			end = NULL;
2242
2243			while (ac >= 1) {
2244			    uint32_t *p32 = NULL;
2245			    uint16_t *p16 = NULL;
2246
2247			    tok = match_token(dummynet_params, *av);
2248			    ac--; av++;
2249			    switch(tok) {
2250			    case TOK_ALL:
2251				    /*
2252				     * special case, all bits significant
2253				     */
2254				    p.fs.flow_mask.dst_ip = ~0;
2255				    p.fs.flow_mask.src_ip = ~0;
2256				    p.fs.flow_mask.dst_port = ~0;
2257				    p.fs.flow_mask.src_port = ~0;
2258				    p.fs.flow_mask.proto = ~0;
2259				    p.fs.flags_fs |= DN_HAVE_FLOW_MASK;
2260				    goto end_mask;
2261
2262			    case TOK_DSTIP:
2263				    p32 = &p.fs.flow_mask.dst_ip;
2264				    break;
2265
2266			    case TOK_SRCIP:
2267				    p32 = &p.fs.flow_mask.src_ip;
2268				    break;
2269
2270			    case TOK_DSTPORT:
2271				    p16 = &p.fs.flow_mask.dst_port;
2272				    break;
2273
2274			    case TOK_SRCPORT:
2275				    p16 = &p.fs.flow_mask.src_port;
2276				    break;
2277
2278			    case TOK_PROTO:
2279				    break;
2280
2281			    default:
2282				    ac++; av--; /* backtrack */
2283				    goto end_mask;
2284			    }
2285			    if (ac < 1)
2286				    errx(EX_USAGE, "mask: value missing");
2287			    if (*av[0] == '/') {
2288				    a = strtoul(av[0]+1, &end, 0);
2289				    a = (a == 32) ? ~0 : (1 << a) - 1;
2290			    } else
2291				    a = strtoul(av[0], &end, 0);
2292			    if (p32 != NULL)
2293				    *p32 = a;
2294			    else if (p16 != NULL) {
2295				    if (a > 65535)
2296					    errx(EX_DATAERR,
2297						"mask: must be 16 bit");
2298				    *p16 = (uint16_t)a;
2299			    } else {
2300				    if (a > 255)
2301					    errx(EX_DATAERR,
2302						"mask: must be 8 bit");
2303				    p.fs.flow_mask.proto = (uint8_t)a;
2304			    }
2305			    if (a != 0)
2306				    p.fs.flags_fs |= DN_HAVE_FLOW_MASK;
2307			    ac--; av++;
2308			} /* end while, config masks */
2309end_mask:
2310			break;
2311
2312		case TOK_RED:
2313		case TOK_GRED:
2314			NEED1("red/gred needs w_q/min_th/max_th/max_p\n");
2315			p.fs.flags_fs |= DN_IS_RED;
2316			if (tok == TOK_GRED)
2317				p.fs.flags_fs |= DN_IS_GENTLE_RED;
2318			/*
2319			 * the format for parameters is w_q/min_th/max_th/max_p
2320			 */
2321			if ((end = strsep(&av[0], "/"))) {
2322			    double w_q = strtod(end, NULL);
2323			    if (w_q > 1 || w_q <= 0)
2324				errx(EX_DATAERR, "0 < w_q <= 1");
2325			    p.fs.w_q = (int) (w_q * (1 << SCALE_RED));
2326			}
2327			if ((end = strsep(&av[0], "/"))) {
2328			    p.fs.min_th = strtoul(end, &end, 0);
2329			    if (*end == 'K' || *end == 'k')
2330				p.fs.min_th *= 1024;
2331			}
2332			if ((end = strsep(&av[0], "/"))) {
2333			    p.fs.max_th = strtoul(end, &end, 0);
2334			    if (*end == 'K' || *end == 'k')
2335				p.fs.max_th *= 1024;
2336			}
2337			if ((end = strsep(&av[0], "/"))) {
2338			    double max_p = strtod(end, NULL);
2339			    if (max_p > 1 || max_p <= 0)
2340				errx(EX_DATAERR, "0 < max_p <= 1");
2341			    p.fs.max_p = (int)(max_p * (1 << SCALE_RED));
2342			}
2343			ac--; av++;
2344			break;
2345
2346		case TOK_DROPTAIL:
2347			p.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED);
2348			break;
2349
2350		case TOK_BW:
2351			NEED1("bw needs bandwidth or interface\n");
2352			if (do_pipe != 1)
2353			    errx(EX_DATAERR, "bandwidth only valid for pipes");
2354			/*
2355			 * set clocking interface or bandwidth value
2356			 */
2357			if (av[0][0] >= 'a' && av[0][0] <= 'z') {
2358			    int l = sizeof(p.if_name)-1;
2359			    /* interface name */
2360			    strncpy(p.if_name, av[0], l);
2361			    p.if_name[l] = '\0';
2362			    p.bandwidth = 0;
2363			} else {
2364			    p.if_name[0] = '\0';
2365			    p.bandwidth = strtoul(av[0], &end, 0);
2366			    if (*end == 'K' || *end == 'k') {
2367				end++;
2368				p.bandwidth *= 1000;
2369			    } else if (*end == 'M') {
2370				end++;
2371				p.bandwidth *= 1000000;
2372			    }
2373			    if (*end == 'B' || !strncmp(end, "by", 2))
2374				p.bandwidth *= 8;
2375			    if (p.bandwidth < 0)
2376				errx(EX_DATAERR, "bandwidth too large");
2377			}
2378			ac--; av++;
2379			break;
2380
2381		case TOK_DELAY:
2382			if (do_pipe != 1)
2383				errx(EX_DATAERR, "delay only valid for pipes");
2384			NEED1("delay needs argument 0..10000ms\n");
2385			p.delay = strtoul(av[0], NULL, 0);
2386			ac--; av++;
2387			break;
2388
2389		case TOK_WEIGHT:
2390			if (do_pipe == 1)
2391				errx(EX_DATAERR,"weight only valid for queues");
2392			NEED1("weight needs argument 0..100\n");
2393			p.fs.weight = strtoul(av[0], &end, 0);
2394			ac--; av++;
2395			break;
2396
2397		case TOK_PIPE:
2398			if (do_pipe == 1)
2399				errx(EX_DATAERR,"pipe only valid for queues");
2400			NEED1("pipe needs pipe_number\n");
2401			p.fs.parent_nr = strtoul(av[0], &end, 0);
2402			ac--; av++;
2403			break;
2404
2405		default:
2406			errx(EX_DATAERR, "unrecognised option ``%s''", *av);
2407		}
2408	}
2409	if (do_pipe == 1) {
2410		if (p.pipe_nr == 0)
2411			errx(EX_DATAERR, "pipe_nr must be > 0");
2412		if (p.delay > 10000)
2413			errx(EX_DATAERR, "delay must be < 10000");
2414	} else { /* do_pipe == 2, queue */
2415		if (p.fs.parent_nr == 0)
2416			errx(EX_DATAERR, "pipe must be > 0");
2417		if (p.fs.weight >100)
2418			errx(EX_DATAERR, "weight must be <= 100");
2419	}
2420	if (p.fs.flags_fs & DN_QSIZE_IS_BYTES) {
2421		if (p.fs.qsize > 1024*1024)
2422			errx(EX_DATAERR, "queue size must be < 1MB");
2423	} else {
2424		if (p.fs.qsize > 100)
2425			errx(EX_DATAERR, "2 <= queue size <= 100");
2426	}
2427	if (p.fs.flags_fs & DN_IS_RED) {
2428		size_t len;
2429		int lookup_depth, avg_pkt_size;
2430		double s, idle, weight, w_q;
2431		struct clockinfo ck;
2432		int t;
2433
2434		if (p.fs.min_th >= p.fs.max_th)
2435		    errx(EX_DATAERR, "min_th %d must be < than max_th %d",
2436			p.fs.min_th, p.fs.max_th);
2437		if (p.fs.max_th == 0)
2438		    errx(EX_DATAERR, "max_th must be > 0");
2439
2440		len = sizeof(int);
2441		if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
2442			&lookup_depth, &len, NULL, 0) == -1)
2443
2444		    errx(1, "sysctlbyname(\"%s\")",
2445			"net.inet.ip.dummynet.red_lookup_depth");
2446		if (lookup_depth == 0)
2447		    errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth"
2448			" must be greater than zero");
2449
2450		len = sizeof(int);
2451		if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
2452			&avg_pkt_size, &len, NULL, 0) == -1)
2453
2454		    errx(1, "sysctlbyname(\"%s\")",
2455			"net.inet.ip.dummynet.red_avg_pkt_size");
2456		if (avg_pkt_size == 0)
2457			errx(EX_DATAERR,
2458			    "net.inet.ip.dummynet.red_avg_pkt_size must"
2459			    " be greater than zero");
2460
2461		len = sizeof(struct clockinfo);
2462		if (sysctlbyname("kern.clockrate", &ck, &len, NULL, 0) == -1)
2463			errx(1, "sysctlbyname(\"%s\")", "kern.clockrate");
2464
2465		/*
2466		 * Ticks needed for sending a medium-sized packet.
2467		 * Unfortunately, when we are configuring a WF2Q+ queue, we
2468		 * do not have bandwidth information, because that is stored
2469		 * in the parent pipe, and also we have multiple queues
2470		 * competing for it. So we set s=0, which is not very
2471		 * correct. But on the other hand, why do we want RED with
2472		 * WF2Q+ ?
2473		 */
2474		if (p.bandwidth==0) /* this is a WF2Q+ queue */
2475			s = 0;
2476		else
2477			s = ck.hz * avg_pkt_size * 8 / p.bandwidth;
2478
2479		/*
2480		 * max idle time (in ticks) before avg queue size becomes 0.
2481		 * NOTA:  (3/w_q) is approx the value x so that
2482		 * (1-w_q)^x < 10^-3.
2483		 */
2484		w_q = ((double)p.fs.w_q) / (1 << SCALE_RED);
2485		idle = s * 3. / w_q;
2486		p.fs.lookup_step = (int)idle / lookup_depth;
2487		if (!p.fs.lookup_step)
2488			p.fs.lookup_step = 1;
2489		weight = 1 - w_q;
2490		for (t = p.fs.lookup_step; t > 0; --t)
2491			weight *= weight;
2492		p.fs.lookup_weight = (int)(weight * (1 << SCALE_RED));
2493	}
2494	i = do_cmd(IP_DUMMYNET_CONFIGURE, &p, sizeof p);
2495	if (i)
2496		err(1, "setsockopt(%s)", "IP_DUMMYNET_CONFIGURE");
2497}
2498
2499static void
2500get_mac_addr_mask(char *p, uint8_t *addr, uint8_t *mask)
2501{
2502	int i, l;
2503
2504	for (i=0; i<6; i++)
2505		addr[i] = mask[i] = 0;
2506	if (!strcmp(p, "any"))
2507		return;
2508
2509	for (i=0; *p && i<6;i++, p++) {
2510		addr[i] = strtol(p, &p, 16);
2511		if (*p != ':') /* we start with the mask */
2512			break;
2513	}
2514	if (*p == '/') { /* mask len */
2515		l = strtol(p+1, &p, 0);
2516		for (i=0; l>0; l -=8, i++)
2517			mask[i] = (l >=8) ? 0xff : (~0) << (8-l);
2518	} else if (*p == '&') { /* mask */
2519		for (i=0, p++; *p && i<6;i++, p++) {
2520			mask[i] = strtol(p, &p, 16);
2521			if (*p != ':')
2522				break;
2523		}
2524	} else if (*p == '\0') {
2525		for (i=0; i<6; i++)
2526			mask[i] = 0xff;
2527	}
2528	for (i=0; i<6; i++)
2529		addr[i] &= mask[i];
2530}
2531
2532/*
2533 * helper function, updates the pointer to cmd with the length
2534 * of the current command, and also cleans up the first word of
2535 * the new command in case it has been clobbered before.
2536 */
2537static ipfw_insn *
2538next_cmd(ipfw_insn *cmd)
2539{
2540	cmd += F_LEN(cmd);
2541	bzero(cmd, sizeof(*cmd));
2542	return cmd;
2543}
2544
2545/*
2546 * Takes arguments and copies them into a comment
2547 */
2548static void
2549fill_comment(ipfw_insn *cmd, int ac, char **av)
2550{
2551	int i, l;
2552	char *p = (char *)(cmd + 1);
2553
2554	cmd->opcode = O_NOP;
2555	cmd->len =  (cmd->len & (F_NOT | F_OR));
2556
2557	/* Compute length of comment string. */
2558	for (i = 0, l = 0; i < ac; i++)
2559		l += strlen(av[i]) + 1;
2560	if (l == 0)
2561		return;
2562	if (l > 84)
2563		errx(EX_DATAERR,
2564		    "comment too long (max 80 chars)");
2565	l = 1 + (l+3)/4;
2566	cmd->len =  (cmd->len & (F_NOT | F_OR)) | l;
2567	for (i = 0; i < ac; i++) {
2568		strcpy(p, av[i]);
2569		p += strlen(av[i]);
2570		*p++ = ' ';
2571	}
2572	*(--p) = '\0';
2573}
2574
2575/*
2576 * A function to fill simple commands of size 1.
2577 * Existing flags are preserved.
2578 */
2579static void
2580fill_cmd(ipfw_insn *cmd, enum ipfw_opcodes opcode, int flags, uint16_t arg)
2581{
2582	cmd->opcode = opcode;
2583	cmd->len =  ((cmd->len | flags) & (F_NOT | F_OR)) | 1;
2584	cmd->arg1 = arg;
2585}
2586
2587/*
2588 * Fetch and add the MAC address and type, with masks. This generates one or
2589 * two microinstructions, and returns the pointer to the last one.
2590 */
2591static ipfw_insn *
2592add_mac(ipfw_insn *cmd, int ac, char *av[])
2593{
2594	ipfw_insn_mac *mac;
2595
2596	if (ac < 2)
2597		errx(EX_DATAERR, "MAC dst src");
2598
2599	cmd->opcode = O_MACADDR2;
2600	cmd->len = (cmd->len & (F_NOT | F_OR)) | F_INSN_SIZE(ipfw_insn_mac);
2601
2602	mac = (ipfw_insn_mac *)cmd;
2603	get_mac_addr_mask(av[0], mac->addr, mac->mask);	/* dst */
2604	get_mac_addr_mask(av[1], &(mac->addr[6]), &(mac->mask[6])); /* src */
2605	return cmd;
2606}
2607
2608static ipfw_insn *
2609add_mactype(ipfw_insn *cmd, int ac, char *av)
2610{
2611	if (ac < 1)
2612		errx(EX_DATAERR, "missing MAC type");
2613	if (strcmp(av, "any") != 0) { /* we have a non-null type */
2614		fill_newports((ipfw_insn_u16 *)cmd, av, IPPROTO_ETHERTYPE);
2615		cmd->opcode = O_MAC_TYPE;
2616		return cmd;
2617	} else
2618		return NULL;
2619}
2620
2621static ipfw_insn *
2622add_proto(ipfw_insn *cmd, char *av)
2623{
2624	struct protoent *pe;
2625	u_char proto = 0;
2626
2627	if (!strncmp(av, "all", strlen(av)))
2628		; /* same as "ip" */
2629	else if ((proto = atoi(av)) > 0)
2630		; /* all done! */
2631	else if ((pe = getprotobyname(av)) != NULL)
2632		proto = pe->p_proto;
2633	else
2634		return NULL;
2635	if (proto != IPPROTO_IP)
2636		fill_cmd(cmd, O_PROTO, 0, proto);
2637	return cmd;
2638}
2639
2640static ipfw_insn *
2641add_srcip(ipfw_insn *cmd, char *av)
2642{
2643	fill_ip((ipfw_insn_ip *)cmd, av);
2644	if (cmd->opcode == O_IP_DST_SET)			/* set */
2645		cmd->opcode = O_IP_SRC_SET;
2646	else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn))		/* me */
2647		cmd->opcode = O_IP_SRC_ME;
2648	else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32))	/* one IP */
2649		cmd->opcode = O_IP_SRC;
2650	else							/* addr/mask */
2651		cmd->opcode = O_IP_SRC_MASK;
2652	return cmd;
2653}
2654
2655static ipfw_insn *
2656add_dstip(ipfw_insn *cmd, char *av)
2657{
2658	fill_ip((ipfw_insn_ip *)cmd, av);
2659	if (cmd->opcode == O_IP_DST_SET)			/* set */
2660		;
2661	else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn))		/* me */
2662		cmd->opcode = O_IP_DST_ME;
2663	else if (F_LEN(cmd) == F_INSN_SIZE(ipfw_insn_u32))	/* one IP */
2664		cmd->opcode = O_IP_DST;
2665	else							/* addr/mask */
2666		cmd->opcode = O_IP_DST_MASK;
2667	return cmd;
2668}
2669
2670static ipfw_insn *
2671add_ports(ipfw_insn *cmd, char *av, u_char proto, int opcode)
2672{
2673	if (!strncmp(av, "any", strlen(av))) {
2674		return NULL;
2675	} else if (fill_newports((ipfw_insn_u16 *)cmd, av, proto)) {
2676		/* XXX todo: check that we have a protocol with ports */
2677		cmd->opcode = opcode;
2678		return cmd;
2679	}
2680	return NULL;
2681}
2682
2683/*
2684 * Parse arguments and assemble the microinstructions which make up a rule.
2685 * Rules are added into the 'rulebuf' and then copied in the correct order
2686 * into the actual rule.
2687 *
2688 * The syntax for a rule starts with the action, followed by an
2689 * optional log action, and the various match patterns.
2690 * In the assembled microcode, the first opcode must be an O_PROBE_STATE
2691 * (generated if the rule includes a keep-state option), then the
2692 * various match patterns, the "log" action, and the actual action.
2693 *
2694 */
2695static void
2696add(int ac, char *av[])
2697{
2698	/*
2699	 * rules are added into the 'rulebuf' and then copied in
2700	 * the correct order into the actual rule.
2701	 * Some things that need to go out of order (prob, action etc.)
2702	 * go into actbuf[].
2703	 */
2704	static uint32_t rulebuf[255], actbuf[255], cmdbuf[255];
2705
2706	ipfw_insn *src, *dst, *cmd, *action, *prev=NULL;
2707	ipfw_insn *first_cmd;	/* first match pattern */
2708
2709	struct ip_fw *rule;
2710
2711	/*
2712	 * various flags used to record that we entered some fields.
2713	 */
2714	ipfw_insn *have_state = NULL;	/* check-state or keep-state */
2715
2716	int i;
2717
2718	int open_par = 0;	/* open parenthesis ( */
2719
2720	/* proto is here because it is used to fetch ports */
2721	u_char proto = IPPROTO_IP;	/* default protocol */
2722
2723	double match_prob = 1; /* match probability, default is always match */
2724
2725	bzero(actbuf, sizeof(actbuf));		/* actions go here */
2726	bzero(cmdbuf, sizeof(cmdbuf));
2727	bzero(rulebuf, sizeof(rulebuf));
2728
2729	rule = (struct ip_fw *)rulebuf;
2730	cmd = (ipfw_insn *)cmdbuf;
2731	action = (ipfw_insn *)actbuf;
2732
2733	av++; ac--;
2734
2735	/* [rule N]	-- Rule number optional */
2736	if (ac && isdigit(**av)) {
2737		rule->rulenum = atoi(*av);
2738		av++;
2739		ac--;
2740	}
2741
2742	/* [set N]	-- set number (0..RESVD_SET), optional */
2743	if (ac > 1 && !strncmp(*av, "set", strlen(*av))) {
2744		int set = strtoul(av[1], NULL, 10);
2745		if (set < 0 || set > RESVD_SET)
2746			errx(EX_DATAERR, "illegal set %s", av[1]);
2747		rule->set = set;
2748		av += 2; ac -= 2;
2749	}
2750
2751	/* [prob D]	-- match probability, optional */
2752	if (ac > 1 && !strncmp(*av, "prob", strlen(*av))) {
2753		match_prob = strtod(av[1], NULL);
2754
2755		if (match_prob <= 0 || match_prob > 1)
2756			errx(EX_DATAERR, "illegal match prob. %s", av[1]);
2757		av += 2; ac -= 2;
2758	}
2759
2760	/* action	-- mandatory */
2761	NEED1("missing action");
2762	i = match_token(rule_actions, *av);
2763	ac--; av++;
2764	action->len = 1;	/* default */
2765	switch(i) {
2766	case TOK_CHECKSTATE:
2767		have_state = action;
2768		action->opcode = O_CHECK_STATE;
2769		break;
2770
2771	case TOK_ACCEPT:
2772		action->opcode = O_ACCEPT;
2773		break;
2774
2775	case TOK_DENY:
2776		action->opcode = O_DENY;
2777		action->arg1 = 0;
2778		break;
2779
2780	case TOK_REJECT:
2781		action->opcode = O_REJECT;
2782		action->arg1 = ICMP_UNREACH_HOST;
2783		break;
2784
2785	case TOK_RESET:
2786		action->opcode = O_REJECT;
2787		action->arg1 = ICMP_REJECT_RST;
2788		break;
2789
2790	case TOK_UNREACH:
2791		action->opcode = O_REJECT;
2792		NEED1("missing reject code");
2793		fill_reject_code(&action->arg1, *av);
2794		ac--; av++;
2795		break;
2796
2797	case TOK_COUNT:
2798		action->opcode = O_COUNT;
2799		break;
2800
2801	case TOK_QUEUE:
2802	case TOK_PIPE:
2803		action->len = F_INSN_SIZE(ipfw_insn_pipe);
2804	case TOK_SKIPTO:
2805		if (i == TOK_QUEUE)
2806			action->opcode = O_QUEUE;
2807		else if (i == TOK_PIPE)
2808			action->opcode = O_PIPE;
2809		else if (i == TOK_SKIPTO)
2810			action->opcode = O_SKIPTO;
2811		NEED1("missing skipto/pipe/queue number");
2812		action->arg1 = strtoul(*av, NULL, 10);
2813		av++; ac--;
2814		break;
2815
2816	case TOK_DIVERT:
2817	case TOK_TEE:
2818		action->opcode = (i == TOK_DIVERT) ? O_DIVERT : O_TEE;
2819		NEED1("missing divert/tee port");
2820		action->arg1 = strtoul(*av, NULL, 0);
2821		if (action->arg1 == 0) {
2822			struct servent *s;
2823			setservent(1);
2824			s = getservbyname(av[0], "divert");
2825			if (s != NULL)
2826				action->arg1 = ntohs(s->s_port);
2827			else
2828				errx(EX_DATAERR, "illegal divert/tee port");
2829		}
2830		ac--; av++;
2831		break;
2832
2833	case TOK_FORWARD: {
2834		ipfw_insn_sa *p = (ipfw_insn_sa *)action;
2835		char *s, *end;
2836
2837		NEED1("missing forward address[:port]");
2838
2839		action->opcode = O_FORWARD_IP;
2840		action->len = F_INSN_SIZE(ipfw_insn_sa);
2841
2842		p->sa.sin_len = sizeof(struct sockaddr_in);
2843		p->sa.sin_family = AF_INET;
2844		p->sa.sin_port = 0;
2845		/*
2846		 * locate the address-port separator (':' or ',')
2847		 */
2848		s = strchr(*av, ':');
2849		if (s == NULL)
2850			s = strchr(*av, ',');
2851		if (s != NULL) {
2852			*(s++) = '\0';
2853			i = strtoport(s, &end, 0 /* base */, 0 /* proto */);
2854			if (s == end)
2855				errx(EX_DATAERR,
2856				    "illegal forwarding port ``%s''", s);
2857			p->sa.sin_port = (u_short)i;
2858		}
2859		lookup_host(*av, &(p->sa.sin_addr));
2860		}
2861		ac--; av++;
2862		break;
2863
2864	case TOK_COMMENT:
2865		/* pretend it is a 'count' rule followed by the comment */
2866		action->opcode = O_COUNT;
2867		ac++; av--;	/* go back... */
2868		break;
2869
2870	default:
2871		errx(EX_DATAERR, "invalid action %s\n", av[-1]);
2872	}
2873	action = next_cmd(action);
2874
2875	/*
2876	 * [log [logamount N]]	-- log, optional
2877	 *
2878	 * If exists, it goes first in the cmdbuf, but then it is
2879	 * skipped in the copy section to the end of the buffer.
2880	 */
2881	if (ac && !strncmp(*av, "log", strlen(*av))) {
2882		ipfw_insn_log *c = (ipfw_insn_log *)cmd;
2883		int l;
2884
2885		cmd->len = F_INSN_SIZE(ipfw_insn_log);
2886		cmd->opcode = O_LOG;
2887		av++; ac--;
2888		if (ac && !strncmp(*av, "logamount", strlen(*av))) {
2889			ac--; av++;
2890			NEED1("logamount requires argument");
2891			l = atoi(*av);
2892			if (l < 0)
2893				errx(EX_DATAERR, "logamount must be positive");
2894			c->max_log = l;
2895			ac--; av++;
2896		}
2897		cmd = next_cmd(cmd);
2898	}
2899
2900	if (have_state)	/* must be a check-state, we are done */
2901		goto done;
2902
2903#define OR_START(target)					\
2904	if (ac && (*av[0] == '(' || *av[0] == '{')) {		\
2905		if (open_par)					\
2906			errx(EX_USAGE, "nested \"(\" not allowed\n"); \
2907		prev = NULL;					\
2908		open_par = 1;					\
2909		if ( (av[0])[1] == '\0') {			\
2910			ac--; av++;				\
2911		} else						\
2912			(*av)++;				\
2913	}							\
2914	target:							\
2915
2916
2917#define	CLOSE_PAR						\
2918	if (open_par) {						\
2919		if (ac && (					\
2920		    !strncmp(*av, ")", strlen(*av)) ||		\
2921		    !strncmp(*av, "}", strlen(*av)) )) {	\
2922			prev = NULL;				\
2923			open_par = 0;				\
2924			ac--; av++;				\
2925		} else						\
2926			errx(EX_USAGE, "missing \")\"\n");	\
2927	}
2928
2929#define NOT_BLOCK						\
2930	if (ac && !strncmp(*av, "not", strlen(*av))) {		\
2931		if (cmd->len & F_NOT)				\
2932			errx(EX_USAGE, "double \"not\" not allowed\n"); \
2933		cmd->len |= F_NOT;				\
2934		ac--; av++;					\
2935	}
2936
2937#define OR_BLOCK(target)					\
2938	if (ac && !strncmp(*av, "or", strlen(*av))) {		\
2939		if (prev == NULL || open_par == 0)		\
2940			errx(EX_DATAERR, "invalid OR block");	\
2941		prev->len |= F_OR;				\
2942		ac--; av++;					\
2943		goto target;					\
2944	}							\
2945	CLOSE_PAR;
2946
2947	first_cmd = cmd;
2948
2949#if 0
2950	/*
2951	 * MAC addresses, optional.
2952	 * If we have this, we skip the part "proto from src to dst"
2953	 * and jump straight to the option parsing.
2954	 */
2955	NOT_BLOCK;
2956	NEED1("missing protocol");
2957	if (!strncmp(*av, "MAC", strlen(*av)) ||
2958	    !strncmp(*av, "mac", strlen(*av))) {
2959		ac--; av++;	/* the "MAC" keyword */
2960		add_mac(cmd, ac, av); /* exits in case of errors */
2961		cmd = next_cmd(cmd);
2962		ac -= 2; av += 2;	/* dst-mac and src-mac */
2963		NOT_BLOCK;
2964		NEED1("missing mac type");
2965		if (add_mactype(cmd, ac, av[0]))
2966			cmd = next_cmd(cmd);
2967		ac--; av++;	/* any or mac-type */
2968		goto read_options;
2969	}
2970#endif
2971
2972	/*
2973	 * protocol, mandatory
2974	 */
2975    OR_START(get_proto);
2976	NOT_BLOCK;
2977	NEED1("missing protocol");
2978	if (add_proto(cmd, *av)) {
2979		av++; ac--;
2980		if (F_LEN(cmd) == 0)	/* plain IP */
2981			proto = 0;
2982		else {
2983			proto = cmd->arg1;
2984			prev = cmd;
2985			cmd = next_cmd(cmd);
2986		}
2987	} else if (first_cmd != cmd) {
2988		errx(EX_DATAERR, "invalid protocol ``%s''", *av);
2989	} else
2990		goto read_options;
2991    OR_BLOCK(get_proto);
2992
2993	/*
2994	 * "from", mandatory
2995	 */
2996	if (!ac || strncmp(*av, "from", strlen(*av)))
2997		errx(EX_USAGE, "missing ``from''");
2998	ac--; av++;
2999
3000	/*
3001	 * source IP, mandatory
3002	 */
3003    OR_START(source_ip);
3004	NOT_BLOCK;	/* optional "not" */
3005	NEED1("missing source address");
3006	if (add_srcip(cmd, *av)) {
3007		ac--; av++;
3008		if (F_LEN(cmd) != 0) {	/* ! any */
3009			prev = cmd;
3010			cmd = next_cmd(cmd);
3011		}
3012	}
3013    OR_BLOCK(source_ip);
3014
3015	/*
3016	 * source ports, optional
3017	 */
3018	NOT_BLOCK;	/* optional "not" */
3019	if (ac) {
3020		if (!strncmp(*av, "any", strlen(*av)) ||
3021		    add_ports(cmd, *av, proto, O_IP_SRCPORT)) {
3022			ac--; av++;
3023			if (F_LEN(cmd) != 0)
3024				cmd = next_cmd(cmd);
3025		}
3026	}
3027
3028	/*
3029	 * "to", mandatory
3030	 */
3031	if (!ac || strncmp(*av, "to", strlen(*av)))
3032		errx(EX_USAGE, "missing ``to''");
3033	av++; ac--;
3034
3035	/*
3036	 * destination, mandatory
3037	 */
3038    OR_START(dest_ip);
3039	NOT_BLOCK;	/* optional "not" */
3040	NEED1("missing dst address");
3041	if (add_dstip(cmd, *av)) {
3042		ac--; av++;
3043		if (F_LEN(cmd) != 0) {	/* ! any */
3044			prev = cmd;
3045			cmd = next_cmd(cmd);
3046		}
3047	}
3048    OR_BLOCK(dest_ip);
3049
3050	/*
3051	 * dest. ports, optional
3052	 */
3053	NOT_BLOCK;	/* optional "not" */
3054	if (ac) {
3055		if (!strncmp(*av, "any", strlen(*av)) ||
3056		    add_ports(cmd, *av, proto, O_IP_DSTPORT)) {
3057			ac--; av++;
3058			if (F_LEN(cmd) != 0)
3059				cmd = next_cmd(cmd);
3060		}
3061	}
3062
3063read_options:
3064	if (ac && first_cmd == cmd) {
3065		/*
3066		 * nothing specified so far, store in the rule to ease
3067		 * printout later.
3068		 */
3069		 rule->_pad = 1;
3070	}
3071	prev = NULL;
3072	while (ac) {
3073		char *s;
3074		ipfw_insn_u32 *cmd32;	/* alias for cmd */
3075
3076		s = *av;
3077		cmd32 = (ipfw_insn_u32 *)cmd;
3078
3079		if (*s == '!') {	/* alternate syntax for NOT */
3080			if (cmd->len & F_NOT)
3081				errx(EX_USAGE, "double \"not\" not allowed\n");
3082			cmd->len = F_NOT;
3083			s++;
3084		}
3085		i = match_token(rule_options, s);
3086		ac--; av++;
3087		switch(i) {
3088		case TOK_NOT:
3089			if (cmd->len & F_NOT)
3090				errx(EX_USAGE, "double \"not\" not allowed\n");
3091			cmd->len = F_NOT;
3092			break;
3093
3094		case TOK_OR:
3095			if (open_par == 0 || prev == NULL)
3096				errx(EX_USAGE, "invalid \"or\" block\n");
3097			prev->len |= F_OR;
3098			break;
3099
3100		case TOK_STARTBRACE:
3101			if (open_par)
3102				errx(EX_USAGE, "+nested \"(\" not allowed\n");
3103			open_par = 1;
3104			break;
3105
3106		case TOK_ENDBRACE:
3107			if (!open_par)
3108				errx(EX_USAGE, "+missing \")\"\n");
3109			open_par = 0;
3110			prev = NULL;
3111        		break;
3112
3113		case TOK_IN:
3114			fill_cmd(cmd, O_IN, 0, 0);
3115			break;
3116
3117		case TOK_OUT:
3118			cmd->len ^= F_NOT; /* toggle F_NOT */
3119			fill_cmd(cmd, O_IN, 0, 0);
3120			break;
3121
3122		case TOK_FRAG:
3123			fill_cmd(cmd, O_FRAG, 0, 0);
3124			break;
3125
3126		case TOK_LAYER2:
3127			fill_cmd(cmd, O_LAYER2, 0, 0);
3128			break;
3129
3130		case TOK_XMIT:
3131		case TOK_RECV:
3132		case TOK_VIA:
3133			NEED1("recv, xmit, via require interface name"
3134				" or address");
3135			fill_iface((ipfw_insn_if *)cmd, av[0]);
3136			ac--; av++;
3137			if (F_LEN(cmd) == 0)	/* not a valid address */
3138				break;
3139			if (i == TOK_XMIT)
3140				cmd->opcode = O_XMIT;
3141			else if (i == TOK_RECV)
3142				cmd->opcode = O_RECV;
3143			else if (i == TOK_VIA)
3144				cmd->opcode = O_VIA;
3145			break;
3146
3147		case TOK_ICMPTYPES:
3148			NEED1("icmptypes requires list of types");
3149			fill_icmptypes((ipfw_insn_u32 *)cmd, *av);
3150			av++; ac--;
3151			break;
3152
3153		case TOK_IPTTL:
3154			NEED1("ipttl requires TTL");
3155			if (strpbrk(*av, "-,")) {
3156			    if (!add_ports(cmd, *av, 0, O_IPTTL))
3157				errx(EX_DATAERR, "invalid ipttl %s", *av);
3158			} else
3159			    fill_cmd(cmd, O_IPTTL, 0, strtoul(*av, NULL, 0));
3160			ac--; av++;
3161			break;
3162
3163		case TOK_IPID:
3164			NEED1("ipid requires id");
3165			if (strpbrk(*av, "-,")) {
3166			    if (!add_ports(cmd, *av, 0, O_IPID))
3167				errx(EX_DATAERR, "invalid ipid %s", *av);
3168			} else
3169			    fill_cmd(cmd, O_IPID, 0, strtoul(*av, NULL, 0));
3170			ac--; av++;
3171			break;
3172
3173		case TOK_IPLEN:
3174			NEED1("iplen requires length");
3175			if (strpbrk(*av, "-,")) {
3176			    if (!add_ports(cmd, *av, 0, O_IPLEN))
3177				errx(EX_DATAERR, "invalid ip len %s", *av);
3178			} else
3179			    fill_cmd(cmd, O_IPLEN, 0, strtoul(*av, NULL, 0));
3180			ac--; av++;
3181			break;
3182
3183		case TOK_IPVER:
3184			NEED1("ipver requires version");
3185			fill_cmd(cmd, O_IPVER, 0, strtoul(*av, NULL, 0));
3186			ac--; av++;
3187			break;
3188
3189		case TOK_IPPRECEDENCE:
3190			NEED1("ipprecedence requires value");
3191			fill_cmd(cmd, O_IPPRECEDENCE, 0,
3192			    (strtoul(*av, NULL, 0) & 7) << 5);
3193			ac--; av++;
3194			break;
3195
3196		case TOK_IPOPTS:
3197			NEED1("missing argument for ipoptions");
3198			fill_flags(cmd, O_IPOPT, f_ipopts, *av);
3199			ac--; av++;
3200			break;
3201
3202		case TOK_IPTOS:
3203			NEED1("missing argument for iptos");
3204			fill_flags(cmd, O_IPTOS, f_iptos, *av);
3205			ac--; av++;
3206			break;
3207
3208		case TOK_UID:
3209			NEED1("uid requires argument");
3210		    {
3211			char *end;
3212			uid_t uid;
3213			struct passwd *pwd;
3214
3215			cmd->opcode = O_UID;
3216			uid = strtoul(*av, &end, 0);
3217			pwd = (*end == '\0') ? getpwuid(uid) : getpwnam(*av);
3218			if (pwd == NULL)
3219				errx(EX_DATAERR, "uid \"%s\" nonexistent", *av);
3220			cmd32->d[0] = pwd->pw_uid;
3221			cmd->len = F_INSN_SIZE(ipfw_insn_u32);
3222			ac--; av++;
3223		    }
3224			break;
3225
3226		case TOK_GID:
3227			NEED1("gid requires argument");
3228		    {
3229			char *end;
3230			gid_t gid;
3231			struct group *grp;
3232
3233			cmd->opcode = O_GID;
3234			gid = strtoul(*av, &end, 0);
3235			grp = (*end == '\0') ? getgrgid(gid) : getgrnam(*av);
3236			if (grp == NULL)
3237				errx(EX_DATAERR, "gid \"%s\" nonexistent", *av);
3238			cmd32->d[0] = grp->gr_gid;
3239			cmd->len = F_INSN_SIZE(ipfw_insn_u32);
3240			ac--; av++;
3241		    }
3242			break;
3243
3244		case TOK_ESTAB:
3245			fill_cmd(cmd, O_ESTAB, 0, 0);
3246			break;
3247
3248		case TOK_SETUP:
3249			fill_cmd(cmd, O_TCPFLAGS, 0,
3250				(TH_SYN) | ( (TH_ACK) & 0xff) <<8 );
3251			break;
3252
3253		case TOK_TCPOPTS:
3254			NEED1("missing argument for tcpoptions");
3255			fill_flags(cmd, O_TCPOPTS, f_tcpopts, *av);
3256			ac--; av++;
3257			break;
3258
3259		case TOK_TCPSEQ:
3260		case TOK_TCPACK:
3261			NEED1("tcpseq/tcpack requires argument");
3262			cmd->len = F_INSN_SIZE(ipfw_insn_u32);
3263			cmd->opcode = (i == TOK_TCPSEQ) ? O_TCPSEQ : O_TCPACK;
3264			cmd32->d[0] = htonl(strtoul(*av, NULL, 0));
3265			ac--; av++;
3266			break;
3267
3268		case TOK_TCPWIN:
3269			NEED1("tcpwin requires length");
3270			fill_cmd(cmd, O_TCPWIN, 0,
3271			    htons(strtoul(*av, NULL, 0)));
3272			ac--; av++;
3273			break;
3274
3275		case TOK_TCPFLAGS:
3276			NEED1("missing argument for tcpflags");
3277			cmd->opcode = O_TCPFLAGS;
3278			fill_flags(cmd, O_TCPFLAGS, f_tcpflags, *av);
3279			ac--; av++;
3280			break;
3281
3282		case TOK_KEEPSTATE:
3283			if (open_par)
3284				errx(EX_USAGE, "keep-state cannot be part "
3285				    "of an or block");
3286			if (have_state)
3287				errx(EX_USAGE, "only one of keep-state "
3288					"and limit is allowed");
3289			have_state = cmd;
3290			fill_cmd(cmd, O_KEEP_STATE, 0, 0);
3291			break;
3292
3293		case TOK_LIMIT:
3294			if (open_par)
3295				errx(EX_USAGE, "limit cannot be part "
3296				    "of an or block");
3297			if (have_state)
3298				errx(EX_USAGE, "only one of keep-state "
3299					"and limit is allowed");
3300			NEED1("limit needs mask and # of connections");
3301			have_state = cmd;
3302		    {
3303			ipfw_insn_limit *c = (ipfw_insn_limit *)cmd;
3304
3305			cmd->len = F_INSN_SIZE(ipfw_insn_limit);
3306			cmd->opcode = O_LIMIT;
3307			c->limit_mask = 0;
3308			c->conn_limit = 0;
3309			for (; ac >1 ;) {
3310				int val;
3311
3312				val = match_token(limit_masks, *av);
3313				if (val <= 0)
3314					break;
3315				c->limit_mask |= val;
3316				ac--; av++;
3317			}
3318			c->conn_limit = atoi(*av);
3319			if (c->conn_limit == 0)
3320				errx(EX_USAGE, "limit: limit must be >0");
3321			if (c->limit_mask == 0)
3322				errx(EX_USAGE, "missing limit mask");
3323			ac--; av++;
3324		    }
3325			break;
3326
3327		case TOK_PROTO:
3328			NEED1("missing protocol");
3329			if (add_proto(cmd, *av)) {
3330				proto = cmd->arg1;
3331				ac--; av++;
3332			} else
3333				errx(EX_DATAERR, "invalid protocol ``%s''",
3334				    *av);
3335			break;
3336
3337		case TOK_SRCIP:
3338			NEED1("missing source IP");
3339			if (add_srcip(cmd, *av)) {
3340				ac--; av++;
3341			}
3342			break;
3343
3344		case TOK_DSTIP:
3345			NEED1("missing destination IP");
3346			if (add_dstip(cmd, *av)) {
3347				ac--; av++;
3348			}
3349			break;
3350
3351		case TOK_SRCPORT:
3352			NEED1("missing source port");
3353			if (!strncmp(*av, "any", strlen(*av)) ||
3354			    add_ports(cmd, *av, proto, O_IP_SRCPORT)) {
3355				ac--; av++;
3356			} else
3357				errx(EX_DATAERR, "invalid source port %s", *av);
3358			break;
3359
3360		case TOK_DSTPORT:
3361			NEED1("missing destination port");
3362			if (!strncmp(*av, "any", strlen(*av)) ||
3363			    add_ports(cmd, *av, proto, O_IP_DSTPORT)) {
3364				ac--; av++;
3365			} else
3366				errx(EX_DATAERR, "invalid destination port %s",
3367				    *av);
3368			break;
3369
3370		case TOK_MAC:
3371			if (ac < 2)
3372				errx(EX_USAGE, "MAC dst-mac src-mac");
3373			if (add_mac(cmd, ac, av)) {
3374				ac -= 2; av += 2;
3375			}
3376			break;
3377
3378		case TOK_MACTYPE:
3379			NEED1("missing mac type");
3380			if (!add_mactype(cmd, ac, *av))
3381				errx(EX_DATAERR, "invalid mac type %s", *av);
3382			ac--; av++;
3383			break;
3384
3385		case TOK_VERREVPATH:
3386			fill_cmd(cmd, O_VERREVPATH, 0, 0);
3387			break;
3388
3389		case TOK_IPSEC:
3390			fill_cmd(cmd, O_IPSEC, 0, 0);
3391			break;
3392
3393		case TOK_COMMENT:
3394			fill_comment(cmd, ac, av);
3395			av += ac;
3396			ac = 0;
3397			break;
3398
3399		default:
3400			errx(EX_USAGE, "unrecognised option [%d] %s\n", i, s);
3401		}
3402		if (F_LEN(cmd) > 0) {	/* prepare to advance */
3403			prev = cmd;
3404			cmd = next_cmd(cmd);
3405		}
3406	}
3407
3408done:
3409	/*
3410	 * Now copy stuff into the rule.
3411	 * If we have a keep-state option, the first instruction
3412	 * must be a PROBE_STATE (which is generated here).
3413	 * If we have a LOG option, it was stored as the first command,
3414	 * and now must be moved to the top of the action part.
3415	 */
3416	dst = (ipfw_insn *)rule->cmd;
3417
3418	/*
3419	 * First thing to write into the command stream is the match probability.
3420	 */
3421	if (match_prob != 1) { /* 1 means always match */
3422		dst->opcode = O_PROB;
3423		dst->len = 2;
3424		*((int32_t *)(dst+1)) = (int32_t)(match_prob * 0x7fffffff);
3425		dst += dst->len;
3426	}
3427
3428	/*
3429	 * generate O_PROBE_STATE if necessary
3430	 */
3431	if (have_state && have_state->opcode != O_CHECK_STATE) {
3432		fill_cmd(dst, O_PROBE_STATE, 0, 0);
3433		dst = next_cmd(dst);
3434	}
3435	/*
3436	 * copy all commands but O_LOG, O_KEEP_STATE, O_LIMIT
3437	 */
3438	for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) {
3439		i = F_LEN(src);
3440
3441		switch (src->opcode) {
3442		case O_LOG:
3443		case O_KEEP_STATE:
3444		case O_LIMIT:
3445			break;
3446		default:
3447			bcopy(src, dst, i * sizeof(uint32_t));
3448			dst += i;
3449		}
3450	}
3451
3452	/*
3453	 * put back the have_state command as last opcode
3454	 */
3455	if (have_state && have_state->opcode != O_CHECK_STATE) {
3456		i = F_LEN(have_state);
3457		bcopy(have_state, dst, i * sizeof(uint32_t));
3458		dst += i;
3459	}
3460	/*
3461	 * start action section
3462	 */
3463	rule->act_ofs = dst - rule->cmd;
3464
3465	/*
3466	 * put back O_LOG if necessary
3467	 */
3468	src = (ipfw_insn *)cmdbuf;
3469	if (src->opcode == O_LOG) {
3470		i = F_LEN(src);
3471		bcopy(src, dst, i * sizeof(uint32_t));
3472		dst += i;
3473	}
3474	/*
3475	 * copy all other actions
3476	 */
3477	for (src = (ipfw_insn *)actbuf; src != action; src += i) {
3478		i = F_LEN(src);
3479		bcopy(src, dst, i * sizeof(uint32_t));
3480		dst += i;
3481	}
3482
3483	rule->cmd_len = (uint32_t *)dst - (uint32_t *)(rule->cmd);
3484	i = (char *)dst - (char *)rule;
3485	if (do_cmd(IP_FW_ADD, rule, (uintptr_t)&i) == -1)
3486		err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD");
3487	if (!do_quiet)
3488		show_ipfw(rule, 0, 0);
3489}
3490
3491static void
3492zero(int ac, char *av[], int optname /* IP_FW_ZERO or IP_FW_RESETLOG */)
3493{
3494	int rulenum;
3495	int failed = EX_OK;
3496	char const *name = optname == IP_FW_ZERO ?  "ZERO" : "RESETLOG";
3497
3498	av++; ac--;
3499
3500	if (!ac) {
3501		/* clear all entries */
3502		if (do_cmd(optname, NULL, 0) < 0)
3503			err(EX_UNAVAILABLE, "setsockopt(IP_FW_%s)", name);
3504		if (!do_quiet)
3505			printf("%s.\n", optname == IP_FW_ZERO ?
3506			    "Accounting cleared":"Logging counts reset");
3507
3508		return;
3509	}
3510
3511	while (ac) {
3512		/* Rule number */
3513		if (isdigit(**av)) {
3514			rulenum = atoi(*av);
3515			av++;
3516			ac--;
3517			if (do_cmd(optname, &rulenum, sizeof rulenum)) {
3518				warn("rule %u: setsockopt(IP_FW_%s)",
3519				    rulenum, name);
3520				failed = EX_UNAVAILABLE;
3521			} else if (!do_quiet)
3522				printf("Entry %d %s.\n", rulenum,
3523				    optname == IP_FW_ZERO ?
3524					"cleared" : "logging count reset");
3525		} else {
3526			errx(EX_USAGE, "invalid rule number ``%s''", *av);
3527		}
3528	}
3529	if (failed != EX_OK)
3530		exit(failed);
3531}
3532
3533static void
3534flush(int force)
3535{
3536	int cmd = do_pipe ? IP_DUMMYNET_FLUSH : IP_FW_FLUSH;
3537
3538	if (!force && !do_quiet) { /* need to ask user */
3539		int c;
3540
3541		printf("Are you sure? [yn] ");
3542		fflush(stdout);
3543		do {
3544			c = toupper(getc(stdin));
3545			while (c != '\n' && getc(stdin) != '\n')
3546				if (feof(stdin))
3547					return; /* and do not flush */
3548		} while (c != 'Y' && c != 'N');
3549		printf("\n");
3550		if (c == 'N')	/* user said no */
3551			return;
3552	}
3553	if (do_cmd(cmd, NULL, 0) < 0)
3554		err(EX_UNAVAILABLE, "setsockopt(IP_%s_FLUSH)",
3555		    do_pipe ? "DUMMYNET" : "FW");
3556	if (!do_quiet)
3557		printf("Flushed all %s.\n", do_pipe ? "pipes" : "rules");
3558}
3559
3560/*
3561 * Free a the (locally allocated) copy of command line arguments.
3562 */
3563static void
3564free_args(int ac, char **av)
3565{
3566	int i;
3567
3568	for (i=0; i < ac; i++)
3569		free(av[i]);
3570	free(av);
3571}
3572
3573/*
3574 * Called with the arguments (excluding program name).
3575 * Returns 0 if successful, 1 if empty command, errx() in case of errors.
3576 */
3577static int
3578ipfw_main(int oldac, char **oldav)
3579{
3580	int ch, ac, save_ac;
3581	char **av, **save_av;
3582	int do_acct = 0;		/* Show packet/byte count */
3583	int do_force = 0;		/* Don't ask for confirmation */
3584
3585#define WHITESP		" \t\f\v\n\r"
3586	if (oldac == 0)
3587		return 1;
3588	else if (oldac == 1) {
3589		/*
3590		 * If we are called with a single string, try to split it into
3591		 * arguments for subsequent parsing.
3592		 * But first, remove spaces after a ',', by copying the string
3593		 * in-place.
3594		 */
3595		char *arg = oldav[0];	/* The string... */
3596		int l = strlen(arg);
3597		int copy = 0;		/* 1 if we need to copy, 0 otherwise */
3598		int i, j;
3599		for (i = j = 0; i < l; i++) {
3600			if (arg[i] == '#')	/* comment marker */
3601				break;
3602			if (copy) {
3603				arg[j++] = arg[i];
3604				copy = !index("," WHITESP, arg[i]);
3605			} else {
3606				copy = !index(WHITESP, arg[i]);
3607				if (copy)
3608					arg[j++] = arg[i];
3609			}
3610		}
3611		if (!copy && j > 0)	/* last char was a 'blank', remove it */
3612			j--;
3613		l = j;			/* the new argument length */
3614		arg[j++] = '\0';
3615		if (l == 0)		/* empty string! */
3616			return 1;
3617
3618		/*
3619		 * First, count number of arguments. Because of the previous
3620		 * processing, this is just the number of blanks plus 1.
3621		 */
3622		for (i = 0, ac = 1; i < l; i++)
3623			if (index(WHITESP, arg[i]) != NULL)
3624				ac++;
3625
3626		av = calloc(ac, sizeof(char *));
3627
3628		/*
3629		 * Second, copy arguments from cmd[] to av[]. For each one,
3630		 * j is the initial character, i is the one past the end.
3631		 */
3632		for (ac = 0, i = j = 0; i < l; i++)
3633			if (index(WHITESP, arg[i]) != NULL || i == l-1) {
3634				if (i == l-1)
3635					i++;
3636				av[ac] = calloc(i-j+1, 1);
3637				bcopy(arg+j, av[ac], i-j);
3638				ac++;
3639				j = i + 1;
3640			}
3641	} else {
3642		/*
3643		 * If an argument ends with ',' join with the next one.
3644		 */
3645		int first, i, l;
3646
3647		av = calloc(oldac, sizeof(char *));
3648		for (first = i = ac = 0, l = 0; i < oldac; i++) {
3649			char *arg = oldav[i];
3650			int k = strlen(arg);
3651
3652			l += k;
3653			if (arg[k-1] != ',' || i == oldac-1) {
3654				/* Time to copy. */
3655				av[ac] = calloc(l+1, 1);
3656				for (l=0; first <= i; first++) {
3657					strcat(av[ac]+l, oldav[first]);
3658					l += strlen(oldav[first]);
3659				}
3660				ac++;
3661				l = 0;
3662				first = i+1;
3663			}
3664		}
3665	}
3666
3667	/* Set the force flag for non-interactive processes */
3668	do_force = !isatty(STDIN_FILENO);
3669
3670	/* Save arguments for final freeing of memory. */
3671	save_ac = ac;
3672	save_av = av;
3673
3674	optind = optreset = 0;
3675	while ((ch = getopt(ac, av, "acdefhnNqs:STtv")) != -1)
3676		switch (ch) {
3677		case 'a':
3678			do_acct = 1;
3679			break;
3680
3681		case 'c':
3682			do_compact = 1;
3683			break;
3684
3685		case 'd':
3686			do_dynamic = 1;
3687			break;
3688
3689		case 'e':
3690			do_expired = 1;
3691			break;
3692
3693		case 'f':
3694			do_force = 1;
3695			break;
3696
3697		case 'h': /* help */
3698			free_args(save_ac, save_av);
3699			help();
3700			break;	/* NOTREACHED */
3701
3702		case 'n':
3703			test_only = 1;
3704			break;
3705
3706		case 'N':
3707			do_resolv = 1;
3708			break;
3709
3710		case 'q':
3711			do_quiet = 1;
3712			break;
3713
3714		case 's': /* sort */
3715			do_sort = atoi(optarg);
3716			break;
3717
3718		case 'S':
3719			show_sets = 1;
3720			break;
3721
3722		case 't':
3723			do_time = 1;
3724			break;
3725
3726		case 'T':
3727			do_time = 2;	/* numeric timestamp */
3728			break;
3729
3730		case 'v': /* verbose */
3731			verbose = 1;
3732			break;
3733
3734		default:
3735			free_args(save_ac, save_av);
3736			return 1;
3737		}
3738
3739	ac -= optind;
3740	av += optind;
3741	NEED1("bad arguments, for usage summary ``ipfw''");
3742
3743	/*
3744	 * An undocumented behaviour of ipfw1 was to allow rule numbers first,
3745	 * e.g. "100 add allow ..." instead of "add 100 allow ...".
3746	 * In case, swap first and second argument to get the normal form.
3747	 */
3748	if (ac > 1 && isdigit(*av[0])) {
3749		char *p = av[0];
3750
3751		av[0] = av[1];
3752		av[1] = p;
3753	}
3754
3755	/*
3756	 * optional: pipe or queue
3757	 */
3758	do_pipe = 0;
3759	if (!strncmp(*av, "pipe", strlen(*av)))
3760		do_pipe = 1;
3761	else if (!strncmp(*av, "queue", strlen(*av)))
3762		do_pipe = 2;
3763	if (do_pipe) {
3764		ac--;
3765		av++;
3766	}
3767	NEED1("missing command");
3768
3769	/*
3770	 * For pipes and queues we normally say 'pipe NN config'
3771	 * but the code is easier to parse as 'pipe config NN'
3772	 * so we swap the two arguments.
3773	 */
3774	if (do_pipe > 0 && ac > 1 && isdigit(*av[0])) {
3775		char *p = av[0];
3776
3777		av[0] = av[1];
3778		av[1] = p;
3779	}
3780
3781	if (!strncmp(*av, "add", strlen(*av)))
3782		add(ac, av);
3783	else if (do_pipe && !strncmp(*av, "config", strlen(*av)))
3784		config_pipe(ac, av);
3785	else if (!strncmp(*av, "delete", strlen(*av)))
3786		delete(ac, av);
3787	else if (!strncmp(*av, "flush", strlen(*av)))
3788		flush(do_force);
3789	else if (!strncmp(*av, "zero", strlen(*av)))
3790		zero(ac, av, IP_FW_ZERO);
3791	else if (!strncmp(*av, "resetlog", strlen(*av)))
3792		zero(ac, av, IP_FW_RESETLOG);
3793	else if (!strncmp(*av, "print", strlen(*av)) ||
3794	         !strncmp(*av, "list", strlen(*av)))
3795		list(ac, av, do_acct);
3796	else if (!strncmp(*av, "set", strlen(*av)))
3797		sets_handler(ac, av);
3798	else if (!strncmp(*av, "enable", strlen(*av)))
3799		sysctl_handler(ac, av, 1);
3800	else if (!strncmp(*av, "disable", strlen(*av)))
3801		sysctl_handler(ac, av, 0);
3802	else if (!strncmp(*av, "show", strlen(*av)))
3803		list(ac, av, 1 /* show counters */);
3804	else
3805		errx(EX_USAGE, "bad command `%s'", *av);
3806
3807	/* Free memory allocated in the argument parsing. */
3808	free_args(save_ac, save_av);
3809	return 0;
3810}
3811
3812
3813static void
3814ipfw_readfile(int ac, char *av[])
3815{
3816#define MAX_ARGS	32
3817	char	buf[BUFSIZ];
3818	char	*cmd = NULL, *filename = av[ac-1];
3819	int	c, lineno=0;
3820	FILE	*f = NULL;
3821	pid_t	preproc = 0;
3822
3823	filename = av[ac-1];
3824
3825	while ((c = getopt(ac, av, "cNnp:qS")) != -1) {
3826		switch(c) {
3827		case 'c':
3828			do_compact = 1;
3829			break;
3830
3831		case 'N':
3832			do_resolv = 1;
3833			break;
3834
3835		case 'n':
3836			test_only = 1;
3837			break;
3838
3839		case 'p':
3840			cmd = optarg;
3841			/*
3842			 * Skip previous args and delete last one, so we
3843			 * pass all but the last argument to the preprocessor
3844			 * via av[optind-1]
3845			 */
3846			av += optind - 1;
3847			ac -= optind - 1;
3848			av[ac-1] = NULL;
3849			fprintf(stderr, "command is %s\n", av[0]);
3850			break;
3851
3852		case 'q':
3853			do_quiet = 1;
3854			break;
3855
3856		case 'S':
3857			show_sets = 1;
3858			break;
3859
3860		default:
3861			errx(EX_USAGE, "bad arguments, for usage"
3862			     " summary ``ipfw''");
3863		}
3864
3865		if (cmd != NULL)
3866			break;
3867	}
3868
3869	if (cmd == NULL && ac != optind + 1) {
3870		fprintf(stderr, "ac %d, optind %d\n", ac, optind);
3871		errx(EX_USAGE, "extraneous filename arguments");
3872	}
3873
3874	if ((f = fopen(filename, "r")) == NULL)
3875		err(EX_UNAVAILABLE, "fopen: %s", filename);
3876
3877	if (cmd != NULL) {			/* pipe through preprocessor */
3878		int pipedes[2];
3879
3880		if (pipe(pipedes) == -1)
3881			err(EX_OSERR, "cannot create pipe");
3882
3883		preproc = fork();
3884		if (preproc == -1)
3885			err(EX_OSERR, "cannot fork");
3886
3887		if (preproc == 0) {
3888			/*
3889			 * Child, will run the preprocessor with the
3890			 * file on stdin and the pipe on stdout.
3891			 */
3892			if (dup2(fileno(f), 0) == -1
3893			    || dup2(pipedes[1], 1) == -1)
3894				err(EX_OSERR, "dup2()");
3895			fclose(f);
3896			close(pipedes[1]);
3897			close(pipedes[0]);
3898			execvp(cmd, av);
3899			err(EX_OSERR, "execvp(%s) failed", cmd);
3900		} else { /* parent, will reopen f as the pipe */
3901			fclose(f);
3902			close(pipedes[1]);
3903			if ((f = fdopen(pipedes[0], "r")) == NULL) {
3904				int savederrno = errno;
3905
3906				(void)kill(preproc, SIGTERM);
3907				errno = savederrno;
3908				err(EX_OSERR, "fdopen()");
3909			}
3910		}
3911	}
3912
3913	while (fgets(buf, BUFSIZ, f)) {		/* read commands */
3914		char linename[10];
3915		char *args[1];
3916
3917		lineno++;
3918		sprintf(linename, "Line %d", lineno);
3919		setprogname(linename); /* XXX */
3920		args[0] = buf;
3921		ipfw_main(1, args);
3922	}
3923	fclose(f);
3924	if (cmd != NULL) {
3925		int status;
3926
3927		if (waitpid(preproc, &status, 0) == -1)
3928			errx(EX_OSERR, "waitpid()");
3929		if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK)
3930			errx(EX_UNAVAILABLE,
3931			    "preprocessor exited with status %d",
3932			    WEXITSTATUS(status));
3933		else if (WIFSIGNALED(status))
3934			errx(EX_UNAVAILABLE,
3935			    "preprocessor exited with signal %d",
3936			    WTERMSIG(status));
3937	}
3938}
3939
3940int
3941main(int ac, char *av[])
3942{
3943	/*
3944	 * If the last argument is an absolute pathname, interpret it
3945	 * as a file to be preprocessed.
3946	 */
3947
3948	if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0)
3949		ipfw_readfile(ac, av);
3950	else {
3951		if (ipfw_main(ac-1, av+1))
3952			show_usage();
3953	}
3954	return EX_OK;
3955}
3956