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