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