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