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