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