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