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