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