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