xref: /dragonfly/sbin/ipfw3/ipfw3.c (revision 7e82238e)
1 /*
2  * Copyright (c) 2002 Luigi Rizzo
3  * Copyright (c) 1996 Alex Nash, Paul Traina, Poul-Henning Kamp
4  * Copyright (c) 1994 Ugen J.S.Antsilevich
5  *
6  * Idea and grammar partially left from:
7  * Copyright (c) 1993 Daniel Boulet
8  *
9  * Redistribution and use in source forms, with and without modification,
10  * are permitted provided that this entire comment appears intact.
11  *
12  * Redistribution in binary form may occur without any restrictions.
13  * Obviously, it would be nice if you gave credit where credit is due
14  * but requiring it would be too onerous.
15  *
16  * This software is provided ``AS IS'' without any warranties of any kind.
17  *
18  * NEW command line interface for IP firewall facility
19  *
20  * $FreeBSD: src/sbin/ipfw/ipfw2.c,v 1.4.2.13 2003/05/27 22:21:11 gshapiro Exp $
21  */
22 
23 #include <sys/param.h>
24 #include <sys/mbuf.h>
25 #include <sys/socket.h>
26 #include <sys/sockio.h>
27 #include <sys/sysctl.h>
28 #include <sys/time.h>
29 #include <sys/wait.h>
30 
31 #include <arpa/inet.h>
32 #include <ctype.h>
33 #include <dlfcn.h>
34 #include <err.h>
35 #include <errno.h>
36 #include <grp.h>
37 #include <limits.h>
38 #include <netdb.h>
39 #include <pwd.h>
40 #include <sysexits.h>
41 #include <signal.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <stdarg.h>
45 #include <string.h>
46 #include <timeconv.h>
47 #include <unistd.h>
48 
49 #include <netinet/in.h>
50 #include <netinet/in_systm.h>
51 #include <netinet/ip.h>
52 #include <netinet/ip_icmp.h>
53 #include <netinet/tcp.h>
54 #include <net/if.h>
55 #include <net/if_dl.h>
56 #include <net/route.h>
57 #include <net/ethernet.h>
58 
59 
60 #include "../../sys/net/ipfw3/ip_fw3.h"
61 #include "../../sys/net/ipfw3/ip_fw3_table.h"
62 #include "../../sys/net/dummynet3/ip_dummynet3.h"
63 #include "../../sys/net/libalias/alias.h"
64 #include "../../sys/net/ipfw3_basic/ip_fw3_basic.h"
65 #include "../../sys/net/ipfw3_nat/ip_fw3_nat.h"
66 #include "ipfw.h"
67 
68 
69 #define KEYWORD_SIZE	256
70 #define MAPPING_SIZE	256
71 
72 #define MAX_KEYWORD_LEN	20
73 #define MAX_ARGS	32
74 #define WHITESP		" \t\f\v\n\r"
75 #define IPFW_LIB_PATH	"/usr/lib/libipfw3%s.so"
76 #define	IP_MASK_ALL	0xffffffff
77 #define NAT_BUF_LEN	1024
78 /*
79  * we use IPPROTO_ETHERTYPE as a fake protocol id to call the print routines
80  * This is only used in this code.
81  */
82 #define IPPROTO_ETHERTYPE	0x1000
83 
84 /*
85  * This macro returns the size of a struct sockaddr when passed
86  * through a routing socket. Basically we round up sa_len to
87  * a multiple of sizeof(long), with a minimum of sizeof(long).
88  * The check for a NULL pointer is just a convenience, probably never used.
89  * The case sa_len == 0 should only apply to empty structures.
90  */
91 #define SA_SIZE(sa)						\
92 	( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ?	\
93 	sizeof(long)		:				\
94 	1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
95 
96 /*
97  * show_rules() prints the body of an ipfw rule.
98  * Because the standard rule has at least proto src_ip dst_ip, we use
99  * a helper function to produce these entries if not provided explicitly.
100  * The first argument is the list of fields we have, the second is
101  * the list of fields we want to be printed.
102  *
103  * Special cases if we have provided a MAC header:
104  * + if the rule does not contain IP addresses/ports, do not print them;
105  * + if the rule does not contain an IP proto, print "all" instead of "ip";
106  *
107  */
108 #define	HAVE_PROTO	0x0001
109 #define	HAVE_SRCIP	0x0002
110 #define	HAVE_DSTIP	0x0004
111 #define	HAVE_MAC	0x0008
112 #define	HAVE_MACTYPE	0x0010
113 #define	HAVE_OPTIONS	0x8000
114 
115 #define	HAVE_IP		(HAVE_PROTO | HAVE_SRCIP | HAVE_DSTIP)
116 
117 /*
118  * Definition of a port range, and macros to deal with values.
119  * FORMAT: HI 16-bits == first port in range, 0 == all ports.
120  *		 LO 16-bits == number of ports in range
121  * NOTES: - Port values are not stored in network byte order.
122  */
123 
124 #define port_range u_long
125 
126 #define GETLOPORT(x)	((x) >> 0x10)
127 #define GETNUMPORTS(x)	((x) & 0x0000ffff)
128 #define GETHIPORT(x)	(GETLOPORT((x)) + GETNUMPORTS((x)))
129 
130 /* Set y to be the low-port value in port_range variable x. */
131 #define SETLOPORT(x, y) ((x) = ((x) & 0x0000ffff) | ((y) << 0x10))
132 
133 /* Set y to be the number of ports in port_range variable x. */
134 #define SETNUMPORTS(x, y) ((x) = ((x) & 0xffff0000) | (y))
135 
136 #define INC_ARGCV() do {			\
137 	(*_av)++;				\
138 	(*_ac)--;				\
139 	av = *_av;				\
140 	ac = *_ac;				\
141 } while (0)
142 
143 
144 int		ipfw_socket = -1;	/* main RAW socket */
145 int		do_resolv, 		/* Would try to resolve all */
146 		do_acct, 		/* Show packet/byte count */
147 		do_time, 		/* Show time stamps */
148 		do_quiet = 1,		/* Be quiet , default is quiet*/
149 		do_force, 		/* Don't ask for confirmation */
150 		do_pipe, 		/* this cmd refers to a pipe */
151 		do_nat, 		/* Nat configuration. */
152 		do_sort, 		/* field to sort results (0 = no) */
153 		do_dynamic, 		/* display dynamic rules */
154 		do_expired, 		/* display expired dynamic rules */
155 		do_compact, 		/* show rules in compact mode */
156 		show_sets, 		/* display rule sets */
157 		verbose;
158 
159 enum tokens {
160 	TOK_NULL=0,
161 
162 	TOK_IP,
163 	TOK_IF,
164 	TOK_ALOG,
165 	TOK_DENY_INC,
166 	TOK_SAME_PORTS,
167 	TOK_UNREG_ONLY,
168 	TOK_RESET_ADDR,
169 	TOK_ALIAS_REV,
170 	TOK_PROXY_ONLY,
171 	TOK_REDIR_ADDR,
172 	TOK_REDIR_PORT,
173 	TOK_REDIR_PROTO,
174 
175 	TOK_PIPE,
176 	TOK_QUEUE,
177 	TOK_PLR,
178 	TOK_NOERROR,
179 	TOK_BUCKETS,
180 	TOK_DSTIP,
181 	TOK_SRCIP,
182 	TOK_DSTPORT,
183 	TOK_SRCPORT,
184 	TOK_ALL,
185 	TOK_MASK,
186 	TOK_BW,
187 	TOK_DELAY,
188 	TOK_RED,
189 	TOK_GRED,
190 	TOK_DROPTAIL,
191 	TOK_PROTO,
192 	TOK_WEIGHT,
193 };
194 
195 struct char_int_map dummynet_params[] = {
196 	{ "plr", 		TOK_PLR },
197 	{ "noerror", 		TOK_NOERROR },
198 	{ "buckets", 		TOK_BUCKETS },
199 	{ "dst-ip", 		TOK_DSTIP },
200 	{ "src-ip", 		TOK_SRCIP },
201 	{ "dst-port", 		TOK_DSTPORT },
202 	{ "src-port", 		TOK_SRCPORT },
203 	{ "proto", 		TOK_PROTO },
204 	{ "weight", 		TOK_WEIGHT },
205 	{ "all", 		TOK_ALL },
206 	{ "mask", 		TOK_MASK },
207 	{ "droptail", 		TOK_DROPTAIL },
208 	{ "red", 		TOK_RED },
209 	{ "gred", 		TOK_GRED },
210 	{ "bw",			TOK_BW },
211 	{ "bandwidth", 		TOK_BW },
212 	{ "delay", 		TOK_DELAY },
213 	{ "pipe", 		TOK_PIPE },
214 	{ "queue", 		TOK_QUEUE },
215 	{ "dummynet-params", 	TOK_NULL },
216 	{ NULL, 0 }
217 };
218 
219 struct char_int_map nat_params[] = {
220 	{ "ip", 		TOK_IP },
221 	{ "if", 		TOK_IF },
222 	{ "log", 		TOK_ALOG },
223 	{ "deny_in", 		TOK_DENY_INC },
224 	{ "same_ports", 	TOK_SAME_PORTS },
225 	{ "unreg_only", 	TOK_UNREG_ONLY },
226 	{ "reset", 		TOK_RESET_ADDR },
227 	{ "reverse", 		TOK_ALIAS_REV },
228 	{ "proxy_only", 	TOK_PROXY_ONLY },
229 	{ "redirect_addr", 	TOK_REDIR_ADDR },
230 	{ "redirect_port", 	TOK_REDIR_PORT },
231 	{ "redirect_proto", 	TOK_REDIR_PROTO },
232 	{ NULL, 0 },
233 };
234 
235 struct ipfw_keyword {
236 	int type;
237 	char word[MAX_KEYWORD_LEN];
238 	int module;
239 	int opcode;
240 };
241 
242 struct ipfw_mapping {
243 	int type;
244 	int module;
245 	int opcode;
246 	parser_func parser;
247 	shower_func shower;
248 };
249 
250 struct ipfw_keyword keywords[KEYWORD_SIZE];
251 struct ipfw_mapping mappings[MAPPING_SIZE];
252 
253 static int
254 match_token(struct char_int_map *table, char *string)
255 {
256 	while (table->key) {
257 		if (strcmp(table->key, string) == 0) {
258 			return table->val;
259 		}
260 		table++;
261 	}
262 	return 0;
263 }
264 
265 static void
266 get_modules(char *modules_str, int len)
267 {
268 	if (do_get_x(IP_FW_MODULE, modules_str, &len) < 0)
269 		errx(EX_USAGE, "ipfw3 not loaded.");
270 }
271 
272 static void
273 list_modules(int ac, char *av[])
274 {
275 	void *module_str = NULL;
276 	int len = 1024;
277 	if ((module_str = realloc(module_str, len)) == NULL)
278 		err(EX_OSERR, "realloc");
279 
280 	get_modules(module_str, len);
281 	printf("%s", (char *)module_str);
282 }
283 void
284 parse_accept(ipfw_insn **cmd, int *ac, char **av[])
285 {
286 	(*cmd)->opcode = O_BASIC_ACCEPT;
287 	(*cmd)->module = MODULE_BASIC_ID;
288 	(*cmd)->len = (*cmd)->len|LEN_OF_IPFWINSN;
289 	NEXT_ARG1;
290 }
291 
292 void
293 parse_deny(ipfw_insn **cmd, int *ac, char **av[])
294 {
295 	(*cmd)->opcode = O_BASIC_DENY;
296 	(*cmd)->module = MODULE_BASIC_ID;
297 	(*cmd)->len = (*cmd)->len|LEN_OF_IPFWINSN;
298 	NEXT_ARG1;
299 }
300 
301 void
302 show_accept(ipfw_insn *cmd, int show_or)
303 {
304 	printf(" allow");
305 }
306 
307 void
308 show_deny(ipfw_insn *cmd, int show_or)
309 {
310 	printf(" deny");
311 }
312 
313 static void
314 load_modules(void)
315 {
316 	const char *error;
317 	init_module mod_init_func;
318 	void *module_lib;
319 	char module_lib_file[50];
320 	void *module_str = NULL;
321 	int len = 1024;
322 
323 	if ((module_str = realloc(module_str, len)) == NULL)
324 		err(EX_OSERR, "realloc");
325 
326 	get_modules(module_str, len);
327 
328 	const char s[2] = ",";
329 	char *token;
330 	token = strtok(module_str, s);
331 	while (token != NULL) {
332 		sprintf(module_lib_file, IPFW_LIB_PATH, token);
333 		token = strtok(NULL, s);
334 		module_lib = dlopen(module_lib_file, RTLD_LAZY);
335 		if (!module_lib) {
336 			fprintf(stderr, "Couldn't open %s: %s\n",
337 				module_lib_file, dlerror());
338 			exit(EX_SOFTWARE);
339 		}
340 		mod_init_func = dlsym(module_lib, "load_module");
341 		if ((error = dlerror()))
342 		{
343 			fprintf(stderr, "Couldn't find init function: %s\n", error);
344 			exit(EX_SOFTWARE);
345 		}
346 		(*mod_init_func)((register_func)register_ipfw_func,
347 				(register_keyword)register_ipfw_keyword);
348 	}
349 }
350 
351 void
352 prepare_default_funcs(void)
353 {
354 	/* register allow*/
355 	register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_ACCEPT, "allow", ACTION);
356 	register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_ACCEPT, "accept", ACTION);
357 	register_ipfw_func(MODULE_BASIC_ID, O_BASIC_ACCEPT,
358 			(parser_func)parse_accept, (shower_func)show_accept);
359 	/* register deny*/
360 	register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_DENY, "deny", ACTION);
361 	register_ipfw_keyword(MODULE_BASIC_ID, O_BASIC_DENY, "reject", ACTION);
362 	register_ipfw_func(MODULE_BASIC_ID, O_BASIC_DENY,
363 			(parser_func)parse_deny, (shower_func)show_deny);
364 }
365 
366 void
367 register_ipfw_keyword(int module, int opcode, char *word, int type)
368 {
369 	struct ipfw_keyword *tmp;
370 
371 	tmp=keywords;
372 	for(;;) {
373 		if (tmp->type == NONE) {
374 			strcpy(tmp->word, word);
375 			tmp->module = module;
376 			tmp->opcode = opcode;
377 			tmp->type = type;
378 			break;
379 		} else {
380 			if (strcmp(tmp->word, word) == 0)
381 				errx(EX_USAGE, "keyword `%s' exists", word);
382 			else
383 				tmp++;
384 		}
385 	}
386 }
387 
388 void
389 register_ipfw_func(int module, int opcode, parser_func parser, shower_func shower)
390 {
391 	struct ipfw_mapping *tmp;
392 
393 	tmp = mappings;
394 	while (1) {
395 		if (tmp->type == NONE) {
396 			tmp->module = module;
397 			tmp->opcode = opcode;
398 			tmp->parser = parser;
399 			tmp->shower = shower;
400 			tmp->type = IN_USE;
401 			break;
402 		} else {
403 			if (tmp->opcode == opcode && tmp->module == module) {
404 				errx(EX_USAGE, "func `%d' of module `%d' exists",
405 					opcode, module);
406 				break;
407 			} else {
408 				tmp++;
409 			}
410 		}
411 	}
412 }
413 
414 /*
415  * this func need to check whether 'or' need to be printed,
416  * when the filter is the first filter with 'or' when dont print
417  * when not first and same as previous, then print or and no filter name
418  * when not first but different from previous, print name without 'or'
419  * show_or = 1: show or and ignore filter name
420  * show_or = 0: show filter name ignore or
421  */
422 void prev_show_chk(ipfw_insn *cmd, uint8_t *prev_module, uint8_t *prev_opcode,
423 		int *show_or)
424 {
425 	if (cmd->len & F_OR) {
426 		if (*prev_module == 0 && *prev_opcode == 0) {
427 			/* first cmd with 'or' flag */
428 			*show_or = 0;
429 			*prev_module = cmd->module;
430 			*prev_opcode = cmd->opcode;
431 		} else if (cmd->module == *prev_module &&
432 				cmd->opcode == *prev_opcode) {
433 			/* cmd same as previous, same module and opcode */
434 			*show_or = 1;
435 		} else {
436 			/* cmd different from prev*/
437 			*show_or = 0;
438 			*prev_module = cmd->module;
439 			*prev_opcode = cmd->opcode;
440 
441 		}
442 	} else {
443 		*show_or = 0;
444 		*prev_module = 0;
445 		*prev_opcode = 0;
446 	}
447 }
448 
449 /*
450  * word can be: proto from to other
451  * proto show proto
452  * from show from
453  * to show to
454  * other show all other filters
455  */
456 int show_filter(ipfw_insn *cmd, char *word, int type)
457 {
458 	struct ipfw_keyword *k;
459 	struct ipfw_mapping *m;
460 	shower_func fn;
461 	int i, j, show_or;
462 	uint8_t prev_module, prev_opcode;
463 
464 	k = keywords;
465 	m = mappings;
466 	for (i = 1; i < KEYWORD_SIZE; i++, k++) {
467 		if (k->type == type) {
468 			if (k->module == cmd->module &&
469 					k->opcode == cmd->opcode) {
470 				for (j = 1; j < MAPPING_SIZE; j++, m++) {
471 					if (m->type == IN_USE &&
472 						k->module == m->module &&
473 						k->opcode == m->opcode) {
474 						prev_show_chk(cmd, &prev_module,
475 							&prev_opcode, &show_or);
476 						if (cmd->len & F_NOT)
477 							printf(" not");
478 
479 						fn = m->shower;
480 						(*fn)(cmd, show_or);
481 						return 1;
482 					}
483 				}
484 			}
485 		}
486 	}
487 	return 0;
488 }
489 
490 static void
491 show_rules(struct ipfw_ioc_rule *rule, int pcwidth, int bcwidth)
492 {
493 	static int twidth = 0;
494 	ipfw_insn *cmd;
495 	int l;
496 
497 	u_int32_t set_disable = rule->set_disable;
498 
499 	if (set_disable & (1 << rule->set)) { /* disabled */
500 		if (!show_sets)
501 			return;
502 		else
503 			printf("# DISABLED ");
504 	}
505 	printf("%05u ", rule->rulenum);
506 
507 	if (do_acct)
508 		printf("%*ju %*ju ", pcwidth, (uintmax_t)rule->pcnt, bcwidth,
509 			(uintmax_t)rule->bcnt);
510 
511 	if (do_time == 1) {
512 		char timestr[30];
513 
514 		if (twidth == 0) {
515 			strcpy(timestr, ctime((time_t *)&twidth));
516 			*strchr(timestr, '\n') = '\0';
517 			twidth = strlen(timestr);
518 		}
519 		if (rule->timestamp) {
520 			time_t t = _long_to_time(rule->timestamp);
521 
522 			strcpy(timestr, ctime(&t));
523 			*strchr(timestr, '\n') = '\0';
524 			printf("%s ", timestr);
525 		} else {
526 			printf("%*s ", twidth, " ");
527 		}
528 	} else if (do_time == 2) {
529 		printf( "%10u ", rule->timestamp);
530 	}
531 
532 	if (show_sets)
533 		printf("set %d ", rule->set);
534 
535 
536 	struct ipfw_keyword *k;
537 	struct ipfw_mapping *m;
538 	shower_func fn, comment_fn = NULL;
539 	ipfw_insn *comment_cmd;
540 	int i, j, changed;
541 
542 	/*
543 	 * show others and actions
544 	 */
545 	for (l = rule->cmd_len - rule->act_ofs, cmd = ACTION_PTR(rule);
546 		l > 0; l -= F_LEN(cmd),
547 		cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
548 		k = keywords;
549 		m = mappings;
550 		for (i = 1; i< KEYWORD_SIZE; i++, k++) {
551 			if ( k->module == cmd->module && k->opcode == cmd->opcode ) {
552 				for (j = 1; j< MAPPING_SIZE; j++, m++) {
553 					if (m->type == IN_USE &&
554 						m->module == cmd->module &&
555 						m->opcode == cmd->opcode) {
556 						if (cmd->module == MODULE_BASIC_ID &&
557 							cmd->opcode == O_BASIC_COMMENT) {
558 							comment_fn = m->shower;
559 							comment_cmd = cmd;
560 						} else {
561 							fn = m->shower;
562 							(*fn)(cmd, 0);
563 						}
564 						if (cmd->module == MODULE_BASIC_ID &&
565 							cmd->opcode ==
566 								O_BASIC_CHECK_STATE) {
567 							goto done;
568 						}
569 						break;
570 					}
571 				}
572 				break;
573 			}
574 		}
575 	}
576 
577 	/*
578 	 * show proto
579 	 */
580 	changed=0;
581 	for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd),
582 			cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
583 		changed = show_filter(cmd, "proto", PROTO);
584 	}
585 	if (!changed && !do_quiet)
586 		printf(" ip");
587 
588 	/*
589 	 * show from
590 	 */
591 	changed = 0;
592 	for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd),
593 			cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
594 		changed = show_filter(cmd, "from", FROM);
595 	}
596 	if (!changed && !do_quiet)
597 		printf(" from any");
598 
599 	/*
600 	 * show to
601 	 */
602 	changed = 0;
603 	for (l = rule->act_ofs, cmd = rule->cmd; l > 0; l -= F_LEN(cmd),
604 			cmd = (ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
605 		changed = show_filter(cmd, "to", TO);
606 	}
607 	if (!changed && !do_quiet)
608 		printf(" to any");
609 
610 	/*
611 	 * show other filters
612 	 */
613 	for (l = rule->act_ofs, cmd = rule->cmd, m = mappings;
614 			l > 0; l -= F_LEN(cmd),
615 			cmd=(ipfw_insn *)((uint32_t *)cmd + F_LEN(cmd))) {
616 		show_filter(cmd, "other", FILTER);
617 	}
618 
619 	/* show the comment in the end */
620 	if (comment_fn != NULL) {
621 		(*comment_fn)(comment_cmd, 0);
622 	}
623 done:
624 	printf("\n");
625 }
626 
627 static void
628 show_states(struct ipfw_ioc_state *d, int pcwidth, int bcwidth)
629 {
630 	struct protoent *pe;
631 	struct in_addr a;
632 
633 	printf("%05u ", d->rulenum);
634 	if (do_acct) {
635 		printf("%*ju %*ju ", pcwidth, (uintmax_t)d->pcnt,
636 				bcwidth, (uintmax_t)d->bcnt);
637 	}
638 
639 	if (do_time == 1) {
640 		/* state->timestamp */
641 		char timestr[30];
642 		time_t t = _long_to_time(d->timestamp);
643 		strcpy(timestr, ctime(&t));
644 		*strchr(timestr, '\n') = '\0';
645 		printf(" (%s", timestr);
646 
647 		/* state->lifetime */
648 		printf(" %ds", d->lifetime);
649 
650 		/* state->expiry */
651 		if (d->expiry !=0) {
652 			t = _long_to_time(d->expiry);
653 			strcpy(timestr, ctime(&t));
654 			*strchr(timestr, '\n') = '\0';
655 			printf(" %s)", timestr);
656 		} else {
657 			printf(" 0)");
658 		}
659 
660 	} else if (do_time == 2) {
661 		printf("(%u %ds %u) ", d->timestamp, d->lifetime, d->expiry);
662 	}
663 
664 	if ((pe = getprotobynumber(d->flow_id.proto)) != NULL)
665 		printf(" %s", pe->p_name);
666 	else
667 		printf(" proto %u", d->flow_id.proto);
668 
669 	a.s_addr = htonl(d->flow_id.src_ip);
670 	printf(" %s %d", inet_ntoa(a), d->flow_id.src_port);
671 
672 	a.s_addr = htonl(d->flow_id.dst_ip);
673 	printf(" <-> %s %d", inet_ntoa(a), d->flow_id.dst_port);
674 	printf(" CPU %d", d->cpuid);
675 	printf("\n");
676 }
677 
678 int
679 sort_q(const void *pa, const void *pb)
680 {
681 	int rev = (do_sort < 0);
682 	int field = rev ? -do_sort : do_sort;
683 	long long res = 0;
684 	const struct dn_ioc_flowqueue *a = pa;
685 	const struct dn_ioc_flowqueue *b = pb;
686 
687 	switch(field) {
688 	case 1: /* pkts */
689 		res = a->len - b->len;
690 		break;
691 	case 2: /* bytes */
692 		res = a->len_bytes - b->len_bytes;
693 		break;
694 
695 	case 3: /* tot pkts */
696 		res = a->tot_pkts - b->tot_pkts;
697 		break;
698 
699 	case 4: /* tot bytes */
700 		res = a->tot_bytes - b->tot_bytes;
701 		break;
702 	}
703 	if (res < 0)
704 		res = -1;
705 	if (res > 0)
706 		res = 1;
707 	return (int)(rev ? res : -res);
708 }
709 
710 static void
711 show_queues(struct dn_ioc_flowset *fs, struct dn_ioc_flowqueue *q)
712 {
713 	int l;
714 
715 	printf("mask: 0x%02x 0x%08x/0x%04x -> 0x%08x/0x%04x\n",
716 		fs->flow_mask.u.ip.proto,
717 		fs->flow_mask.u.ip.src_ip, fs->flow_mask.u.ip.src_port,
718 		fs->flow_mask.u.ip.dst_ip, fs->flow_mask.u.ip.dst_port);
719 	if (fs->rq_elements == 0)
720 		return;
721 
722 	printf("BKT Prot ___Source IP/port____ "
723 		"____Dest. IP/port____ Tot_pkt/bytes Pkt/Byte Drp\n");
724 	if (do_sort != 0)
725 		heapsort(q, fs->rq_elements, sizeof(*q), sort_q);
726 	for (l = 0; l < fs->rq_elements; l++) {
727 		struct in_addr ina;
728 		struct protoent *pe;
729 
730 		ina.s_addr = htonl(q[l].id.u.ip.src_ip);
731 		printf("%3d ", q[l].hash_slot);
732 		pe = getprotobynumber(q[l].id.u.ip.proto);
733 		if (pe)
734 			printf("%-4s ", pe->p_name);
735 		else
736 			printf("%4u ", q[l].id.u.ip.proto);
737 		printf("%15s/%-5d ",
738 			inet_ntoa(ina), q[l].id.u.ip.src_port);
739 		ina.s_addr = htonl(q[l].id.u.ip.dst_ip);
740 		printf("%15s/%-5d ",
741 			inet_ntoa(ina), q[l].id.u.ip.dst_port);
742 		printf("%4ju %8ju %2u %4u %3u\n",
743 			(uintmax_t)q[l].tot_pkts, (uintmax_t)q[l].tot_bytes,
744 			q[l].len, q[l].len_bytes, q[l].drops);
745 		if (verbose)
746 			printf(" S %20ju F %20ju\n",
747 				(uintmax_t)q[l].S, (uintmax_t)q[l].F);
748 	}
749 }
750 
751 static void
752 show_flowset_parms(struct dn_ioc_flowset *fs, char *prefix)
753 {
754 	char qs[30];
755 	char plr[30];
756 	char red[90]; 	/* Display RED parameters */
757 	int l;
758 
759 	l = fs->qsize;
760 	if (fs->flags_fs & DN_QSIZE_IS_BYTES) {
761 		if (l >= 8192)
762 			sprintf(qs, "%d KB", l / 1024);
763 		else
764 			sprintf(qs, "%d B", l);
765 	} else
766 		sprintf(qs, "%3d sl.", l);
767 	if (fs->plr)
768 		sprintf(plr, "plr %f", 1.0 * fs->plr / (double)(0x7fffffff));
769 	else
770 		plr[0] = '\0';
771 	if (fs->flags_fs & DN_IS_RED)	/* RED parameters */
772 		sprintf(red,
773 			"\n\t %cRED w_q %f min_th %d max_th %d max_p %f",
774 			(fs->flags_fs & DN_IS_GENTLE_RED) ? 'G' : ' ',
775 			1.0 * fs->w_q / (double)(1 << SCALE_RED),
776 			SCALE_VAL(fs->min_th),
777 			SCALE_VAL(fs->max_th),
778 			1.0 * fs->max_p / (double)(1 << SCALE_RED));
779 	else
780 		sprintf(red, "droptail");
781 
782 	printf("%s %s%s %d queues (%d buckets) %s\n",
783 		prefix, qs, plr, fs->rq_elements, fs->rq_size, red);
784 }
785 
786 static void
787 show_pipes(void *data, int nbytes, int ac, char *av[])
788 {
789 	u_long rulenum;
790 	void *next = data;
791 	struct dn_ioc_pipe *p = (struct dn_ioc_pipe *)data;
792 	struct dn_ioc_flowset *fs;
793 	struct dn_ioc_flowqueue *q;
794 	int l;
795 
796 	if (ac > 0)
797 		rulenum = strtoul(*av++, NULL, 10);
798 	else
799 		rulenum = 0;
800 	for (; nbytes >= sizeof(*p); p = (struct dn_ioc_pipe *)next) {
801 		double b = p->bandwidth;
802 		char buf[30];
803 		char prefix[80];
804 
805 		if (p->fs.fs_type != DN_IS_PIPE)
806 			break; 	/* done with pipes, now queues */
807 
808 		/*
809 		 * compute length, as pipe have variable size
810 		 */
811 		l = sizeof(*p) + p->fs.rq_elements * sizeof(*q);
812 		next = (void *)p + l;
813 		nbytes -= l;
814 
815 		if (rulenum != 0 && rulenum != p->pipe_nr)
816 			continue;
817 
818 		/*
819 		 * Print rate
820 		 */
821 		if (b == 0)
822 			sprintf(buf, "unlimited");
823 		else if (b >= 1000000)
824 			sprintf(buf, "%7.3f Mbit/s", b/1000000);
825 		else if (b >= 1000)
826 			sprintf(buf, "%7.3f Kbit/s", b/1000);
827 		else
828 			sprintf(buf, "%7.3f bit/s ", b);
829 
830 		sprintf(prefix, "%05d: %s %4d ms ",
831 			p->pipe_nr, buf, p->delay);
832 		show_flowset_parms(&p->fs, prefix);
833 		if (verbose)
834 			printf(" V %20ju\n", (uintmax_t)p->V >> MY_M);
835 
836 		q = (struct dn_ioc_flowqueue *)(p+1);
837 		show_queues(&p->fs, q);
838 	}
839 
840 	for (fs = next; nbytes >= sizeof(*fs); fs = next) {
841 		char prefix[80];
842 
843 		if (fs->fs_type != DN_IS_QUEUE)
844 			break;
845 		l = sizeof(*fs) + fs->rq_elements * sizeof(*q);
846 		next = (void *)fs + l;
847 		nbytes -= l;
848 		q = (struct dn_ioc_flowqueue *)(fs+1);
849 		sprintf(prefix, "q%05d: weight %d pipe %d ",
850 			fs->fs_nr, fs->weight, fs->parent_nr);
851 		show_flowset_parms(fs, prefix);
852 		show_queues(fs, q);
853 	}
854 }
855 
856 /*
857  * This one handles all set-related commands
858  * 	ipfw set { show | enable | disable }
859  * 	ipfw set swap X Y
860  * 	ipfw set move X to Y
861  * 	ipfw set move rule X to Y
862  */
863 static void
864 sets_handler(int ac, char *av[])
865 {
866 	u_int32_t set_disable, masks[2];
867 	u_int16_t rulenum;
868 	u_int8_t cmd, new_set;
869 	int i, nbytes;
870 
871 	NEXT_ARG;
872 	if (!ac)
873 		errx(EX_USAGE, "set needs command");
874 	if (!strncmp(*av, "show", strlen(*av)) ) {
875 		void *data = NULL;
876 		char *msg;
877 		int nalloc=1000;
878 		nbytes = nalloc;
879 
880 		while (nbytes >= nalloc) {
881 			nalloc = nalloc * 2+321;
882 			nbytes = nalloc;
883 			if (data == NULL) {
884 				if ((data = malloc(nbytes)) == NULL) {
885 					err(EX_OSERR, "malloc");
886 				}
887 			} else if ((data = realloc(data, nbytes)) == NULL) {
888 				err(EX_OSERR, "realloc");
889 			}
890 			if (do_get_x(IP_FW_GET, data, &nbytes) < 0) {
891 				err(EX_OSERR, "getsockopt(IP_FW_GET)");
892 			}
893 		}
894 		set_disable = ((struct ipfw_ioc_rule *)data)->set_disable;
895 		for (i = 0, msg = "disable" ; i < 31; i++)
896 			if ( (set_disable & (1<<i))) {
897 				printf("%s %d", msg, i);
898 				msg = "";
899 			}
900 		msg = (set_disable) ? " enable" : "enable";
901 		for (i = 0; i < 31; i++)
902 			if ( !(set_disable & (1<<i))) {
903 				printf("%s %d", msg, i);
904 				msg = "";
905 			}
906 		printf("\n");
907 	} else if (!strncmp(*av, "swap", strlen(*av))) {
908 		NEXT_ARG;
909 		if (ac != 2)
910 			errx(EX_USAGE, "set swap needs 2 set numbers\n");
911 		rulenum = atoi(av[0]);
912 		new_set = atoi(av[1]);
913 		if (!isdigit(*(av[0])) || rulenum > 30)
914 			errx(EX_DATAERR, "invalid set number %s\n", av[0]);
915 		if (!isdigit(*(av[1])) || new_set > 30)
916 			errx(EX_DATAERR, "invalid set number %s\n", av[1]);
917 		masks[0] = (4 << 24) | (new_set << 16) | (rulenum);
918 		i = do_set_x(IP_FW_DEL, masks, sizeof(u_int32_t));
919 	} else if (!strncmp(*av, "move", strlen(*av))) {
920 		NEXT_ARG;
921 		if (ac && !strncmp(*av, "rule", strlen(*av))) {
922 			cmd = 2;
923 			NEXT_ARG;
924 		} else
925 			cmd = 3;
926 		if (ac != 3 || strncmp(av[1], "to", strlen(*av)))
927 			errx(EX_USAGE, "syntax: set move [rule] X to Y\n");
928 		rulenum = atoi(av[0]);
929 		new_set = atoi(av[2]);
930 		if (!isdigit(*(av[0])) || (cmd == 3 && rulenum > 30) ||
931 				(cmd == 2 && rulenum == 65535) )
932 			errx(EX_DATAERR, "invalid source number %s\n", av[0]);
933 		if (!isdigit(*(av[2])) || new_set > 30)
934 			errx(EX_DATAERR, "invalid dest. set %s\n", av[1]);
935 		masks[0] = (cmd << 24) | (new_set << 16) | (rulenum);
936 		i = do_set_x(IP_FW_DEL, masks, sizeof(u_int32_t));
937 	} else if (!strncmp(*av, "disable", strlen(*av)) ||
938 			!strncmp(*av, "enable", strlen(*av)) ) {
939 		int which = !strncmp(*av, "enable", strlen(*av)) ? 1 : 0;
940 
941 		NEXT_ARG;
942 		masks[0] = masks[1] = 0;
943 
944 		while (ac) {
945 			if (isdigit(**av)) {
946 				i = atoi(*av);
947 				if (i < 0 || i > 30)
948 					errx(EX_DATAERR, "invalid set number %d\n", i);
949 				masks[which] |= (1<<i);
950 			} else if (!strncmp(*av, "disable", strlen(*av)))
951 				which = 0;
952 			else if (!strncmp(*av, "enable", strlen(*av)))
953 				which = 1;
954 			else
955 				errx(EX_DATAERR, "invalid set command %s\n", *av);
956 			NEXT_ARG;
957 		}
958 		if ( (masks[0] & masks[1]) != 0 )
959 			errx(EX_DATAERR, "cannot enable and disable the same set\n");
960 		i = do_set_x(IP_FW_DEL, masks, sizeof(masks));
961 		if (i)
962 			warn("set enable/disable: setsockopt(IP_FW_DEL)");
963 	} else
964 		errx(EX_USAGE, "invalid set command %s\n", *av);
965 }
966 
967 static void
968 add_state(int ac, char *av[])
969 {
970 	struct ipfw_ioc_state ioc_state;
971 	ioc_state.expiry = 0;
972 	ioc_state.lifetime = 0;
973 	NEXT_ARG;
974 	if (strcmp(*av, "rulenum") == 0) {
975 		NEXT_ARG;
976 		ioc_state.rulenum = atoi(*av);
977 	} else {
978 		errx(EX_USAGE, "ipfw state add rule");
979 	}
980 	NEXT_ARG;
981 	struct protoent *pe;
982 	pe = getprotobyname(*av);
983 	ioc_state.flow_id.proto = pe->p_proto;
984 
985 	NEXT_ARG;
986 	ioc_state.flow_id.src_ip = inet_addr(*av);
987 
988 	NEXT_ARG;
989 	ioc_state.flow_id.src_port = atoi(*av);
990 
991 	NEXT_ARG;
992 	ioc_state.flow_id.dst_ip = inet_addr(*av);
993 
994 	NEXT_ARG;
995 	ioc_state.flow_id.dst_port = atoi(*av);
996 
997 	NEXT_ARG;
998 	if (strcmp(*av, "live") == 0) {
999 		NEXT_ARG;
1000 		ioc_state.lifetime = atoi(*av);
1001 		NEXT_ARG;
1002 	}
1003 
1004 	if (strcmp(*av, "expiry") == 0) {
1005 		NEXT_ARG;
1006 		ioc_state.expiry = strtoul(*av, NULL, 10);
1007 		printf("ioc_state.expiry=%d\n", ioc_state.expiry);
1008 	}
1009 
1010 	if (do_set_x(IP_FW_STATE_ADD, &ioc_state, sizeof(struct ipfw_ioc_state)) < 0 ) {
1011 		err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_ADD)");
1012 	}
1013 	if (!do_quiet) {
1014 		printf("Flushed all states.\n");
1015 	}
1016 }
1017 
1018 static void
1019 delete_state(int ac, char *av[])
1020 {
1021 	int rulenum;
1022 	NEXT_ARG;
1023 	if (ac == 1 && isdigit(**av))
1024 		rulenum = atoi(*av);
1025 	if (do_set_x(IP_FW_STATE_DEL, &rulenum, sizeof(int)) < 0 )
1026 		err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_DEL)");
1027 	if (!do_quiet)
1028 		printf("Flushed all states.\n");
1029 }
1030 
1031 static void
1032 flush_state(int ac, char *av[])
1033 {
1034 	if (!do_force) {
1035 		int c;
1036 
1037 		printf("Are you sure? [yn] ");
1038 		fflush(stdout);
1039 		do {
1040 			c = toupper(getc(stdin));
1041 			while (c != '\n' && getc(stdin) != '\n')
1042 				if (feof(stdin))
1043 					return; /* and do not flush */
1044 		} while (c != 'Y' && c != 'N');
1045 		if (c == 'N')	/* user said no */
1046 			return;
1047 	}
1048 	if (do_set_x(IP_FW_STATE_FLUSH, NULL, 0) < 0 )
1049 		err(EX_UNAVAILABLE, "do_set_x(IP_FW_STATE_FLUSH)");
1050 	if (!do_quiet)
1051 		printf("Flushed all states.\n");
1052 }
1053 
1054 static int
1055 lookup_host (char *host, struct in_addr *ipaddr)
1056 {
1057 	struct hostent *he;
1058 
1059 	if (!inet_aton(host, ipaddr)) {
1060 		if ((he = gethostbyname(host)) == NULL)
1061 			return(-1);
1062 		*ipaddr = *(struct in_addr *)he->h_addr_list[0];
1063 	}
1064 	return(0);
1065 }
1066 
1067 static void
1068 table_append(int ac, char *av[])
1069 {
1070 	struct ipfw_ioc_table tbl;
1071 	char *p;
1072 	int size;
1073 
1074 	NEXT_ARG;
1075 	if (isdigit(**av))
1076 		tbl.id = atoi(*av);
1077 	else
1078 		errx(EX_USAGE, "table id `%s' invalid", *av);
1079 
1080 	if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
1081 		errx(EX_USAGE, "table id `%d' invalid", tbl.id);
1082 
1083 	NEXT_ARG;
1084 	if (strcmp(*av, "ip") == 0)
1085 		tbl.type = 1;
1086 	else if (strcmp(*av, "mac") == 0)
1087 		tbl.type = 2;
1088 	else
1089 		errx(EX_USAGE, "table type `%s' not supported", *av);
1090 
1091 	NEXT_ARG;
1092         if (tbl.type == 1) { /* table type ipv4 */
1093                 struct ipfw_ioc_table_ip_entry ip_ent;
1094                 if (!ac)
1095                         errx(EX_USAGE, "IP address required");
1096 
1097                 p = strchr(*av, '/');
1098                 if (p) {
1099                         *p++ = '\0';
1100                         ip_ent.masklen = atoi(p);
1101                         if (ip_ent.masklen > 32)
1102                                 errx(EX_DATAERR, "bad width ``%s''", p);
1103                 } else {
1104                         ip_ent.masklen = 32;
1105                 }
1106 
1107                 if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
1108                         errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
1109 
1110                 tbl.ip_ent[0] = ip_ent;
1111                 size = sizeof(tbl) + sizeof(ip_ent);
1112         } else if (tbl.type == 2) { /* table type mac */
1113                 struct ipfw_ioc_table_mac_entry mac_ent;
1114                 if (!ac)
1115                         errx(EX_USAGE, "MAC address required");
1116 
1117                 mac_ent.addr = *ether_aton(*av);
1118                 tbl.mac_ent[0] = mac_ent;
1119                 size = sizeof(tbl) + sizeof(mac_ent);
1120         }
1121 	if (do_set_x(IP_FW_TABLE_APPEND, &tbl, size) < 0 )
1122 		errx(EX_USAGE, "do_set_x(IP_FW_TABLE_APPEND) "
1123 			"table `%d' append `%s' failed", tbl.id, *av);
1124 }
1125 
1126 static void
1127 table_remove(int ac, char *av[])
1128 {
1129 	struct ipfw_ioc_table tbl;
1130 	struct ipfw_ioc_table_ip_entry ip_ent;
1131 	char *p;
1132 	int size;
1133 
1134 	NEXT_ARG;
1135 	if (isdigit(**av))
1136 		tbl.id = atoi(*av);
1137 	else
1138 		errx(EX_USAGE, "table id `%s' invalid", *av);
1139 
1140 	if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
1141 		errx(EX_USAGE, "table id `%d' invalid", tbl.id);
1142 
1143 	NEXT_ARG;
1144 	if (strcmp(*av, "ip") == 0)
1145 		tbl.type = 1;
1146 	else if (strcmp(*av, "mac") == 0)
1147 		tbl.type = 2;
1148 	else
1149 		errx(EX_USAGE, "table type `%s' not supported", *av);
1150 
1151 	NEXT_ARG;
1152 	if (!ac)
1153 		errx(EX_USAGE, "IP address required");
1154 	p = strchr(*av, '/');
1155 	if (p) {
1156 		*p++ = '\0';
1157 		ip_ent.masklen = atoi(p);
1158 		if (ip_ent.masklen > 32)
1159 			errx(EX_DATAERR, "bad width ``%s''", p);
1160 	} else {
1161 		ip_ent.masklen = 32;
1162 	}
1163 
1164 	if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
1165 		errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
1166 
1167 	tbl.ip_ent[0] = ip_ent;
1168 	size = sizeof(tbl) + sizeof(ip_ent);
1169 	if (do_set_x(IP_FW_TABLE_REMOVE, &tbl, size) < 0 ) {
1170 		errx(EX_USAGE, "do_set_x(IP_FW_TABLE_REMOVE) "
1171 			"table `%d' append `%s' failed", tbl.id, *av);
1172 	}
1173 }
1174 
1175 static void
1176 table_flush(int ac, char *av[])
1177 {
1178 	struct ipfw_ioc_table ioc_table;
1179 	struct ipfw_ioc_table *t = &ioc_table;
1180 
1181 	NEXT_ARG;
1182 	if (isdigit(**av)) {
1183 		t->id = atoi(*av);
1184 		if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1185 			errx(EX_USAGE, "table id `%d' invalid", t->id);
1186 	} else {
1187 		errx(EX_USAGE, "table id `%s' invalid", *av);
1188 	}
1189 	if (do_set_x(IP_FW_TABLE_FLUSH, t, sizeof(struct ipfw_ioc_table)) < 0 )
1190 		errx(EX_USAGE, "do_set_x(IP_FW_TABLE_FLUSH) "
1191 					"table `%s' flush failed", *av);
1192 }
1193 
1194 static void
1195 table_list(int ac, char *av[])
1196 {
1197 	struct ipfw_ioc_table *ioc_table;
1198 	int i, count, nbytes, nalloc = 1024;
1199 	void *data = NULL;
1200 	NEXT_ARG;
1201 	if (strcmp(*av, "list") == 0) {
1202 		nbytes = nalloc;
1203 		while (nbytes >= nalloc) {
1204 			nalloc = nalloc * 2 ;
1205 			nbytes = nalloc;
1206 			if ((data = realloc(data, nbytes)) == NULL)
1207 				err(EX_OSERR, "realloc");
1208 			if (do_get_x(IP_FW_TABLE_LIST, data, &nbytes) < 0)
1209 				err(EX_OSERR, "do_get_x(IP_FW_TABLE_LIST)");
1210 		}
1211 		ioc_table = (struct ipfw_ioc_table *)data;
1212 		count = nbytes / sizeof(struct ipfw_ioc_table);
1213 		for (i = 0; i < count; i++, ioc_table++) {
1214 			if (ioc_table->type > 0) {
1215 				printf("table %d",ioc_table->id);
1216 				if (ioc_table->type == 1)
1217 					printf(" type ip");
1218 				else if (ioc_table->type == 2)
1219 					printf(" type mac");
1220 				printf(" count %d",ioc_table->count);
1221 				if (strlen(ioc_table->name) > 0)
1222 					printf(" name %s",ioc_table->name);
1223 				printf("\n");
1224 
1225 			}
1226 		}
1227 	} else {
1228 		errx(EX_USAGE, "ipfw3 table `%s' delete invalid", *av);
1229 	}
1230 }
1231 
1232 void
1233 print_table(struct ipfw_ioc_table * tbl)
1234 {
1235 	int i;
1236         if (tbl->type == 0)
1237                 errx(EX_USAGE, "table %d is not in use", tbl->id);
1238 
1239         printf("table %d", tbl->id);
1240         if (tbl->type == 1)
1241                 printf(" type ip");
1242         else if (tbl->type == 2)
1243                 printf(" type mac");
1244 
1245         printf(" count %d", tbl->count);
1246 	if (strlen(tbl->name) > 0)
1247 		printf(" name %s", tbl->name);
1248 
1249 	printf("\n");
1250 
1251         if (tbl->type == 1) {
1252                 struct ipfw_ioc_table_ip_entry *ip_ent;
1253                 ip_ent = tbl->ip_ent;
1254                 for (i = 0; i < tbl->count; i++) {
1255                         printf("%s", inet_ntoa(*(struct in_addr *)&ip_ent->addr));
1256                         printf("/%d ", ip_ent->masklen);
1257                         printf("\n");
1258                         ip_ent++;
1259                 }
1260         } else if (tbl->type == 2) {
1261                 struct ipfw_ioc_table_mac_entry *mac_ent;
1262                 mac_ent = tbl->mac_ent;
1263                 for (i = 0; i < tbl->count; i++) {
1264                         printf("%s", ether_ntoa(&mac_ent->addr));
1265                         printf("\n");
1266                         mac_ent++;
1267                 }
1268         }
1269 }
1270 
1271 static void
1272 table_show(int ac, char *av[])
1273 {
1274 	int nbytes, nalloc = 1024;
1275 	void *data = NULL;
1276 	NEXT_ARG;
1277 	if (isdigit(**av)) {
1278 		nbytes = nalloc;
1279 		while (nbytes >= nalloc) {
1280 			nalloc = nalloc * 2 + 256;
1281 			nbytes = nalloc;
1282 			if (data == NULL) {
1283 				if ((data = malloc(nbytes)) == NULL) {
1284 					err(EX_OSERR, "malloc");
1285 				}
1286 			} else if ((data = realloc(data, nbytes)) == NULL) {
1287 				err(EX_OSERR, "realloc");
1288 			}
1289 			/* store table id in the header of data */
1290 			int *head = (int *)data;
1291 			*head = atoi(*av);
1292 			if (*head < 0 || *head > IPFW_TABLES_MAX - 1)
1293 				errx(EX_USAGE, "table id `%d' invalid", *head);
1294 			if (do_get_x(IP_FW_TABLE_SHOW, data, &nbytes) < 0)
1295 				err(EX_OSERR, "do_get_x(IP_FW_TABLE_LIST)");
1296 			struct ipfw_ioc_table *tbl;
1297 			tbl = (struct ipfw_ioc_table *)data;
1298 			print_table(tbl);
1299 		}
1300 	} else {
1301 		errx(EX_USAGE, "ipfw3 table `%s' show invalid", *av);
1302 	}
1303 }
1304 
1305 static void
1306 table_create(int ac, char *av[])
1307 {
1308 	struct ipfw_ioc_table ioc_table;
1309 	struct ipfw_ioc_table *t = &ioc_table;
1310 
1311 	NEXT_ARG;
1312 	if (ac < 2)
1313 		errx(EX_USAGE, "table parameters invalid");
1314 	if (isdigit(**av)) {
1315 		t->id = atoi(*av);
1316 		if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1317 			errx(EX_USAGE, "table id `%d' invalid", t->id);
1318 	} else {
1319 		errx(EX_USAGE, "table id `%s' invalid", *av);
1320 	}
1321 	NEXT_ARG;
1322 	if (strcmp(*av, "ip") == 0)
1323 		t->type = 1;
1324 	else if (strcmp(*av, "mac") == 0)
1325 		t->type = 2;
1326 	else
1327 		errx(EX_USAGE, "table type `%s' not supported", *av);
1328 
1329 	NEXT_ARG;
1330 	memset(t->name, 0, IPFW_TABLE_NAME_LEN);
1331 	if (ac == 2 && strcmp(*av, "name") == 0) {
1332 		NEXT_ARG;
1333 		if (strlen(*av) < IPFW_TABLE_NAME_LEN) {
1334 			strncpy(t->name, *av, strlen(*av));
1335 		} else {
1336 			errx(EX_USAGE, "table name `%s' too long", *av);
1337 		}
1338 	} else if (ac == 1) {
1339 		errx(EX_USAGE, "table `%s' invalid", *av);
1340 	}
1341 
1342 	if (do_set_x(IP_FW_TABLE_CREATE, t, sizeof(struct ipfw_ioc_table)) < 0)
1343 		errx(EX_USAGE, "do_set_x(IP_FW_TABLE_CREATE) "
1344 					"table `%d' in use", t->id);
1345 }
1346 
1347 static void
1348 table_delete(int ac, char *av[])
1349 {
1350 	struct ipfw_ioc_table ioc_table;
1351 	struct ipfw_ioc_table *t = &ioc_table;
1352 
1353 	NEXT_ARG;
1354 	if (isdigit(**av)) {
1355 		t->id = atoi(*av);
1356 		if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1357 			errx(EX_USAGE, "table id `%d' invalid", t->id);
1358 	} else {
1359 		errx(EX_USAGE, "table id `%s' invalid", *av);
1360 	}
1361 	if (t->id < 0 || t->id > IPFW_TABLES_MAX - 1)
1362 		errx(EX_USAGE, "table id `%d' invalid", t->id);
1363 
1364 	if (do_set_x(IP_FW_TABLE_DELETE, t, sizeof(struct ipfw_ioc_table)) < 0)
1365 		errx(EX_USAGE, "do_set_x(IP_FW_TABLE_DELETE) "
1366 					"table `%s' delete failed", *av);
1367 }
1368 
1369 static void
1370 table_test(int ac, char *av[])
1371 {
1372 	struct ipfw_ioc_table tbl;
1373 	int size;
1374 
1375 	NEXT_ARG;
1376 	if (isdigit(**av))
1377 		tbl.id = atoi(*av);
1378 	else
1379 		errx(EX_USAGE, "table id `%s' invalid", *av);
1380 
1381 	if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
1382 		errx(EX_USAGE, "table id `%d' invalid", tbl.id);
1383 
1384 	NEXT_ARG;
1385 	if (strcmp(*av, "ip") == 0)
1386 		tbl.type = 1;
1387 	else if (strcmp(*av, "mac") == 0)
1388 		tbl.type = 2;
1389 	else
1390 		errx(EX_USAGE, "table type `%s' not supported", *av);
1391 
1392 	NEXT_ARG;
1393         if (tbl.type == 1) { /* table type ipv4 */
1394                 struct ipfw_ioc_table_ip_entry ip_ent;
1395                 if (lookup_host(*av, (struct in_addr *)&ip_ent.addr) != 0)
1396                         errx(EX_NOHOST, "hostname ``%s'' unknown", *av);
1397 
1398                 tbl.ip_ent[0] = ip_ent;
1399                 size = sizeof(tbl) + sizeof(ip_ent);
1400         } else if (tbl.type == 2) { /* table type mac */
1401                 struct ipfw_ioc_table_mac_entry mac_ent;
1402                 if (!ac)
1403                         errx(EX_USAGE, "MAC address required");
1404 
1405                 mac_ent.addr = *ether_aton(*av);
1406                 tbl.mac_ent[0] = mac_ent;
1407                 size = sizeof(tbl) + sizeof(mac_ent);
1408         }
1409 	if (do_set_x(IP_FW_TABLE_TEST, &tbl, size) < 0 ) {
1410 		printf("NO, %s not exists in table %d\n", *av, tbl.id);
1411 	} else {
1412 		printf("YES, %s exists in table %d\n", *av, tbl.id);
1413 	}
1414 }
1415 
1416 static void
1417 table_rename(int ac, char *av[])
1418 {
1419 	struct ipfw_ioc_table tbl;
1420 	int size;
1421 
1422 	bzero(&tbl, sizeof(tbl));
1423 	NEXT_ARG;
1424 	if (isdigit(**av))
1425 		tbl.id = atoi(*av);
1426 	else
1427 		errx(EX_USAGE, "table id `%s' invalid", *av);
1428 
1429 	if (tbl.id < 0 || tbl.id > IPFW_TABLES_MAX - 1)
1430 		errx(EX_USAGE, "table id `%d' invalid", tbl.id);
1431 
1432 	NEXT_ARG;
1433 	strlcpy(tbl.name, *av, IPFW_TABLE_NAME_LEN);
1434 	size = sizeof(tbl);
1435 	if (do_set_x(IP_FW_TABLE_RENAME, &tbl, size) < 0 )
1436 		errx(EX_USAGE, "do_set_x(IP_FW_TABLE_RENAME) "
1437 					"table `%d' not in use", tbl.id);
1438 }
1439 
1440 static void
1441 list(int ac, char *av[])
1442 {
1443 	struct ipfw_ioc_state *dynrules, *d;
1444 	struct ipfw_ioc_rule *r;
1445 
1446 	u_long rnum;
1447 	void *data = NULL;
1448 	int bcwidth, n, nbytes, nstat, ndyn, pcwidth, width;
1449 	int exitval = EX_OK, lac;
1450 	char **lav, *endptr;
1451 	int seen = 0;
1452 	int nalloc = 1024;
1453 
1454 	NEXT_ARG;
1455 
1456 	/* get rules or pipes from kernel, resizing array as necessary */
1457 	nbytes = nalloc;
1458 
1459 	while (nbytes >= nalloc) {
1460 		nalloc = nalloc * 2 ;
1461 		nbytes = nalloc;
1462 		if ((data = realloc(data, nbytes)) == NULL)
1463 			err(EX_OSERR, "realloc");
1464 		if (do_get_x(IP_FW_GET, data, &nbytes) < 0)
1465 			err(EX_OSERR, "do_get_x(IP_FW_GET)");
1466 	}
1467 
1468 	/*
1469 	 * Count static rules.
1470 	 */
1471 	r = data;
1472 	nstat = r->static_count;
1473 
1474 	/*
1475 	 * Count dynamic rules. This is easier as they have
1476 	 * fixed size.
1477 	 */
1478 	dynrules = (struct ipfw_ioc_state *)((void *)r + r->static_len);
1479 	ndyn = (nbytes - r->static_len) / sizeof(*dynrules);
1480 
1481 	/* if showing stats, figure out column widths ahead of time */
1482 	bcwidth = pcwidth = 0;
1483 	if (do_acct) {
1484 		for (n = 0, r = data; n < nstat;
1485 			n++, r = (void *)r + IOC_RULESIZE(r)) {
1486 			/* packet counter */
1487 			width = snprintf(NULL, 0, "%ju", (uintmax_t)r->pcnt);
1488 			if (width > pcwidth)
1489 				pcwidth = width;
1490 
1491 			/* byte counter */
1492 			width = snprintf(NULL, 0, "%ju", (uintmax_t)r->bcnt);
1493 			if (width > bcwidth)
1494 				bcwidth = width;
1495 		}
1496 	}
1497 	if (do_dynamic && ndyn) {
1498 		for (n = 0, d = dynrules; n < ndyn; n++, d++) {
1499 			width = snprintf(NULL, 0, "%ju", (uintmax_t)d->pcnt);
1500 			if (width > pcwidth)
1501 				pcwidth = width;
1502 
1503 			width = snprintf(NULL, 0, "%ju", (uintmax_t)d->bcnt);
1504 			if (width > bcwidth)
1505 				bcwidth = width;
1506 		}
1507 	}
1508 
1509 	/* if no rule numbers were specified, list all rules */
1510 	if (ac == 0) {
1511 		if (do_dynamic != 2) {
1512 			for (n = 0, r = data; n < nstat; n++,
1513 				r = (void *)r + IOC_RULESIZE(r)) {
1514 				show_rules(r, pcwidth, bcwidth);
1515 			}
1516 		}
1517 		if (do_dynamic && ndyn) {
1518 			if (do_dynamic != 2) {
1519 				printf("## States (%d):\n", ndyn);
1520 			}
1521 			for (n = 0, d = dynrules; n < ndyn; n++, d++)
1522 				show_states(d, pcwidth, bcwidth);
1523 		}
1524 		goto done;
1525 	}
1526 
1527 	/* display specific rules requested on command line */
1528 
1529 	if (do_dynamic != 2) {
1530 		for (lac = ac, lav = av; lac != 0; lac--) {
1531 			/* convert command line rule # */
1532 			rnum = strtoul(*lav++, &endptr, 10);
1533 			if (*endptr) {
1534 				exitval = EX_USAGE;
1535 				warnx("invalid rule number: %s", *(lav - 1));
1536 				continue;
1537 			}
1538 			for (n = seen = 0, r = data; n < nstat;
1539 				n++, r = (void *)r + IOC_RULESIZE(r) ) {
1540 				if (r->rulenum > rnum)
1541 					break;
1542 				if (r->rulenum == rnum) {
1543 					show_rules(r, pcwidth, bcwidth);
1544 					seen = 1;
1545 				}
1546 			}
1547 			if (!seen) {
1548 				/* give precedence to other error(s) */
1549 				if (exitval == EX_OK)
1550 					exitval = EX_UNAVAILABLE;
1551 				warnx("rule %lu does not exist", rnum);
1552 			}
1553 		}
1554 	}
1555 
1556 	if (do_dynamic && ndyn) {
1557 		if (do_dynamic != 2) {
1558 			printf("## States (%d):\n", ndyn);
1559 		}
1560 		for (lac = ac, lav = av; lac != 0; lac--) {
1561 			rnum = strtoul(*lav++, &endptr, 10);
1562 			if (*endptr)
1563 				/* already warned */
1564 				continue;
1565 			for (n = 0, d = dynrules; n < ndyn; n++, d++) {
1566 				if (d->rulenum > rnum)
1567 					break;
1568 				if (d->rulenum == rnum)
1569 					show_states(d, pcwidth, bcwidth);
1570 			}
1571 		}
1572 	}
1573 
1574 	ac = 0;
1575 
1576 done:
1577 	free(data);
1578 
1579 	if (exitval != EX_OK)
1580 		exit(exitval);
1581 }
1582 
1583 static void
1584 show_dummynet(int ac, char *av[])
1585 {
1586 	void *data = NULL;
1587 	int nbytes;
1588 	int nalloc = 1024; 	/* start somewhere... */
1589 
1590 	NEXT_ARG;
1591 
1592 	nbytes = nalloc;
1593 	while (nbytes >= nalloc) {
1594 		nalloc = nalloc * 2 + 200;
1595 		nbytes = nalloc;
1596 		if ((data = realloc(data, nbytes)) == NULL)
1597 			err(EX_OSERR, "realloc");
1598 		if (do_get_x(IP_DUMMYNET_GET, data, &nbytes) < 0) {
1599 			err(EX_OSERR, "do_get_x(IP_%s_GET)",
1600 				do_pipe ? "DUMMYNET" : "FW");
1601 		}
1602 	}
1603 
1604 	show_pipes(data, nbytes, ac, av);
1605 	free(data);
1606 }
1607 
1608 static void
1609 help(void)
1610 {
1611 	fprintf(stderr, "usage: ipfw [options]\n"
1612 			"	ipfw add [rulenum] [set id] action filters\n"
1613 			"	ipfw delete [rulenum]\n"
1614 			"	ipfw flush\n"
1615 			"	ipfw list [rulenum]\n"
1616 			"	ipfw show [rulenum]\n"
1617 			"	ipfw zero [rulenum]\n"
1618 			"	ipfw set [show|enable|disable]\n"
1619 			"	ipfw module\n"
1620 			"	ipfw [enable|disable]\n"
1621 			"	ipfw log [reset|off|on]\n"
1622 			"	ipfw nat [config|show|delete]\n"
1623 			"	ipfw pipe [config|show|delete]\n"
1624 			"	ipfw state [add|delete|list|show]"
1625 			"\nsee ipfw manpage for details\n");
1626 	exit(EX_USAGE);
1627 }
1628 
1629 static void
1630 delete_nat_config(int ac, char *av[])
1631 {
1632 	NEXT_ARG;
1633 	int i = 0;
1634 	if (ac > 0) {
1635 		i = atoi(*av);
1636 	}
1637 	if (do_set_x(IP_FW_NAT_DEL, &i, sizeof(i)) == -1)
1638 		errx(EX_USAGE, "NAT %d in use or not exists", i);
1639 }
1640 
1641 static void
1642 delete_rules(int ac, char *av[])
1643 {
1644 	struct dn_ioc_pipe pipe;
1645 	u_int32_t rulenum;
1646 	int exitval = EX_OK;
1647 	int do_set = 0;
1648 	int i;
1649 
1650 	memset(&pipe, 0, sizeof pipe);
1651 
1652 	NEXT_ARG;
1653 	if (ac > 0 && !strncmp(*av, "set", strlen(*av))) {
1654 		do_set = 1; 	/* delete set */
1655 		NEXT_ARG;
1656 	}
1657 
1658 	/* Rule number */
1659 	while (ac && isdigit(**av)) {
1660 		i = atoi(*av);
1661 		NEXT_ARG;
1662 		if (do_pipe) {
1663 			if (do_pipe == 1)
1664 				pipe.pipe_nr = i;
1665 			else
1666 				pipe.fs.fs_nr = i;
1667 
1668 			i = do_set_x(IP_DUMMYNET_DEL, &pipe, sizeof pipe);
1669 			if (i) {
1670 				exitval = 1;
1671 				warn("rule %u: setsockopt(IP_DUMMYNET_DEL)",
1672 					do_pipe == 1 ? pipe.pipe_nr : pipe.fs.fs_nr);
1673 			}
1674 		} else {
1675 			rulenum = (i & 0xffff) | (do_set << 24);
1676 			i = do_set_x(IP_FW_DEL, &rulenum, sizeof rulenum);
1677 			if (i) {
1678 				exitval = EX_UNAVAILABLE;
1679 				warn("rule %u: setsockopt(IP_FW_DEL)",
1680 					rulenum);
1681 			}
1682 		}
1683 	}
1684 	if (exitval != EX_OK)
1685 		exit(exitval);
1686 }
1687 
1688 
1689 static unsigned long
1690 getbw(const char *str, u_short *flags, int kb)
1691 {
1692 	unsigned long val;
1693 	int inbytes = 0;
1694 	char *end;
1695 
1696 	val = strtoul(str, &end, 0);
1697 	if (*end == 'k' || *end == 'K') {
1698 		++end;
1699 		val *= kb;
1700 	} else if (*end == 'm' || *end == 'M') {
1701 		++end;
1702 		val *= kb * kb;
1703 	}
1704 
1705 	/*
1706 	 * Deal with bits or bytes or b(bits) or B(bytes). If there is no
1707 	 * trailer assume bits.
1708 	 */
1709 	if (strncasecmp(end, "bit", 3) == 0) {
1710 		;
1711 	} else if (strncasecmp(end, "byte", 4) == 0) {
1712 		inbytes = 1;
1713 	} else if (*end == 'b') {
1714 		;
1715 	} else if (*end == 'B') {
1716 		inbytes = 1;
1717 	}
1718 
1719 	/*
1720 	 * Return in bits if flags is NULL, else flag bits
1721 	 * or bytes in flags and return the unconverted value.
1722 	 */
1723 	if (inbytes && flags)
1724 		*flags |= DN_QSIZE_IS_BYTES;
1725 	else if (inbytes && flags == NULL)
1726 		val *= 8;
1727 
1728 	return(val);
1729 }
1730 
1731 /*
1732  * config dummynet pipe/queue
1733  */
1734 static void
1735 config_dummynet(int ac, char **av)
1736 {
1737 	struct dn_ioc_pipe pipe;
1738 	u_int32_t a;
1739 	void *par = NULL;
1740 	int i;
1741 	char *end;
1742 
1743 	NEXT_ARG;
1744 	memset(&pipe, 0, sizeof pipe);
1745 	/* Pipe number */
1746 	if (ac && isdigit(**av)) {
1747 		i = atoi(*av);
1748 		NEXT_ARG;
1749 		if (do_pipe == 1)
1750 			pipe.pipe_nr = i;
1751 		else
1752 			pipe.fs.fs_nr = i;
1753 	}
1754 
1755 	while (ac > 0) {
1756 		double d;
1757 
1758 		int tok = match_token(dummynet_params, *av);
1759 		NEXT_ARG;
1760 
1761 		switch(tok) {
1762 		case TOK_NOERROR:
1763 			pipe.fs.flags_fs |= DN_NOERROR;
1764 			break;
1765 
1766 		case TOK_PLR:
1767 			NEED1("plr needs argument 0..1\n");
1768 			d = strtod(av[0], NULL);
1769 			if (d > 1)
1770 				d = 1;
1771 			else if (d < 0)
1772 				d = 0;
1773 			pipe.fs.plr = (int)(d*0x7fffffff);
1774 			NEXT_ARG;
1775 			break;
1776 
1777 		case TOK_QUEUE:
1778 			NEED1("queue needs queue size\n");
1779 			end = NULL;
1780 			pipe.fs.qsize = getbw(av[0], &pipe.fs.flags_fs, 1024);
1781 			NEXT_ARG;
1782 			break;
1783 
1784 		case TOK_BUCKETS:
1785 			NEED1("buckets needs argument\n");
1786 			pipe.fs.rq_size = strtoul(av[0], NULL, 0);
1787 			NEXT_ARG;
1788 			break;
1789 
1790 		case TOK_MASK:
1791 			NEED1("mask needs mask specifier\n");
1792 			/*
1793 			 * per-flow queue, mask is dst_ip, dst_port,
1794 			 * src_ip, src_port, proto measured in bits
1795 			 */
1796 			par = NULL;
1797 
1798 			pipe.fs.flow_mask.type = ETHERTYPE_IP;
1799 			pipe.fs.flow_mask.u.ip.dst_ip = 0;
1800 			pipe.fs.flow_mask.u.ip.src_ip = 0;
1801 			pipe.fs.flow_mask.u.ip.dst_port = 0;
1802 			pipe.fs.flow_mask.u.ip.src_port = 0;
1803 			pipe.fs.flow_mask.u.ip.proto = 0;
1804 			end = NULL;
1805 
1806 			while (ac >= 1) {
1807 				u_int32_t *p32 = NULL;
1808 				u_int16_t *p16 = NULL;
1809 
1810 				tok = match_token(dummynet_params, *av);
1811 				NEXT_ARG;
1812 				switch(tok) {
1813 				case TOK_ALL:
1814 					/*
1815 					 * special case, all bits significant
1816 					 */
1817 					pipe.fs.flow_mask.u.ip.dst_ip = ~0;
1818 					pipe.fs.flow_mask.u.ip.src_ip = ~0;
1819 					pipe.fs.flow_mask.u.ip.dst_port = ~0;
1820 					pipe.fs.flow_mask.u.ip.src_port = ~0;
1821 					pipe.fs.flow_mask.u.ip.proto = ~0;
1822 					pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
1823 					goto end_mask;
1824 
1825 				case TOK_DSTIP:
1826 					p32 = &pipe.fs.flow_mask.u.ip.dst_ip;
1827 					break;
1828 
1829 				case TOK_SRCIP:
1830 					p32 = &pipe.fs.flow_mask.u.ip.src_ip;
1831 					break;
1832 
1833 				case TOK_DSTPORT:
1834 					p16 = &pipe.fs.flow_mask.u.ip.dst_port;
1835 					break;
1836 
1837 				case TOK_SRCPORT:
1838 					p16 = &pipe.fs.flow_mask.u.ip.src_port;
1839 					break;
1840 
1841 				case TOK_PROTO:
1842 					break;
1843 
1844 				default:
1845 					NEXT_ARG;
1846 					goto end_mask;
1847 				}
1848 				if (ac < 1)
1849 					errx(EX_USAGE, "mask: value missing");
1850 				if (*av[0] == '/') {
1851 					a = strtoul(av[0]+1, &end, 0);
1852 					a = (a == 32) ? ~0 : (1 << a) - 1;
1853 				} else
1854 					a = strtoul(av[0], &end, 0);
1855 				if (p32 != NULL)
1856 					*p32 = a;
1857 				else if (p16 != NULL) {
1858 					if (a > 65535)
1859 						errx(EX_DATAERR,
1860 						"mask: must be 16 bit");
1861 					*p16 = (u_int16_t)a;
1862 				} else {
1863 					if (a > 255)
1864 						errx(EX_DATAERR,
1865 						"mask: must be 8 bit");
1866 					pipe.fs.flow_mask.u.ip.proto = (uint8_t)a;
1867 				}
1868 				if (a != 0)
1869 					pipe.fs.flags_fs |= DN_HAVE_FLOW_MASK;
1870 				NEXT_ARG;
1871 			} /* end while, config masks */
1872 
1873 end_mask:
1874 			break;
1875 
1876 		case TOK_RED:
1877 		case TOK_GRED:
1878 			NEED1("red/gred needs w_q/min_th/max_th/max_p\n");
1879 			pipe.fs.flags_fs |= DN_IS_RED;
1880 			if (tok == TOK_GRED)
1881 				pipe.fs.flags_fs |= DN_IS_GENTLE_RED;
1882 			/*
1883 			 * the format for parameters is w_q/min_th/max_th/max_p
1884 			 */
1885 			if ((end = strsep(&av[0], "/"))) {
1886 				double w_q = strtod(end, NULL);
1887 				if (w_q > 1 || w_q <= 0)
1888 					errx(EX_DATAERR, "0 < w_q <= 1");
1889 				pipe.fs.w_q = (int) (w_q * (1 << SCALE_RED));
1890 			}
1891 			if ((end = strsep(&av[0], "/"))) {
1892 				pipe.fs.min_th = strtoul(end, &end, 0);
1893 				if (*end == 'K' || *end == 'k')
1894 					pipe.fs.min_th *= 1024;
1895 			}
1896 			if ((end = strsep(&av[0], "/"))) {
1897 				pipe.fs.max_th = strtoul(end, &end, 0);
1898 				if (*end == 'K' || *end == 'k')
1899 					pipe.fs.max_th *= 1024;
1900 			}
1901 			if ((end = strsep(&av[0], "/"))) {
1902 				double max_p = strtod(end, NULL);
1903 				if (max_p > 1 || max_p <= 0)
1904 					errx(EX_DATAERR, "0 < max_p <= 1");
1905 				pipe.fs.max_p = (int)(max_p * (1 << SCALE_RED));
1906 			}
1907 			NEXT_ARG;
1908 			break;
1909 
1910 		case TOK_DROPTAIL:
1911 			pipe.fs.flags_fs &= ~(DN_IS_RED|DN_IS_GENTLE_RED);
1912 			break;
1913 
1914 		case TOK_BW:
1915 			NEED1("bw needs bandwidth\n");
1916 			if (do_pipe != 1)
1917 				errx(EX_DATAERR, "bandwidth only valid for pipes");
1918 			/*
1919 			 * set bandwidth value
1920 			 */
1921 			pipe.bandwidth = getbw(av[0], NULL, 1000);
1922 			if (pipe.bandwidth < 0)
1923 				errx(EX_DATAERR, "bandwidth too large");
1924 			NEXT_ARG;
1925 			break;
1926 
1927 		case TOK_DELAY:
1928 			if (do_pipe != 1)
1929 				errx(EX_DATAERR, "delay only valid for pipes");
1930 			NEED1("delay needs argument 0..10000ms\n");
1931 			pipe.delay = strtoul(av[0], NULL, 0);
1932 			NEXT_ARG;
1933 			break;
1934 
1935 		case TOK_WEIGHT:
1936 			if (do_pipe == 1)
1937 				errx(EX_DATAERR, "weight only valid for queues");
1938 			NEED1("weight needs argument 0..100\n");
1939 			pipe.fs.weight = strtoul(av[0], &end, 0);
1940 			NEXT_ARG;
1941 			break;
1942 
1943 		case TOK_PIPE:
1944 			if (do_pipe == 1)
1945 				errx(EX_DATAERR, "pipe only valid for queues");
1946 			NEED1("pipe needs pipe_number\n");
1947 			pipe.fs.parent_nr = strtoul(av[0], &end, 0);
1948 			NEXT_ARG;
1949 			break;
1950 
1951 		default:
1952 			errx(EX_DATAERR, "unrecognised option ``%s''", *av);
1953 		}
1954 	}
1955 	if (do_pipe == 1) {
1956 		if (pipe.pipe_nr == 0)
1957 			errx(EX_DATAERR, "pipe_nr must be > 0");
1958 		if (pipe.delay > 10000)
1959 			errx(EX_DATAERR, "delay must be < 10000");
1960 	} else { /* do_pipe == 2, queue */
1961 		if (pipe.fs.parent_nr == 0)
1962 			errx(EX_DATAERR, "pipe must be > 0");
1963 		if (pipe.fs.weight >100)
1964 			errx(EX_DATAERR, "weight must be <= 100");
1965 	}
1966 	if (pipe.fs.flags_fs & DN_QSIZE_IS_BYTES) {
1967 		if (pipe.fs.qsize > 1024*1024)
1968 			errx(EX_DATAERR, "queue size must be < 1MB");
1969 	} else {
1970 		if (pipe.fs.qsize > 100)
1971 			errx(EX_DATAERR, "2 <= queue size <= 100");
1972 	}
1973 	if (pipe.fs.flags_fs & DN_IS_RED) {
1974 		size_t len;
1975 		int lookup_depth, avg_pkt_size;
1976 		double s, idle, weight, w_q;
1977 		int clock_hz;
1978 		int t;
1979 
1980 		if (pipe.fs.min_th >= pipe.fs.max_th)
1981 			errx(EX_DATAERR, "min_th %d must be < than max_th %d",
1982 			pipe.fs.min_th, pipe.fs.max_th);
1983 		if (pipe.fs.max_th == 0)
1984 			errx(EX_DATAERR, "max_th must be > 0");
1985 
1986 		len = sizeof(int);
1987 		if (sysctlbyname("net.inet.ip.dummynet.red_lookup_depth",
1988 			&lookup_depth, &len, NULL, 0) == -1)
1989 
1990 			errx(1, "sysctlbyname(\"%s\")",
1991 				"net.inet.ip.dummynet.red_lookup_depth");
1992 		if (lookup_depth == 0)
1993 			errx(EX_DATAERR, "net.inet.ip.dummynet.red_lookup_depth"
1994 				" must be greater than zero");
1995 
1996 		len = sizeof(int);
1997 		if (sysctlbyname("net.inet.ip.dummynet.red_avg_pkt_size",
1998 			&avg_pkt_size, &len, NULL, 0) == -1)
1999 
2000 			errx(1, "sysctlbyname(\"%s\")",
2001 				"net.inet.ip.dummynet.red_avg_pkt_size");
2002 		if (avg_pkt_size == 0)
2003 			errx(EX_DATAERR,
2004 				"net.inet.ip.dummynet.red_avg_pkt_size must"
2005 				" be greater than zero");
2006 
2007 		len = sizeof(clock_hz);
2008 		if (sysctlbyname("net.inet.ip.dummynet.hz", &clock_hz, &len,
2009 				 NULL, 0) == -1) {
2010 			errx(1, "sysctlbyname(\"%s\")",
2011 				 "net.inet.ip.dummynet.hz");
2012 		}
2013 
2014 		/*
2015 		 * Ticks needed for sending a medium-sized packet.
2016 		 * Unfortunately, when we are configuring a WF2Q+ queue, we
2017 		 * do not have bandwidth information, because that is stored
2018 		 * in the parent pipe, and also we have multiple queues
2019 		 * competing for it. So we set s=0, which is not very
2020 		 * correct. But on the other hand, why do we want RED with
2021 		 * WF2Q+ ?
2022 		 */
2023 		if (pipe.bandwidth == 0) /* this is a WF2Q+ queue */
2024 			s = 0;
2025 		else
2026 			s = clock_hz * avg_pkt_size * 8 / pipe.bandwidth;
2027 
2028 		/*
2029 		 * max idle time (in ticks) before avg queue size becomes 0.
2030 		 * NOTA: (3/w_q) is approx the value x so that
2031 		 * (1-w_q)^x < 10^-3.
2032 		 */
2033 		w_q = ((double)pipe.fs.w_q) / (1 << SCALE_RED);
2034 		idle = s * 3. / w_q;
2035 		pipe.fs.lookup_step = (int)idle / lookup_depth;
2036 		if (!pipe.fs.lookup_step)
2037 			pipe.fs.lookup_step = 1;
2038 		weight = 1 - w_q;
2039 		for (t = pipe.fs.lookup_step; t > 0; --t)
2040 			weight *= weight;
2041 		pipe.fs.lookup_weight = (int)(weight * (1 << SCALE_RED));
2042 	}
2043 	i = do_set_x(IP_DUMMYNET_CONFIGURE, &pipe, sizeof pipe);
2044 	if (i)
2045 		err(1, "do_set_x(%s)", "IP_DUMMYNET_CONFIGURE");
2046 }
2047 
2048 /*
2049  * helper function, updates the pointer to cmd with the length
2050  * of the current command, and also cleans up the first word of
2051  * the new command in case it has been clobbered before.
2052  */
2053 static ipfw_insn*
2054 next_cmd(ipfw_insn *cmd)
2055 {
2056 	cmd += F_LEN(cmd);
2057 	bzero(cmd, sizeof(*cmd));
2058 	return cmd;
2059 }
2060 
2061 /*
2062  * Parse arguments and assemble the microinstructions which make up a rule.
2063  * Rules are added into the 'rulebuf' and then copied in the correct order
2064  * into the actual rule.
2065  *
2066  *
2067  */
2068 static void
2069 add(int ac, char *av[])
2070 {
2071 	/*
2072 	 * rules are added into the 'rulebuf' and then copied in
2073 	 * the correct order into the actual rule.
2074 	 * Some things that need to go out of order (prob, action etc.)
2075 	 * go into actbuf[].
2076 	 */
2077 	static uint32_t rulebuf[IPFW_RULE_SIZE_MAX];
2078 	static uint32_t actbuf[IPFW_RULE_SIZE_MAX];
2079 	static uint32_t othbuf[IPFW_RULE_SIZE_MAX];
2080 	static uint32_t cmdbuf[IPFW_RULE_SIZE_MAX];
2081 
2082 	ipfw_insn *src, *dst, *cmd, *action, *other;
2083 	ipfw_insn *prev;
2084 	char *prev_av;
2085 	ipfw_insn *the_comment = NULL;
2086 	struct ipfw_ioc_rule *rule;
2087 	struct ipfw_keyword *key;
2088 	struct ipfw_mapping *map;
2089 	parser_func fn;
2090 	int i, j;
2091 
2092 	bzero(actbuf, sizeof(actbuf)); 		/* actions go here */
2093 	bzero(othbuf, sizeof(actbuf)); 		/* others */
2094 	bzero(cmdbuf, sizeof(cmdbuf)); 		/* filters */
2095 	bzero(rulebuf, sizeof(rulebuf));
2096 
2097 	rule = (struct ipfw_ioc_rule *)rulebuf;
2098 	cmd = (ipfw_insn *)cmdbuf;
2099 	action = (ipfw_insn *)actbuf;
2100 	other = (ipfw_insn *)othbuf;
2101 
2102 	NEED2("need more parameters");
2103 	NEXT_ARG;
2104 
2105 	/* [rule N]	-- Rule number optional */
2106 	if (ac && isdigit(**av)) {
2107 		rule->rulenum = atoi(*av);
2108 		NEXT_ARG;
2109 	}
2110 
2111 	/* [set N]	-- set number (0..30), optional */
2112 	if (ac > 1 && !strncmp(*av, "set", strlen(*av))) {
2113 		int set = strtoul(av[1], NULL, 10);
2114 		if (set < 0 || set > 30)
2115 			errx(EX_DATAERR, "illegal set %s", av[1]);
2116 		rule->set = set;
2117 		av += 2; ac -= 2;
2118 	}
2119 
2120 	/*
2121 	 * parse before
2122 	 */
2123 	for (;;) {
2124 		for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
2125 			if (key->type == BEFORE &&
2126 				strcmp(key->word, *av) == 0) {
2127 				for (j = 0, map = mappings;
2128 					j < MAPPING_SIZE; j++, map++) {
2129 					if (map->type == IN_USE &&
2130 						map->module == key->module &&
2131 						map->opcode == key->opcode ) {
2132 						fn = map->parser;
2133 						(*fn)(&other, &ac, &av);
2134 						break;
2135 					}
2136 				}
2137 				break;
2138 			}
2139 		}
2140 		if (i >= KEYWORD_SIZE) {
2141 			break;
2142 		} else if (F_LEN(other) > 0) {
2143 			if (other->module == MODULE_BASIC_ID &&
2144 				other->opcode == O_BASIC_CHECK_STATE) {
2145 				other = next_cmd(other);
2146 				goto done;
2147 			}
2148 			other = next_cmd(other);
2149 		}
2150 	}
2151 
2152 	/*
2153 	 * parse actions
2154 	 *
2155 	 * only accept 1 action
2156 	 */
2157 	NEED1("missing action");
2158 	for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
2159 		if (ac > 0 && key->type == ACTION &&
2160 			strcmp(key->word, *av) == 0) {
2161 			for (j = 0, map = mappings; j<MAPPING_SIZE; j++, map++) {
2162 				if (map->type == IN_USE &&
2163 					map->module == key->module &&
2164 					map->opcode == key->opcode) {
2165 					fn = map->parser;
2166 					(*fn)(&action, &ac, &av);
2167 					break;
2168 				}
2169 			}
2170 			break;
2171 		}
2172 	}
2173 	if (F_LEN(action) > 0)
2174 		action = next_cmd(action);
2175 
2176 	/*
2177 	 * parse protocol
2178 	 */
2179 	if (strcmp(*av, "proto") == 0){
2180 		NEXT_ARG;
2181 	}
2182 
2183 	NEED1("missing protocol");
2184 	for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
2185 		if (key->type == PROTO &&
2186 			strcmp(key->word, "proto") == 0) {
2187 			for (j = 0, map = mappings; j<MAPPING_SIZE; j++, map++) {
2188 				if (map->type == IN_USE &&
2189 					map->module == key->module &&
2190 					map->opcode == key->opcode ) {
2191 					fn = map->parser;
2192 					(*fn)(&cmd, &ac, &av);
2193 					break;
2194 				}
2195 			}
2196 			break;
2197 		}
2198 	}
2199 	if (F_LEN(cmd) > 0)
2200 		cmd = next_cmd(cmd);
2201 
2202 	/*
2203 	 * other filters
2204 	 */
2205 	while (ac > 0) {
2206 		char *s, *cur;		/* current filter */
2207 		ipfw_insn_u32 *cmd32; 	/* alias for cmd */
2208 
2209 		s = *av;
2210 		cmd32 = (ipfw_insn_u32 *)cmd;
2211 		if (strcmp(*av, "or") == 0) {
2212 			if (prev == NULL)
2213 				errx(EX_USAGE, "'or' should"
2214 						"between two filters\n");
2215 			prev->len |= F_OR;
2216 			cmd->len = F_OR;
2217 			*av = prev_av;
2218 		}
2219 		if (strcmp(*av, "not") == 0) {
2220 			if (cmd->len & F_NOT)
2221 				errx(EX_USAGE, "double \"not\" not allowed\n");
2222 			cmd->len = F_NOT;
2223 			NEXT_ARG;
2224 			continue;
2225 		}
2226 		cur = *av;
2227 		for (i = 0, key = keywords; i < KEYWORD_SIZE; i++, key++) {
2228 			if ((key->type == FILTER ||
2229                                 key->type == AFTER ||
2230                                 key->type == FROM ||
2231                                 key->type == TO) &&
2232 				strcmp(key->word, cur) == 0) {
2233 				for (j = 0, map = mappings;
2234 					j< MAPPING_SIZE; j++, map++) {
2235 					if (map->type == IN_USE &&
2236 						map->module == key->module &&
2237 						map->opcode == key->opcode ) {
2238 						fn = map->parser;
2239 						(*fn)(&cmd, &ac, &av);
2240 						break;
2241 					}
2242 				}
2243 				break;
2244 			} else if (i == KEYWORD_SIZE - 1) {
2245 				errx(EX_USAGE, "bad command `%s'", cur);
2246 			}
2247 		}
2248 		if (i >= KEYWORD_SIZE) {
2249 			break;
2250 		} else if (F_LEN(cmd) > 0) {
2251 			prev = cmd;
2252 			prev_av = cur;
2253 			cmd = next_cmd(cmd);
2254 		}
2255 	}
2256 
2257 done:
2258 	if (ac>0)
2259 		errx(EX_USAGE, "bad command `%s'", *av);
2260 
2261 	/*
2262 	 * Now copy stuff into the rule.
2263 	 * [filters][others][action][comment]
2264 	 */
2265 	dst = (ipfw_insn *)rule->cmd;
2266 	/*
2267 	 * copy all filters, except comment
2268 	 */
2269 	src = (ipfw_insn *)cmdbuf;
2270 	for (src = (ipfw_insn *)cmdbuf; src != cmd; src += i) {
2271 		/* pick comment out */
2272 		i = F_LEN(src);
2273 		if (src->module == MODULE_BASIC_ID && src->opcode == O_BASIC_COMMENT) {
2274 			the_comment=src;
2275 		} else {
2276 			bcopy(src, dst, i * sizeof(u_int32_t));
2277 			dst = (ipfw_insn *)((uint32_t *)dst + i);
2278 		}
2279 	}
2280 
2281 	/*
2282 	 * start action section, it begin with others
2283 	 */
2284 	rule->act_ofs = (uint32_t *)dst - (uint32_t *)(rule->cmd);
2285 
2286 	/*
2287 	 * copy all other others
2288 	 */
2289 	for (src = (ipfw_insn *)othbuf; src != other; src += i) {
2290 		i = F_LEN(src);
2291 		bcopy(src, dst, i * sizeof(u_int32_t));
2292 		dst = (ipfw_insn *)((uint32_t *)dst + i);
2293 	}
2294 
2295 	/* copy the action to the end of rule */
2296 	src = (ipfw_insn *)actbuf;
2297 	i = F_LEN(src);
2298 	bcopy(src, dst, i * sizeof(u_int32_t));
2299 	dst = (ipfw_insn *)((uint32_t *)dst + i);
2300 
2301 	/*
2302 	 * comment place behind the action
2303 	 */
2304 	if (the_comment != NULL) {
2305 		i = F_LEN(the_comment);
2306 		bcopy(the_comment, dst, i * sizeof(u_int32_t));
2307 		dst = (ipfw_insn *)((uint32_t *)dst + i);
2308 	}
2309 
2310 	rule->cmd_len = (u_int32_t *)dst - (u_int32_t *)(rule->cmd);
2311 	i = (void *)dst - (void *)rule;
2312 	if (do_set_x(IP_FW_ADD, (void *)rule, i) == -1) {
2313 		err(EX_UNAVAILABLE, "getsockopt(%s)", "IP_FW_ADD");
2314 	}
2315 	if (!do_quiet)
2316 		show_rules(rule, 10, 10);
2317 }
2318 
2319 static void
2320 zero(int ac, char *av[])
2321 {
2322 	int rulenum;
2323 	int failed = EX_OK;
2324 
2325 	NEXT_ARG;
2326 
2327 	if (!ac) {
2328 		/* clear all entries */
2329 		if (do_set_x(IP_FW_ZERO, NULL, 0) < 0)
2330 			err(EX_UNAVAILABLE, "do_set_x(IP_FW_ZERO)");
2331 		if (!do_quiet)
2332 			printf("Accounting cleared.\n");
2333 		return;
2334 	}
2335 
2336 	while (ac) {
2337 		/* Rule number */
2338 		if (isdigit(**av)) {
2339 			rulenum = atoi(*av);
2340 			NEXT_ARG;
2341 			if (do_set_x(IP_FW_ZERO, &rulenum, sizeof rulenum)) {
2342 				warn("rule %u: do_set_x(IP_FW_ZERO)", rulenum);
2343 				failed = EX_UNAVAILABLE;
2344 			} else if (!do_quiet)
2345 				printf("Entry %d cleared\n", rulenum);
2346 		} else {
2347 			errx(EX_USAGE, "invalid rule number ``%s''", *av);
2348 		}
2349 	}
2350 	if (failed != EX_OK)
2351 		exit(failed);
2352 }
2353 
2354 static void
2355 resetlog(int ac, char *av[])
2356 {
2357 	int rulenum;
2358 	int failed = EX_OK;
2359 
2360 	NEXT_ARG;
2361 
2362 	if (!ac) {
2363 		/* clear all entries */
2364 		if (setsockopt(ipfw_socket, IPPROTO_IP, IP_FW_RESETLOG, NULL, 0) < 0)
2365 			err(EX_UNAVAILABLE, "setsockopt(IP_FW_RESETLOG)");
2366 		if (!do_quiet)
2367 			printf("Logging counts reset.\n");
2368 
2369 		return;
2370 	}
2371 
2372 	while (ac) {
2373 		/* Rule number */
2374 		if (isdigit(**av)) {
2375 			rulenum = atoi(*av);
2376 			NEXT_ARG;
2377 			if (setsockopt(ipfw_socket, IPPROTO_IP,
2378 				IP_FW_RESETLOG, &rulenum, sizeof rulenum)) {
2379 				warn("rule %u: setsockopt(IP_FW_RESETLOG)", rulenum);
2380 				failed = EX_UNAVAILABLE;
2381 			} else if (!do_quiet)
2382 				printf("Entry %d logging count reset\n", rulenum);
2383 		} else {
2384 			errx(EX_DATAERR, "invalid rule number ``%s''", *av);
2385 		}
2386 	}
2387 	if (failed != EX_OK)
2388 		exit(failed);
2389 }
2390 
2391 static void
2392 flush(void)
2393 {
2394 	int cmd = IP_FW_FLUSH;
2395 	if (do_pipe) {
2396 		cmd = IP_DUMMYNET_FLUSH;
2397 	} else if (do_nat) {
2398 		cmd = IP_FW_NAT_FLUSH;
2399 	}
2400 	if (!do_force) {
2401 		int c;
2402 
2403 		printf("Are you sure? [yn] ");
2404 		fflush(stdout);
2405 		do {
2406 			c = toupper(getc(stdin));
2407 			while (c != '\n' && getc(stdin) != '\n')
2408 				if (feof(stdin))
2409 					return; /* and do not flush */
2410 		} while (c != 'Y' && c != 'N');
2411 		if (c == 'N')	/* user said no */
2412 			return;
2413 	}
2414 	if (do_set_x(cmd, NULL, 0) < 0 ) {
2415 		if (do_pipe)
2416 			errx(EX_USAGE, "pipe/queue in use");
2417 		else if (do_nat)
2418 			errx(EX_USAGE, "NAT configuration in use");
2419 		else
2420 			errx(EX_USAGE, "do_set_x(IP_FWFLUSH) failed");
2421 	}
2422 	if (!do_quiet) {
2423 		printf("Flushed all %s.\n", do_pipe ? "pipes":
2424 				(do_nat?"nat configurations":"rules"));
2425 	}
2426 }
2427 
2428 static void
2429 str2addr(const char* str, struct in_addr* addr)
2430 {
2431 	struct hostent* hp;
2432 
2433 	if (inet_aton (str, addr))
2434 		return;
2435 
2436 	hp = gethostbyname (str);
2437 	if (!hp)
2438 		errx (1, "unknown host %s", str);
2439 
2440 	memcpy (addr, hp->h_addr, sizeof (struct in_addr));
2441 }
2442 
2443 static int
2444 str2portrange(const char* str, const char* proto, port_range *portRange)
2445 {
2446 	struct servent*	sp;
2447 	char*	sep;
2448 	char*	end;
2449 	u_short	loPort, hiPort;
2450 
2451 	/* First see if this is a service, return corresponding port if so. */
2452 	sp = getservbyname (str, proto);
2453 	if (sp) {
2454 		SETLOPORT(*portRange, ntohs(sp->s_port));
2455 		SETNUMPORTS(*portRange, 1);
2456 		return 0;
2457 	}
2458 
2459 	/* Not a service, see if it's a single port or port range. */
2460 	sep = strchr (str, '-');
2461 	if (sep == NULL) {
2462 		SETLOPORT(*portRange, strtol(str, &end, 10));
2463 		if (end != str) {
2464 			/* Single port. */
2465 			SETNUMPORTS(*portRange, 1);
2466 			return 0;
2467 		}
2468 
2469 		/* Error in port range field. */
2470 		errx (EX_DATAERR, "%s/%s: unknown service", str, proto);
2471 	}
2472 
2473 	/* Port range, get the values and sanity check. */
2474 	sscanf (str, "%hu-%hu", &loPort, &hiPort);
2475 	SETLOPORT(*portRange, loPort);
2476 	SETNUMPORTS(*portRange, 0); 	/* Error by default */
2477 	if (loPort <= hiPort)
2478 		SETNUMPORTS(*portRange, hiPort - loPort + 1);
2479 
2480 	if (GETNUMPORTS(*portRange) == 0)
2481 		errx (EX_DATAERR, "invalid port range %s", str);
2482 
2483 	return 0;
2484 }
2485 
2486 static int
2487 str2proto(const char* str)
2488 {
2489 	if (!strcmp (str, "tcp"))
2490 		return IPPROTO_TCP;
2491 	if (!strcmp (str, "udp"))
2492 		return IPPROTO_UDP;
2493 	errx (EX_DATAERR, "unknown protocol %s. Expected tcp or udp", str);
2494 }
2495 
2496 static int
2497 str2addr_portrange (const char* str, struct in_addr* addr,
2498 	char* proto, port_range *portRange)
2499 {
2500 	char*	ptr;
2501 
2502 	ptr = strchr (str, ':');
2503 	if (!ptr)
2504 		errx (EX_DATAERR, "%s is missing port number", str);
2505 
2506 	*ptr = '\0';
2507 	++ptr;
2508 
2509 	str2addr (str, addr);
2510 	return str2portrange (ptr, proto, portRange);
2511 }
2512 
2513 /*
2514  * Search for interface with name "ifn", and fill n accordingly:
2515  *
2516  * n->ip		ip address of interface "ifn"
2517  * n->if_name copy of interface name "ifn"
2518  */
2519 static void
2520 set_addr_dynamic(const char *ifn, struct cfg_nat *n)
2521 {
2522 	struct if_msghdr *ifm;
2523 	struct ifa_msghdr *ifam;
2524 	struct sockaddr_dl *sdl;
2525 	struct sockaddr_in *sin;
2526 	char *buf, *lim, *next;
2527 	size_t needed;
2528 	int mib[6];
2529 	int ifIndex, ifMTU;
2530 
2531 	mib[0] = CTL_NET;
2532 	mib[1] = PF_ROUTE;
2533 	mib[2] = 0;
2534 	mib[3] = AF_INET;
2535 	mib[4] = NET_RT_IFLIST;
2536 	mib[5] = 0;
2537 
2538 	/*
2539 	 * Get interface data.
2540 	 */
2541 	if (sysctl(mib, 6, NULL, &needed, NULL, 0) == -1)
2542 		err(1, "iflist-sysctl-estimate");
2543 	if ((buf = malloc(needed)) == NULL)
2544 		errx(1, "malloc failed");
2545 	if (sysctl(mib, 6, buf, &needed, NULL, 0) == -1)
2546 		err(1, "iflist-sysctl-get");
2547 	lim = buf + needed;
2548 	/*
2549 	 * Loop through interfaces until one with
2550 	 * given name is found. This is done to
2551 	 * find correct interface index for routing
2552 	 * message processing.
2553 	 */
2554 	ifIndex	= 0;
2555 	next = buf;
2556 	while (next < lim) {
2557 		ifm = (struct if_msghdr *)next;
2558 		next += ifm->ifm_msglen;
2559 		if (ifm->ifm_version != RTM_VERSION) {
2560 			if (verbose)
2561 				warnx("routing message version %d "
2562 					"not understood", ifm->ifm_version);
2563 			continue;
2564 		}
2565 		if (ifm->ifm_type == RTM_IFINFO) {
2566 			sdl = (struct sockaddr_dl *)(ifm + 1);
2567 			if (strlen(ifn) == sdl->sdl_nlen &&
2568 				strncmp(ifn, sdl->sdl_data, sdl->sdl_nlen) == 0) {
2569 				ifIndex = ifm->ifm_index;
2570 				ifMTU = ifm->ifm_data.ifi_mtu;
2571 				break;
2572 			}
2573 		}
2574 	}
2575 	if (!ifIndex)
2576 		errx(1, "unknown interface name %s", ifn);
2577 	/*
2578 	 * Get interface address.
2579 	 */
2580 	sin = NULL;
2581 	while (next < lim) {
2582 		ifam = (struct ifa_msghdr *)next;
2583 		next += ifam->ifam_msglen;
2584 		if (ifam->ifam_version != RTM_VERSION) {
2585 			if (verbose)
2586 				warnx("routing message version %d "
2587 					"not understood", ifam->ifam_version);
2588 			continue;
2589 		}
2590 		if (ifam->ifam_type != RTM_NEWADDR)
2591 			break;
2592 		if (ifam->ifam_addrs & RTA_IFA) {
2593 			int i;
2594 			char *cp = (char *)(ifam + 1);
2595 
2596 			for (i = 1; i < RTA_IFA; i <<= 1) {
2597 				if (ifam->ifam_addrs & i)
2598 					cp += SA_SIZE((struct sockaddr *)cp);
2599 			}
2600 			if (((struct sockaddr *)cp)->sa_family == AF_INET) {
2601 				sin = (struct sockaddr_in *)cp;
2602 				break;
2603 			}
2604 		}
2605 	}
2606 	if (sin == NULL)
2607 		errx(1, "%s: cannot get interface address", ifn);
2608 
2609 	n->ip = sin->sin_addr;
2610 	strncpy(n->if_name, ifn, IF_NAMESIZE);
2611 
2612 	free(buf);
2613 }
2614 
2615 static int
2616 setup_redir_addr(char *spool_buf, int len, int *_ac, char ***_av)
2617 {
2618 	struct cfg_redir *r;
2619 	struct cfg_spool *tmp;
2620 	char **av, *sep;
2621 	char tmp_spool_buf[NAT_BUF_LEN];
2622 	int ac, i, space, lsnat;
2623 
2624 	i=0;
2625 	av = *_av;
2626 	ac = *_ac;
2627 	space = 0;
2628 	lsnat = 0;
2629 	if (len >= SOF_REDIR) {
2630 		r = (struct cfg_redir *)spool_buf;
2631 		/* Skip cfg_redir at beginning of buf. */
2632 		spool_buf = &spool_buf[SOF_REDIR];
2633 		space = SOF_REDIR;
2634 		len -= SOF_REDIR;
2635 	} else {
2636 		goto nospace;
2637 	}
2638 
2639 	r->mode = REDIR_ADDR;
2640 	/* Extract local address. */
2641 	if (ac == 0)
2642 		errx(EX_DATAERR, "redirect_addr: missing local address");
2643 
2644 	sep = strchr(*av, ',');
2645 	if (sep) {		/* LSNAT redirection syntax. */
2646 		r->laddr.s_addr = INADDR_NONE;
2647 		/* Preserve av, copy spool servers to tmp_spool_buf. */
2648 		strncpy(tmp_spool_buf, *av, strlen(*av)+1);
2649 		lsnat = 1;
2650 	} else {
2651 		str2addr(*av, &r->laddr);
2652 	}
2653 	INC_ARGCV();
2654 
2655 	/* Extract public address. */
2656 	if (ac == 0)
2657 		errx(EX_DATAERR, "redirect_addr: missing public address");
2658 
2659 	str2addr(*av, &r->paddr);
2660 	INC_ARGCV();
2661 
2662 	/* Setup LSNAT server pool. */
2663 	if (sep) {
2664 		sep = strtok(tmp_spool_buf, ", ");
2665 		while (sep != NULL) {
2666 			tmp = (struct cfg_spool *)spool_buf;
2667 			if (len < SOF_SPOOL)
2668 				goto nospace;
2669 
2670 			len -= SOF_SPOOL;
2671 			space += SOF_SPOOL;
2672 			str2addr(sep, &tmp->addr);
2673 			tmp->port = ~0;
2674 			r->spool_cnt++;
2675 			/* Point to the next possible cfg_spool. */
2676 			spool_buf = &spool_buf[SOF_SPOOL];
2677 			sep = strtok(NULL, ", ");
2678 		}
2679 	}
2680 	return(space);
2681 
2682 nospace:
2683 	errx(EX_DATAERR, "redirect_addr: buf is too small\n");
2684 }
2685 
2686 static int
2687 setup_redir_port(char *spool_buf, int len, int *_ac, char ***_av)
2688 {
2689 	char **av, *sep, *protoName;
2690 	char tmp_spool_buf[NAT_BUF_LEN];
2691 	int ac, space, lsnat;
2692 	struct cfg_redir *r;
2693 	struct cfg_spool *tmp;
2694 	u_short numLocalPorts;
2695 	port_range portRange;
2696 
2697 	av = *_av;
2698 	ac = *_ac;
2699 	space = 0;
2700 	lsnat = 0;
2701 	numLocalPorts = 0;
2702 
2703 	if (len >= SOF_REDIR) {
2704 		r = (struct cfg_redir *)spool_buf;
2705 		/* Skip cfg_redir at beginning of buf. */
2706 		spool_buf = &spool_buf[SOF_REDIR];
2707 		space = SOF_REDIR;
2708 		len -= SOF_REDIR;
2709 	} else {
2710 		goto nospace;
2711 	}
2712 
2713 	r->mode = REDIR_PORT;
2714 	/*
2715 	 * Extract protocol.
2716 	 */
2717 	if (ac == 0)
2718 		errx (EX_DATAERR, "redirect_port: missing protocol");
2719 
2720 	r->proto = str2proto(*av);
2721 	protoName = *av;
2722 	INC_ARGCV();
2723 
2724 	/*
2725 	 * Extract local address.
2726 	 */
2727 	if (ac == 0)
2728 		errx (EX_DATAERR, "redirect_port: missing local address");
2729 
2730 	sep = strchr(*av, ',');
2731 	/* LSNAT redirection syntax. */
2732 	if (sep) {
2733 		r->laddr.s_addr = INADDR_NONE;
2734 		r->lport = ~0;
2735 		numLocalPorts = 1;
2736 		/* Preserve av, copy spool servers to tmp_spool_buf. */
2737 		strncpy(tmp_spool_buf, *av, strlen(*av)+1);
2738 		lsnat = 1;
2739 	} else {
2740 		if (str2addr_portrange (*av, &r->laddr, protoName, &portRange) != 0)
2741 			errx(EX_DATAERR, "redirect_port:"
2742 				"invalid local port range");
2743 
2744 		r->lport = GETLOPORT(portRange);
2745 		numLocalPorts = GETNUMPORTS(portRange);
2746 	}
2747 	INC_ARGCV();
2748 
2749 	/*
2750 	 * Extract public port and optionally address.
2751 	 */
2752 	if (ac == 0)
2753 		errx (EX_DATAERR, "redirect_port: missing public port");
2754 
2755 	sep = strchr (*av, ':');
2756 	if (sep) {
2757 		if (str2addr_portrange (*av, &r->paddr, protoName, &portRange) != 0)
2758 			errx(EX_DATAERR, "redirect_port:"
2759 				"invalid public port range");
2760 	} else {
2761 		r->paddr.s_addr = INADDR_ANY;
2762 		if (str2portrange(*av, protoName, &portRange) != 0)
2763 			errx(EX_DATAERR, "redirect_port:"
2764 				"invalid public port range");
2765 	}
2766 
2767 	r->pport = GETLOPORT(portRange);
2768 	r->pport_cnt = GETNUMPORTS(portRange);
2769 	INC_ARGCV();
2770 
2771 	/*
2772 	 * Extract remote address and optionally port.
2773 	 */
2774 	/*
2775 	 * NB: isalpha(**av) => we've to check that next parameter is really an
2776 	 * option for this redirect entry, else stop here processing arg[cv].
2777 	 */
2778 	if (ac != 0 && !isalpha(**av)) {
2779 		sep = strchr (*av, ':');
2780 		if (sep) {
2781 			if (str2addr_portrange (*av, &r->raddr,
2782 				protoName, &portRange) != 0)
2783 				errx(EX_DATAERR, "redirect_port:"
2784 					"invalid remote port range");
2785 		} else {
2786 			SETLOPORT(portRange, 0);
2787 			SETNUMPORTS(portRange, 1);
2788 			str2addr (*av, &r->raddr);
2789 		}
2790 		INC_ARGCV();
2791 	} else {
2792 		SETLOPORT(portRange, 0);
2793 		SETNUMPORTS(portRange, 1);
2794 		r->raddr.s_addr = INADDR_ANY;
2795 	}
2796 	r->rport = GETLOPORT(portRange);
2797 	r->rport_cnt = GETNUMPORTS(portRange);
2798 
2799 	/*
2800 	 * Make sure port ranges match up, then add the redirect ports.
2801 	 */
2802 	if (numLocalPorts != r->pport_cnt)
2803 		errx(EX_DATAERR, "redirect_port:"
2804 			"port ranges must be equal in size");
2805 
2806 	/* Remote port range is allowed to be '0' which means all ports. */
2807 	if (r->rport_cnt != numLocalPorts &&
2808 		(r->rport_cnt != 1 || r->rport != 0))
2809 			errx(EX_DATAERR, "redirect_port: remote port must"
2810 				"be 0 or equal to local port range in size");
2811 
2812 	/*
2813 	 * Setup LSNAT server pool.
2814 	 */
2815 	if (lsnat) {
2816 		sep = strtok(tmp_spool_buf, ", ");
2817 		while (sep != NULL) {
2818 			tmp = (struct cfg_spool *)spool_buf;
2819 			if (len < SOF_SPOOL)
2820 				goto nospace;
2821 
2822 			len -= SOF_SPOOL;
2823 			space += SOF_SPOOL;
2824 			if (str2addr_portrange(sep,
2825 				&tmp->addr, protoName, &portRange) != 0)
2826 				errx(EX_DATAERR, "redirect_port:"
2827 					"invalid local port range");
2828 			if (GETNUMPORTS(portRange) != 1)
2829 				errx(EX_DATAERR, "redirect_port: local port"
2830 					"must be single in this context");
2831 			tmp->port = GETLOPORT(portRange);
2832 			r->spool_cnt++;
2833 			/* Point to the next possible cfg_spool. */
2834 			spool_buf = &spool_buf[SOF_SPOOL];
2835 			sep = strtok(NULL, ", ");
2836 		}
2837 	}
2838 	return (space);
2839 
2840 nospace:
2841 	errx(EX_DATAERR, "redirect_port: buf is too small\n");
2842 }
2843 
2844 static int
2845 setup_redir_proto(char *spool_buf, int len, int *_ac, char ***_av)
2846 {
2847 	struct protoent *protoent;
2848 	struct cfg_redir *r;
2849 	int ac, i, space;
2850 	char **av;
2851 
2852 	i=0;
2853 	av = *_av;
2854 	ac = *_ac;
2855 	if (len >= SOF_REDIR) {
2856 		r = (struct cfg_redir *)spool_buf;
2857 		/* Skip cfg_redir at beginning of buf. */
2858 		spool_buf = &spool_buf[SOF_REDIR];
2859 		space = SOF_REDIR;
2860 		len -= SOF_REDIR;
2861 	} else {
2862 		goto nospace;
2863 	}
2864 	r->mode = REDIR_PROTO;
2865 	/*
2866 	 * Extract protocol.
2867 	 */
2868 	if (ac == 0)
2869 		errx(EX_DATAERR, "redirect_proto: missing protocol");
2870 
2871 	protoent = getprotobyname(*av);
2872 	if (protoent == NULL)
2873 		errx(EX_DATAERR, "redirect_proto: unknown protocol %s", *av);
2874 	else
2875 		r->proto = protoent->p_proto;
2876 
2877 	INC_ARGCV();
2878 
2879 	/*
2880 	 * Extract local address.
2881 	 */
2882 	if (ac == 0)
2883 		errx(EX_DATAERR, "redirect_proto: missing local address");
2884 	else
2885 		str2addr(*av, &r->laddr);
2886 	INC_ARGCV();
2887 
2888 	/*
2889 	 * Extract optional public address.
2890 	 */
2891 	if (ac == 0) {
2892 		r->paddr.s_addr = INADDR_ANY;
2893 		r->raddr.s_addr = INADDR_ANY;
2894 	} else {
2895 		/* see above in setup_redir_port() */
2896 		if (!isalpha(**av)) {
2897 			str2addr(*av, &r->paddr);
2898 			INC_ARGCV();
2899 
2900 			/*
2901 			 * Extract optional remote address.
2902 			 */
2903 			/* see above in setup_redir_port() */
2904 			if (ac != 0 && !isalpha(**av)) {
2905 				str2addr(*av, &r->raddr);
2906 				INC_ARGCV();
2907 			}
2908 		}
2909 	}
2910 	return (space);
2911 
2912 nospace:
2913 	errx(EX_DATAERR, "redirect_proto: buf is too small\n");
2914 }
2915 
2916 static void
2917 show_nat_config(char *buf) {
2918 	struct cfg_nat *n;
2919 	struct cfg_redir *t;
2920 	struct cfg_spool *s;
2921 	struct protoent *p;
2922 	int i, cnt, flag, off;
2923 
2924 	n = (struct cfg_nat *)buf;
2925 	flag = 1;
2926 	off = sizeof(*n);
2927 	printf("ipfw nat %u config", n->id);
2928 	if (strlen(n->if_name) != 0)
2929 		printf(" if %s", n->if_name);
2930 	else if (n->ip.s_addr != 0)
2931 		printf(" ip %s", inet_ntoa(n->ip));
2932 	while (n->mode != 0) {
2933 		if (n->mode & PKT_ALIAS_LOG) {
2934 			printf(" log");
2935 			n->mode &= ~PKT_ALIAS_LOG;
2936 		} else if (n->mode & PKT_ALIAS_DENY_INCOMING) {
2937 			printf(" deny_in");
2938 			n->mode &= ~PKT_ALIAS_DENY_INCOMING;
2939 		} else if (n->mode & PKT_ALIAS_SAME_PORTS) {
2940 			printf(" same_ports");
2941 			n->mode &= ~PKT_ALIAS_SAME_PORTS;
2942 		} else if (n->mode & PKT_ALIAS_UNREGISTERED_ONLY) {
2943 			printf(" unreg_only");
2944 			n->mode &= ~PKT_ALIAS_UNREGISTERED_ONLY;
2945 		} else if (n->mode & PKT_ALIAS_RESET_ON_ADDR_CHANGE) {
2946 			printf(" reset");
2947 			n->mode &= ~PKT_ALIAS_RESET_ON_ADDR_CHANGE;
2948 		} else if (n->mode & PKT_ALIAS_REVERSE) {
2949 			printf(" reverse");
2950 			n->mode &= ~PKT_ALIAS_REVERSE;
2951 		} else if (n->mode & PKT_ALIAS_PROXY_ONLY) {
2952 			printf(" proxy_only");
2953 			n->mode &= ~PKT_ALIAS_PROXY_ONLY;
2954 		}
2955 	}
2956 	/* Print all the redirect's data configuration. */
2957 	for (cnt = 0; cnt < n->redir_cnt; cnt++) {
2958 		t = (struct cfg_redir *)&buf[off];
2959 		off += SOF_REDIR;
2960 		switch (t->mode) {
2961 		case REDIR_ADDR:
2962 			printf(" redirect_addr");
2963 			if (t->spool_cnt == 0)
2964 				printf(" %s", inet_ntoa(t->laddr));
2965 			else
2966 				for (i = 0; i < t->spool_cnt; i++) {
2967 					s = (struct cfg_spool *)&buf[off];
2968 					if (i)
2969 						printf(", ");
2970 					else
2971 						printf(" ");
2972 					printf("%s", inet_ntoa(s->addr));
2973 					off += SOF_SPOOL;
2974 				}
2975 			printf(" %s", inet_ntoa(t->paddr));
2976 			break;
2977 		case REDIR_PORT:
2978 			p = getprotobynumber(t->proto);
2979 			printf(" redirect_port %s ", p->p_name);
2980 			if (!t->spool_cnt) {
2981 				printf("%s:%u", inet_ntoa(t->laddr), t->lport);
2982 				if (t->pport_cnt > 1)
2983 					printf("-%u", t->lport + t->pport_cnt - 1);
2984 			} else
2985 				for (i=0; i < t->spool_cnt; i++) {
2986 					s = (struct cfg_spool *)&buf[off];
2987 					if (i)
2988 						printf(", ");
2989 					printf("%s:%u", inet_ntoa(s->addr), s->port);
2990 					off += SOF_SPOOL;
2991 				}
2992 
2993 			printf(" ");
2994 			if (t->paddr.s_addr)
2995 				printf("%s:", inet_ntoa(t->paddr));
2996 			printf("%u", t->pport);
2997 			if (!t->spool_cnt && t->pport_cnt > 1)
2998 				printf("-%u", t->pport + t->pport_cnt - 1);
2999 
3000 			if (t->raddr.s_addr) {
3001 				printf(" %s", inet_ntoa(t->raddr));
3002 				if (t->rport) {
3003 					printf(":%u", t->rport);
3004 					if (!t->spool_cnt && t->rport_cnt > 1)
3005 						printf("-%u", t->rport +
3006 							t->rport_cnt - 1);
3007 				}
3008 			}
3009 			break;
3010 		case REDIR_PROTO:
3011 			p = getprotobynumber(t->proto);
3012 			printf(" redirect_proto %s %s", p->p_name,
3013 				inet_ntoa(t->laddr));
3014 			if (t->paddr.s_addr != 0) {
3015 				printf(" %s", inet_ntoa(t->paddr));
3016 				if (t->raddr.s_addr)
3017 					printf(" %s", inet_ntoa(t->raddr));
3018 			}
3019 			break;
3020 		default:
3021 			errx(EX_DATAERR, "unknown redir mode");
3022 			break;
3023 		}
3024 	}
3025 	printf("\n");
3026 }
3027 
3028 
3029 static void
3030 show_nat(int ac, char **av) {
3031 	struct cfg_nat *n;
3032 	struct cfg_redir *e;
3033 	int i, nbytes, nalloc, size;
3034 	int nat_cnt, redir_cnt, nat_id;
3035 	uint8_t *data;
3036 
3037 	nalloc = 1024;
3038 	size = 0;
3039 	data = NULL;
3040 
3041 	NEXT_ARG;
3042 
3043 	if (ac == 0)
3044 		nat_id = 0;
3045 	else
3046 		nat_id = strtoul(*av, NULL, 10);
3047 
3048 	nbytes = nalloc;
3049 	while (nbytes >= nalloc) {
3050 		nalloc = nalloc * 2;
3051 		nbytes = nalloc;
3052 		if ((data = realloc(data, nbytes)) == NULL) {
3053 			err(EX_OSERR, "realloc");
3054 		}
3055 		if (do_get_x(IP_FW_NAT_GET, data, &nbytes) < 0) {
3056 			err(EX_OSERR, "do_get_x(IP_FW_NAT_GET)");
3057 		}
3058 	}
3059 
3060 	if (nbytes == 0) {
3061 		exit(EX_OK);
3062 	}
3063 
3064 	nat_cnt = *((int *)data);
3065 	for (i = sizeof(nat_cnt); nat_cnt; nat_cnt--) {
3066 		n = (struct cfg_nat *)&data[i];
3067 		if (n->id >= 0 && n->id <= IPFW_DEFAULT_RULE) {
3068 			if (nat_id == 0 || n->id == nat_id)
3069 				show_nat_config(&data[i]);
3070 		}
3071 		i += sizeof(struct cfg_nat);
3072 		for (redir_cnt = 0; redir_cnt < n->redir_cnt; redir_cnt++) {
3073 			e = (struct cfg_redir *)&data[i];
3074 			i += sizeof(struct cfg_redir) +
3075 				e->spool_cnt * sizeof(struct cfg_spool);
3076 		}
3077 	}
3078 }
3079 
3080 int
3081 get_kern_boottime(void)
3082 {
3083 	struct timeval boottime;
3084 	size_t size;
3085 	int mib[2];
3086 	mib[0] = CTL_KERN;
3087 	mib[1] = KERN_BOOTTIME;
3088 	size = sizeof(boottime);
3089 	if (sysctl(mib, 2, &boottime, &size, NULL, 0) != -1 &&
3090 			boottime.tv_sec != 0) {
3091 		return boottime.tv_sec;
3092 	}
3093 	return -1;
3094 }
3095 
3096 void
3097 show_nat_state(int ac, char **av)
3098 {
3099 	int nbytes, nalloc;
3100 	int nat_id;
3101 	uint8_t *data;
3102 
3103 	nalloc = 1024;
3104 	data = NULL;
3105 
3106 	NEXT_ARG;
3107 	if (ac == 0)
3108 		nat_id = 0;
3109 	else
3110 		nat_id = strtoul(*av, NULL, 10);
3111 
3112 	nbytes = nalloc;
3113 	while (nbytes >= nalloc) {
3114 		nalloc = nalloc * 2;
3115 		nbytes = nalloc;
3116 		if ((data = realloc(data, nbytes)) == NULL) {
3117 			err(EX_OSERR, "realloc");
3118 		}
3119 		memcpy(data, &nat_id, sizeof(int));
3120 		if (do_get_x(IP_FW_NAT_LOG, data, &nbytes) < 0) {
3121 			err(EX_OSERR, "do_get_x(IP_FW_NAT_GET_STATE)");
3122 		}
3123 	}
3124 	if (nbytes == 0)
3125 		exit(EX_OK);
3126 	struct ipfw_ioc_nat_state *nat_state;
3127 	nat_state =(struct ipfw_ioc_nat_state *)data;
3128 	int count = nbytes / sizeof( struct ipfw_ioc_nat_state);
3129 	int i, uptime_sec;
3130 	uptime_sec = get_kern_boottime();
3131 	for (i = 0; i < count; i ++) {
3132 		struct protoent *pe = getprotobynumber(nat_state->link_type);
3133 		printf("%s ", pe->p_name);
3134 		printf("%s:%hu => ",inet_ntoa(nat_state->src_addr),
3135 				htons(nat_state->src_port));
3136 		printf("%s:%hu",inet_ntoa(nat_state->alias_addr),
3137 				htons(nat_state->alias_port));
3138 		printf(" -> %s:%hu ",inet_ntoa(nat_state->dst_addr),
3139 				htons(nat_state->dst_port));
3140 		if (do_time == 1) {
3141 			char timestr[30];
3142 			time_t t = _long_to_time(uptime_sec + nat_state->timestamp);
3143 			strcpy(timestr, ctime(&t));
3144 			*strchr(timestr, '\n') = '\0';
3145 			printf("%s ", timestr);
3146 		} else if (do_time == 2) {
3147 			printf( "%10u ", uptime_sec + nat_state->timestamp);
3148 		}
3149 		printf("\n");
3150 		nat_state++;
3151 	}
3152 }
3153 
3154 /*
3155  * do_set_x - extended version og do_set
3156  * insert a x_header in the beginning of the rule buf
3157  * and call setsockopt() with IP_FW_X.
3158  */
3159 int
3160 do_set_x(int optname, void *rule, int optlen)
3161 {
3162 	int len, *newbuf;
3163 
3164 	ip_fw_x_header *x_header;
3165 	if (ipfw_socket < 0)
3166 		err(EX_UNAVAILABLE, "socket not avaialble");
3167 	len = optlen + sizeof(ip_fw_x_header);
3168 	newbuf = malloc(len);
3169 	if (newbuf == NULL)
3170 		err(EX_OSERR, "malloc newbuf in do_set_x");
3171 	bzero(newbuf, len);
3172 	x_header = (ip_fw_x_header *)newbuf;
3173 	x_header->opcode = optname;
3174 	/* copy the rule into the newbuf, just after the x_header*/
3175 	bcopy(rule, ++x_header, optlen);
3176 	return setsockopt(ipfw_socket, IPPROTO_IP, IP_FW_X, newbuf, len);
3177 }
3178 
3179 /*
3180  * same as do_set_x
3181  */
3182 int
3183 do_get_x(int optname, void *rule, int *optlen)
3184 {
3185 	int len, *newbuf, retval;
3186 
3187 	ip_fw_x_header *x_header;
3188 	if (ipfw_socket < 0)
3189 		err(EX_UNAVAILABLE, "socket not avaialble");
3190 	len = *optlen + sizeof(ip_fw_x_header);
3191 	newbuf = malloc(len);
3192 	if (newbuf == NULL)
3193 		err(EX_OSERR, "malloc newbuf in do_get_x");
3194 	bzero(newbuf, len);
3195 	x_header = (ip_fw_x_header *)newbuf;
3196 	x_header->opcode = optname;
3197 	/* copy the rule into the newbuf, just after the x_header*/
3198 	bcopy(rule, ++x_header, *optlen);
3199 	retval = getsockopt(ipfw_socket, IPPROTO_IP, IP_FW_X, newbuf, &len);
3200 	bcopy(newbuf, rule, len);
3201 	*optlen=len;
3202 	return retval;
3203 }
3204 
3205 static void
3206 config_nat(int ac, char **av)
3207 {
3208 	struct cfg_nat *n; 			 /* Nat instance configuration. */
3209 	int i, len, off, tok;
3210 	char *id, buf[NAT_BUF_LEN]; 	/* Buffer for serialized data. */
3211 
3212 	len = NAT_BUF_LEN;
3213 	/* Offset in buf: save space for n at the beginning. */
3214 	off = sizeof(struct cfg_nat);
3215 	memset(buf, 0, sizeof(buf));
3216 	n = (struct cfg_nat *)buf;
3217 
3218 	NEXT_ARG;
3219 	/* Nat id. */
3220 	if (ac && isdigit(**av)) {
3221 		id = *av;
3222 		i = atoi(*av);
3223 		NEXT_ARG;
3224 		n->id = i;
3225 	} else
3226 		errx(EX_DATAERR, "missing nat id");
3227 	if (ac == 0)
3228 		errx(EX_DATAERR, "missing option");
3229 
3230 	while (ac > 0) {
3231 		tok = match_token(nat_params, *av);
3232 		NEXT_ARG;
3233 		switch (tok) {
3234 		case TOK_IP:
3235 			if (ac == 0)
3236 				errx(EX_DATAERR, "missing option");
3237 			if (!inet_aton(av[0], &(n->ip)))
3238 				errx(EX_DATAERR, "bad ip address ``%s''",
3239 					av[0]);
3240 			NEXT_ARG;
3241 			break;
3242 		case TOK_IF:
3243 			if (ac == 0)
3244 				errx(EX_DATAERR, "missing option");
3245 			set_addr_dynamic(av[0], n);
3246 			NEXT_ARG;
3247 			break;
3248 		case TOK_ALOG:
3249 			n->mode |= PKT_ALIAS_LOG;
3250 			break;
3251 		case TOK_DENY_INC:
3252 			n->mode |= PKT_ALIAS_DENY_INCOMING;
3253 			break;
3254 		case TOK_SAME_PORTS:
3255 			n->mode |= PKT_ALIAS_SAME_PORTS;
3256 			break;
3257 		case TOK_UNREG_ONLY:
3258 			n->mode |= PKT_ALIAS_UNREGISTERED_ONLY;
3259 			break;
3260 		case TOK_RESET_ADDR:
3261 			n->mode |= PKT_ALIAS_RESET_ON_ADDR_CHANGE;
3262 			break;
3263 		case TOK_ALIAS_REV:
3264 			n->mode |= PKT_ALIAS_REVERSE;
3265 			break;
3266 		case TOK_PROXY_ONLY:
3267 			n->mode |= PKT_ALIAS_PROXY_ONLY;
3268 			break;
3269 			/*
3270 			 * All the setup_redir_* functions work directly in the final
3271 			 * buffer, see above for details.
3272 			 */
3273 		case TOK_REDIR_ADDR:
3274 		case TOK_REDIR_PORT:
3275 		case TOK_REDIR_PROTO:
3276 			switch (tok) {
3277 			case TOK_REDIR_ADDR:
3278 				i = setup_redir_addr(&buf[off], len, &ac, &av);
3279 				break;
3280 			case TOK_REDIR_PORT:
3281 				i = setup_redir_port(&buf[off], len, &ac, &av);
3282 				break;
3283 			case TOK_REDIR_PROTO:
3284 				i = setup_redir_proto(&buf[off], len, &ac, &av);
3285 				break;
3286 			}
3287 			n->redir_cnt++;
3288 			off += i;
3289 			len -= i;
3290 			break;
3291 		default:
3292 			errx(EX_DATAERR, "unrecognised option ``%s''", av[-1]);
3293 		}
3294 	}
3295 	i = do_set_x(IP_FW_NAT_CFG, buf, off);
3296 	if (i)
3297 		err(1, "do_set_x(%s)", "IP_FW_NAT_CFG");
3298 
3299 	/* After every modification, we show the resultant rule. */
3300 	int _ac = 2;
3301 	char *_av[] = {"config", id};
3302 	show_nat(_ac, _av);
3303 }
3304 
3305 
3306 static int
3307 ipfw_main(int ac, char **av)
3308 {
3309 	int ch;
3310 
3311 	if (ac == 1)
3312 		help();
3313 
3314 	/* Set the force flag for non-interactive processes */
3315 	do_force = !isatty(STDIN_FILENO);
3316 
3317 	optind = optreset = 1;
3318 	while ((ch = getopt(ac, av, "hs:acdDefNStTv")) != -1)
3319 		switch (ch) {
3320 		case 'h': /* help */
3321 			help();
3322 			break; 	/* NOTREACHED */
3323 
3324 		case 's': /* sort */
3325 			do_sort = atoi(optarg);
3326 			break;
3327 		case 'a':
3328 			do_acct = 1;
3329 			break;
3330 		case 'c':
3331 			do_compact = 1;
3332 			break;
3333 		case 'd':
3334 			do_dynamic = 1;
3335 			break;
3336 		case 'D':
3337 			do_dynamic = 2;
3338 			break;
3339 		case 'e':
3340 			do_expired = 1;
3341 			break;
3342 		case 'f':
3343 			do_force = 1;
3344 			break;
3345 		case 'N':
3346 			do_resolv = 1;
3347 			break;
3348 		case 'S':
3349 			show_sets = 1;
3350 			break;
3351 		case 't':
3352 			do_time = 1;
3353 			break;
3354 		case 'T':
3355 			do_time = 2;
3356 			break;
3357 		case 'v':
3358 			do_quiet = 0;
3359 			verbose++;
3360 			break;
3361 		default:
3362 			help();
3363 		}
3364 
3365 	ac -= optind;
3366 	av += optind;
3367 	NEED1("bad arguments, for usage summary ``ipfw''");
3368 
3369 	/*
3370 	 * optional: pipe or queue or nat
3371 	 */
3372 	do_nat = 0;
3373 	do_pipe = 0;
3374 	if (!strncmp(*av, "nat", strlen(*av)))
3375 		do_nat = 1;
3376 	else if (!strncmp(*av, "pipe", strlen(*av))) {
3377 		do_pipe = 1;
3378 	} else if (!strncmp(*av, "queue", strlen(*av))) {
3379 		do_pipe = 2;
3380 	}
3381 	NEED1("missing command");
3382 
3383 	/*
3384 	 * for pipes and queues and nat we normally say 'pipe NN config'
3385 	 * but the code is easier to parse as 'pipe config NN'
3386 	 * so we swap the two arguments.
3387 	 */
3388 	if ((do_pipe || do_nat) && ac > 2 && isdigit(*(av[1]))) {
3389 		char *p = av[1];
3390 		av[1] = av[2];
3391 		av[2] = p;
3392 	}
3393 
3394 	if (!strncmp(*av, "add", strlen(*av))) {
3395 		load_modules();
3396 		add(ac, av);
3397 	} else if (!strncmp(*av, "delete", strlen(*av))) {
3398 		delete_rules(ac, av);
3399 	} else if (!strncmp(*av, "flush", strlen(*av))) {
3400 		flush();
3401 	} else if (!strncmp(*av, "list", strlen(*av))) {
3402 		load_modules();
3403 		list(ac, av);
3404 	} else if (!strncmp(*av, "show", strlen(*av))) {
3405 		do_acct++;
3406 		load_modules();
3407 		list(ac, av);
3408 	} else if (!strncmp(*av, "zero", strlen(*av))) {
3409 		zero(ac, av);
3410 	} else if (!strncmp(*av, "set", strlen(*av))) {
3411 		sets_handler(ac, av);
3412 	} else if (!strncmp(*av, "module", strlen(*av))) {
3413 		NEXT_ARG;
3414 		if (!strncmp(*av, "show", strlen(*av)) ||
3415 			!strncmp(*av, "show", strlen(*av))) {
3416 			list_modules(ac, av);
3417 		} else {
3418 			errx(EX_USAGE, "bad ipfw module command `%s'", *av);
3419 		}
3420 	} else if (!strncmp(*av, "resetlog", strlen(*av))) {
3421 		resetlog(ac, av);
3422 	} else if (!strncmp(*av, "log", strlen(*av))) {
3423 		NEXT_ARG;
3424 		if (!strncmp(*av, "reset", strlen(*av))) {
3425 			resetlog(ac, av);
3426 		} else if (!strncmp(*av, "off", strlen(*av))) {
3427 
3428 		} else if (!strncmp(*av, "on", strlen(*av))) {
3429 
3430 		} else {
3431 			errx(EX_USAGE, "bad command `%s'", *av);
3432 		}
3433 	} else if (!strncmp(*av, "nat", strlen(*av))) {
3434 		NEXT_ARG;
3435 		if (!strncmp(*av, "config", strlen(*av))) {
3436 			config_nat(ac, av);
3437 		} else if (!strncmp(*av, "flush", strlen(*av))) {
3438 			flush();
3439 		} else if (!strncmp(*av, "show", strlen(*av)) ||
3440 				!strncmp(*av, "list", strlen(*av))) {
3441 			if (ac > 2 && isdigit(*(av[1]))) {
3442 				char *p = av[1];
3443 				av[1] = av[2];
3444 				av[2] = p;
3445 			}
3446 			NEXT_ARG;
3447 			if (!strncmp(*av, "config", strlen(*av))) {
3448 				show_nat(ac, av);
3449 			} else if (!strncmp(*av, "state", strlen(*av))) {
3450 				show_nat_state(ac,av);
3451 			} else {
3452 				 errx(EX_USAGE,
3453 					"bad nat show command `%s'", *av);
3454 			}
3455 		} else if (!strncmp(*av, "delete", strlen(*av))) {
3456 			delete_nat_config(ac, av);
3457 		} else {
3458 			errx(EX_USAGE, "bad ipfw nat command `%s'", *av);
3459 		}
3460 	} else if (!strncmp(*av, "pipe", strlen(*av)) ||
3461 		!strncmp(*av, "queue", strlen(*av))) {
3462 		NEXT_ARG;
3463 		if (!strncmp(*av, "config", strlen(*av))) {
3464 			config_dummynet(ac, av);
3465 		} else if (!strncmp(*av, "flush", strlen(*av))) {
3466 			flush();
3467 		} else if (!strncmp(*av, "show", strlen(*av))) {
3468 			show_dummynet(ac, av);
3469 		} else {
3470 			errx(EX_USAGE, "bad ipfw pipe command `%s'", *av);
3471 		}
3472 	} else if (!strncmp(*av, "state", strlen(*av))) {
3473 		NEXT_ARG;
3474 		if (!strncmp(*av, "add", strlen(*av))) {
3475 			add_state(ac, av);
3476 		} else if (!strncmp(*av, "delete", strlen(*av))) {
3477 			delete_state(ac, av);
3478 		} else if (!strncmp(*av, "flush", strlen(*av))) {
3479 			flush_state(ac, av);
3480 		} else if (!strncmp(*av, "list", strlen(*av))) {
3481 			do_dynamic = 2;
3482 			list(ac, av);
3483 		} else if (!strncmp(*av, "show", strlen(*av))) {
3484 			do_acct = 1;
3485 			do_dynamic =2;
3486 			list(ac, av);
3487 		} else {
3488 			errx(EX_USAGE, "bad ipfw state command `%s'", *av);
3489 		}
3490 	} else if (!strncmp(*av, "table", strlen(*av))) {
3491 		if (ac > 2 && isdigit(*(av[1]))) {
3492 			char *p = av[1];
3493 			av[1] = av[2];
3494 			av[2] = p;
3495 		}
3496 		NEXT_ARG;
3497 		if (!strncmp(*av, "append", strlen(*av))) {
3498 			table_append(ac, av);
3499 		} else if (!strncmp(*av, "remove", strlen(*av))) {
3500 			table_remove(ac, av);
3501 		} else if (!strncmp(*av, "flush", strlen(*av))) {
3502 			table_flush(ac, av);
3503 		} else if (!strncmp(*av, "list", strlen(*av))) {
3504 			table_list(ac, av);
3505 		} else if (!strncmp(*av, "show", strlen(*av))) {
3506 			table_show(ac, av);
3507 		} else if (!strncmp(*av, "type", strlen(*av))) {
3508 			table_create(ac, av);
3509 		} else if (!strncmp(*av, "delete", strlen(*av))) {
3510 			table_delete(ac, av);
3511 		} else if (!strncmp(*av, "test", strlen(*av))) {
3512 			table_test(ac,av);
3513 		} else if (!strncmp(*av, "name", strlen(*av))) {
3514 			table_rename(ac, av);
3515 		} else {
3516 			errx(EX_USAGE, "bad ipfw table command `%s'", *av);
3517 		}
3518 
3519 	} else {
3520 		errx(EX_USAGE, "bad ipfw command `%s'", *av);
3521 	}
3522 	return 0;
3523 }
3524 
3525 static void
3526 ipfw_readfile(int ac, char *av[])
3527 {
3528 	char	buf[BUFSIZ];
3529 	char	*a, *p, *args[MAX_ARGS], *cmd = NULL;
3530 	char	linename[10];
3531 	int	i=0, lineno=0, qflag=0, pflag=0, status;
3532 	FILE	*f = NULL;
3533 	pid_t	preproc = 0;
3534 	int	c;
3535 
3536 	while ((c = getopt(ac, av, "D:U:p:q")) != -1) {
3537 		switch (c) {
3538 		case 'D':
3539 			if (!pflag)
3540 				errx(EX_USAGE, "-D requires -p");
3541 			if (i > MAX_ARGS - 2)
3542 				errx(EX_USAGE, "too many -D or -U options");
3543 			args[i++] = "-D";
3544 			args[i++] = optarg;
3545 			break;
3546 
3547 		case 'U':
3548 			if (!pflag)
3549 				errx(EX_USAGE, "-U requires -p");
3550 			if (i > MAX_ARGS - 2)
3551 				errx(EX_USAGE, "too many -D or -U options");
3552 			args[i++] = "-U";
3553 			args[i++] = optarg;
3554 			break;
3555 
3556 		case 'p':
3557 			pflag = 1;
3558 			cmd = optarg;
3559 			args[0] = cmd;
3560 			i = 1;
3561 			break;
3562 
3563 		case 'q':
3564 			qflag = 1;
3565 			break;
3566 
3567 		default:
3568 			errx(EX_USAGE, "bad arguments, for usage"
3569 			    " summary ``ipfw''");
3570 		}
3571 	}
3572 
3573 	av += optind;
3574 	ac -= optind;
3575 	if (ac != 1)
3576 		errx(EX_USAGE, "extraneous filename arguments");
3577 
3578 	if ((f = fopen(av[0], "r")) == NULL)
3579 		err(EX_UNAVAILABLE, "fopen: %s", av[0]);
3580 
3581 	if (pflag) {
3582 		/* pipe through preprocessor (cpp or m4) */
3583 		int pipedes[2];
3584 
3585 		args[i] = NULL;
3586 
3587 		if (pipe(pipedes) == -1)
3588 			err(EX_OSERR, "cannot create pipe");
3589 
3590 		switch ((preproc = fork())) {
3591 		case -1:
3592 			err(EX_OSERR, "cannot fork");
3593 
3594 		case 0:
3595 			/* child */
3596 			if (dup2(fileno(f), 0) == -1 ||
3597 			    dup2(pipedes[1], 1) == -1) {
3598 				err(EX_OSERR, "dup2()");
3599 			}
3600 			fclose(f);
3601 			close(pipedes[1]);
3602 			close(pipedes[0]);
3603 			execvp(cmd, args);
3604 			err(EX_OSERR, "execvp(%s) failed", cmd);
3605 
3606 		default:
3607 			/* parent */
3608 			fclose(f);
3609 			close(pipedes[1]);
3610 			if ((f = fdopen(pipedes[0], "r")) == NULL) {
3611 				int savederrno = errno;
3612 
3613 				kill(preproc, SIGTERM);
3614 				errno = savederrno;
3615 				err(EX_OSERR, "fdopen()");
3616 			}
3617 		}
3618 	}
3619 
3620 	while (fgets(buf, BUFSIZ, f)) {
3621 		lineno++;
3622 		sprintf(linename, "Line %d", lineno);
3623 		args[0] = linename;
3624 
3625 		if (*buf == '#')
3626 			continue;
3627 		if ((p = strchr(buf, '#')) != NULL)
3628 			*p = '\0';
3629 		i = 1;
3630 		if (qflag)
3631 			args[i++] = "-q";
3632 		for (a = strtok(buf, WHITESP); a && i < MAX_ARGS;
3633 			a = strtok(NULL, WHITESP), i++) {
3634 			args[i] = a;
3635 		}
3636 
3637 		if (i == (qflag? 2: 1))
3638 			continue;
3639 		if (i == MAX_ARGS)
3640 			errx(EX_USAGE, "%s: too many arguments", linename);
3641 
3642 		args[i] = NULL;
3643 		ipfw_main(i, args);
3644 	}
3645 	fclose(f);
3646 	if (pflag) {
3647 		if (waitpid(preproc, &status, 0) == -1)
3648 			errx(EX_OSERR, "waitpid()");
3649 		if (WIFEXITED(status) && WEXITSTATUS(status) != EX_OK)
3650 			errx(EX_UNAVAILABLE, "preprocessor exited with status %d",
3651 				WEXITSTATUS(status));
3652 		else if (WIFSIGNALED(status))
3653 			errx(EX_UNAVAILABLE, "preprocessor exited with signal %d",
3654 				WTERMSIG(status));
3655 	}
3656 }
3657 
3658 int
3659 main(int ac, char *av[])
3660 {
3661 	ipfw_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
3662 	if (ipfw_socket < 0)
3663 		err(EX_UNAVAILABLE, "socket");
3664 
3665 	memset(keywords, 0, sizeof(struct ipfw_keyword) * KEYWORD_SIZE);
3666 	memset(mappings, 0, sizeof(struct ipfw_mapping) * MAPPING_SIZE);
3667 
3668 	prepare_default_funcs();
3669 
3670 	if (ac > 1 && av[ac - 1][0] == '/' && access(av[ac - 1], R_OK) == 0)
3671 		ipfw_readfile(ac, av);
3672 	else
3673 		ipfw_main(ac, av);
3674 	return EX_OK;
3675 }
3676