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