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